-
Notifications
You must be signed in to change notification settings - Fork 207
build: Add actions to automate release #1429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [closed] | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| release: | ||
| name: Create Release | ||
| if: | | ||
| (github.event_name == 'pull_request' && | ||
| github.event.pull_request.merged == true && | ||
| contains(github.event.pull_request.labels.*.name, 'release')) | ||
| runs-on: ubuntu-latest | ||
| container: quay.io/coreos-assembler/fcos-buildroot:testing-devel | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Extract version | ||
| id: extract_version | ||
| run: | | ||
| # Extract version from crates/lib/Cargo.toml | ||
| VERSION=$(cargo read-manifest --manifest-path crates/lib/Cargo.toml | jq -r '.version') | ||
|
|
||
| # Validate version format | ||
| if ! echo "$VERSION" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' >/dev/null; then | ||
| echo "Error: Invalid version format in Cargo.toml: $VERSION" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "Extracted version: $VERSION" | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "TAG_NAME=v$VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Install deps | ||
| run: ./ci/installdeps.sh | ||
|
|
||
| - name: Mark git checkout as safe | ||
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | ||
|
|
||
| - name: Import GPG key | ||
| if: github.event_name != 'push' | ||
| uses: crazy-max/ghaction-import-gpg@v6 | ||
| with: | ||
| gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to make this keypair and add to secrets in this repo right? And when we do that we'll also want to sign it via web of trust and/or just document the public key explicitly in the repo.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ckyrouac Did we ever do anything here? here's my proposal:
My goal here is to be able to reuse exactly the same release workflow (including signing) for bcvk. |
||
| passphrase: ${{ secrets.GPG_PASSPHRASE }} | ||
| git_user_signingkey: true | ||
| git_commit_gpgsign: true | ||
| git_tag_gpgsign: true | ||
|
|
||
| - name: Create and push tag | ||
| if: github.event_name != 'push' | ||
| run: | | ||
| VERSION="${{ steps.extract_version.outputs.version }}" | ||
| TAG_NAME="v$VERSION" | ||
|
|
||
| if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then | ||
| echo "Tag $TAG_NAME already exists" | ||
| exit 0 | ||
| fi | ||
|
|
||
| git tag -s -m "Release $VERSION" "$TAG_NAME" | ||
| git push origin "$TAG_NAME" | ||
|
|
||
| echo "Successfully created and pushed tag $TAG_NAME" | ||
|
|
||
| git checkout "$TAG_NAME" | ||
|
|
||
| - name: Install vendor tool | ||
| run: cargo install cargo-vendor-filterer | ||
|
|
||
| - name: Cache Dependencies | ||
| uses: Swatinem/rust-cache@v2 | ||
| with: | ||
| key: "release" | ||
|
|
||
| - name: Run cargo xtask package | ||
| run: cargo xtask package | ||
|
|
||
| - name: Create Release | ||
| id: create_release | ||
| uses: actions/create-release@v1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| tag_name: ${{ steps.extract_version.outputs.TAG_NAME }} | ||
| release_name: Release ${{ steps.extract_version.outputs.TAG_NAME }} | ||
| draft: true | ||
| prerelease: false | ||
| body: | | ||
| ## bootc ${{ steps.extract_version.outputs.version }} | ||
|
|
||
| ### Changes | ||
|
|
||
| Auto-generated release notes will be populated here. | ||
|
|
||
| ### Assets | ||
|
|
||
| - `bootc-${{ steps.extract_version.outputs.version }}-vendor.tar.zstd` - Vendored dependencies archive | ||
| - `bootc-${{ steps.extract_version.outputs.version }}.tar.zstd` - Source archive | ||
|
|
||
| - name: Upload vendor archive | ||
| uses: actions/upload-release-asset@v1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| upload_url: ${{ steps.create_release.outputs.upload_url }} | ||
| asset_path: ./target/bootc-${{ steps.extract_version.outputs.version }}-vendor.tar.zstd | ||
| asset_name: bootc-${{ steps.extract_version.outputs.version }}-vendor.tar.zstd | ||
| asset_content_type: application/zstd | ||
|
|
||
| - name: Upload source archive | ||
| uses: actions/upload-release-asset@v1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| upload_url: ${{ steps.create_release.outputs.upload_url }} | ||
| asset_path: ./target/bootc-${{ steps.extract_version.outputs.version }}.tar.zstd | ||
| asset_name: bootc-${{ steps.extract_version.outputs.version }}.tar.zstd | ||
| asset_content_type: application/zstd | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| name: Create Release PR | ||
|
|
||
| on: | ||
| schedule: | ||
| # Run every 3 weeks on Monday at 8:00 AM UTC | ||
| # Note: GitHub Actions doesn't support "every 3 weeks" directly, | ||
| # so we use a workaround by running weekly and checking if it's been 3 weeks | ||
| - cron: '0 8 * * 1' | ||
| workflow_dispatch: | ||
| inputs: | ||
| version: | ||
| description: 'Version to release (e.g., 1.5.1). Leave empty to auto-increment.' | ||
| required: false | ||
| type: string | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| jobs: | ||
| create-release-pr: | ||
| runs-on: ubuntu-latest | ||
| container: quay.io/coreos-assembler/fcos-buildroot:testing-devel | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Install deps | ||
| run: ./ci/installdeps.sh | ||
|
|
||
| - name: Mark git checkout as safe | ||
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | ||
|
|
||
| - name: Check if it's time for a release | ||
| id: check_schedule | ||
| run: | | ||
| # For manual workflow dispatch, always proceed | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "should_release=true" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
|
|
||
| # For scheduled runs, check if it's been 3 weeks since the last release | ||
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | ||
| LAST_TAG_DATE=$(git log -1 --format=%ct "$LAST_TAG" 2>/dev/null || echo "0") | ||
| CURRENT_DATE=$(date +%s) | ||
| DAYS_SINCE_RELEASE=$(( (CURRENT_DATE - LAST_TAG_DATE) / 86400 )) | ||
|
|
||
| echo "Days since last release: $DAYS_SINCE_RELEASE" | ||
|
|
||
| # Release if it's been at least 21 days (3 weeks) | ||
| if [ $DAYS_SINCE_RELEASE -ge 21 ]; then | ||
| echo "should_release=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "should_release=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Import GPG key | ||
| if: steps.check_schedule.outputs.should_release == 'true' | ||
| uses: crazy-max/ghaction-import-gpg@v6 | ||
| with: | ||
| gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} | ||
| passphrase: ${{ secrets.GPG_PASSPHRASE }} | ||
| git_user_signingkey: true | ||
| git_commit_gpgsign: true | ||
| git_tag_gpgsign: true | ||
|
|
||
| - name: Create release commit | ||
| id: create_commit | ||
| if: steps.check_schedule.outputs.should_release == 'true' | ||
| env: | ||
| INPUT_VERSION: ${{ github.event.inputs.version }} | ||
| run: | | ||
| dnf -y install pandoc | ||
| cargo install cargo-edit | ||
|
|
||
| # If version is provided via workflow dispatch, validate and use it | ||
| if [ -n "$INPUT_VERSION" ]; then | ||
| VERSION="$INPUT_VERSION" | ||
| # Validate version format strictly | ||
| if ! echo "$VERSION" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' >/dev/null; then | ||
| echo "Error: Invalid version format. Expected X.Y.Z (e.g., 1.5.1)" | ||
| exit 1 | ||
| fi | ||
| cargo set-version --manifest-path crates/lib/Cargo.toml --package bootc-lib "$VERSION" | ||
| else | ||
| # default to bump the minor since that is most common | ||
| cargo set-version --manifest-path crates/lib/Cargo.toml --package bootc-lib --bump minor | ||
| VERSION=$(cargo read-manifest --manifest-path crates/lib/Cargo.toml | jq -r '.version') | ||
| fi | ||
|
|
||
| cargo update --workspace | ||
| cargo xtask update-generated | ||
| git commit -am "Release $VERSION" | ||
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Create release branch | ||
| if: steps.check_schedule.outputs.should_release == 'true' | ||
| id: create_branch | ||
| env: | ||
| VERSION: ${{ steps.create_commit.outputs.VERSION }} | ||
| run: | | ||
| BRANCH_NAME="release-${VERSION}" | ||
| git checkout -b "$BRANCH_NAME" | ||
| echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Push branch | ||
| if: steps.check_schedule.outputs.should_release == 'true' | ||
| env: | ||
| BRANCH_NAME: ${{ steps.create_branch.outputs.branch_name }} | ||
| run: | | ||
| git push origin "${BRANCH_NAME}" | ||
|
|
||
| - name: Create Pull Request | ||
| if: steps.check_schedule.outputs.should_release == 'true' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| VERSION: ${{ steps.create_commit.outputs.VERSION }} | ||
| BRANCH_NAME: ${{ steps.create_branch.outputs.branch_name }} | ||
| with: | ||
| script: | | ||
| const version = process.env.VERSION; | ||
| const branchName = process.env.BRANCH_NAME; | ||
|
|
||
| const { data: pr } = await github.rest.pulls.create({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| title: `Release ${version}`, | ||
| body: `## Release ${version} | ||
|
|
||
| This is an automated release PR created by the scheduled release workflow. | ||
|
|
||
| ### Release Process | ||
|
|
||
| 1. Review the changes in this PR | ||
| 2. Ensure all tests pass | ||
| 3. Merge the PR | ||
| 4. The release tag will be automatically created and signed when this PR is merged | ||
|
|
||
| The release workflow will automatically trigger when the tag is pushed.`, | ||
| head: branchName, | ||
| base: 'main', | ||
| draft: false | ||
| }); | ||
|
|
||
| // Add the release label | ||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: pr.number, | ||
| labels: ['release'] | ||
| }); | ||
|
|
||
| console.log(`Created PR #${pr.number}: ${pr.html_url}`); |
Uh oh!
There was an error while loading. Please reload this page.