Skip to content

chore(release): bfabric 1.22.0 #60

chore(release): bfabric 1.22.0

chore(release): bfabric 1.22.0 #60

name: PR Release Preview
on:
pull_request:
branches:
- release
# `edited` is required to catch PR base-branch retargeting (e.g. a PR first
# opened against `main` and later retargeted to `release`); GitHub fires
# `edited` rather than `synchronize` for that. See #409.
types: [opened, synchronize, reopened, edited]
jobs:
preview-release:
runs-on: ubuntu-latest
outputs:
packages_to_release: ${{ steps.check-versions.outputs.packages-to-release }}
version_info: ${{ steps.check-versions.outputs.version-info }}
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v7
- name: Install hatch
run: pip install hatch
- name: Check which packages will be released
id: check-versions
uses: ./.github/actions/check-package-versions
with:
packages: "bfabric,bfabric_scripts,bfabric_app_runner"
pypi-url: "https://pypi.org"
priority-order: "bfabric,bfabric_scripts,bfabric_app_runner"
include-versions: "true"
- name: Build version table
id: build-table
run: |
packages='${{ steps.check-versions.outputs.packages-to-release }}'
version_info='${{ steps.check-versions.outputs.version-info }}'
# Build table with current PyPI and new versions
table="| Package | Current (PyPI) | New Version |\n|---------|----------------|-------------|"
for pkg in $(echo $packages | jq -r '.[]'); do
current_version=$(echo $version_info | jq -r ".$pkg.current_version")
new_version=$(echo $version_info | jq -r ".$pkg.local_version")
table="$table\n| $pkg | $current_version | $new_version |"
done
echo "table<<TABLE_EOF" >> $GITHUB_OUTPUT
echo -e "$table" >> $GITHUB_OUTPUT
echo "TABLE_EOF" >> $GITHUB_OUTPUT
- name: Create or update PR comment
uses: actions/github-script@v9
with:
script: |
const packages = JSON.parse('${{ steps.check-versions.outputs.packages-to-release }}');
const table = `${{ steps.build-table.outputs.table }}`;
let commentBody;
if (packages.length === 0) {
commentBody = `## πŸš€ Release Preview
No packages will be released - all versions already exist on PyPI.`;
} else {
commentBody = `## πŸš€ Release Preview
The following packages will be released when this PR is merged:
${table}
---
*This comment is automatically updated when the PR changes.*`;
}
// Find existing comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existingComment = comments.data.find(comment =>
comment.user.login === 'github-actions[bot]' &&
comment.body.includes('πŸš€ Release Preview')
);
if (existingComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: commentBody
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: commentBody
});
}
validate-and-test-release:
needs: preview-release
# Skip the (expensive) build/test matrix on title/body edits; only re-run it
# for real changes β€” i.e. anything except an `edited` event whose `changes`
# don't include the base branch.
if: ${{ needs.preview-release.outputs.packages_to_release != '[]' && (github.event.action != 'edited' || github.event.changes.base != null) }}
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.13"]
resolution: ["highest", "lowest-direct"]
exclude:
# Only test lowest-direct on Python 3.11
- python-version: "3.13"
resolution: "lowest-direct"
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install build and test tools
run: pip install hatch nox uv
- name: Build distributions
id: build
run: |
packages='${{ needs.preview-release.outputs.packages_to_release }}'
wheels=""
for pkg in $(echo $packages | jq -r '.[]'); do
echo "Building $pkg..."
cd $pkg
hatch build
cd ..
# Find the wheel file
wheel=$(ls $pkg/dist/*.whl | head -1)
wheel_abs=$(realpath $wheel)
# Add to wheels list
if [ -z "$wheels" ]; then
wheels="--wheels $wheel_abs"
else
wheels="$wheels --wheels $wheel_abs"
fi
done
echo "wheels_args=$wheels" >> $GITHUB_OUTPUT
echo "Built wheels: $wheels"
- name: Verify package contents
if: ${{ matrix.python-version == '3.11' && matrix.resolution == 'highest' }}
run: |
packages='${{ needs.preview-release.outputs.packages_to_release }}'
for pkg in $(echo $packages | jq -r '.[]'); do
echo "Verifying $pkg..."
wheel=$(ls $pkg/dist/*.whl | head -1)
# List wheel contents
echo "Contents of $wheel:"
unzip -l $wheel
# Check for py.typed in bfabric
if [ "$pkg" = "bfabric" ]; then
if ! unzip -l $wheel | grep -q "py.typed"; then
echo "❌ py.typed missing from bfabric wheel"
exit 1
fi
echo "βœ… py.typed found in bfabric wheel"
fi
# Check for resources in bfabric_app_runner
if [ "$pkg" = "bfabric_app_runner" ]; then
if ! unzip -l $wheel | grep -q "resources/.*\.mk"; then
echo "❌ .mk resources missing from bfabric_app_runner wheel"
exit 1
fi
echo "βœ… Resources found in bfabric_app_runner wheel"
fi
done
- name: Test distributions
run: |
# This will install the built wheels and run tests
# If version constraints are incompatible, installation will fail naturally
nox -s test_distributions-${{ matrix.python-version }} -- \
${{ steps.build.outputs.wheels_args }} \
--resolution ${{ matrix.resolution }}
comment-test-results:
needs: [preview-release, validate-and-test-release]
# Mirror the guard on validate-and-test-release so we don't post a stale
# "tests failed" comment when the matrix was intentionally skipped.
if: always() && needs.preview-release.outputs.packages_to_release != '[]' && (github.event.action != 'edited' || github.event.changes.base != null)
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/github-script@v9
with:
script: |
const packages = JSON.parse('${{ needs.preview-release.outputs.packages_to_release }}');
// Determine overall status
const testResult = '${{ needs.validate-and-test-release.result }}';
const allPassed = testResult === 'success';
const emoji = allPassed ? 'βœ…' : '❌';
// Get current timestamp
const timestamp = new Date().toISOString();
const commentBody = `## ${emoji} Release Distribution Testing
**Packages to release:** ${packages.join(', ')}
**Test Results:**
- Python 3.11 (highest): ${testResult === 'success' ? 'βœ… passed' : '❌ failed'}
- Python 3.11 (lowest-direct): ${testResult === 'success' ? 'βœ… passed' : '❌ failed'}
- Python 3.13 (highest): ${testResult === 'success' ? 'βœ… passed' : '❌ failed'}
${allPassed ?
'**Status:** All tests passed with built distributions. The packages are ready for release.' :
`**Status:** Tests failed. Please check the [workflow logs](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`}
*Last updated: ${timestamp}*
`;
// Find existing comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existingComment = comments.data.find(comment =>
comment.user.login === 'github-actions[bot]' &&
comment.body.includes('Release Distribution Testing')
);
if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: commentBody
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: commentBody
});
}