From 5e7c3dddd4a0057931e158a0735a5188fc25ea3c Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Mon, 26 Oct 2026 19:04:47 -0400 Subject: [PATCH] fix(ci): emit each job's api-calls count as a notice the hub reads The log-api-budget action wrote `api-calls =N not-modified=M` as a plain log line. The hub collector reads only check-run annotations, so it never saw the count. Write it as a `::notice title=api-calls::` annotation with its message escaped per the workflow-command rules; the step summary line and the costs output are unchanged. Co-Authored-By: Claude Opus 5.5 --- .github/actions/log-api-budget/action.yml | 14 +++++++++----- .../actions/log-api-budget/log-api-budget.test.mjs | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/actions/log-api-budget/action.yml b/.github/actions/log-api-budget/action.yml index 143b09ea1b4..303fb80e546 100644 --- a/.github/actions/log-api-budget/action.yml +++ b/.github/actions/log-api-budget/action.yml @@ -4,8 +4,8 @@ description: > named token, from the rate-limit readings the job's own API responses left in $RUNNER_TEMP/api-budget (api-budget.bash): one per refused (403/429) response and one for the last. GET /rate_limit is never read: it reports a - different bucket from the one the job spends. Then an `api-calls =N - not-modified=M` line: N is this job's own calls, which cost (the rise in a + different bucket from the one the job spends. Then an `api-calls` notice, + `=N not-modified=M`: N is this job's own calls, which cost (the rise in a counter every concurrent job shares) is not, and M its 304 answers, which GitHub does not count. Then one line for the job's content-creating writes (count and most in any 60 s). Also writes each line and a `-cost=N` @@ -43,9 +43,13 @@ runs: printf '%s\n' "$lines" sed 's/^::notice title=api-budget::/api-budget: /' <<<"$lines" >>"$GITHUB_STEP_SUMMARY" # This job's own calls, one reading each: unlike cost, no other job's. - calls=$(awk '$1 != 304 { n++ } $1 == 304 { m++ } END { printf "api-calls %s=%d not-modified=%d", token, n, m }' token="$name" "$RUNNER_TEMP/api-budget/$name") - echo "$calls" - echo "$calls" >>"$GITHUB_STEP_SUMMARY" + # A notice, as the hub reads annotations, not the log; its message + # escaped as workflow commands require. + calls=$(awk '$1 != 304 { n++ } $1 == 304 { m++ } END { printf "%s=%d not-modified=%d", token, n, m }' token="$name" "$RUNNER_TEMP/api-budget/$name") + notice=${calls//%/%25} + notice=${notice//$'\r'/%0D} + echo "::notice title=api-calls::${notice//$'\n'/%0A}" + echo "api-calls $calls" >>"$GITHUB_STEP_SUMMARY" cost=${lines##*cost=} costs+=("$name-cost=${cost/na/unknown}") done diff --git a/.github/actions/log-api-budget/log-api-budget.test.mjs b/.github/actions/log-api-budget/log-api-budget.test.mjs index 5eb6e18f7b4..6b1cf5d4a42 100644 --- a/.github/actions/log-api-budget/log-api-budget.test.mjs +++ b/.github/actions/log-api-budget/log-api-budget.test.mjs @@ -155,7 +155,7 @@ test("recordReading appends the same line shape, na for a missing or malformed v assert.equal(existsSync(join(dir, "api-budget", "lanes-app")), false); })); -test("the action emits each named token, writes the summary, the call count and the costs output, and reads no /rate_limit", () => +test("the action emits each named token, the call count as an api-calls notice the hub reads, the summary and the costs output, and reads no /rate_limit", () => withDir((dir) => { // Two calls GitHub counted, then a conditional GET answered 304. readEach(dir, "github-token", head({ used: 13 }), head({ used: 41 }), head({ status: 304, used: 41 })); @@ -177,7 +177,7 @@ test("the action emits each named token, writes the summary, the call count and assert.equal( out, `${NOTICE}token=github-token ${WHERE} limit=5000 remaining=4959 used=41 reset=1792748042 resource=core cost=28\n` + - "api-calls github-token=2 not-modified=1\n", + "::notice title=api-calls::github-token=2 not-modified=1\n", ); assert.equal( readFileSync(join(dir, "summary"), "utf8"),