Skip to content

🛞 fix(ci): brew install 🛞 #76

🛞 fix(ci): brew install 🛞

🛞 fix(ci): brew install 🛞 #76

Workflow file for this run

name: Pull Request
on:
pull_request:
branches:
- master
permissions:
contents: write # Needed to push QR code updates
pull-requests: write
id-token: write # Required for OIDC trusted publishing to TestPyPI
jobs:
test:
name: Test
uses: ./.github/workflows/test.yml
qr:
name: QR Codes
needs: test
runs-on: ubuntu-latest
# Skip if triggered by QR code update commit to prevent infinite loop
if: "!contains(github.event.head_commit.message, '[skip-qr]')"
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install dependencies
run: make install
- name: Generate QR codes
run: make qr
- name: Commit if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add assets/
if ! git diff --cached --quiet; then
git commit -m "Update QR codes [skip-qr]"
git push
fi
version:
name: Version Preview
needs: test # Only run after tests pass
runs-on: ubuntu-latest
outputs:
pypi_version: ${{ steps.set-version.outputs.pypi_version }}
environment:
name: testpypi
url: https://test.pypi.org/p/${{ github.event.repository.name }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # Need full history for version calculation
- name: Calculate next version (dry run)
id: version
uses: anothrNick/github-tag-action@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DRY_RUN: true
DEFAULT_BUMP: minor
WITH_V: true
PRERELEASE: true
PRERELEASE_SUFFIX: rc
BRANCH_HISTORY: compare
INITIAL_VERSION: 1.0.3
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Calculate prerelease version
id: set-version
run: |
# Get base version from tag action (e.g., v1.2.0-rc.0)
BASE_TAG="${NEW_TAG}"
# Strip 'v' prefix and '-rc.X' suffix to get base version (e.g., 1.2.0)
BASE_VERSION="${BASE_TAG#v}"
BASE_VERSION="${BASE_VERSION%-rc.*}"
# Create unique prerelease version: {base}rc{pr_number}.dev{run_number}
# e.g., 1.2.0rc42.dev7 for PR #42, run #7
PYPI_VERSION="${BASE_VERSION}rc${{ github.event.pull_request.number }}.dev${{ github.run_number }}"
echo "Tag version: $NEW_TAG"
echo "PyPI version: $PYPI_VERSION"
echo "pypi_version=$PYPI_VERSION" >> $GITHUB_OUTPUT
env:
NEW_TAG: ${{ steps.version.outputs.new_tag }}
- name: Build distributions
env:
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.set-version.outputs.pypi_version }}
run: |
uv build --sdist
uv build --wheel
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
# Uses OIDC trusted publishing - configure at:
# https://test.pypi.org/manage/account/publishing/
- name: Comment version info on PR
uses: actions/github-script@v8
with:
script: |
const oldTag = '${{ steps.version.outputs.old_tag }}' || 'none';
const newTag = '${{ steps.version.outputs.new_tag }}';
const part = '${{ steps.version.outputs.part }}';
// Extract base version (remove -rc.X suffix for display)
const baseVersion = newTag.replace(/-rc\.\d+$/, '');
const body = `## 📦 Version Preview
- **Current version:** \`${oldTag}\`
- **Bump type:** \`${part}\`
- **Release version:** \`${baseVersion}\`
- **TestPyPI version:** \`${newTag}\`
When this PR is merged, version will be bumped to \`${baseVersion}\`.
To change the bump type, include in commit message: \`#major\`, \`#minor\`, or \`#patch\``;
// Find existing bot comment with version preview
const { data: comments } = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});
const botComment = comments.find(c =>
c.user.type === 'Bot' &&
c.body.includes('## 📦 Version Preview')
);
if (botComment) {
// Check if version info changed by comparing release version and bump type
const oldVersionMatch = botComment.body.match(/Release version:\*\* `([^`]+)`/);
const oldBumpMatch = botComment.body.match(/Bump type:\*\* `([^`]+)`/);
const oldReleaseVersion = oldVersionMatch ? oldVersionMatch[1] : '';
const oldBumpType = oldBumpMatch ? oldBumpMatch[1] : '';
if (oldReleaseVersion === baseVersion && oldBumpType === part) {
console.log('Version info unchanged, skipping comment update');
return;
}
// Update existing comment
await github.rest.issues.updateComment({
comment_id: botComment.id,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
console.log('Updated existing version comment');
} else {
// Create new comment
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
console.log('Created new version comment');
}
smoke-pypi:
name: Smoke PyPI
needs: version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Wait for TestPyPI indexing
run: |
NAME="${{ github.event.repository.name }}"
VERSION="${{ needs.version.outputs.pypi_version }}"
MAX_ATTEMPTS=40
SLEEP_SECONDS=15
echo "Waiting for ${NAME}==${VERSION} to be available on TestPyPI..."
for i in $(seq 1 $MAX_ATTEMPTS); do
if curl -sf "https://test.pypi.org/pypi/${NAME}/${VERSION}/json" > /dev/null 2>&1; then
echo "Package available after $((i * SLEEP_SECONDS)) seconds"
exit 0
fi
echo "Attempt $i/$MAX_ATTEMPTS: Package not yet available, waiting ${SLEEP_SECONDS}s..."
sleep $SLEEP_SECONDS
done
echo "Timed out waiting for package after $((MAX_ATTEMPTS * SLEEP_SECONDS)) seconds"
exit 1
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install from TestPyPI
run: |
pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
${{ github.event.repository.name }}==${{ needs.version.outputs.pypi_version }}
- name: Run smoke tests
run: python tests/smoke.py ${{ github.event.repository.name }}
smoke-homebrew:
name: Smoke Homebrew
needs: test
runs-on: macos-latest
steps:
- uses: actions/checkout@v5
- name: Create local tap and generate formula
run: |
NAME="${{ github.event.repository.name }}"
REPO="${{ github.repository }}"
# Create a local tap
brew tap-new local/tap
TAP_PATH="$(brew --repository)/Library/Taps/local/homebrew-tap/Formula"
mkdir -p "$TAP_PATH"
# Get description from pyproject.toml
DESCRIPTION=$(grep '^description' pyproject.toml | sed 's/description = "\(.*\)"/\1/')
# Convert name to Ruby class name (capitalize, remove hyphens)
CLASS_NAME=$(echo "$NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1' | tr -d ' ')
# Build source line for HEAD install (points to PR branch)
SOURCE_LINE="head \"https://github.com/${REPO}.git\", branch: \"${{ github.head_ref }}\""
# Generate formula from template into the tap
sed -e "s|{{NAME}}|${NAME}|g" \
-e "s|{{CLASS_NAME}}|${CLASS_NAME}|g" \
-e "s|{{DESCRIPTION}}|${DESCRIPTION}|g" \
-e "s|{{HOMEPAGE}}|https://github.com/${REPO}|g" \
-e "s|{{SOURCE_LINE}}|${SOURCE_LINE}|g" \
.github/templates/formula.rb.template > "$TAP_PATH/${NAME}.rb"
echo "Generated formula at $TAP_PATH/${NAME}.rb:"
cat "$TAP_PATH/${NAME}.rb"
- name: Install formula from HEAD
run: brew install --HEAD local/tap/${{ github.event.repository.name }}
- name: Run formula test
run: brew test local/tap/${{ github.event.repository.name }}
- name: Verify CLI works
run: |
${{ github.event.repository.name }} version
${{ github.event.repository.name }} --help