Compare Performance #38
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: Compare Performance | |
| # Runs up to 5 parallel performance test configurations (an optional no-agent | |
| # baseline plus up to 4 agent runs) and generates a comparative report with | |
| # ScottPlot charts and a markdown summary table. | |
| # | |
| # Nightly scheduled run compares the latest published release against the most | |
| # recent successful scheduled all_solutions.yml build (today's nightly build). | |
| # | |
| # Required secrets (when any agent run is included): | |
| # PERF_TEST_ACCOUNT - New Relic license key and collector host separated by a | |
| # comma. Example: XXXXXXXXXXXX,collector.newrelic.com | |
| # | |
| # The 'agent' input for each run accepts: | |
| # "" - Latest published release (github_release, no version pin) | |
| # "10.49.0" - Specific release version (github_release) | |
| # "12345678901" - all_solutions.yml run ID (build_artifact) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| # --- No-agent baseline --- | |
| include_no_agent: | |
| description: 'Include a no-agent baseline run' | |
| type: boolean | |
| default: true | |
| required: false | |
| no_agent_env: | |
| description: 'Extra env vars for the no-agent run, semicolon-separated NAME=VALUE pairs (e.g. VAR1=val1;VAR2=val2)' | |
| type: string | |
| default: '' | |
| required: false | |
| # --- Agent run 1 (always runs) --- | |
| run1_label: | |
| description: 'Label for agent run 1' | |
| type: string | |
| default: 'latest-release' | |
| required: false | |
| run1_agent: | |
| description: 'Run 1 agent: version (e.g. "10.49.0"), run ID, or empty for latest' | |
| type: string | |
| default: '' | |
| required: false | |
| run1_agent_env: | |
| description: 'Extra env vars for agent run 1, semicolon-separated NAME=VALUE pairs (e.g. VAR1=val1;VAR2=val2)' | |
| type: string | |
| default: '' | |
| required: false | |
| # --- Agent run 2 (optional) --- | |
| include_run2: | |
| description: 'Include agent run 2' | |
| type: boolean | |
| default: false | |
| required: false | |
| run2_label: | |
| description: 'Label for agent run 2' | |
| type: string | |
| default: 'run2' | |
| required: false | |
| run2_agent: | |
| description: 'Run 2 agent: version, run ID, or empty for latest' | |
| type: string | |
| default: '' | |
| required: false | |
| run2_agent_env: | |
| description: 'Extra env vars for agent run 2, semicolon-separated NAME=VALUE pairs (e.g. VAR1=val1;VAR2=val2)' | |
| type: string | |
| default: '' | |
| required: false | |
| # --- Agent run 3 (optional) --- | |
| include_run3: | |
| description: 'Include agent run 3' | |
| type: boolean | |
| default: false | |
| required: false | |
| run3_label: | |
| description: 'Label for agent run 3' | |
| type: string | |
| default: 'run3' | |
| required: false | |
| run3_agent: | |
| description: 'Run 3 agent: version, run ID, or empty for latest' | |
| type: string | |
| default: '' | |
| required: false | |
| run3_agent_env: | |
| description: 'Extra env vars for agent run 3, semicolon-separated NAME=VALUE pairs (e.g. VAR1=val1;VAR2=val2)' | |
| type: string | |
| default: '' | |
| required: false | |
| # --- Agent run 4 (optional) --- | |
| include_run4: | |
| description: 'Include agent run 4' | |
| type: boolean | |
| default: false | |
| required: false | |
| run4_label: | |
| description: 'Label for agent run 4' | |
| type: string | |
| default: 'run4' | |
| required: false | |
| run4_agent: | |
| description: 'Run 4 agent: version, run ID, or empty for latest' | |
| type: string | |
| default: '' | |
| required: false | |
| run4_agent_env: | |
| description: 'Extra env vars for agent run 4, semicolon-separated NAME=VALUE pairs (e.g. VAR1=val1;VAR2=val2)' | |
| type: string | |
| default: '' | |
| required: false | |
| # --- Shared test parameters --- | |
| test_duration: | |
| description: 'Traffic duration (Locust --run-time, e.g. "2m", "5m")' | |
| type: string | |
| default: '2m' | |
| required: false | |
| locust_users: | |
| description: 'Number of concurrent Locust users' | |
| type: number | |
| default: 10 | |
| required: false | |
| locust_spawn_rate: | |
| description: 'Locust users to spawn per second' | |
| type: number | |
| default: 2 | |
| required: false | |
| dotnet_version: | |
| description: '.NET version for the test app container (e.g. "10.0", "8.0")' | |
| type: string | |
| default: '10.0' | |
| required: false | |
| schedule: | |
| # Run nightly on weekdays: latest published release vs. latest scheduled nightly build | |
| # all_solutions.yml runs at 9:00 UTC and may take more than an hour, so start at 11:00 UTC | |
| - cron: '0 11 * * 1-5' | |
| env: | |
| DOTNET_NOLOGO: true | |
| PERF_TEST_DIR: tests/Agent/PerformanceTests | |
| # Only allow one compare run at a time | |
| concurrency: | |
| group: compare-performance-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| actions: read | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Resolve inputs — normalises both triggers to a common set of outputs and | |
| # parses each agent string into agent_source / agent_version / build_run_id. | |
| # | |
| # Agent string format: | |
| # "" → github_release, no version pin (latest) | |
| # "X.Y.Z" → github_release, pinned to that version | |
| # "<digits>" → build_artifact, that run ID | |
| # --------------------------------------------------------------------------- | |
| resolve-inputs: | |
| name: Resolve Inputs | |
| runs-on: ubuntu-latest | |
| outputs: | |
| include_no_agent: ${{ steps.inputs.outputs.include_no_agent }} | |
| run1_label: ${{ steps.inputs.outputs.run1_label }} | |
| run1_agent_source: ${{ steps.inputs.outputs.run1_agent_source }} | |
| run1_agent_version: ${{ steps.inputs.outputs.run1_agent_version }} | |
| run1_build_run_id: ${{ steps.inputs.outputs.run1_build_run_id }} | |
| include_run2: ${{ steps.inputs.outputs.include_run2 }} | |
| run2_label: ${{ steps.inputs.outputs.run2_label }} | |
| run2_agent_source: ${{ steps.inputs.outputs.run2_agent_source }} | |
| run2_agent_version: ${{ steps.inputs.outputs.run2_agent_version }} | |
| run2_build_run_id: ${{ steps.inputs.outputs.run2_build_run_id }} | |
| include_run3: ${{ steps.inputs.outputs.include_run3 }} | |
| run3_label: ${{ steps.inputs.outputs.run3_label }} | |
| run3_agent_source: ${{ steps.inputs.outputs.run3_agent_source }} | |
| run3_agent_version: ${{ steps.inputs.outputs.run3_agent_version }} | |
| run3_build_run_id: ${{ steps.inputs.outputs.run3_build_run_id }} | |
| include_run4: ${{ steps.inputs.outputs.include_run4 }} | |
| run4_label: ${{ steps.inputs.outputs.run4_label }} | |
| run4_agent_source: ${{ steps.inputs.outputs.run4_agent_source }} | |
| run4_agent_version: ${{ steps.inputs.outputs.run4_agent_version }} | |
| run4_build_run_id: ${{ steps.inputs.outputs.run4_build_run_id }} | |
| no_agent_env: ${{ steps.inputs.outputs.no_agent_env }} | |
| run1_agent_env: ${{ steps.inputs.outputs.run1_agent_env }} | |
| run2_agent_env: ${{ steps.inputs.outputs.run2_agent_env }} | |
| run3_agent_env: ${{ steps.inputs.outputs.run3_agent_env }} | |
| run4_agent_env: ${{ steps.inputs.outputs.run4_agent_env }} | |
| test_duration: ${{ steps.inputs.outputs.test_duration }} | |
| locust_users: ${{ steps.inputs.outputs.locust_users }} | |
| locust_spawn_rate: ${{ steps.inputs.outputs.locust_spawn_rate }} | |
| dotnet_version: ${{ steps.inputs.outputs.dotnet_version }} | |
| license_key: ${{ steps.inputs.outputs.license_key }} | |
| collector_host: ${{ steps.inputs.outputs.collector_host }} | |
| steps: | |
| - name: Resolve inputs | |
| id: inputs | |
| env: | |
| PERF_TEST_ACCOUNT: ${{ secrets.PERF_TEST_ACCOUNT }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Parse an agent string into agent_source / agent_version / build_run_id | |
| # and write the three outputs prefixed with $1. | |
| parse_agent() { | |
| local PREFIX="$1" | |
| local AGENT="$2" | |
| if echo "$AGENT" | grep -qE '^[0-9]+\.[0-9]'; then | |
| # Version string (e.g. "10.49.0") → github_release | |
| echo "${PREFIX}_agent_source=github_release" >> "$GITHUB_OUTPUT" | |
| echo "${PREFIX}_agent_version=$AGENT" >> "$GITHUB_OUTPUT" | |
| echo "${PREFIX}_build_run_id=" >> "$GITHUB_OUTPUT" | |
| elif [ -n "$AGENT" ]; then | |
| # Pure digits → build_artifact run ID | |
| echo "${PREFIX}_agent_source=build_artifact" >> "$GITHUB_OUTPUT" | |
| echo "${PREFIX}_agent_version=" >> "$GITHUB_OUTPUT" | |
| echo "${PREFIX}_build_run_id=$AGENT" >> "$GITHUB_OUTPUT" | |
| else | |
| # Empty → latest release | |
| echo "${PREFIX}_agent_source=github_release" >> "$GITHUB_OUTPUT" | |
| echo "${PREFIX}_agent_version=" >> "$GITHUB_OUTPUT" | |
| echo "${PREFIX}_build_run_id=" >> "$GITHUB_OUTPUT" | |
| fi | |
| } | |
| if [ "${{ github.event_name }}" = "schedule" ]; then | |
| # Find the most recent successful all_solutions.yml run triggered by schedule | |
| NIGHTLY_RUN_ID=$(gh run list \ | |
| --repo "${{ github.repository }}" \ | |
| --workflow all_solutions.yml \ | |
| --event schedule \ | |
| --status success \ | |
| --limit 1 \ | |
| --json databaseId \ | |
| --jq '.[0].databaseId') | |
| if [ -z "$NIGHTLY_RUN_ID" ]; then | |
| echo "ERROR: Could not find a recent successful scheduled all_solutions.yml run" >&2 | |
| exit 1 | |
| fi | |
| echo "Found nightly build run ID: $NIGHTLY_RUN_ID" | |
| echo "include_no_agent=true" >> "$GITHUB_OUTPUT" | |
| echo "run1_label=latest-release" >> "$GITHUB_OUTPUT" | |
| parse_agent "run1" "" | |
| echo "include_run2=true" >> "$GITHUB_OUTPUT" | |
| echo "run2_label=nightly-build" >> "$GITHUB_OUTPUT" | |
| parse_agent "run2" "$NIGHTLY_RUN_ID" | |
| echo "include_run3=false" >> "$GITHUB_OUTPUT" | |
| echo "run3_label=" >> "$GITHUB_OUTPUT" | |
| parse_agent "run3" "" | |
| echo "include_run4=false" >> "$GITHUB_OUTPUT" | |
| echo "run4_label=" >> "$GITHUB_OUTPUT" | |
| parse_agent "run4" "" | |
| echo "no_agent_env=" >> "$GITHUB_OUTPUT" | |
| echo "run1_agent_env=" >> "$GITHUB_OUTPUT" | |
| echo "run2_agent_env=" >> "$GITHUB_OUTPUT" | |
| echo "run3_agent_env=" >> "$GITHUB_OUTPUT" | |
| echo "run4_agent_env=" >> "$GITHUB_OUTPUT" | |
| echo "test_duration=2m" >> "$GITHUB_OUTPUT" | |
| echo "locust_users=10" >> "$GITHUB_OUTPUT" | |
| echo "locust_spawn_rate=2" >> "$GITHUB_OUTPUT" | |
| echo "dotnet_version=10.0" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "include_no_agent=${{ inputs.include_no_agent }}" >> "$GITHUB_OUTPUT" | |
| echo "run1_label=${{ inputs.run1_label }}" >> "$GITHUB_OUTPUT" | |
| parse_agent "run1" "${{ inputs.run1_agent }}" | |
| echo "include_run2=${{ inputs.include_run2 }}" >> "$GITHUB_OUTPUT" | |
| echo "run2_label=${{ inputs.run2_label }}" >> "$GITHUB_OUTPUT" | |
| parse_agent "run2" "${{ inputs.run2_agent }}" | |
| echo "include_run3=${{ inputs.include_run3 }}" >> "$GITHUB_OUTPUT" | |
| echo "run3_label=${{ inputs.run3_label }}" >> "$GITHUB_OUTPUT" | |
| parse_agent "run3" "${{ inputs.run3_agent }}" | |
| echo "include_run4=${{ inputs.include_run4 }}" >> "$GITHUB_OUTPUT" | |
| echo "run4_label=${{ inputs.run4_label }}" >> "$GITHUB_OUTPUT" | |
| parse_agent "run4" "${{ inputs.run4_agent }}" | |
| echo "no_agent_env=${{ inputs.no_agent_env }}" >> "$GITHUB_OUTPUT" | |
| echo "run1_agent_env=${{ inputs.run1_agent_env }}" >> "$GITHUB_OUTPUT" | |
| echo "run2_agent_env=${{ inputs.run2_agent_env }}" >> "$GITHUB_OUTPUT" | |
| echo "run3_agent_env=${{ inputs.run3_agent_env }}" >> "$GITHUB_OUTPUT" | |
| echo "run4_agent_env=${{ inputs.run4_agent_env }}" >> "$GITHUB_OUTPUT" | |
| echo "test_duration=${{ inputs.test_duration }}" >> "$GITHUB_OUTPUT" | |
| echo "locust_users=${{ inputs.locust_users }}" >> "$GITHUB_OUTPUT" | |
| echo "locust_spawn_rate=${{ inputs.locust_spawn_rate }}" >> "$GITHUB_OUTPUT" | |
| echo "dotnet_version=${{ inputs.dotnet_version }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "license_key=${PERF_TEST_ACCOUNT%%,*}" >> "$GITHUB_OUTPUT" | |
| echo "collector_host=${PERF_TEST_ACCOUNT##*,}" >> "$GITHUB_OUTPUT" | |
| # --------------------------------------------------------------------------- | |
| # Parallel test runs | |
| # --------------------------------------------------------------------------- | |
| no-agent: | |
| name: 'Perf Run: no-agent' | |
| needs: resolve-inputs | |
| if: needs.resolve-inputs.outputs.include_no_agent == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Run perf test | |
| uses: ./.github/actions/run-perf-test | |
| with: | |
| run-label: no-agent | |
| attach-agent: 'false' | |
| agent-env: ${{ needs.resolve-inputs.outputs.no_agent_env }} | |
| test-duration: ${{ needs.resolve-inputs.outputs.test_duration }} | |
| locust-users: ${{ needs.resolve-inputs.outputs.locust_users }} | |
| locust-spawn-rate: ${{ needs.resolve-inputs.outputs.locust_spawn_rate }} | |
| dotnet-version: ${{ needs.resolve-inputs.outputs.dotnet_version }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-1: | |
| name: 'Perf Run: ${{ needs.resolve-inputs.outputs.run1_label }}' | |
| needs: resolve-inputs | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run perf test | |
| uses: ./.github/actions/run-perf-test | |
| with: | |
| run-label: ${{ needs.resolve-inputs.outputs.run1_label }} | |
| attach-agent: 'true' | |
| agent-source: ${{ needs.resolve-inputs.outputs.run1_agent_source }} | |
| agent-version: ${{ needs.resolve-inputs.outputs.run1_agent_version }} | |
| build-run-id: ${{ needs.resolve-inputs.outputs.run1_build_run_id }} | |
| agent-env: ${{ needs.resolve-inputs.outputs.run1_agent_env }} | |
| test-duration: ${{ needs.resolve-inputs.outputs.test_duration }} | |
| locust-users: ${{ needs.resolve-inputs.outputs.locust_users }} | |
| locust-spawn-rate: ${{ needs.resolve-inputs.outputs.locust_spawn_rate }} | |
| dotnet-version: ${{ needs.resolve-inputs.outputs.dotnet_version }} | |
| license-key: ${{ needs.resolve-inputs.outputs.license_key }} | |
| collector-host: ${{ needs.resolve-inputs.outputs.collector_host }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-2: | |
| name: 'Perf Run: ${{ needs.resolve-inputs.outputs.run2_label }}' | |
| needs: resolve-inputs | |
| if: needs.resolve-inputs.outputs.include_run2 == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run perf test | |
| uses: ./.github/actions/run-perf-test | |
| with: | |
| run-label: ${{ needs.resolve-inputs.outputs.run2_label }} | |
| attach-agent: 'true' | |
| agent-source: ${{ needs.resolve-inputs.outputs.run2_agent_source }} | |
| agent-version: ${{ needs.resolve-inputs.outputs.run2_agent_version }} | |
| build-run-id: ${{ needs.resolve-inputs.outputs.run2_build_run_id }} | |
| agent-env: ${{ needs.resolve-inputs.outputs.run2_agent_env }} | |
| test-duration: ${{ needs.resolve-inputs.outputs.test_duration }} | |
| locust-users: ${{ needs.resolve-inputs.outputs.locust_users }} | |
| locust-spawn-rate: ${{ needs.resolve-inputs.outputs.locust_spawn_rate }} | |
| dotnet-version: ${{ needs.resolve-inputs.outputs.dotnet_version }} | |
| license-key: ${{ needs.resolve-inputs.outputs.license_key }} | |
| collector-host: ${{ needs.resolve-inputs.outputs.collector_host }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-3: | |
| name: 'Perf Run: ${{ needs.resolve-inputs.outputs.run3_label }}' | |
| needs: resolve-inputs | |
| if: needs.resolve-inputs.outputs.include_run3 == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run perf test | |
| uses: ./.github/actions/run-perf-test | |
| with: | |
| run-label: ${{ needs.resolve-inputs.outputs.run3_label }} | |
| attach-agent: 'true' | |
| agent-source: ${{ needs.resolve-inputs.outputs.run3_agent_source }} | |
| agent-version: ${{ needs.resolve-inputs.outputs.run3_agent_version }} | |
| build-run-id: ${{ needs.resolve-inputs.outputs.run3_build_run_id }} | |
| agent-env: ${{ needs.resolve-inputs.outputs.run3_agent_env }} | |
| test-duration: ${{ needs.resolve-inputs.outputs.test_duration }} | |
| locust-users: ${{ needs.resolve-inputs.outputs.locust_users }} | |
| locust-spawn-rate: ${{ needs.resolve-inputs.outputs.locust_spawn_rate }} | |
| dotnet-version: ${{ needs.resolve-inputs.outputs.dotnet_version }} | |
| license-key: ${{ needs.resolve-inputs.outputs.license_key }} | |
| collector-host: ${{ needs.resolve-inputs.outputs.collector_host }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-4: | |
| name: 'Perf Run: ${{ needs.resolve-inputs.outputs.run4_label }}' | |
| needs: resolve-inputs | |
| if: needs.resolve-inputs.outputs.include_run4 == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run perf test | |
| uses: ./.github/actions/run-perf-test | |
| with: | |
| run-label: ${{ needs.resolve-inputs.outputs.run4_label }} | |
| attach-agent: 'true' | |
| agent-source: ${{ needs.resolve-inputs.outputs.run4_agent_source }} | |
| agent-version: ${{ needs.resolve-inputs.outputs.run4_agent_version }} | |
| build-run-id: ${{ needs.resolve-inputs.outputs.run4_build_run_id }} | |
| agent-env: ${{ needs.resolve-inputs.outputs.run4_agent_env }} | |
| test-duration: ${{ needs.resolve-inputs.outputs.test_duration }} | |
| locust-users: ${{ needs.resolve-inputs.outputs.locust_users }} | |
| locust-spawn-rate: ${{ needs.resolve-inputs.outputs.locust_spawn_rate }} | |
| dotnet-version: ${{ needs.resolve-inputs.outputs.dotnet_version }} | |
| license-key: ${{ needs.resolve-inputs.outputs.license_key }} | |
| collector-host: ${{ needs.resolve-inputs.outputs.collector_host }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| # --------------------------------------------------------------------------- | |
| # Report generation | |
| # --------------------------------------------------------------------------- | |
| generate-report: | |
| name: Generate Report | |
| needs: [no-agent, run-1, run-2, run-3, run-4] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Download all perf result artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: perf-results-* | |
| path: downloaded-results | |
| merge-multiple: false | |
| - name: Build report generator image | |
| run: docker build -t perf-report-generator ${{ env.PERF_TEST_DIR }}/ReportGenerator | |
| - name: Generate report | |
| run: | | |
| mkdir -p report-output | |
| docker run --rm \ | |
| -v "${{ github.workspace }}/downloaded-results:/input:ro" \ | |
| -v "${{ github.workspace }}/report-output:/output" \ | |
| perf-report-generator \ | |
| --input-dir /input \ | |
| --output-dir /output | |
| - name: Append summary to GitHub Step Summary | |
| if: always() | |
| run: | | |
| if [ -f report-output/summary.md ]; then | |
| # Strip markdown image lines — charts are not directly linkable from | |
| # step summaries; download the perf-report artifact to view them. | |
| grep -v '^!\[' report-output/summary.md >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "_Charts are available in the **perf-report** artifact._" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "No summary.md generated." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: Upload report artifacts | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: perf-report | |
| path: report-output/ | |
| if-no-files-found: warn |