fix(spec): 锚点漂移提示按实测方向措辞,不再把「领先」说成 trails … by 0 key(s) (#5847) #1243
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Console Pin Freshness | |
| # Is `.objectui-sha` still CURRENT? (#3340 P0) | |
| # | |
| # ⚠️ NOT ci.yml's "Console Pin Gate" (#4290). The names are close and the | |
| # questions are opposite ends of the same fact: | |
| # | |
| # Console Pin Gate (#4290) "does the PINNED SHA still BUILD?" — clones | |
| # objectui at the pin and builds the SPA. | |
| # Console Pin Freshness "is the PIN still CURRENT?" — compares the pin | |
| # (this workflow) against objectui `main`. | |
| # | |
| # A two-month-old pin builds perfectly (Pin Gate green) while hiding two months | |
| # of frontend releases from the release record (this gate red). Keep both. | |
| # | |
| # WHERE IT BLOCKS | |
| # --------------- | |
| # On the changesets **Version Packages / release PR** only. Between pin bumps an | |
| # ordinary code PR sits behind objectui almost always — that is the normal state | |
| # of the repo, not a defect, and failing every PR over it would train everyone to | |
| # ignore this check. So the job runs everywhere and blocks only on the release | |
| # lane, where a lagging pin silently drops frontend changes from the release | |
| # record (#3340: four changes, two of them `minor` features, lost from v16). | |
| # | |
| # WHY THE JOB IS NEVER SKIPPED | |
| # ---------------------------- | |
| # It carries no job-level `if:` and no paths filter on purpose. A check that | |
| # does not run reports nothing, and a *required* context that reports nothing | |
| # leaves every PR stuck "Expected — waiting for status". Advisory mode is | |
| # expressed in the EXIT CODE, not by skipping: the report is printed in full | |
| # either way, so a green run on an ordinary PR still shows how far the pin has | |
| # drifted. | |
| # | |
| # REQUIRED-CHECK ENFORCEMENT IS NOT SELF-DECLARED — AND IT HAS A PRECONDITION | |
| # ---------------------------------------------------------------------------- | |
| # A workflow cannot make itself required. A maintainer must add the | |
| # `Console Pin Freshness` context to the branch-protection rule for `main` | |
| # (Settings → Branches → main → Require status checks to pass). Until then this | |
| # workflow REPORTS on the release PR without blocking the merge button. | |
| # | |
| # ⚠️ THE PRECONDITION IS THE `merge_group:` TRIGGER BELOW (#6121). Adding this | |
| # context to a required set is safe ONLY BECAUSE that trigger now exists. The | |
| # paragraph above states the PR half of the rule — "a required context that | |
| # reports nothing leaves every PR stuck" — and until #6121 this file invited | |
| # maintainers into the required set while missing the QUEUE half: branch | |
| # protection is evaluated AGAIN on the `gh-readonly-queue/**` generation, so a | |
| # required context that produces no run THERE parks every queue generation | |
| # forever (#3622 is the prototype for that deadlock). | |
| # | |
| # FUTURE EDITORS: before this context is added to — or left in — any required | |
| # set, confirm `merge_group:` is still in `on:` below. Deleting that trigger | |
| # does not fail loudly; it deadlocks the merge queue for every PR in the repo. | |
| on: | |
| pull_request: | |
| branches: [main] | |
| # Merge queue (see ci.yml for the full note): a required context must report | |
| # on queue generations too, or queue builds wait forever on a check that never | |
| # arrives. This is the precondition documented above (#6121). Which LANE the | |
| # event lands in — blocking vs reporting — is decided in the pin-freshness | |
| # step below, not here. | |
| merge_group: | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Job name == the branch-protection context. Keep it stable: renaming it | |
| # silently detaches the required check (the #3622 lesson ci.yml records). | |
| pin-freshness: | |
| name: Console Pin Freshness | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '22' | |
| # "A change to the guard runs the guard" — the rule this repo applies to | |
| # every other scripts/ gate. No install: the script is dependency-free. | |
| - name: Self-test the gate | |
| run: node scripts/check-objectui-pin-fresh.mjs --self-test | |
| - name: Check objectui pin freshness | |
| env: | |
| # Only ITEMIZES an already-established lag (`git ls-remote` decides the | |
| # verdict), but the token keeps the API off the 60/hr anonymous limit | |
| # so the report names the commits and changesets instead of degrading. | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Read through env, never inlined into the shell: a PR title is | |
| # attacker-controlled text. | |
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| EVENT: ${{ github.event_name }} | |
| run: | | |
| # The changesets action opens the version PR from `changeset-release/<base>` | |
| # with the title configured in release.yml. Either identifies the lane; | |
| # both are checked so a future rename of one does not silently disarm | |
| # the gate. | |
| # | |
| # LANE BY EVENT — classify every new trigger HERE, explicitly (#6121). | |
| # This test used to read `[ "$EVENT" != "pull_request" ]`, a negation | |
| # that meant "workflow_dispatch" back when `on:` had exactly two | |
| # entries. Adding `merge_group:` is the moment that proxy breaks: the | |
| # negation would sweep every queue generation into the BLOCKING lane, | |
| # where this gate goes red whenever the pin lags — the repo's normal | |
| # state between bumps (see WHERE IT BLOCKS at the top) — and a required | |
| # context that is systematically red EJECTS every PR from the queue. | |
| # That would trade one deadlock for another rather than fix it. | |
| # | |
| # workflow_dispatch → BLOCKS. A human asked for the full check. | |
| # merge_group → reports. The queue generation of an ordinary PR | |
| # is an ordinary PR; the Version Packages PR is | |
| # enforced on its own `pull_request` run, and | |
| # release.yml runs this same script on the publish | |
| # path — the backstop with no override input. | |
| # pull_request → BLOCKS on the release lane only. | |
| # | |
| # HEAD_REF and PR_TITLE are empty on merge_group (no `pull_request` in | |
| # the payload), so the two release-lane tests are false there anyway. | |
| if [ "$EVENT" = "workflow_dispatch" ] \ | |
| || [ "$HEAD_REF" = "changeset-release/main" ] \ | |
| || [ "$PR_TITLE" = "chore: version packages" ]; then | |
| echo "::notice::Release lane or manual run — the objectui pin-freshness gate BLOCKS here (#3340)." | |
| node scripts/check-objectui-pin-fresh.mjs | |
| else | |
| echo "::notice::Not the release lane — pin freshness is reported but does not block (a pin lagging between bumps is normal). It blocks on the Version Packages PR and on the publish path." | |
| node scripts/check-objectui-pin-fresh.mjs --advisory | |
| fi |