Skip to content

fix(parser): object-literal async shorthand methods now track async-function context (#129) #104

fix(parser): object-literal async shorthand methods now track async-function context (#129)

fix(parser): object-literal async shorthand methods now track async-function context (#129) #104

Workflow file for this run

name: Perf PR
# Same-runner A/B microbenchmark check for pull requests. Benches the PR's
# merge-base and its head on the SAME runner, back to back, then posts the
# delta. Running both halves on one machine cancels the cross-runner CPU-tier
# noise that makes comparing against a stored baseline unreliable — base-vs-head
# in one job is the only honest signal on free shared runners.
#
# Informational only: it never fails the PR. The micro-benchmarks have real
# within-run variance, so it reports deltas for a human to read rather than
# gating. A budget gate could come later, once the noise floor is known.
#
# Opt-in: a two-pass bench costs runner minutes, so it runs only on PRs carrying
# the `perf` label — add the label to run it, and it re-runs on each push while
# the label is on; remove the label to stop. Without the label the job skips
# instantly. The path filter is a second guard so a labeled doc-only PR skips.
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
paths:
- 'pkg/**'
- 'cmd/**'
- '.github/workflows/perf-pr.yml'
# Manual escape hatch: run against any PR by number without touching labels.
workflow_dispatch:
inputs:
pr:
description: 'PR number to benchmark'
required: true
permissions:
contents: read
concurrency:
group: perf-pr-${{ github.event.pull_request.number || github.event.inputs.pr }}
cancel-in-progress: true
jobs:
bench:
if: github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'perf')
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
pr: ${{ steps.refs.outputs.pr }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Resolve base and head
id: refs
env:
EVENT: ${{ github.event_name }}
PR_FROM_EVENT: ${{ github.event.pull_request.number }}
PR_FROM_INPUT: ${{ github.event.inputs.pr }}
BASE_FROM_EVENT: ${{ github.event.pull_request.base.ref }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# workflow_dispatch has no PR context, so take the number from the
# input and look the base branch up via the API. pull_request carries
# both directly.
if [ "$EVENT" = "workflow_dispatch" ]; then
pr="$PR_FROM_INPUT"
[[ "$pr" =~ ^[0-9]+$ ]] || { echo "pr input must be a number, got: ${pr}" >&2; exit 1; }
base_ref="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${pr}" --jq .base.ref)"
else
pr="$PR_FROM_EVENT"
base_ref="$BASE_FROM_EVENT"
fi
# refs/pull/<n>/head is on the BASE repo for both same-repo and fork
# PRs, so this resolves the head without needing fork remote access.
git fetch --no-tags origin "$base_ref" "refs/pull/${pr}/head:pr-head"
head_sha="$(git rev-parse pr-head)"
# The merge-base is the PR's own fork point, so we measure the PR's
# delta, not unrelated drift that landed on the base branch since.
base_sha="$(git merge-base "origin/${base_ref}" pr-head)"
{
echo "pr=${pr}"
echo "head=${head_sha}"
echo "base=${base_sha}"
} >> "$GITHUB_OUTPUT"
echo "Base (merge-base): ${base_sha}"
echo "Head: ${head_sha}"
- name: Bench merge-base
env:
BASE: ${{ steps.refs.outputs.base }}
run: |
set -euo pipefail
git checkout --force "$BASE"
# Use the lower-envelope reducer for this throwaway per-run A/B baseline
# (RUNNER_TEMP, not the durable ratchet). But the merge-base binary is built
# from an OLD commit that may predate the -reducer flag, so feature-detect it
# here and reuse the same decision for the head half (via GITHUB_ENV) — that
# keeps both halves on the SAME reducer. A base too old for the flag falls
# back to its default (mean), and head then omits the flag too (also mean),
# so the informational compare stays like-for-like across the transition.
# Capture then match (not a pipe): -h exits non-zero, which under
# `set -o pipefail` would poison an `if ... | grep` and misreport support.
RFLAG=""
help="$(go run ./cmd/bench-ratchet -h 2>&1 || true)"
case "$help" in *-reducer*) RFLAG="-reducer min" ;; esac
echo "RFLAG=${RFLAG}" >> "$GITHUB_ENV"
# shellcheck disable=SC2086 # RFLAG is intentionally split: "-reducer min" or empty
go run ./cmd/bench-ratchet \
-baseline "${RUNNER_TEMP}/base.json" \
-count 3 -benchtime 500ms -timeout 15m \
${RFLAG} \
update
- name: Bench head and compare
id: bench
env:
BASE: ${{ steps.refs.outputs.base }}
HEAD: ${{ steps.refs.outputs.head }}
run: |
set -euo pipefail
git checkout --force "$HEAD"
# Inform-only: never fail the job on a regression (|| true). The
# markdown report is the product; the exit code is ignored.
# $RFLAG comes from the base half (via GITHUB_ENV) so both halves use the
# same reducer — like-for-like even when the base was too old for the flag.
# shellcheck disable=SC2086 # RFLAG is intentionally split: "-reducer min" or empty
go run ./cmd/bench-ratchet \
-baseline "${RUNNER_TEMP}/base.json" \
-count 3 -benchtime 500ms -timeout 15m \
${RFLAG:-} \
-budget 0.10 -allow-incomplete \
-format markdown \
check > "${RUNNER_TEMP}/report.md" || true
run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
report() {
echo "## Perf — base vs head, same runner"
echo
echo "Base \`${BASE:0:12}\` vs head \`${HEAD:0:12}\`. Anchor-normalized; informational, not a gate."
echo
sed -n '/\*\*bench-ratchet\*\*/,$p' "${RUNNER_TEMP}/report.md"
}
# Full table → job summary (the only channel that works on fork PRs,
# where the comment token is read-only).
report >> "$GITHUB_STEP_SUMMARY"
{ report; echo; echo "_[Run details →](${run_url})_"; } > "${RUNNER_TEMP}/comment.md"
- name: Upload PR comment artifact
uses: actions/upload-artifact@v4
with:
name: perf-pr-comment
path: ${{ runner.temp }}/comment.md
if-no-files-found: error
comment:
needs: bench
if: needs.bench.result == 'success'
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
issues: write
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
name: perf-pr-comment
path: ${{ runner.temp }}/perf-pr-comment
# Sticky PR comment (upsert by marker). Fork PRs get a read-only token, so
# this can't post there — continue-on-error keeps the workflow green and
# the benchmark job summary still carries the report.
- name: Upsert PR comment
continue-on-error: true
uses: actions/github-script@v7
env:
PR: ${{ needs.bench.outputs.pr }}
COMMENT_PATH: ${{ runner.temp }}/perf-pr-comment/comment.md
with:
script: |
const fs = require('fs');
const marker = '<!-- perf-pr-report -->';
const body = marker + '\n' + fs.readFileSync(process.env.COMMENT_PATH, 'utf8');
const { owner, repo } = context.repo;
const issue_number = Number(process.env.PR);
const { data: comments } = await github.rest.issues.listComments({ owner, repo, issue_number });
const existing = comments.find(c => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
} else {
await github.rest.issues.createComment({ owner, repo, issue_number, body });
}