chore: sunshine: rebuild bottles #971
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: brew test-bot | |
| permissions: {} | |
| on: | |
| push: | |
| branches: | |
| - master | |
| pull_request: | |
| concurrency: | |
| group: "${{ github.workflow }}-${{ github.ref }}" | |
| cancel-in-progress: true | |
| jobs: | |
| # Check syntax and detect which platforms need testing | |
| setup: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| outputs: | |
| platforms: ${{ steps.detect.outputs.platforms }} | |
| has-formulae: ${{ steps.detect.outputs.has-formulae }} | |
| changed-files: ${{ steps.detect.outputs.changed-files }} | |
| disable-failfast: ${{ steps.detect.outputs.disable-failfast }} | |
| steps: | |
| - name: Set up Homebrew | |
| id: set-up-homebrew | |
| uses: Homebrew/actions/setup-homebrew@main | |
| with: | |
| stable: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Cache Homebrew Bundler RubyGems | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 | |
| with: | |
| path: ${{ steps.set-up-homebrew.outputs.gems-path }} | |
| key: ubuntu-latest-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} | |
| restore-keys: ubuntu-latest-rubygems- | |
| - name: Brew cleanup before | |
| run: brew test-bot --fail-fast --only-cleanup-before | |
| - name: Brew setup | |
| run: brew test-bot --fail-fast --only-setup | |
| - name: Update actionlint config | |
| run: | | |
| # find file | |
| actionlint_config_file="$(brew --repo)/.github/actionlint.yaml" | |
| echo "Found actionlint config: ${actionlint_config_file}" | |
| echo "=== ORIGINAL CONTENTS ===" | |
| cat "${actionlint_config_file}" | |
| # amend file | |
| echo " - GH_BOT_NAME" >> "${actionlint_config_file}" | |
| echo "=== MODIFIED CONTENTS ===" | |
| cat "${actionlint_config_file}" | |
| - name: Check syntax | |
| run: brew test-bot --fail-fast --only-tap-syntax | |
| - name: Detect required platforms | |
| id: detect | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| HEAD_SHA: ${{ github.sha }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| run: | | |
| # Get the tap repository path | |
| TAP_PATH="$(brew --repository "${GITHUB_REPOSITORY}")" | |
| # Detect changed files in Formula/ and lib/ directories | |
| # We check manually rather than relying solely on brew test-bot --only-formulae-detect | |
| # because we need to analyze the specific formula files to determine platform requirements | |
| if [ "${GITHUB_EVENT_NAME}" == "pull_request" ]; then | |
| ALL_CHANGED=$(git -C "${TAP_PATH}" diff --name-only \ | |
| "${BASE_SHA}" "${HEAD_SHA}" || true) | |
| else | |
| ALL_CHANGED=$(git -C "${TAP_PATH}" diff --name-only \ | |
| "${BEFORE_SHA}" "${HEAD_SHA}" || true) | |
| fi | |
| # Get directly changed formula files | |
| CHANGED_FORMULAE=$(echo "${ALL_CHANGED}" | grep '^Formula/' || true) | |
| # Get changed lib files | |
| CHANGED_LIB=$(echo "${ALL_CHANGED}" | grep '^lib/' || true) | |
| # If lib files changed, find all formulae that require them | |
| if [ -n "${CHANGED_LIB}" ]; then | |
| echo "Changed lib files detected:" | |
| echo "${CHANGED_LIB}" | |
| # For each changed lib file, find formulas that require it | |
| for lib_file in ${CHANGED_LIB}; do | |
| lib_basename=$(basename "${lib_file}") | |
| echo "Finding formulae that use ${lib_basename}..." | |
| # Search for require_relative statements referencing this lib file | |
| # Pattern: require_relative "../../lib/filename" or similar | |
| DEPENDENT_FORMULAE=$(find "${TAP_PATH}/Formula" -name "*.rb" -type f -exec \ | |
| grep -l "require_relative.*${lib_basename%.rb}" {} \; | \ | |
| sed "s|${TAP_PATH}/||" || true) | |
| if [ -n "${DEPENDENT_FORMULAE}" ]; then | |
| echo "Found dependent formulae:" | |
| echo "${DEPENDENT_FORMULAE}" | |
| CHANGED_FORMULAE=$(printf "%s\n%s" "${CHANGED_FORMULAE}" "${DEPENDENT_FORMULAE}" | sort -u) | |
| fi | |
| done | |
| fi | |
| # Remove empty lines | |
| CHANGED_FILES=$(echo "${CHANGED_FORMULAE}" | sed '/^$/d') | |
| if [ -z "${CHANGED_FILES}" ]; then | |
| echo "No formula files changed, skipping tests" | |
| { | |
| echo "has-formulae=false" | |
| echo "platforms=[]" | |
| echo "changed-files=" | |
| } >> "${GITHUB_OUTPUT}" | |
| exit 0 | |
| fi | |
| echo "has-formulae=true" >> "${GITHUB_OUTPUT}" | |
| echo "Formula files to test:" | |
| echo "${CHANGED_FILES}" | |
| # Output changed files for reuse in other jobs (newline-separated list) | |
| { | |
| echo "changed-files<<EOF" | |
| echo "${CHANGED_FILES}" | |
| echo "EOF" | |
| } >> "${GITHUB_OUTPUT}" | |
| # Check if any changed formula is in the failfast skiplist | |
| DISABLE_FAILFAST=false | |
| SKIPLIST_FILE="${TAP_PATH}/ci_config/failfast_skiplist.json" | |
| if [ -f "${SKIPLIST_FILE}" ]; then | |
| echo "Checking formulas against failfast skiplist..." | |
| for file in ${CHANGED_FILES}; do | |
| # Extract formula name from path (e.g., Formula/c/cuda@13.1.rb -> cuda@13.1) | |
| FORMULA_NAME=$(basename "${file}" .rb) | |
| # Check if this formula is in the skiplist | |
| if grep -q "\"${FORMULA_NAME}\"" "${SKIPLIST_FILE}"; then | |
| echo " -> ${FORMULA_NAME} is in failfast skiplist" | |
| DISABLE_FAILFAST=true | |
| fi | |
| done | |
| fi | |
| echo "disable-failfast=${DISABLE_FAILFAST}" >> "${GITHUB_OUTPUT}" | |
| echo "Failfast disabled: ${DISABLE_FAILFAST}" | |
| # Default to empty arrays | |
| NEEDS_LINUX=false | |
| NEEDS_MACOS=false | |
| MACOS_VERSIONS=() | |
| # Check each changed formula | |
| for file in ${CHANGED_FILES}; do | |
| FULL_PATH="${TAP_PATH}/${file}" | |
| if [ -f "${FULL_PATH}" ]; then | |
| echo "Checking ${file}..." | |
| HAS_LINUX_DEPENDS=false | |
| HAS_MACOS_DEPENDS=false | |
| # Build list of files to check for dependencies | |
| FILES_TO_CHECK="${FULL_PATH}" | |
| # If formula includes a module, also check the module file for dependencies | |
| if grep -q 'require_relative.*lib/' "${FULL_PATH}"; then | |
| # Extract the lib file path | |
| LIB_RELATIVE=$(grep -oE "require_relative ['\"].*lib/[^'\"]+['\"]" "${FULL_PATH}" | \ | |
| sed "s/require_relative ['\"]//; s/['\"]//g" | head -n 1 || true) | |
| if [ -n "${LIB_RELATIVE}" ]; then | |
| # Convert relative path to absolute path | |
| # Use realpath or manual resolution since formulas can be in subdirectories | |
| # Formula/c/cuda@13.1.rb with ../../lib/cuda_formula.rb -> lib/cuda_formula.rb | |
| FORMULA_DIR="${TAP_PATH}/$(dirname "${file}")" | |
| LIB_FILE=$(cd "${FORMULA_DIR}" && realpath -m "${LIB_RELATIVE}.rb" 2>/dev/null \ | |
| || echo "${TAP_PATH}/${LIB_RELATIVE}.rb") | |
| # Fallback: if realpath fails, manually resolve ../../lib/file -> lib/file | |
| if [ ! -f "${LIB_FILE}" ]; then | |
| LIB_FILE="${TAP_PATH}/${LIB_RELATIVE#../../}.rb" | |
| fi | |
| if [ -f "${LIB_FILE}" ]; then | |
| echo " -> Also checking included lib file: ${LIB_FILE}" | |
| FILES_TO_CHECK="${FILES_TO_CHECK} ${LIB_FILE}" | |
| else | |
| echo " -> Warning: Could not find lib file: ${LIB_FILE}" | |
| fi | |
| fi | |
| fi | |
| # Check all relevant files for Linux dependency | |
| for check_file in ${FILES_TO_CHECK}; do | |
| if grep -q 'depends_on :linux' "${check_file}"; then | |
| HAS_LINUX_DEPENDS=true | |
| break | |
| fi | |
| done | |
| # Check all relevant files for macOS dependency | |
| for check_file in ${FILES_TO_CHECK}; do | |
| if grep -qE 'depends_on :macos|depends_on macos:' "${check_file}"; then | |
| HAS_MACOS_DEPENDS=true | |
| # Extract specific macOS versions if specified | |
| # Pattern: depends_on macos: :ventura, depends_on macos: :sonoma, etc. | |
| if grep -qE 'depends_on macos: :' "${check_file}"; then | |
| # Extract the macOS version(s) | |
| MACOS_VERSION_MATCHES=$(grep -oE 'depends_on macos: :[a-z_]+' "${check_file}" | \ | |
| sed 's/depends_on macos: ://' || true) | |
| for version in ${MACOS_VERSION_MATCHES}; do | |
| case "${version}" in | |
| ventura) | |
| # macOS 13 Ventura - not commonly available in GitHub Actions | |
| MACOS_VERSIONS+=("macos-13") | |
| ;; | |
| sonoma) | |
| # macOS 14 Sonoma | |
| MACOS_VERSIONS+=("macos-14") | |
| ;; | |
| sequoia) | |
| # macOS 15 Sequoia | |
| MACOS_VERSIONS+=("macos-15") | |
| ;; | |
| tahoe) | |
| # macOS 16 Tahoe | |
| MACOS_VERSIONS+=("macos-26") | |
| ;; | |
| *) | |
| echo " -> Unknown macOS version: ${version}, will use all macOS runners" | |
| ;; | |
| esac | |
| done | |
| fi | |
| fi | |
| done | |
| # Determine platform requirements | |
| if [ "${HAS_LINUX_DEPENDS}" == "true" ] && [ "${HAS_MACOS_DEPENDS}" == "false" ]; then | |
| echo " -> Linux-only formula detected" | |
| NEEDS_LINUX=true | |
| elif [ "${HAS_MACOS_DEPENDS}" == "true" ] && [ "${HAS_LINUX_DEPENDS}" == "false" ]; then | |
| echo " -> macOS-only formula detected" | |
| NEEDS_MACOS=true | |
| else | |
| echo " -> Multi-platform formula (no specific OS dependency)" | |
| NEEDS_LINUX=true | |
| NEEDS_MACOS=true | |
| fi | |
| fi | |
| done | |
| # Build the platform matrix | |
| # macOS version mapping to GitHub Actions runners: | |
| # - macos-13 = macOS 13.x Ventura (x86_64) | |
| # - macos-14 = macOS 14.x Sonoma (arm64) | |
| # - macos-15 = macOS 15.x Sequoia (arm64) | |
| # - macos-26 = macOS 16.x Tahoe (arm64) | |
| PLATFORMS="[" | |
| if [ "${NEEDS_LINUX}" == "true" ]; then | |
| PLATFORMS="${PLATFORMS}\"ubuntu-22.04\"," | |
| PLATFORMS="${PLATFORMS}\"ubuntu-22.04-arm\"," | |
| fi | |
| if [ "${NEEDS_MACOS}" == "true" ]; then | |
| # If specific macOS versions were detected, use only those | |
| if [ ${#MACOS_VERSIONS[@]} -gt 0 ]; then | |
| echo " -> Using specific macOS versions: ${MACOS_VERSIONS[*]}" | |
| for macos_runner in "${MACOS_VERSIONS[@]}"; do | |
| PLATFORMS="${PLATFORMS}\"${macos_runner}\"," | |
| done | |
| else | |
| # Otherwise use all available macOS runners | |
| PLATFORMS="${PLATFORMS}\"macos-14\",\"macos-15\",\"macos-26\"," | |
| fi | |
| fi | |
| # Remove trailing comma and close array | |
| PLATFORMS="${PLATFORMS%,}]" | |
| # If no platforms detected, default to all platforms | |
| if [ "${PLATFORMS}" == "]" ]; then | |
| PLATFORMS='["ubuntu-22.04","macos-14","macos-15","macos-26"]' | |
| fi | |
| echo "Platforms to test: ${PLATFORMS}" | |
| echo "platforms=${PLATFORMS}" >> "${GITHUB_OUTPUT}" | |
| # Build bottles on required platforms | |
| build-bottles: | |
| if: needs.setup.outputs.has-formulae == 'true' | |
| needs: setup | |
| permissions: | |
| actions: read | |
| checks: read | |
| contents: read | |
| packages: read | |
| pull-requests: read | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: ${{ needs.setup.outputs.disable-failfast == 'false' }} | |
| matrix: | |
| os: ${{ fromJson(needs.setup.outputs.platforms) }} | |
| steps: | |
| - name: More space | |
| if: runner.os == 'Linux' | |
| uses: LizardByte/actions/actions/more_space@4125866b7b655a6fe038b0e22a43a4c5d259af79 # v2026.417.35446 | |
| with: | |
| analyze-space-savings: true | |
| clean-all: true | |
| safe-packages: brew | |
| - name: Set up Homebrew | |
| id: set-up-homebrew | |
| uses: Homebrew/actions/setup-homebrew@main | |
| with: | |
| stable: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Cache Homebrew Bundler RubyGems | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 | |
| with: | |
| path: ${{ steps.set-up-homebrew.outputs.gems-path }} | |
| key: ${{ matrix.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} | |
| restore-keys: ${{ matrix.os }}-rubygems- | |
| # TODO: periodically check if this gets fixed in Homebrew | |
| # https://github.com/orgs/Homebrew/discussions/6615 | |
| # https://github.com/ruby/rubygems/issues/7983 | |
| - name: Fix ruby gems directory permissions | |
| if: matrix.os == 'ubuntu-22.04-arm' | |
| run: | | |
| # Fix ownership first so current user can write, then remove world-writable | |
| BUNDLE_DIR="$(brew --prefix)/Homebrew/Library/Homebrew/vendor/bundle/ruby" | |
| if [ -d "${BUNDLE_DIR}" ]; then | |
| # Take ownership so we can write to it | |
| sudo chown -R "$(whoami):$(id -gn)" "${BUNDLE_DIR}" | |
| # Remove world-writable permissions to satisfy Bundler security | |
| chmod -R o-w "${BUNDLE_DIR}" | |
| echo "Fixed ownership and permissions for ${BUNDLE_DIR}" | |
| fi | |
| - name: Brew cleanup before | |
| run: brew test-bot --fail-fast --only-cleanup-before | |
| - name: Brew setup | |
| run: brew test-bot --fail-fast --only-setup | |
| - name: Base64-encode GITHUB_TOKEN for HOMEBREW_DOCKER_REGISTRY_TOKEN | |
| id: base64-encode | |
| if: github.event_name == 'pull_request' | |
| env: | |
| TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| base64_token=$(echo -n "${TOKEN}" | base64 | tr -d "\n") | |
| echo "::add-mask::${base64_token}" | |
| echo "token=${base64_token}" >> "${GITHUB_OUTPUT}" | |
| - name: Build bottles | |
| if: github.event_name == 'pull_request' | |
| env: | |
| HOMEBREW_DOCKER_REGISTRY_TOKEN: ${{ steps.base64-encode.outputs.token }} | |
| run: brew test-bot --fail-fast --only-formulae --root-url=https://ghcr.io/v2/lizardbyte/homebrew | |
| - name: Upload bottles as artifact | |
| if: always() && github.event_name == 'pull_request' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: bottles_${{ matrix.os }} | |
| path: '*.bottle.*' | |
| # Conclusion job that checks test results | |
| conclusion: | |
| if: always() | |
| needs: | |
| - setup | |
| - build-bottles | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Check workflow results | |
| env: | |
| SETUP_RESULT: ${{ needs.setup.result }} | |
| BOTTLES_RESULT: ${{ needs.build-bottles.result }} | |
| HAS_FORMULAE: ${{ needs.setup.outputs.has-formulae }} | |
| run: | | |
| echo "Workflow Status Summary:" | |
| echo " setup: ${SETUP_RESULT}" | |
| echo " build-bottles: ${BOTTLES_RESULT}" | |
| echo " has-formulae: ${HAS_FORMULAE}" | |
| # If no formulae were changed, workflow should succeed | |
| if [ "${HAS_FORMULAE}" == "false" ]; then | |
| echo "✅ No formula changes detected - workflow succeeded" | |
| exit 0 | |
| fi | |
| # Check for failures (not skipped or cancelled) | |
| if [ "${SETUP_RESULT}" == "failure" ]; then | |
| echo "❌ Setup and detection failed" | |
| exit 1 | |
| fi | |
| if [ "${BOTTLES_RESULT}" == "failure" ]; then | |
| echo "❌ Test bot failed" | |
| exit 1 | |
| fi | |
| # Success if all required jobs succeeded or were skipped | |
| echo "✅ All tests passed" | |
| exit 0 | |
| # Check if bottles have been published (for PRs with formula changes) | |
| check-bottle-published: | |
| if: always() && github.event_name == 'pull_request' | |
| needs: | |
| - setup | |
| - conclusion | |
| permissions: | |
| pull-requests: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check for bottle published label | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| env: | |
| HAS_FORMULAE: ${{ needs.setup.outputs.has-formulae }} | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const hasFormulae = process.env.HAS_FORMULAE === 'true'; | |
| const prNumber = context.issue.number; | |
| // If no formula changes, pass automatically | |
| if (!hasFormulae) { | |
| console.log('✅ No formula changes detected - skipping bottle published check'); | |
| return; | |
| } | |
| console.log(`Checking for bottle-published label on PR #${prNumber}...`); | |
| // Get PR labels | |
| const { data: labels } = await github.rest.issues.listLabelsOnIssue({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber | |
| }); | |
| const labelNames = labels.map(label => label.name); | |
| console.log(`PR labels: ${labelNames.join(', ')}`); | |
| // Check if bottle published label exists | |
| const hasBottlePublished = labelNames.includes('bottle-published'); | |
| if (hasBottlePublished) { | |
| console.log('✅ bottle-published label found - PR can be merged'); | |
| } else { | |
| console.log('❌ bottle-published label not found - bottles must be published before merging'); | |
| throw new Error('bottle-published label not found'); | |
| } | |
| auto-approve-lizardbyte-bot: | |
| if: | | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.user.login == 'LizardByte-bot' | |
| needs: conclusion | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Label PR with pr-pull | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| github-token: ${{ secrets.GH_BOT_TOKEN }} | |
| script: | | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| labels: ['pr-pull'] | |
| }); |