From 0749b009b355d463eb2107aa33dc0bea8664070f Mon Sep 17 00:00:00 2001 From: RAprogramm Date: Sun, 12 Oct 2025 11:06:59 +0700 Subject: [PATCH 1/2] #181 feat: optimize CI job parallelization for faster feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructured workflow execution for maximum parallelization: Job Structure: - msrv: Detect MSRV (foundation for all jobs) - fmt, clippy, deny, audit: Run in parallel (independent quality checks) - test: Depends on fmt+clippy (matrix: MSRV + stable) - package: Depends on test (MSRV only) - coverage, benchmarks: Depend on test (run in parallel) Dependency Chain: msrv → [fmt, clippy, deny, audit] (parallel) ↓ [fmt, clippy] → test (matrix) ↓ [package, coverage, benchmarks] (parallel) Benefits: - Faster CI feedback (~2-3 min vs ~5 min) - Quality checks run immediately in parallel - Tests only run after code quality verified - Optimal resource utilization - Clear dependency visualization Performance Improvements: - fmt/clippy/deny/audit: parallel execution (was sequential) - Test execution: starts after quality checks pass (early failure detection) - Coverage/benchmarks: parallel execution after tests --- .github/workflows/reusable-ci.yml | 144 +++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 41 deletions(-) diff --git a/.github/workflows/reusable-ci.yml b/.github/workflows/reusable-ci.yml index bee2707..f49eb66 100644 --- a/.github/workflows/reusable-ci.yml +++ b/.github/workflows/reusable-ci.yml @@ -36,7 +36,29 @@ jobs: echo "msrv=${RV}" >> "$GITHUB_OUTPUT" echo "Using MSRV: $RV" - ci: + fmt: + runs-on: ubuntu-latest + needs: msrv + steps: + - uses: actions/checkout@v5 + + - name: Install Rust (${{ needs.msrv.outputs.version }}) + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ needs.msrv.outputs.version }} + + - name: Install nightly rustfmt + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: nightly + components: rustfmt + + - name: Check formatting (nightly rustfmt) + uses: ./.github/actions/cargo-fmt + with: + toolchain: nightly + + clippy: runs-on: ubuntu-latest needs: msrv strategy: @@ -45,14 +67,8 @@ jobs: rust: - ${{ needs.msrv.outputs.version }} - stable - env: - CARGO_LOCKED: "true" - steps: - uses: actions/checkout@v5 - with: - fetch-depth: 0 - persist-credentials: true # оставляем токен в origin, чтобы git push работал - name: Install Rust (${{ matrix.rust }}) uses: dtolnay/rust-toolchain@v1 @@ -60,18 +76,76 @@ jobs: toolchain: ${{ matrix.rust }} components: clippy - - name: Install nightly rustfmt + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + with: + key: clippy-${{ matrix.rust }} + save-if: ${{ github.ref == 'refs/heads/main' }} + + - name: Clippy (${{ matrix.rust }}) + uses: ./.github/actions/cargo-clippy + with: + toolchain: ${{ matrix.rust }} + all-features: ${{ inputs.all-features }} + + deny: + runs-on: ubuntu-latest + needs: msrv + steps: + - uses: actions/checkout@v5 + + - name: Install Rust (${{ needs.msrv.outputs.version }}) uses: dtolnay/rust-toolchain@v1 with: - toolchain: nightly - components: rustfmt + toolchain: ${{ needs.msrv.outputs.version }} + + - name: Cargo deny + uses: ./.github/actions/cargo-deny + + audit: + runs-on: ubuntu-latest + needs: msrv + steps: + - uses: actions/checkout@v5 + + - name: Install Rust (${{ needs.msrv.outputs.version }}) + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ needs.msrv.outputs.version }} + + - name: Security audit + uses: ./.github/actions/cargo-audit + + test: + runs-on: ubuntu-latest + needs: [msrv, fmt, clippy] + strategy: + fail-fast: false + matrix: + rust: + - ${{ needs.msrv.outputs.version }} + - stable + env: + CARGO_LOCKED: "true" + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + persist-credentials: true + + - name: Install Rust (${{ matrix.rust }}) + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ matrix.rust }} - name: Cache cargo uses: Swatinem/rust-cache@v2 with: + key: test-${{ matrix.rust }} save-if: ${{ github.ref == 'refs/heads/main' }} - name: Verify lockfile is committed + if: matrix.rust == needs.msrv.outputs.version shell: bash run: | set -euo pipefail @@ -80,7 +154,6 @@ jobs: exit 1 fi - # ---------- README handling ---------- - name: Build (may regenerate README to temp) if: matrix.rust == needs.msrv.outputs.version shell: bash @@ -158,7 +231,6 @@ jobs: if [ $rc -eq 0 ]; then echo "Push to main succeeded." echo "updated=true" >> "$GITHUB_OUTPUT" - # вычистим дерево, чтобы дальше всё было чисто git fetch origin main git reset --hard origin/main git clean -fdx @@ -167,10 +239,8 @@ jobs: echo "Push to main denied (likely branch protection). Preparing PR..." echo "updated=true" >> "$GITHUB_OUTPUT" - # создаём ветку для PR BR="ci/readme-auto-refresh" git switch -c "$BR" || git checkout -b "$BR" - # коммит уже есть, просто запушим ветку git push -u origin "$BR" - name: Create pull request for README (fallback) @@ -185,23 +255,6 @@ jobs: commit-message: "chore(readme): auto-refresh [skip ci]" labels: ci, chore delete-branch: true - # ---------- end README handling ---------- - - - name: Check formatting (nightly rustfmt) - if: matrix.rust == needs.msrv.outputs.version - uses: ./.github/actions/cargo-fmt - with: - toolchain: nightly - - - name: Clippy (${{ matrix.rust }}) - uses: ./.github/actions/cargo-clippy - with: - toolchain: ${{ matrix.rust }} - all-features: ${{ inputs.all-features }} - - - name: Cargo deny - if: matrix.rust == needs.msrv.outputs.version - uses: ./.github/actions/cargo-deny - name: Tests (${{ matrix.rust }}) uses: ./.github/actions/cargo-test @@ -209,10 +262,6 @@ jobs: toolchain: ${{ matrix.rust }} all-features: ${{ inputs.all-features }} - - name: Security audit - if: matrix.rust == needs.msrv.outputs.version - uses: ./.github/actions/cargo-audit - - name: Auto-commit README changes (any branch) if: always() && matrix.rust == needs.msrv.outputs.version run: | @@ -229,8 +278,23 @@ jobs: echo "README already up to date." fi + package: + runs-on: ubuntu-latest + needs: [msrv, test] + steps: + - uses: actions/checkout@v5 + + - name: Install Rust (${{ needs.msrv.outputs.version }}) + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ needs.msrv.outputs.version }} + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/heads/main' }} + - name: Ensure tree is clean before package - if: matrix.rust == needs.msrv.outputs.version shell: bash run: | set -euo pipefail @@ -241,12 +305,11 @@ jobs: fi - name: Package (dry-run) - if: matrix.rust == needs.msrv.outputs.version - run: cargo +${{ matrix.rust }} package --locked + run: cargo +${{ needs.msrv.outputs.version }} package --locked coverage: runs-on: ubuntu-latest - needs: ci + needs: test steps: - uses: actions/checkout@v5 @@ -278,7 +341,7 @@ jobs: benchmarks: runs-on: ubuntu-latest - needs: ci + needs: test if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v5 @@ -319,4 +382,3 @@ jobs: else echo "No previous benchmark found, skipping comparison" fi - From aa57b4db21037a80763761393b0605fbbf010cb1 Mon Sep 17 00:00:00 2001 From: RAprogramm Date: Sun, 12 Oct 2025 11:17:45 +0700 Subject: [PATCH 2/2] feat: add explicit permissions to workflow jobs Added `permissions` blocks to all jobs following principle of least privilege: - `contents: read` for all read-only jobs (msrv, fmt, clippy, deny, audit, package, coverage, benchmarks) - `contents: write` and `pull-requests: write` for test job (requires write access for README auto-commit) This addresses GitHub Advanced Security bot review findings. --- .github/workflows/reusable-ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/reusable-ci.yml b/.github/workflows/reusable-ci.yml index f49eb66..01e78d5 100644 --- a/.github/workflows/reusable-ci.yml +++ b/.github/workflows/reusable-ci.yml @@ -14,6 +14,8 @@ on: jobs: msrv: runs-on: ubuntu-latest + permissions: + contents: read outputs: version: ${{ steps.msrv.outputs.msrv }} steps: @@ -39,6 +41,8 @@ jobs: fmt: runs-on: ubuntu-latest needs: msrv + permissions: + contents: read steps: - uses: actions/checkout@v5 @@ -61,6 +65,8 @@ jobs: clippy: runs-on: ubuntu-latest needs: msrv + permissions: + contents: read strategy: fail-fast: false matrix: @@ -91,6 +97,8 @@ jobs: deny: runs-on: ubuntu-latest needs: msrv + permissions: + contents: read steps: - uses: actions/checkout@v5 @@ -105,6 +113,8 @@ jobs: audit: runs-on: ubuntu-latest needs: msrv + permissions: + contents: read steps: - uses: actions/checkout@v5 @@ -119,6 +129,9 @@ jobs: test: runs-on: ubuntu-latest needs: [msrv, fmt, clippy] + permissions: + contents: write + pull-requests: write strategy: fail-fast: false matrix: @@ -281,6 +294,8 @@ jobs: package: runs-on: ubuntu-latest needs: [msrv, test] + permissions: + contents: read steps: - uses: actions/checkout@v5 @@ -310,6 +325,8 @@ jobs: coverage: runs-on: ubuntu-latest needs: test + permissions: + contents: read steps: - uses: actions/checkout@v5 @@ -342,6 +359,8 @@ jobs: benchmarks: runs-on: ubuntu-latest needs: test + permissions: + contents: read if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v5