Skip to content

ci(release): replace the 30-minute CI polling loop in npm-publish.yml with workflow_run chaining #469

Description

@IgorShevchik

Split out of #91 §4, which was filed as a note rather than an action and stayed unaddressed when #468 closed the rest of that issue. Recording it so it is not lost.

What it is now

.github/workflows/npm-publish.yml gates the publish on ci.yml being green for the exact SHA it is about to ship. It does that by polling:

- name: Wait for ci.yml to succeed on ${{ github.sha }}
  run: |
    for i in $(seq 1 60); do
      run=$(gh api "repos/$REPO/actions/workflows/ci.yml/runs?head_sha=$SHA&per_page=1" --jq '.workflow_runs[0] // empty')
      ...
      sleep 30
    done

Sixty attempts, thirty seconds apart — a thirty-minute ceiling.

Why it is worth changing

It works, and it has not failed. The objections are about shape rather than correctness:

  • A runner sits idle for the duration. Thirty minutes of billed time doing nothing but gh api calls every half minute.
  • The ceiling is arbitrary. A CI run slower than thirty minutes — a cold cache, a queued runner, a re-run — times out and fails a release that was going to be fine. There is no signal distinguishing "CI failed" from "CI was slow today".
  • It re-implements something the platform provides. workflow_run fires when a workflow completes, with the conclusion attached.

Why it is not trivial

The obvious rewrite does not work as-is, which is presumably why it was left as a note:

  • workflow_run runs against the default branch's copy of the workflow file, and its github.sha is the default branch head, not the SHA that triggered the upstream run. The publish job would have to read github.event.workflow_run.head_sha and check that commit out explicitly.
  • The publish is also reachable by release: published and by workflow_dispatch, so workflow_run would be a third trigger rather than a replacement, and all three would need to converge on the same guard.
  • The merged-history assert (compare/main...$SHA) and the "already published / older than latest" check must keep running on whichever path fires.

So this is a real piece of work on the release path, not a cleanup. It should be done on its own, with the understanding that a mistake here is only visible at the next release.

Acceptance

  • The publish no longer holds a runner idle waiting for CI.
  • A CI run that takes longer than thirty minutes still publishes.
  • A CI run that fails still blocks the publish, on every trigger path.
  • The merged-history assert and the version checks still run.

Priority: P3 — the current loop is correct, this is cost and robustness.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions