From 4dea7ec895bb08ba3e95fe599bcaebd65ac34fbc Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Tue, 23 Sep 2025 15:36:02 +0800 Subject: [PATCH] feat: Release with PR (#11) --- .github/workflows/ci.yml | 2 +- .github/workflows/cuda-builder.yml | 2 +- .github/workflows/release-proposal.yml | 185 ++++++++++++++++++++++ .github/workflows/release-publish.yml | 145 +++++++++++++++++ .github/workflows/release.yml | 208 ------------------------- 5 files changed, 332 insertions(+), 210 deletions(-) create mode 100644 .github/workflows/release-proposal.yml create mode 100644 .github/workflows/release-publish.yml delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f44a70..0134409 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,5 @@ --- -name: continuous integration +name: CI on: pull_request: diff --git a/.github/workflows/cuda-builder.yml b/.github/workflows/cuda-builder.yml index 0cc57ed..e7365ef 100644 --- a/.github/workflows/cuda-builder.yml +++ b/.github/workflows/cuda-builder.yml @@ -1,4 +1,4 @@ -name: cuda builder +name: Cuda Docker Image Builder on: workflow_dispatch: diff --git a/.github/workflows/release-proposal.yml b/.github/workflows/release-proposal.yml new file mode 100644 index 0000000..832f3f7 --- /dev/null +++ b/.github/workflows/release-proposal.yml @@ -0,0 +1,185 @@ +--- +name: Release Proposal + +env: + CARGO_TERM_COLOR: always + +on: + workflow_dispatch: + inputs: + target_branch: + description: 'Target branch for the PR (default: main)' + required: false + type: string + default: 'main' + version_type: + description: 'Type of version bump' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + - custom + custom_version: + description: 'Custom version string (e.g., 1.2.3). Only used if version_type is "custom".' + required: false + is_draft: + description: 'Is this a draft release?' + required: true + type: boolean + default: false + +jobs: + calculate-next-version: + name: 🧮 Calculate Next Version + runs-on: ubuntu-latest + outputs: + new_version: ${{ steps.versioner.outputs.new_version }} + new_tag: ${{ steps.versioner.outputs.new_tag }} + commit_sha_short: ${{ steps.vars.outputs.commit_sha_short }} + source_branch: ${{ steps.vars.outputs.source_branch }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Get current branch and commit SHA + id: vars + run: | + echo "commit_sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "source_branch=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_OUTPUT + + - name: Get current version from Cargo.toml + id: current_version + run: | + current=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version') + echo "current=$current" >> $GITHUB_OUTPUT + echo "Current version: $current" + + - name: Calculate new version + id: versioner + env: + CURRENT_VERSION: ${{ steps.current_version.outputs.current }} + VERSION_TYPE: ${{ github.event.inputs.version_type }} + CUSTOM_VERSION: ${{ github.event.inputs.custom_version }} + run: | + if [[ "$VERSION_TYPE" == "custom" ]]; then + if [[ -z "$CUSTOM_VERSION" ]]; then + echo "Error: Custom version is selected but no custom_version string provided." + exit 1 + fi + new_version="$CUSTOM_VERSION" + else + # Parse current version + IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION" + major=${VERSION_PARTS[0]} + minor=${VERSION_PARTS[1]} + patch=${VERSION_PARTS[2]} + + # Calculate new version + case $VERSION_TYPE in + major) + major=$((major + 1)) + minor=0 + patch=0 + ;; + minor) + minor=$((minor + 1)) + patch=0 + ;; + patch) + patch=$((patch + 1)) + ;; + esac + + new_version="$major.$minor.$patch" + fi + + new_tag="v$new_version" + + echo "new_version=$new_version" >> $GITHUB_OUTPUT + echo "new_tag=$new_tag" >> $GITHUB_OUTPUT + echo "New version: $new_version" + echo "New tag: $new_tag" + + update-cargo-toml: + name: 📝 Update version files + needs: calculate-next-version + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install cargo-edit + run: cargo install cargo-edit --locked + + - name: Create version bump branch and PR + env: + NEW_VERSION: ${{ needs.calculate-next-version.outputs.new_version }} + NEW_TAG: ${{ needs.calculate-next-version.outputs.new_tag }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SOURCE_BRANCH: ${{ needs.calculate-next-version.outputs.source_branch }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch }} + run: | + set -ex + branch_name="release/${NEW_TAG}" + + # Create new branch from source branch + git checkout "$SOURCE_BRANCH" + git checkout -b "$branch_name" + + # Update version in Cargo.toml + echo "Updating Cargo.toml to version: $NEW_VERSION" + cargo set-version "$NEW_VERSION" + + # Commit changes + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + + git add Cargo.toml Cargo.lock + git commit -m "bump version to $NEW_TAG" + git push origin "$branch_name" + + # Prepare PR title and body + PR_TITLE="Release $NEW_TAG" + PR_BODY="Automated version bump for release $NEW_TAG. + + ## Overview + - Version bump: ${{ github.event.inputs.version_type }} + - Type: ${{ github.event.inputs.version_type }} + - Draft: ${{ github.event.inputs.is_draft }} + + ## What changed + - Updated version in Cargo.toml and Cargo.lock + + ## Validation + - [ ] Version number is correct + - [ ] All tests pass + - [ ] Ready for release + + Triggered by workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # Prepare labels + PR_LABELS="release-proposal" + if [[ "${{ github.event.inputs.is_draft }}" == "true" ]]; then + PR_LABELS="$PR_LABELS,draft-release" + fi + + gh pr create \ + --title "$PR_TITLE" \ + --body "$PR_BODY" \ + --base "$TARGET_BRANCH" \ + --head "$branch_name" \ + --label "$PR_LABELS" diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 0000000..bfd4c1c --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,145 @@ +--- +name: Release Publish + +on: + pull_request: + types: [closed] + branches: + - main + +permissions: + contents: write + packages: write + +env: + CARGO_TERM_COLOR: always + +jobs: + create-tag: + name: Create Tag + if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release-proposal') + runs-on: ubuntu-latest + outputs: + version: ${{ steps.extract_version.outputs.version }} + tag: ${{ steps.extract_version.outputs.tag }} + is_draft: ${{ steps.extract_version.outputs.is_draft }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Extract version from PR title + id: extract_version + run: | + # Extract version from PR title (format: "Release vX.Y.Z") + VERSION_TAG=$(echo "${{ github.event.pull_request.title }}" | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+') + if [ -z "$VERSION_TAG" ]; then + echo "Error: Could not extract version from PR title: ${{ github.event.pull_request.title }}" + exit 1 + fi + + VERSION=${VERSION_TAG#v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=$VERSION_TAG" >> $GITHUB_OUTPUT + + # Check if this is a draft release + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'draft-release') }}" == "true" ]]; then + echo "is_draft=true" >> $GITHUB_OUTPUT + else + echo "is_draft=false" >> $GITHUB_OUTPUT + fi + + echo "Extracted version: $VERSION" + echo "Extracted tag: $VERSION_TAG" + + - name: Create and push tag + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + git tag -a "${{ steps.extract_version.outputs.tag }}" -m "Release ${{ steps.extract_version.outputs.tag }}" + git push origin "${{ steps.extract_version.outputs.tag }}" + + build: + needs: create-tag + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + binary_name: quantus-miner + asset_name: quantus-miner-linux-x86_64 + - os: windows-latest + target: x86_64-pc-windows-msvc + binary_name: quantus-miner.exe + asset_name: quantus-miner-windows-x86_64.exe + - os: macos-latest + target: aarch64-apple-darwin + binary_name: quantus-miner + asset_name: quantus-miner-macos-aarch64 + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.create-tag.outputs.tag }} + + - name: setup rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + target: ${{ matrix.target }} + + - name: build binary + run: cargo build --release --locked --target ${{ matrix.target }} + + - name: prepare binary + shell: bash + run: | + cd target/${{ matrix.target }}/release + if [[ "${{ matrix.os }}" == "windows-latest" ]]; then + cp ${{ matrix.binary_name }} ${{ matrix.asset_name }} + else + cp ${{ matrix.binary_name }} ${{ matrix.asset_name }} + strip ${{ matrix.asset_name }} + fi + + - name: upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.asset_name }} + path: target/${{ matrix.target }}/release/${{ matrix.asset_name }} + + release: + needs: [create-tag, build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.create-tag.outputs.tag }} + + - name: download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ needs.create-tag.outputs.tag }} + IS_DRAFT: ${{ needs.create-tag.outputs.is_draft }} + run: | + # Prepare draft flag + if [[ "$IS_DRAFT" == "true" ]]; then + DRAFT_FLAG="--draft" + else + DRAFT_FLAG="" + fi + + # Create release with all artifacts + gh release create "$TAG" \ + --title "Release $TAG" \ + --generate-notes \ + $DRAFT_FLAG \ + artifacts/quantus-miner-linux-x86_64/quantus-miner-linux-x86_64 \ + artifacts/quantus-miner-windows-x86_64.exe/quantus-miner-windows-x86_64.exe \ + artifacts/quantus-miner-macos-aarch64/quantus-miner-macos-aarch64 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 5104cda..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,208 +0,0 @@ ---- -name: release - -on: - workflow_dispatch: - inputs: - version_bump: - description: 'Version bump type' - required: true - default: 'patch' - type: choice - options: - - patch - - minor - - major - -permissions: - contents: write - packages: write - -env: - CARGO_TERM_COLOR: always - -jobs: - # Run CI checks if releasing from non-main branch - ci-validation: - runs-on: ubuntu-latest - if: github.ref != 'refs/heads/main' - steps: - - uses: actions/checkout@v4 - - - name: setup rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - components: rustfmt, clippy - - - name: install taplo - run: cargo install taplo-cli --locked - - - name: format checks - run: | - taplo format --check --config taplo.toml - cargo fmt --all -- --check - timeout-minutes: 5 - - - name: clippy - run: cargo clippy --locked --workspace --all-targets -- -D warnings - timeout-minutes: 30 - - - name: build and test - run: | - cargo build --locked --workspace - cargo test --locked --workspace - timeout-minutes: 90 - - version: - runs-on: ubuntu-latest - needs: [ci-validation] - if: always() && (needs.ci-validation.result == 'success' || needs.ci-validation.result == 'skipped') - outputs: - version: ${{ steps.version.outputs.version }} - tag: ${{ steps.version.outputs.tag }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: setup rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - - - name: install cargo-edit - run: cargo install cargo-edit --locked - - - name: get current version - id: current_version - run: | - current=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version') - echo "current=$current" >> $GITHUB_OUTPUT - - - name: calculate new version - id: version - run: | - current="${{ steps.current_version.outputs.current }}" - bump_type="${{ github.event.inputs.version_bump }}" - - # Parse current version - IFS='.' read -ra VERSION_PARTS <<< "$current" - major=${VERSION_PARTS[0]} - minor=${VERSION_PARTS[1]} - patch=${VERSION_PARTS[2]} - - # Calculate new version - case $bump_type in - major) - major=$((major + 1)) - minor=0 - patch=0 - ;; - minor) - minor=$((minor + 1)) - patch=0 - ;; - patch) - patch=$((patch + 1)) - ;; - esac - - new_version="$major.$minor.$patch" - tag="v$new_version" - - echo "version=$new_version" >> $GITHUB_OUTPUT - echo "tag=$tag" >> $GITHUB_OUTPUT - echo "New version will be: $new_version" - - - name: update Cargo.toml version - run: | - cargo set-version ${{ steps.version.outputs.version }} - - - name: commit version bump - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add Cargo.toml Cargo.lock - git commit -m "bump version to v${{ steps.version.outputs.version }}" - git push origin main - - - name: create tag - run: | - git tag ${{ steps.version.outputs.tag }} - git push origin ${{ steps.version.outputs.tag }} - - build: - needs: version - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - binary_name: quantus-miner - asset_name: quantus-miner-linux-x86_64 - - os: windows-latest - target: x86_64-pc-windows-msvc - binary_name: quantus-miner.exe - asset_name: quantus-miner-windows-x86_64.exe - - os: macos-latest - target: aarch64-apple-darwin - binary_name: quantus-miner - asset_name: quantus-miner-macos-aarch64 - - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ needs.version.outputs.tag }} - - - name: setup rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - target: ${{ matrix.target }} - - - name: build binary - run: cargo build --release --locked --target ${{ matrix.target }} - - - name: prepare binary - shell: bash - run: | - cd target/${{ matrix.target }}/release - if [[ "${{ matrix.os }}" == "windows-latest" ]]; then - cp ${{ matrix.binary_name }} ${{ matrix.asset_name }} - else - cp ${{ matrix.binary_name }} ${{ matrix.asset_name }} - strip ${{ matrix.asset_name }} - fi - - - name: upload binary artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.asset_name }} - path: target/${{ matrix.target }}/release/${{ matrix.asset_name }} - - release: - needs: [version, build] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ needs.version.outputs.tag }} - - - name: download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: create release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ needs.version.outputs.tag }} - name: Release ${{ needs.version.outputs.tag }} - draft: false - prerelease: false - generate_release_notes: true - files: | - artifacts/quantus-miner-linux-x86_64/quantus-miner-linux-x86_64 - artifacts/quantus-miner-windows-x86_64.exe/quantus-miner-windows-x86_64.exe - artifacts/quantus-miner-macos-aarch64/quantus-miner-macos-aarch64 - env: - GITHUB_TOKEN: ${{ secrets.ADMIN_PAT }} \ No newline at end of file