Skip to content

ci: Version Packages #223

ci: Version Packages

ci: Version Packages #223

name: Chart library benchmarks
on:
pull_request:
push:
branches:
- main
schedule:
- cron: '17 7 * * 1'
workflow_dispatch:
inputs:
upload_bundle_baseline_candidate:
description: Upload exact comparison bundle measurements
required: false
type: boolean
default: false
playwright_container_canary:
description: Compare the host runner with the exact Playwright container
required: false
type: boolean
default: false
permissions:
contents: read
actions: read
concurrency:
group: chart-library-benchmarks-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Select CI partitions
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
compare: ${{ steps.classify.outputs.compare || steps.full.outputs.compare }}
stress: ${{ steps.classify.outputs.stress || steps.full.outputs.stress }}
steps:
- name: Checkout pull request
if: github.event_name == 'pull_request'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 2
persist-credentials: false
- name: Classify pull request changes
if: github.event_name == 'pull_request'
id: classify
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -o pipefail
git cat-file -e "${BASE_SHA}^{commit}"
git cat-file -e "${HEAD_SHA}^{commit}"
git diff --no-renames --name-only -z "$BASE_SHA" "$HEAD_SHA" |
node scripts/classify-ci-changes.mjs >> "$GITHUB_OUTPUT"
- name: Select every partition
if: github.event_name != 'pull_request'
id: full
run: |
echo 'compare=true' >> "$GITHUB_OUTPUT"
echo 'stress=true' >> "$GITHUB_OUTPUT"
static:
name: Static checks
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
NX_CLOUD_CONTINUOUS_ASSIGNMENT: 'true'
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Classify static pull request changes
if: github.event_name == 'pull_request'
id: static-changes
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -o pipefail
git cat-file -e "${BASE_SHA}^{commit}"
git cat-file -e "${HEAD_SHA}^{commit}"
git diff --no-renames --name-only -z "$BASE_SHA" "$HEAD_SHA" |
node scripts/classify-ci-changes.mjs >> "$GITHUB_OUTPUT"
- name: Setup
uses: ./.github/actions/setup
- name: Set Nx SHAs
uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5.0.1
- name: Start Nx Agents
id: nx-agents
if: github.event_name != 'pull_request' || steps.static-changes.outputs.static == 'full'
run: pnpm exec nx start-ci-run --distribute-on=".nx/workflows/distribution.yaml"
- name: Run full cached validation graph
if: github.event_name != 'pull_request' || steps.static-changes.outputs.static == 'full'
env:
NX_PARALLEL: 4
run: pnpm exec nx run charts-workspace:ci
- name: Stop Nx Agents
if: always() && steps.nx-agents.outcome == 'success'
run: pnpm exec nx stop-all-agents
- name: Run documentation validation graph
if: github.event_name == 'pull_request' && steps.static-changes.outputs.static == 'docs'
run: pnpm exec nx run-many --targets=format-check,docs-check,docs-test --projects=charts-workspace --parallel=4
- name: Check workspace diff
run: git diff --check
- name: Upload production catalog
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: charts-catalog-${{ github.sha }}
path: .catalog-artifact
if-no-files-found: error
include-hidden-files: true
compare:
name: Comparison (${{ matrix.chart }})
if: needs.changes.outputs.compare == 'true'
needs: changes
runs-on: ubuntu-24.04
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
chart:
- line
- bar
- area
- scatter
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: ${{ matrix.chart == 'line' && '0' || '1' }}
persist-credentials: false
- name: Setup
uses: ./.github/actions/setup
with:
playwright: 'true'
- name: Run comparison shard
env:
CHECK_BASELINE_PROVENANCE: ${{ matrix.chart == 'line' }}
run: |
baseline_args=(--check-bundle-baseline)
if [ "$CHECK_BASELINE_PROVENANCE" = true ]; then
baseline_args+=(--check-bundle-provenance)
fi
pnpm benchmark -- --profile=ci --chart=${{ matrix.chart }} "${baseline_args[@]}"
- name: Publish comparison summary
if: success()
run: |
summaries=(.benchmark-output/results/*.md)
test -e "${summaries[0]}"
cat "${summaries[@]}" >> "$GITHUB_STEP_SUMMARY"
- name: Upload comparison
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: chart-library-comparison-${{ matrix.chart }}-${{ github.run_id }}
path: .benchmark-output/results
if-no-files-found: error
retention-days: 14
bundle-baseline-candidate:
name: Bundle baseline candidate
if: github.event_name == 'workflow_dispatch' && inputs.upload_bundle_baseline_candidate
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Setup
uses: ./.github/actions/setup
- name: Check comparison bundle baseline
id: benchmark-check
run: node scripts/compare-chart-libraries.mjs --check
- name: Upload comparison bundle baseline candidate
if: always() && steps.benchmark-check.outcome != 'skipped'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: comparison-bundle-baseline-${{ github.sha }}
path: .benchmark-output/results/bundle-baseline.candidate.json
if-no-files-found: error
retention-days: 14
stress:
name: Stress (${{ matrix.name }})
if: needs.changes.outputs.stress == 'true'
needs: changes
runs-on: ubuntu-24.04
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
include:
- name: partition-1
workloads: raw-line,raw-scatter,interactive-scatter
shard: 1/4
- name: partition-2
workloads: binned-density,pixel-envelope,viewport-envelope
shard: 2/4
- name: partition-3
workloads: stats-multi-series-line,rolling-keyed-window,histogram-128
shard: 3/4
- name: partition-4
workloads: top-categories,dashboard-lines
shard: 4/4
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup
uses: ./.github/actions/setup
with:
playwright: 'true'
- name: Run quick stress shard
if: github.event_name == 'pull_request' || github.event_name == 'push'
run: pnpm benchmark:stress:quick -- --workload=${{ matrix.workloads }}
- name: Run standard stress shard
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
run: pnpm benchmark:stress:standard -- --shard=${{ matrix.shard }}
- name: Publish stress summary
if: success()
run: |
summaries=(.benchmark-output/stress/results/*.md)
test -e "${summaries[0]}"
cat "${summaries[@]}" >> "$GITHUB_STEP_SUMMARY"
- name: Upload stress results
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: chart-library-stress-${{ matrix.name }}-${{ github.run_id }}
path: .benchmark-output/stress/results
if-no-files-found: error
retention-days: 14
compare-container-canary:
name: Comparison container canary
if: github.event_name == 'workflow_dispatch' && inputs.playwright_container_canary
runs-on: ubuntu-24.04
timeout-minutes: 20
container:
image: mcr.microsoft.com/playwright:v1.62.0-noble@sha256:baed2032d533817f3dbe6425de795788430ba345e819a1201337009ba17c9d07
env:
PLAYWRIGHT_BROWSERS_PATH: /ms-playwright
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup
uses: ./.github/actions/setup
- name: Run line comparison in container
run: pnpm benchmark -- --profile=ci --chart=line
- name: Upload container comparison
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: chart-library-comparison-container-line-${{ github.run_id }}
path: .benchmark-output/results
if-no-files-found: error
retention-days: 14
ci:
name: CI
if: always()
needs:
- changes
- static
- compare
- stress
- bundle-baseline-candidate
- compare-container-canary
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Require every CI partition
env:
CHANGES_RESULT: ${{ needs.changes.result }}
STATIC_RESULT: ${{ needs.static.result }}
COMPARISON_REQUIRED: ${{ needs.changes.outputs.compare }}
COMPARISON_RESULT: ${{ needs.compare.result }}
STRESS_REQUIRED: ${{ needs.changes.outputs.stress }}
STRESS_RESULT: ${{ needs.stress.result }}
BUNDLE_CANDIDATE_REQUIRED: ${{ github.event_name == 'workflow_dispatch' && inputs.upload_bundle_baseline_candidate }}
BUNDLE_CANDIDATE_RESULT: ${{ needs.bundle-baseline-candidate.result }}
CANARY_REQUIRED: ${{ github.event_name == 'workflow_dispatch' && inputs.playwright_container_canary }}
CANARY_RESULT: ${{ needs.compare-container-canary.result }}
run: |
require_partition() {
case "$1:$2" in
true:success|false:skipped) return 0 ;;
*) return 1 ;;
esac
}
test "$CHANGES_RESULT" = success
test "$STATIC_RESULT" = success
require_partition "$COMPARISON_REQUIRED" "$COMPARISON_RESULT"
require_partition "$STRESS_REQUIRED" "$STRESS_RESULT"
require_partition "$BUNDLE_CANDIDATE_REQUIRED" "$BUNDLE_CANDIDATE_RESULT"
require_partition "$CANARY_REQUIRED" "$CANARY_RESULT"
publish-catalog:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs:
- static
- ci
runs-on: ubuntu-24.04
timeout-minutes: 10
concurrency:
group: catalog-dist-publication
cancel-in-progress: false
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Download validated catalog
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: charts-catalog-${{ github.sha }}
path: .catalog-artifact
- name: Publish generated catalog
env:
CATALOG_BRANCH: catalog-dist
run: |
source_revision="$(jq -er '.revision | select(test("^[0-9a-f]{40}$"))' .catalog-artifact/catalog.json)"
if [ "$source_revision" != "$GITHUB_SHA" ]; then
echo "Catalog revision $source_revision does not match workflow revision $GITHUB_SHA." >&2
exit 1
fi
git fetch origin main:refs/remotes/origin/main
if ! git merge-base --is-ancestor "$source_revision" origin/main; then
echo "Catalog revision $source_revision is not on the current main branch." >&2
exit 1
fi
publication_dir="$(mktemp -d)"
if git ls-remote --exit-code --heads origin "$CATALOG_BRANCH" >/dev/null 2>&1; then
git fetch origin "$CATALOG_BRANCH"
git worktree add -B "$CATALOG_BRANCH" "$publication_dir" "origin/$CATALOG_BRANCH"
else
git worktree add --detach "$publication_dir"
git -C "$publication_dir" switch --orphan "$CATALOG_BRANCH"
fi
if [ -f "$publication_dir/catalog.json" ]; then
published_revision="$(jq -er '.revision | select(test("^[0-9a-f]{40}$"))' "$publication_dir/catalog.json")"
if [ "$published_revision" = "$source_revision" ]; then
exit 0
fi
if git merge-base --is-ancestor "$published_revision" origin/main 2>/dev/null; then
if git merge-base --is-ancestor "$source_revision" "$published_revision"; then
echo "Skipping stale catalog revision $source_revision; $published_revision is already published."
exit 0
fi
if ! git merge-base --is-ancestor "$published_revision" "$source_revision"; then
echo "Catalog revision $source_revision diverges from published revision $published_revision." >&2
exit 1
fi
else
echo "Replacing legacy catalog revision $published_revision with canonical main revision $source_revision."
fi
fi
git -C "$publication_dir" rm -rf --ignore-unmatch .
cp -R "$GITHUB_WORKSPACE/.catalog-artifact/." "$publication_dir/"
git -C "$publication_dir" add --all
if git -C "$publication_dir" diff --cached --quiet; then
exit 0
fi
git -C "$publication_dir" config user.name "github-actions[bot]"
git -C "$publication_dir" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C "$publication_dir" commit -m "Publish catalog $GITHUB_SHA"
git -C "$publication_dir" push origin "HEAD:$CATALOG_BRANCH"