name: CI on: push: branches: - master pull_request: merge_group: permissions: contents: read env: HOMEBREW_DEVELOPER: 1 HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_ENV_HINTS: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 HOMEBREW_VERIFY_ATTESTATIONS: 1 defaults: run: shell: bash -xeuo pipefail {0} concurrency: group: "${{ github.ref }}" cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: syntax: if: github.repository_owner == 'Homebrew' runs-on: ubuntu-latest steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: false cask: false test-bot: false - name: Cache Bundler RubyGems uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ steps.set-up-homebrew.outputs.gems-path }} key: ${{ runner.os }}-rubygems-syntax-${{ steps.set-up-homebrew.outputs.gems-hash }} restore-keys: ${{ runner.os }}-rubygems-syntax- - name: Install Bundler RubyGems run: brew install-bundler-gems --groups=style,typecheck - name: Install shellcheck and shfmt run: brew install shellcheck shfmt - name: Cache style cache uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.cache/Homebrew/style key: syntax-style-cache-${{ github.sha }} restore-keys: syntax-style-cache- - run: brew style - run: brew typecheck - name: Check RuboCop filepaths working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}/Library/Homebrew run: | public_apis="$(git grep -l "@api public" -- :^sorbet/ :^vendor/ | sort)" rubocop_docs="$(yq '.Style/Documentation.Include[]' .rubocop.yml | sort)" if [[ "${public_apis}" != "${rubocop_docs}" ]]; then echo "All public Homebrew APIs should be included in the \`Style/Documentation\` RuboCop." echo "Add/remove the following paths from \`Library/Homebrew/.rubocop.yml\` as appropriate:" echo "${public_apis} ${rubocop_docs}" | tr ' ' '\n' | sort | uniq -u exit 1 fi tap-syntax: name: tap syntax needs: syntax if: github.repository_owner == 'Homebrew' runs-on: macos-14 steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: true cask: true test-bot: true - name: Cache Bundler RubyGems uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ steps.set-up-homebrew.outputs.gems-path }} key: ${{ runner.os }}-rubygems-tap-syntax-${{ steps.set-up-homebrew.outputs.gems-hash }} restore-keys: ${{ runner.os }}-rubygems-tap-syntax- - name: Install Bundler RubyGems run: brew install-bundler-gems --groups=style - name: Cache style cache uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.cache/Homebrew/style key: tap-syntax-style-cache-${{ github.sha }} restore-keys: tap-syntax-style-cache- - name: Run brew style on homebrew-core run: brew style homebrew/core - name: Set up all Homebrew taps run: | brew tap homebrew/command-not-found brew tap homebrew/portable-ruby # brew style doesn't like world writable directories sudo chmod -R g-w,o-w "$(brew --repo)/Library/Taps" - name: Run brew style on official taps run: | brew style homebrew/test-bot brew style homebrew/command-not-found \ homebrew/portable-ruby - name: Run brew style on homebrew/cask run: | brew style homebrew/cask formula-audit: name: formula audit needs: syntax if: github.repository_owner == 'Homebrew' && github.event_name != 'push' runs-on: ubuntu-latest container: image: ghcr.io/homebrew/brew:master steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: true cask: false test-bot: false - name: Run brew readall on homebrew/core run: brew readall --os=all --arch=all --aliases homebrew/core - name: Run brew audit --skip-style on homebrew/core run: brew audit --skip-style --except=version --tap=homebrew/core - name: Generate formula API run: brew generate-formula-api --dry-run cask-audit: name: cask audit needs: syntax if: github.repository_owner == 'Homebrew' && github.event_name != 'push' runs-on: macos-15 steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: true cask: true test-bot: false - name: Run brew readall on all casks run: brew readall --os=all --arch=all homebrew/cask - name: Run brew audit --skip-style on homebrew/cask run: | brew audit --skip-style --except=version --tap=homebrew/cask - name: Generate cask API run: brew generate-cask-api --dry-run vendored-gems: name: vendored gems needs: syntax runs-on: ubuntu-latest steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: false cask: false test-bot: false - name: Configure Git user uses: Homebrew/actions/git-user-config@master with: username: BrewTestBot # Can't cache this because we need to check that it doesn't fail the # "uncommitted RubyGems" step with a cold cache. - name: Install Bundler RubyGems run: brew install-bundler-gems --groups=all - name: Check for uncommitted RubyGems working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }} run: git diff --stat --exit-code Library/Homebrew/vendor/bundle/ruby update-test: name: ${{ matrix.name }} runs-on: ${{ matrix.runs-on }} needs: syntax if: github.event_name != 'push' strategy: matrix: include: - name: update-test (Ubuntu) runs-on: ubuntu-latest - name: update-test (macOS) runs-on: macos-15 steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: false cask: false test-bot: false - name: Run brew update-tests run: | brew update-test brew update-test --to-tag brew update-test --commit=HEAD tests: if: github.event_name != 'push' name: ${{ matrix.name }} needs: syntax runs-on: ${{ matrix.runs-on }} container: ${{ matrix.container }} strategy: matrix: include: - name: tests (online) test-flags: --online --coverage runs-on: ubuntu-latest - name: tests (generic OS) test-flags: --generic --coverage runs-on: ubuntu-latest - name: tests (Ubuntu 24.04) test-flags: --coverage runs-on: ubuntu-24.04 - name: tests (Ubuntu 22.04) test-flags: --coverage runs-on: ubuntu-22.04 - name: tests (Ubuntu 20.04) test-flags: --coverage runs-on: ubuntu-latest container: ghcr.io/homebrew/ubuntu20.04:latest - name: tests (macOS 15 arm64) test-flags: --coverage runs-on: macos-15 steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: # We only test needs_homebrew_core tests on macOS because # homebrew/core is not available by default on GitHub-hosted Ubuntu # runners, and it's expensive to tap it. core: ${{ runner.os == 'macOS' }} cask: false test-bot: false - name: Cache Bundler RubyGems uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ steps.set-up-homebrew.outputs.gems-path }} key: ${{ matrix.runs-on }}-tests-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} restore-keys: ${{ matrix.runs-on }}-tests-rubygems- - run: brew config - name: Install Bundler RubyGems run: brew install-bundler-gems --groups=all - name: Create parallel test log directory run: mkdir tests - name: Cache parallel tests log uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: tests key: ${{ runner.os }}-${{ matrix.test-flags }}-parallel_runtime_rspec-${{ github.sha }} restore-keys: ${{ runner.os }}-${{ matrix.test-flags }}-parallel_runtime_rspec- - name: Install brew tests --online dependencies if: matrix.name == 'tests (online)' run: brew install subversion curl - name: Install brew tests macOS dependencies if: runner.os != 'Linux' run: | # Workaround GitHub Actions Python issues brew unlink python && brew link --overwrite python brew install subversion # brew tests doesn't like world writable directories - name: Cleanup permissions if: runner.os == 'Linux' run: sudo chmod -R g-w,o-w /home/linuxbrew/.linuxbrew/Homebrew - name: Run brew tests if: github.event_name == 'pull_request' || matrix.name != 'tests (online)' run: | # Retry multiple times to detect and submit flakiness to CodeCov (because rspec-retry is disabled). if [[ -n "${CODECOV_TOKEN-}" ]] then brew tests ${{ matrix.test-flags }} || brew tests ${{ matrix.test-flags }} else brew tests ${{ matrix.test-flags }} fi env: HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} # These cannot be queried at the macOS level on GitHub Actions. HOMEBREW_LANGUAGES: en-GB CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - name: Get RSpec JUnit XML filenames id: junit_xml working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }} run: | mkdir -p Library/Homebrew/test/junit filenames=$(find Library/Homebrew/test/junit -name 'rspec*.xml' -print | tr '\n' ',') echo "filenames=${filenames%,}" >> "$GITHUB_OUTPUT" - uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1 with: working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }} files: ${{ steps.junit_xml.outputs.filenames }} disable_search: true token: ${{ secrets.CODECOV_TOKEN }} - uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }} files: Library/Homebrew/test/coverage/coverage.xml disable_search: true token: ${{ secrets.CODECOV_TOKEN }} test-default-formula: name: ${{ matrix.name }} needs: syntax if: github.repository_owner == 'Homebrew' && github.event_name != 'push' runs-on: ${{ matrix.runs-on }} container: ${{ matrix.container }} strategy: matrix: include: - name: test default formula (Ubuntu 24.04) runs-on: ubuntu-latest container: ghcr.io/homebrew/ubuntu24.04:latest - name: test default formula (Ubuntu 22.04) runs-on: ubuntu-latest container: ghcr.io/homebrew/ubuntu22.04:master - name: test default formula (Ubuntu 20.04) runs-on: ubuntu-latest container: ghcr.io/homebrew/ubuntu20.04:latest - name: test default formula (macOS 13 x86_64) runs-on: macos-13 - name: test default formula (macOS 15 arm64) runs-on: macos-15 env: HOMEBREW_TEST_BOT_ANALYTICS: 1 HOMEBREW_ENFORCE_SBOM: 1 steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: true cask: false test-bot: true - run: brew test-bot --only-cleanup-before - name: Setup environment variables if: matrix.container == 'ghcr.io/homebrew/ubuntu20.04:latest' run: echo "HOMEBREW_GLIBC_TESTING=1" >> "$GITHUB_ENV" - run: brew test-bot --only-setup - run: brew install gnu-tar - run: brew test-bot --only-formulae --only-json-tab --test-default-formula test-brew-bundle-services: name: ${{ matrix.name }} needs: syntax if: github.repository_owner == 'Homebrew' && github.event_name != 'push' runs-on: ${{ matrix.runs-on }} strategy: matrix: include: - name: test brew bundle and brew services (Ubuntu) runs-on: ubuntu-latest - name: test brew bundle and brew services (macOS) runs-on: macos-15 steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master with: core: true cask: false test-bot: false - run: brew test-bot --only-cleanup-before - run: brew test-bot --only-setup - name: Run brew bundle and brew services integration tests run: | cat <> Brewfile brew "git" brew "memcached", restart_service: true brew "postgresql@15", restart_service: true cask "1password" cask "1password-cli" cask "google-chrome" # VSCode cask is not available on Linux. vscode "github.copilot" if OS.mac? EOS brew bundle check && exit 1 brew bundle check --verbose && exit 1 brew bundle list brew bundle --verbose brew bundle --upgrade-formulae=memcached,postgresql@15 brew bundle upgrade brew bundle env | grep PATH | grep git brew bundle env --install brew bundle exec --services true brew bundle dump --force --describe brew services list brew services info memcached postgresql@15 brew services info --json memcached postgresql@15 brew services cleanup brew bundle cleanup --force test-analytics: runs-on: ${{ matrix.os }} strategy: matrix: os: - ubuntu-latest - macos-latest needs: syntax if: github.repository_owner == 'Homebrew' && github.event_name != 'push' steps: - name: Set up Homebrew id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master - name: Setup Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version-file: ${{ steps.set-up-homebrew.outputs.repository-path }}/Library/Homebrew/formula-analytics/.python-version - name: Cache Homebrew Bundler RubyGems id: cache uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ steps.set-up-homebrew.outputs.gems-path }} key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} restore-keys: ${{ runner.os }}-rubygems- - name: Install Homebrew Bundler RubyGems if: steps.cache.outputs.cache-hit != 'true' run: brew install-bundler-gems - run: brew formula-analytics --setup - run: brew formula-analytics --install --json --days-ago=2 if: github.event.pull_request.head.repo.fork == false && (github.event_name == 'pull_request' && github.event.pull_request.user.login != 'dependabot[bot]') env: HOMEBREW_INFLUXDB_TOKEN: ${{ secrets.HOMEBREW_INFLUXDB_READ_TOKEN }} - run: brew generate-analytics-api if: github.event.pull_request.head.repo.fork == false && (github.event_name == 'pull_request' && github.event.pull_request.user.login != 'dependabot[bot]') env: HOMEBREW_INFLUXDB_TOKEN: ${{ secrets.HOMEBREW_INFLUXDB_READ_TOKEN }}