Skip to content

chore: Update formulas list in bug-report.yml #948

chore: Update formulas list in bug-report.yml

chore: Update formulas list in bug-report.yml #948

Workflow file for this run

---
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']
});