From 2ae1e8ad05a03283adb2f4f1eb9efb868372f966 Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Thu, 9 Jul 2026 05:22:39 +0800 Subject: [PATCH] ci: right-size pipelines, fix prerelease latest.json overwrite (#4582) - build.yml: update latest.json only for stable release tags (alpha/beta/rc tags previously overwrote the stable pointer with release_type "stable"); drop the placeholder .asc files; build the Linux targets only on main pushes (tags/schedule/dispatch keep the full matrix); remove the unreachable --build clause and a needless full-history clone - ci.yml: event-scoped concurrency so merges stop cancelling the weekly scheduled run; drop the redundant skip-duplicate-actions gate job; run clippy before tests; trim the unused toolchain from the typos job - ci-docs-only.yml (new): satisfy the required "Test and Lint" check on docs-only PRs that ci.yml skips via paths-ignore - audit.yml: drop cargo-audit (cargo-deny advisories covers the same RustSec database); same event-scoped concurrency fix - docker.yml: job-level short-circuit for per-merge dev builds; send the Trivy SARIF to code scanning; unify the upload-artifact pin - performance-ab.yml: add concurrency; only re-run on labeled events when the added label is perf-ab - stagger the Sunday crons (build 01:00, audit 03:00, nix-flake-update 05:00, mint 06:00) - delete performance.yml: disabled since 2025-07; idle-server profiling, no benchmark baseline, stale ecstore package name --- .github/workflows/audit.yml | 37 ++----- .github/workflows/build.yml | 36 +++--- .github/workflows/ci-docs-only.yml | 60 ++++++++++ .github/workflows/ci.yml | 85 ++++++-------- .github/workflows/docker.yml | 27 ++++- .github/workflows/mint.yml | 5 +- .github/workflows/nix-flake-update.yml | 2 +- .github/workflows/performance-ab.yml | 16 ++- .github/workflows/performance.yml | 146 ------------------------- 9 files changed, 162 insertions(+), 252 deletions(-) create mode 100644 .github/workflows/ci-docs-only.yml delete mode 100644 .github/workflows/performance.yml diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index f545ee3d2..99fe9d4b2 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -35,15 +35,17 @@ on: - '.github/workflows/**' - 'scripts/security/check_workflow_pins.sh' schedule: - - cron: '0 0 * * 0' # Weekly on Sunday at midnight UTC + - cron: '0 3 * * 0' # Weekly on Sunday 03:00 UTC (staggered after the midnight ci/build crons) workflow_dispatch: permissions: contents: read +# Event-scoped groups: merges to main must not cancel the weekly scheduled +# run (same rationale as ci.yml). concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name != 'schedule' }} env: CARGO_TERM_COLOR: always @@ -57,32 +59,9 @@ jobs: - name: Explain cancellation run run: echo "PR closed; this run only cancels older runs in the same concurrency group." - security-audit: - name: Security Audit - if: github.event_name != 'pull_request' || github.event.action != 'closed' - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - - name: Install cargo-audit - uses: taiki-e/install-action@bffeee26d4db9be238a4ea78d8826604ebcb594d # v2 - with: - tool: cargo-audit - - - name: Run security audit - run: | - cargo audit -D warnings --json | tee audit-results.json - - - name: Upload audit results - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: security-audit-results-${{ github.run_number }} - path: audit-results.json - retention-days: 30 - + # RustSec advisory scanning is covered by the `advisories` check of + # cargo-deny below; a separate cargo-audit job would duplicate the same + # database lookup with a second ignore list to maintain. cargo-deny: name: Cargo Deny if: github.event_name != 'pull_request' || github.event.action != 'closed' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec94d0c96..8008c4cfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,11 @@ # 2. Upload binaries to OSS storage # 3. Trigger docker.yml to build and push images using the uploaded binaries # +# Platform scope: +# - Pushes to main (development builds) build the Linux targets only — they +# feed the dev download channel and Docker dev images. Tags, the weekly +# schedule and manual dispatch build the full platform matrix. +# # Manual Parameters: # - build_docker: Build and push Docker images (default: true) # - platforms: Comma-separated platform IDs or 'all' (default: all) @@ -46,7 +51,7 @@ on: - ".gitignore" - ".dockerignore" schedule: - - cron: "0 0 * * 0" # Weekly on Sunday at midnight UTC + - cron: "0 1 * * 0" # Weekly on Sunday 01:00 UTC (staggered after the ci.yml midnight cron) workflow_dispatch: inputs: build_docker: @@ -87,8 +92,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - with: - fetch-depth: 0 - name: Determine build strategy id: check @@ -125,8 +128,7 @@ jobs: version="dev-${short_sha}" echo "🛠️ Development build detected" elif [[ "${{ github.event_name }}" == "schedule" ]] || \ - [[ "${{ github.event_name }}" == "workflow_dispatch" ]] || \ - [[ "${{ contains(github.event.head_commit.message, '--build') }}" == "true" ]]; then + [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then # Scheduled or manual build should_build=true build_type="development" @@ -150,6 +152,7 @@ jobs: # Build RustFS binaries prepare-platform-matrix: name: Prepare Platform Matrix + needs: build-check runs-on: ubuntu-latest outputs: matrix: ${{ steps.select.outputs.matrix }} @@ -167,6 +170,18 @@ jobs: selected="all" fi + # Per-merge development builds only feed the dev download channel + # and the Docker dev images, which consume the Linux binaries; at + # the usual merge cadence most per-merge builds are cancelled by the + # next merge anyway. macOS and Windows stay covered by tag builds, + # the weekly scheduled build and manual dispatch. + if [[ "${selected}" == "all" \ + && "${{ github.event_name }}" == "push" \ + && "${{ needs.build-check.outputs.build_type }}" == "development" ]]; then + selected="linux-x86_64-musl,linux-aarch64-musl,linux-x86_64-gnu,linux-aarch64-gnu" + echo "Development (main push) build: restricting to Linux targets" + fi + all='{"include":[ {"target_id":"linux-x86_64-musl","os":"sm-standard-2","target":"x86_64-unknown-linux-musl","cross":false,"platform":"linux","rustflags":""}, {"target_id":"linux-aarch64-musl","os":"sm-standard-2","target":"aarch64-unknown-linux-musl","cross":true,"platform":"linux","rustflags":""}, @@ -783,12 +798,6 @@ jobs: sha512sum *.zip > SHA512SUMS fi - # Create signature placeholder files - for file in *.zip; do - echo "# Signature for $file" > "${file}.asc" - echo "# GPG signature will be added in future versions" >> "${file}.asc" - done - cd .. python3 scripts/security/generate_release_supply_chain_assets.py \ --asset-dir ./release-assets \ @@ -826,11 +835,12 @@ jobs: echo "✅ All assets uploaded successfully" - # Update latest.json for stable releases only + # Update latest.json for stable releases only: prerelease tags (alpha/beta/ + # rc) must never overwrite the stable version pointer. update-latest-version: name: Update Latest Version needs: [ build-check, upload-release-assets ] - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') && needs.build-check.outputs.build_type == 'release' runs-on: ubuntu-latest steps: - name: Update latest.json diff --git a/.github/workflows/ci-docs-only.yml b/.github/workflows/ci-docs-only.yml new file mode 100644 index 000000000..fd5efc2d1 --- /dev/null +++ b/.github/workflows/ci-docs-only.yml @@ -0,0 +1,60 @@ +# Copyright 2026 RustFS Team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Companion to ci.yml for the required "Test and Lint" status check. +# +# ci.yml skips docs-only pull requests via paths-ignore, but the branch +# ruleset requires a check named "Test and Lint" — without this workflow a +# docs-only PR would wait on that check forever. This workflow triggers on +# exactly the paths ci.yml ignores and reports an instant success under the +# same job name. Mixed PRs trigger both workflows and the real check still +# gates: a required check with any failing run blocks the merge. +# https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks +# +# Keep the paths list below in sync with the pull_request paths-ignore list +# in ci.yml. + +name: Continuous Integration (docs only) + +on: + pull_request: + types: [ opened, synchronize, reopened ] + branches: [ main ] + paths: + - "**.md" + - "docs/**" + - "deploy/**" + - "scripts/dev_*.sh" + - "scripts/probe.sh" + - "LICENSE*" + - ".gitignore" + - ".dockerignore" + - "README*" + - "**/*.png" + - "**/*.jpg" + - "**/*.svg" + - ".github/workflows/build.yml" + - ".github/workflows/docker.yml" + - ".github/workflows/audit.yml" + +permissions: + contents: read + +jobs: + test-and-lint: + name: Test and Lint + runs-on: ubuntu-latest + steps: + - name: Satisfy required check for docs-only changes + run: echo "Docs-only change — code CI is skipped by paths-ignore; reporting success for the required 'Test and Lint' check." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8b60c770..6c57d8d4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,10 +33,11 @@ on: - ".github/workflows/build.yml" - ".github/workflows/docker.yml" - ".github/workflows/audit.yml" - - ".github/workflows/performance.yml" pull_request: types: [ opened, synchronize, reopened, closed ] branches: [ main ] + # Keep this list in sync with the `paths` list in ci-docs-only.yml, which + # reports the required "Test and Lint" check for PRs skipped here. paths-ignore: - "**.md" - "docs/**" @@ -53,7 +54,6 @@ on: - ".github/workflows/build.yml" - ".github/workflows/docker.yml" - ".github/workflows/audit.yml" - - ".github/workflows/performance.yml" merge_group: types: [ checks_requested ] schedule: @@ -63,9 +63,13 @@ on: permissions: contents: read +# Concurrency groups are scoped per event so different triggers never cancel +# each other: PR pushes cancel the previous run of that PR, main pushes keep +# latest-wins semantics among themselves, and scheduled runs always complete +# (a shared group used to let every merge kill the weekly scheduled run). concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name != 'schedule' }} env: CARGO_TERM_COLOR: always @@ -81,33 +85,12 @@ jobs: - name: Explain cancellation run run: echo "PR closed; this run only cancels older runs in the same concurrency group." - skip-check: - name: Skip Duplicate Actions - if: github.event_name != 'pull_request' || github.event.action != 'closed' - permissions: - actions: write - contents: read - runs-on: ubuntu-latest - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - name: Skip duplicate actions - id: skip_check - uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5 - with: - concurrent_skipping: "same_content_newer" - cancel_others: true - paths_ignore: '["*.md", "docs/**", "deploy/**"]' - do_not_skip: '["workflow_dispatch", "schedule", "merge_group", "release", "push"]' - typos: name: Typos - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Typos check with custom config file uses: crate-ci/typos@37bb98842b0d8c4ffebdb75301a13db0267cef89 # master @@ -115,8 +98,7 @@ jobs: # ~1 minute instead of waiting for the full test job. quick-checks: name: Quick Checks - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -148,8 +130,7 @@ jobs: test-and-lint: name: Test and Lint - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: sm-standard-4 timeout-minutes: 60 env: @@ -166,6 +147,12 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} cache-save-if: ${{ github.ref == 'refs/heads/main' }} + # Clippy runs before the test pass: lint failures are the most common + # CI-only breakage and should surface in minutes, not after 20+ minutes + # of tests. + - name: Run clippy lints + run: cargo clippy --all-targets -- -D warnings + - name: Run tests run: | cargo nextest run --all --exclude e2e_test @@ -179,13 +166,9 @@ jobs: cargo nextest run -p rustfs-ecstore --lib \ -E 'test(data_movement) or test(rebalance) or test(decommission) or test(source_cleanup) or test(delete_marker)' - - name: Run clippy lints - run: cargo clippy --all-targets -- -D warnings - test-and-lint-rio-v2: name: Test and Lint (rio-v2) - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: sm-standard-4 timeout-minutes: 60 env: @@ -202,18 +185,17 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} cache-save-if: ${{ github.ref == 'refs/heads/main' }} + - name: Run rio-v2 clippy lints + run: cargo clippy -p rustfs -p rustfs-ecstore --all-targets --features rio-v2 -- -D warnings + - name: Run rio-v2 feature tests run: | cargo nextest run -p rustfs -p rustfs-ecstore --features rio-v2 cargo test -p rustfs --doc --features rio-v2 - - name: Run rio-v2 clippy lints - run: cargo clippy -p rustfs -p rustfs-ecstore --all-targets --features rio-v2 -- -D warnings - test-and-lint-protocols: name: "Test and Lint (${{ matrix.features.name }})" - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: sm-standard-4 timeout-minutes: 60 strategy: @@ -238,18 +220,17 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} cache-save-if: ${{ github.ref == 'refs/heads/main' }} - - name: Run tests with ${{ matrix.features.name }} - run: | - cargo nextest run -p rustfs -p rustfs-protocols ${{ matrix.features.flags }} - - name: Run clippy with ${{ matrix.features.name }} run: | cargo clippy -p rustfs -p rustfs-protocols --all-targets ${{ matrix.features.flags }} -- -D warnings + - name: Run tests with ${{ matrix.features.name }} + run: | + cargo nextest run -p rustfs -p rustfs-protocols ${{ matrix.features.flags }} + build-rustfs-debug-binary: name: Build RustFS Debug Binary - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: sm-standard-4 timeout-minutes: 30 env: @@ -279,8 +260,7 @@ jobs: build-rustfs-debug-binary-rio-v2: name: Build RustFS Debug Binary (rio-v2) - needs: skip-check - if: needs.skip-check.outputs.should_skip != 'true' + if: github.event_name != 'pull_request' || github.event.action != 'closed' runs-on: sm-standard-4 timeout-minutes: 30 env: @@ -310,8 +290,7 @@ jobs: e2e-tests: name: End-to-End Tests - needs: [ skip-check, build-rustfs-debug-binary ] - if: needs.skip-check.outputs.should_skip != 'true' + needs: [ build-rustfs-debug-binary ] runs-on: sm-standard-2 timeout-minutes: 30 steps: @@ -370,8 +349,7 @@ jobs: e2e-tests-rio-v2: name: End-to-End Tests (rio-v2) - needs: [ skip-check, build-rustfs-debug-binary-rio-v2 ] - if: needs.skip-check.outputs.should_skip != 'true' + needs: [ build-rustfs-debug-binary-rio-v2 ] runs-on: sm-standard-2 timeout-minutes: 30 steps: @@ -417,8 +395,7 @@ jobs: s3-implemented-tests: name: S3 Implemented Tests - needs: [ skip-check, build-rustfs-debug-binary, e2e-tests ] - if: needs.skip-check.outputs.should_skip != 'true' + needs: [ build-rustfs-debug-binary, e2e-tests ] runs-on: sm-standard-4 timeout-minutes: 60 steps: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c8140edc9..aa1a62a05 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -70,9 +70,19 @@ env: DOCKER_PLATFORMS: linux/amd64,linux/arm64 jobs: - # Check if we should build Docker images + # Check if we should build Docker images. + # Short-circuit at job level so per-merge development builds (workflow_run + # from a push to main) skip the whole run without spawning a checkout job: + # images are only published for tag builds — build.yml push triggers cover + # only main and tags, so a non-main head_branch is a tag name — and for + # manual dispatch. build-check: name: Docker Build Check + if: >- + github.event_name == 'workflow_dispatch' || + (github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + github.event.workflow_run.head_branch != 'main') runs-on: ubuntu-latest outputs: should_build: ${{ steps.check.outputs.should_build }} @@ -86,7 +96,6 @@ jobs: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: - fetch-depth: 0 # For workflow_run events, checkout the specific commit that triggered the workflow ref: ${{ github.event.workflow_run.head_sha || github.sha }} @@ -421,6 +430,9 @@ jobs: needs: [ build-check, build-docker ] if: needs.build-check.outputs.should_build == 'true' && needs.build-check.outputs.should_push == 'true' runs-on: ubuntu-latest + permissions: + contents: read + security-events: write strategy: fail-fast: false matrix: @@ -450,9 +462,16 @@ jobs: severity: CRITICAL,HIGH exit-code: "0" + # Surface findings in the Security tab; an artifact alone is write-only + # reporting nobody reviews. + - name: Upload scan results to code scanning + uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + with: + sarif_file: trivy-${{ matrix.variant }}.sarif + category: container-image-${{ matrix.variant }} + - name: Upload container scan report - # actions/upload-artifact v7.0.1 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: container-image-scan-${{ matrix.variant }} path: trivy-${{ matrix.variant }}.sarif diff --git a/.github/workflows/mint.yml b/.github/workflows/mint.yml index 7f5c240f5..bd9d6a658 100644 --- a/.github/workflows/mint.yml +++ b/.github/workflows/mint.yml @@ -50,8 +50,9 @@ on: required: false default: "minio/mint:edge" schedule: - # Weekly, after the Sunday s3-tests full sweep. - - cron: "0 4 * * 0" + # Weekly, after the Sunday s3-tests full sweep (starts 02:00 UTC, up to + # 3h) has finished, so the two never contend for the same runner pool. + - cron: "0 6 * * 0" env: S3_ACCESS_KEY: rustfsadmin diff --git a/.github/workflows/nix-flake-update.yml b/.github/workflows/nix-flake-update.yml index 8d4dc9be6..9857d0b55 100644 --- a/.github/workflows/nix-flake-update.yml +++ b/.github/workflows/nix-flake-update.yml @@ -17,7 +17,7 @@ name: Update Nix Flake on: workflow_dispatch: schedule: - - cron: '0 0 * * 0' # Weekly on Sundays + - cron: '0 5 * * 0' # Weekly on Sunday 05:00 UTC (staggered after the midnight ci/build crons) permissions: contents: write diff --git a/.github/workflows/performance-ab.yml b/.github/workflows/performance-ab.yml index 28a29cdfe..320e11c77 100644 --- a/.github/workflows/performance-ab.yml +++ b/.github/workflows/performance-ab.yml @@ -46,6 +46,13 @@ permissions: contents: read pull-requests: write +# Per-PR: a new push cancels the previous (up to 90-minute) A/B run instead of +# stacking them. Nightly schedule and manual dispatch get a unique group and +# always run to completion. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 @@ -53,11 +60,14 @@ env: jobs: warp-ab: name: Warp A/B budget gate - # Opt-in on PRs: only run when the `perf-ab` label is present. Always run on - # schedule / manual dispatch. + # Opt-in on PRs: only run when the `perf-ab` label is present, and for + # `labeled` events only when the label being added is `perf-ab` itself — + # adding an unrelated label to an opted-in PR must not re-run the gate. + # Always run on schedule / manual dispatch. if: >- github.event_name != 'pull_request' || - contains(github.event.pull_request.labels.*.name, 'perf-ab') + (contains(github.event.pull_request.labels.*.name, 'perf-ab') && + (github.event.action != 'labeled' || github.event.label.name == 'perf-ab')) runs-on: sm-standard-2 timeout-minutes: 90 steps: diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml deleted file mode 100644 index 19770cb92..000000000 --- a/.github/workflows/performance.yml +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2024 RustFS Team -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Performance Testing - -on: - push: - branches: [ main ] - paths: - - "**/*.rs" - - "**/Cargo.toml" - - "**/Cargo.lock" - - ".github/workflows/performance.yml" - workflow_dispatch: - inputs: - profile_duration: - description: "Profiling duration in seconds" - required: false - default: "120" - type: string - -permissions: - contents: read - -env: - CARGO_TERM_COLOR: always - RUST_BACKTRACE: 1 - -jobs: - performance-profile: - name: Performance Profiling - runs-on: sm-standard-2 - timeout-minutes: 30 - env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - - name: Setup Rust environment - uses: ./.github/actions/setup - with: - rust-version: nightly - cache-shared-key: perf-${{ hashFiles('**/Cargo.lock') }} - cache-save-if: ${{ github.ref == 'refs/heads/main' }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install additional nightly components - run: rustup component add llvm-tools-preview - - - name: Install samply profiler - uses: taiki-e/cache-cargo-install-action@7447f04c51f2ba27ca35e7f1e28fab848c5b3ba7 # v2 - with: - tool: samply - - - name: Configure kernel for profiling - run: echo '1' | sudo tee /proc/sys/kernel/perf_event_paranoid - - - name: Prepare test environment - run: | - # Create test volumes - for i in {0..4}; do - mkdir -p ./target/volume/test$i - done - - # Set environment variables - echo "RUSTFS_VOLUMES=./target/volume/test{0...4}" >> $GITHUB_ENV - echo "RUST_LOG=rustfs=info,ecstore=info,s3s=info,iam=info,rustfs-obs=info" >> $GITHUB_ENV - - - name: Verify console static assets - run: | - # Console static assets are already embedded in the repository - echo "Console static assets size: $(du -sh rustfs/static/)" - echo "Console static assets are embedded via rust-embed, no external download needed" - - - name: Build with profiling optimizations - run: | - RUSTFLAGS="-C force-frame-pointers=yes -C debug-assertions=off --cfg tokio_unstable" \ - cargo +nightly build --profile profiling -p rustfs --bins - - - name: Run performance profiling - id: profiling - run: | - DURATION="${{ github.event.inputs.profile_duration || '120' }}" - echo "Running profiling for ${DURATION} seconds..." - - timeout "${DURATION}s" samply record \ - --output samply-profile.json \ - ./target/profiling/rustfs ${RUSTFS_VOLUMES} || true - - if [ -f "samply-profile.json" ]; then - echo "profile_generated=true" >> $GITHUB_OUTPUT - echo "Profile generated successfully" - else - echo "profile_generated=false" >> $GITHUB_OUTPUT - echo "::warning::Profile data not generated" - fi - - - name: Upload profile data - if: steps.profiling.outputs.profile_generated == 'true' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: performance-profile-${{ github.run_number }} - path: samply-profile.json - retention-days: 30 - - benchmark: - name: Benchmark Tests - runs-on: sm-standard-2 - timeout-minutes: 45 - env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - - - name: Setup Rust environment - uses: ./.github/actions/setup - with: - rust-version: stable - cache-shared-key: bench-${{ hashFiles('**/Cargo.lock') }} - github-token: ${{ secrets.GITHUB_TOKEN }} - cache-save-if: ${{ github.ref == 'refs/heads/main' }} - - - name: Run benchmarks - run: | - cargo bench --package ecstore --bench comparison_benchmark -- --output-format json | \ - tee benchmark-results.json - - - name: Upload benchmark results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: benchmark-results-${{ github.run_number }} - path: benchmark-results.json - retention-days: 7