Migrate Rust code to latest stable toolchain #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Rust CI/CD Pipeline | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'rust/**' | |
| - '.github/workflows/rust.yml' | |
| - 'scripts/**' | |
| - 'changelog.d/**' | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| paths: | |
| - 'rust/**' | |
| - '.github/workflows/rust.yml' | |
| - 'scripts/**' | |
| - 'changelog.d/**' | |
| workflow_dispatch: | |
| inputs: | |
| bump_type: | |
| description: 'Version bump type' | |
| required: true | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| description: | |
| description: 'Release description (optional)' | |
| required: false | |
| type: string | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CARGO_TERM_COLOR: always | |
| defaults: | |
| run: | |
| working-directory: rust | |
| jobs: | |
| # REQUIRED CI CHECKS - All must pass before release | |
| # These jobs ensure code quality and tests pass before any release | |
| # Linting and formatting | |
| lint: | |
| name: Lint and Format Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| rust/target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Check formatting | |
| run: cargo fmt --all -- --check | |
| - name: Check file size limit | |
| working-directory: . | |
| run: node scripts/check-file-size.mjs | |
| # Test on multiple OS | |
| test: | |
| name: Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| rust/target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Run tests | |
| run: cargo test --all-features --verbose | |
| # Code coverage | |
| coverage: | |
| name: Code Coverage | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: llvm-tools-preview | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| rust/target | |
| key: ${{ runner.os }}-cargo-coverage-${{ hashFiles('rust/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-coverage- | |
| - name: Install cargo-llvm-cov | |
| uses: taiki-e/install-action@cargo-llvm-cov | |
| - name: Generate code coverage | |
| run: cargo llvm-cov --all-features --lcov --output-path lcov.info | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| files: rust/lcov.info | |
| fail_ci_if_error: false | |
| # Build package - only runs if lint and test pass | |
| build: | |
| name: Build Package | |
| runs-on: ubuntu-latest | |
| needs: [lint, test] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| rust/target | |
| key: ${{ runner.os }}-cargo-build-${{ hashFiles('rust/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-build- | |
| - name: Build release | |
| run: cargo build --release --verbose | |
| # Check for changelog fragments in PRs | |
| changelog: | |
| name: Changelog Fragment Check | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for changelog fragments | |
| working-directory: . | |
| run: | | |
| # Get list of fragment files (excluding README and template) | |
| FRAGMENTS=$(find changelog.d -name "*.md" ! -name "README.md" 2>/dev/null | wc -l) | |
| # Get changed files in PR | |
| CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) | |
| # Check if any source files changed (excluding docs and config) | |
| SOURCE_CHANGED=$(echo "$CHANGED_FILES" | grep -E "^(rust/src/|rust/tests/|scripts/)" | wc -l) | |
| if [ "$SOURCE_CHANGED" -gt 0 ] && [ "$FRAGMENTS" -eq 0 ]; then | |
| echo "::warning::No changelog fragment found. Please add a changelog entry in changelog.d/" | |
| echo "" | |
| echo "To create a changelog fragment:" | |
| echo " Create a new .md file in changelog.d/ with your changes" | |
| echo "" | |
| echo "See changelog.d/README.md for more information." | |
| # Note: This is a warning, not a failure, to allow flexibility | |
| # Change 'exit 0' to 'exit 1' to make it required | |
| exit 0 | |
| fi | |
| echo "Changelog check passed" | |
| # Automatic release on push to main using changelog fragments | |
| # This job automatically bumps version based on fragments in changelog.d/ | |
| auto-release: | |
| name: Auto Release | |
| needs: [lint, test, build, coverage] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| working-directory: . | |
| - name: Determine bump type from changelog fragments | |
| id: bump_type | |
| working-directory: . | |
| run: node scripts/get-bump-type.mjs | |
| - name: Check if version already released or no fragments | |
| id: check | |
| working-directory: . | |
| run: | | |
| # Check if there are changelog fragments | |
| if [ "${{ steps.bump_type.outputs.has_fragments }}" != "true" ]; then | |
| # No fragments - check if current version tag exists | |
| CURRENT_VERSION=$(grep -Po '(?<=^version = ")[^"]*' rust/Cargo.toml) | |
| if git rev-parse "v$CURRENT_VERSION" >/dev/null 2>&1; then | |
| echo "No changelog fragments and v$CURRENT_VERSION already released" | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "No changelog fragments but v$CURRENT_VERSION not yet released" | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| echo "skip_bump=true" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "Found changelog fragments, proceeding with release" | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| echo "skip_bump=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Collect changelog and bump version | |
| id: version | |
| if: steps.check.outputs.should_release == 'true' && steps.check.outputs.skip_bump != 'true' | |
| working-directory: . | |
| run: | | |
| node scripts/version-and-commit.mjs \ | |
| --bump-type "${{ steps.bump_type.outputs.bump_type }}" | |
| - name: Get current version | |
| id: current_version | |
| if: steps.check.outputs.should_release == 'true' | |
| working-directory: . | |
| run: | | |
| CURRENT_VERSION=$(grep -Po '(?<=^version = ")[^"]*' rust/Cargo.toml) | |
| echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT | |
| - name: Build release | |
| if: steps.check.outputs.should_release == 'true' | |
| run: cargo build --release | |
| - name: Create GitHub Release | |
| if: steps.check.outputs.should_release == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| working-directory: . | |
| run: | | |
| node scripts/create-github-release.mjs \ | |
| --release-version "${{ steps.current_version.outputs.version }}" \ | |
| --repository "${{ github.repository }}" | |
| # Manual release via workflow_dispatch - only after CI passes | |
| manual-release: | |
| name: Manual Release | |
| needs: [lint, test, build, coverage] | |
| if: github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| working-directory: . | |
| - name: Collect changelog fragments | |
| working-directory: . | |
| run: | | |
| # Check if there are any fragments to collect | |
| FRAGMENTS=$(find changelog.d -name "*.md" ! -name "README.md" 2>/dev/null | wc -l) | |
| if [ "$FRAGMENTS" -gt 0 ]; then | |
| echo "Found $FRAGMENTS changelog fragment(s), collecting..." | |
| node scripts/collect-changelog.mjs | |
| else | |
| echo "No changelog fragments found, skipping collection" | |
| fi | |
| - name: Version and commit | |
| id: version | |
| working-directory: . | |
| run: | | |
| node scripts/version-and-commit.mjs \ | |
| --bump-type "${{ github.event.inputs.bump_type }}" \ | |
| --description "${{ github.event.inputs.description }}" | |
| - name: Build release | |
| if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true' | |
| run: cargo build --release | |
| - name: Create GitHub Release | |
| if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| working-directory: . | |
| run: | | |
| node scripts/create-github-release.mjs \ | |
| --release-version "${{ steps.version.outputs.new_version }}" \ | |
| --repository "${{ github.repository }}" |