Files
iptvnator/.github/workflows/performance-ratchet.yml
T
e998d7418a chore(deps): bump the actions-minor-patch group across 1 directory with 2 updates (#1840)
* chore(deps): bump the actions-minor-patch group across 1 directory with 2 updates

Bumps the actions-minor-patch group with 2 updates in the / directory: [pnpm/action-setup](https://github.com/pnpm/action-setup) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `pnpm/action-setup` from 6.0.10 to 6.1.0
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v6.0.10...v6.1.0)

Updates `github/codeql-action` from 4.37.7 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4.37.7...v4.38.2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions-minor-patch
- dependency-name: pnpm/action-setup
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* test(packaging): allow pnpm/action-setup v6.1.0 in the Snap build workflow policy

The bump moves every workflow to pnpm/action-setup@v6.1.0; the build
workflow's allowlist pins the exact version and must move with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 12:59:54 +02:00

247 lines
11 KiB
YAML

name: Performance ratchet
# Weekly tightening of tools/performance/journey-baselines.json (plan item B4;
# contract in the Ratchet section of docs/architecture/performance-journeys.md).
# Three runners measure the same master commit independently; a pull request
# lowers every baseline that all three beat. Nothing is ever raised, and slack
# and tolerances are left alone. A manual dispatch on another branch measures
# and reports but never opens a pull request.
on:
schedule:
- cron: '41 4 * * 1'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: performance-ratchet-${{ github.ref }}
cancel-in-progress: false
jobs:
measure:
name: Measure (run ${{ matrix.run }})
if: github.repository == '4gray/iptvnator'
runs-on: ubuntu-latest
# Production web build plus the journeys (their electron-performance
# build and seven Electron processes per journey).
timeout-minutes: 60
strategy:
# Separate runners, so one machine's noise cannot pass for a
# reduction. The tightener needs all three runs.
fail-fast: true
matrix:
run: [1, 2, 3]
env:
NX_SKIP_NX_CACHE: true
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Install pnpm
uses: pnpm/action-setup@v6.1.0
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Same build as the Initial bytes ratchet job in ci.yml. Measured
# before the journeys, whose build also writes to dist/.
- name: Build web app (production)
run: pnpm nx build web --skip-nx-cache
env:
CI: true
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
- name: Measure renderer.initialBytes
run: node tools/performance/measure-initial-bytes.mjs --summary dist/performance/ratchet/initial-bytes.summary.json
# A failed journey run must not block tightening the initial bytes:
# its entries are then missing from this run's summary, and the
# tightener keeps any baseline that a run did not measure.
- name: Run the performance journeys
id: journeys
continue-on-error: true
uses: ./.github/actions/performance-journeys
- name: Keep the journey summary
if: steps.journeys.outputs.summary != ''
env:
SUMMARY: ${{ steps.journeys.outputs.summary }}
run: cp "$SUMMARY" dist/performance/ratchet/journeys.summary.json
- name: Upload run summaries
uses: actions/upload-artifact@v7
with:
name: performance-ratchet-run-${{ matrix.run }}
path: dist/performance/ratchet/
if-no-files-found: error
retention-days: 30
tighten:
name: Tighten baselines
needs: measure
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
# This job later receives secrets.PAT, so its actions are pinned
# to reviewed commits, as in refresh-windows-embedded-mpv-runtime.
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# The ratchet scripts are dependency-free Node; no pnpm install.
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
- name: Download run summaries
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: performance-ratchet-run-*
path: ${{ runner.temp }}/runs
# Each run directory holds that runner's initial-bytes and journeys
# summaries. The direction check is the same one ci.yml runs on the
# PR, without --allow-increase: a tightening can only lower limits.
- name: Lower baselines every run beat
id: tighten
env:
RUNS_DIR: ${{ runner.temp }}/runs
REPORT: ${{ runner.temp }}/tighten-report.md
BASE_BASELINES: ${{ runner.temp }}/base-journey-baselines.json
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
baselines=tools/performance/journey-baselines.json
cp "$baselines" "$BASE_BASELINES"
runs=()
for dir in "$RUNS_DIR"/performance-ratchet-run-*; do
runs+=(--run "$dir")
done
node tools/performance/tighten-baselines.mjs \
"${runs[@]}" \
--evidence-run "$RUN_URL" \
--report "$REPORT"
{
echo "## Performance ratchet"
echo
cat "$REPORT"
} >> "$GITHUB_STEP_SUMMARY"
node tools/performance/check-baseline-direction.mjs \
--base "$BASE_BASELINES" \
--head "$baselines"
if git diff --quiet -- "$baselines"; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
git diff -- "$baselines"
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Report a dispatch outside master
if: steps.tighten.outputs.changed == 'true' && github.ref != 'refs/heads/master'
env:
REF_NAME: ${{ github.ref_name }}
run: echo "Dispatched on $REF_NAME, not master; the diff above is not proposed as a pull request."
# PAT, not GITHUB_TOKEN: a pull request pushed with GITHUB_TOKEN
# triggers no workflows, and this one needs ci.yml's Initial bytes
# ratchet run. Same secret as refresh-windows-embedded-mpv-runtime.
# The PR number is only known once the PR exists, so evidencePr is
# filled in afterwards and the single commit amended. Each run
# replaces the branch with one fresh commit, but never over an open
# tightening PR that someone else committed to (review edits, an
# "Update branch" merge); explicit leases also refuse a push that
# lands between that check and ours.
- name: Create or update the tightening pull request
if: steps.tighten.outputs.changed == 'true' && github.ref == 'refs/heads/master'
env:
GH_TOKEN: ${{ secrets.PAT }}
REPOSITORY: ${{ github.repository }}
BRANCH_NAME: automation/performance-ratchet
TITLE: 'ci(perf): tighten journey baselines'
LABEL: no-release-note
REPORT: ${{ runner.temp }}/tighten-report.md
BODY: ${{ runner.temp }}/pr-body.md
HEAD_SHA: ${{ github.sha }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
if [ -z "${GH_TOKEN}" ]; then
echo "::error::The PAT secret is required so the bot-created PR triggers normal CI."
exit 1
fi
baselines=tools/performance/journey-baselines.json
bot_email="41898282+github-actions[bot]@users.noreply.github.com"
gh auth setup-git
git config user.name "github-actions[bot]"
git config user.email "$bot_email"
pr="$(gh api "repos/$REPOSITORY/pulls?base=master&head=${REPOSITORY%%/*}:$BRANCH_NAME&state=open" --jq '.[0].number // empty')"
remote_tip="$(git ls-remote --heads origin "refs/heads/$BRANCH_NAME" | cut -f1)"
if [ -n "$pr" ] && [ -n "$remote_tip" ]; then
foreign="$(gh api "repos/$REPOSITORY/compare/master...$remote_tip" |
jq -r --arg bot "$bot_email" '.commits[] | select(.commit.author.email != $bot) | "\(.sha[0:9]) \(.commit.author.name)"')"
if [ -n "$foreign" ]; then
echo "::warning::Pull request #$pr has commits this workflow did not make; its branch is left as is. Merge or close it so the next run can refresh it. This run's numbers are in the job summary."
echo "$foreign"
exit 0
fi
fi
if [ -n "$remote_tip" ]; then
git fetch --no-tags --depth=1 origin "$remote_tip"
fi
git switch -C "$BRANCH_NAME"
git add -- "$baselines"
git commit -m "$TITLE" -m "Measured by $RUN_URL"
git push --force-with-lease="refs/heads/$BRANCH_NAME:$remote_tip" origin "HEAD:refs/heads/$BRANCH_NAME"
pushed="$(git rev-parse HEAD)"
if [ -z "$pr" ]; then
pr="$(gh api -X POST "repos/$REPOSITORY/pulls" \
-f title="$TITLE" -f head="$BRANCH_NAME" -f base=master \
-f body="Measurements follow." --jq '.number')"
fi
gh api -X POST "repos/$REPOSITORY/issues/$pr/labels" -f "labels[]=$LABEL" --silent
node tools/performance/tighten-baselines.mjs \
--fill-evidence-pr "$pr" --evidence-run "$RUN_URL"
git add -- "$baselines"
git commit --amend --no-edit
git push --force-with-lease="refs/heads/$BRANCH_NAME:$pushed" origin "HEAD:refs/heads/$BRANCH_NAME"
{
echo "Automated weekly tightening of \`$baselines\` from [three runner measurements]($RUN_URL) of \`$HEAD_SHA\`."
echo
echo "Each lowered baseline was strictly below its value in all three runs and now holds the largest of the three. Slack and tolerances are unchanged; \`check-baseline-direction.mjs\` accepted the file without \`--allow-increase\`."
echo
echo "## Per-run measurements"
echo
cat "$REPORT"
echo
echo "## Diff"
echo
echo '```diff'
git diff "$HEAD_SHA" HEAD -- "$baselines"
echo '```'
echo
echo "If \`master\` moved since \`$HEAD_SHA\`, make sure the Initial bytes ratchet and Performance journeys jobs pass on this PR before merging."
} > "$BODY"
gh api -X PATCH "repos/$REPOSITORY/pulls/$pr" -F "body=@$BODY" --silent
echo "Pull request: ${GITHUB_SERVER_URL}/$REPOSITORY/pull/$pr"