Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions .github/workflows/changeset-presence.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,33 @@ name: Changeset Presence
#
# Why this is a SECOND changeset workflow rather than a wider trigger on the
# first. `changeset-guard.yml` runs only when `.changeset/**` changes, and that
# inversion is deliberate and documented in its own header: `ci.yml` and
# `lint.yml` both list `.changeset/**` under `paths-ignore`, so a PR that adds
# ONLY a changeset starts nothing else, and that guard exists to see exactly that
# PR. A PR which FORGOT its changeset does not touch `.changeset/**` at all, so
# the one check that could notice is the one guaranteed not to run. Widening those
# paths would break the case it was built for. Hence two workflows, opposite
# directions: that one polices the level of a declaration that exists, this one
# polices the existence of a declaration at all.
# inversion is deliberate and documented in its own header: on a PR that adds
# ONLY a changeset, every gate inside `ci.yml` and `lint.yml` skips, so nothing
# in either of them ever reads the changeset — and that guard exists to see
# exactly that PR. A PR which FORGOT its changeset does not touch `.changeset/**`
# at all, so the one check that could notice is the one guaranteed not to run.
# Widening those paths would break the case it was built for. Hence two
# workflows, opposite directions: that one polices the level of a declaration
# that exists, this one polices the existence of a declaration at all.
#
# That is no longer the reason this header used to give. It said `ci.yml` and
# `lint.yml` both list `.changeset/**` under `paths-ignore`, so a PR adding ONLY
# a changeset "starts nothing else". objectui#3523 step 2 deleted `paths-ignore`
# from their `pull_request` trigger; it remains ONLY on `push`. Such a PR does
# start both workflows and does produce their contexts — measured: PR #3856 (one
# markdown file) 16 checks, PR #4339 (one line added to AGENTS.md) 17. The
# correction is objectui#3857; an author had already acted on the old sentence
# and got the opposite result.
#
# What #3523 moved rather than deleted is the path DECISION: it is now the
# `Decide whether this change needs a full run` step in `ci.yml`, with a twin in
# `lint.yml`, and its exclusion list is that `push` filter unchanged — markdown
# and `.changeset/**` included, held identical to it by
# `scripts/__tests__/merge-queue-reporting.test.ts`. Both workflows therefore
# start, report, and skip every expensive step on precisely this PR: the
# conclusion survives its premise, and `changeset-guard.yml`, running outside
# that in-job switch with no install and no build, is still the only thing that
# judges a changeset-only PR at all.
#
# Hence also: no `paths` and no `paths-ignore` here, deliberately — the same
# choice `control-bytes.yml` and `docs-links.yml` made and for a stronger reason.
Expand Down
36 changes: 30 additions & 6 deletions scripts/__tests__/check-changeset-no-major.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,17 @@ import { findMajorBumps, parseFrontmatterBumps } from '../check-changeset-no-maj
* Four pending changesets had scored `major` (17 package entries) during the
* 17.x line, which would have shipped 39 packages as 18.0.0 against an
* `@objectstack` still on 17. The rule was written down and nothing ran it:
* `ci.yml` and `lint.yml` both `paths-ignore` `.changeset/**`, so a
* changeset-only PR started no workflow at all.
* back then `ci.yml` and `lint.yml` both carried `paths-ignore` on their
* `pull_request` trigger with `.changeset/**` in it, so a changeset-only PR
* started no workflow at all.
*
* That last sentence is history. objectui#3523 step 2 deleted `paths-ignore`
* from those `pull_request` triggers — it survives only on `push` — so such a
* PR does start both workflows and does produce their contexts today. What it
* still does not do is run anything expensive in them: the `Decide whether this
* change needs a full run` step excludes markdown and `.changeset/**` and skips
* every step below itself. Either way no gate inside those workflows reads the
* changeset, which is why the locks below still stand (objectui#3857).
*
* These tests are the second lock. `.github/workflows/changeset-guard.yml`
* catches it on the PR that adds the changeset; the repo-state test below
Expand Down Expand Up @@ -117,10 +126,25 @@ describe('changeset-guard.yml', () => {
});

it('triggers on `.changeset/**` — the paths every other workflow ignores', () => {
// The inverse pin. `ci.yml` cannot host this check: a changeset-only PR
// matches its `paths-ignore` twice over (`**/*.md` and `.changeset/**`), so
// no job in it would ever run. If that ever stops being true, this test
// fails and the separate workflow can be folded back in.
// The inverse pin, and the reason `ci.yml` still cannot host this check: on
// a changeset-only PR its `Decide whether this change needs a full run` step
// finds nothing outside its exclusion list (markdown and `.changeset/**`
// among it) and skips every step below itself, so no gate in that workflow
// ever reads the changeset. This one has to run outside that decision.
//
// Not the reason this comment used to give — "a changeset-only PR matches
// its `paths-ignore` twice over, so no job in it would ever run". Since
// objectui#3523 step 2, `paths-ignore` is gone from the `pull_request`
// trigger and survives only on `push`: such a PR does start `ci.yml` and
// does produce its contexts (measured — PR #3856, one markdown file, 16
// checks; PR #4339, one line added to AGENTS.md, 17). The conclusion
// outlived the premise; objectui#3857 pinned the correction.
//
// That surviving `push` copy is what the two assertions below read, and it
// is why they stay green — `ci.yml` genuinely still declares `paths-ignore`
// with markdown in it, on `push`. The in-job exclusion list is held
// identical to that filter by `scripts/__tests__/merge-queue-reporting.test.ts`,
// so the pair cannot drift apart silently.
expect(guard).toMatch(/paths:\s*\n\s*- '\.changeset\/\*\*'/);

const ci = fs.readFileSync(path.join(workflowDir, 'ci.yml'), 'utf8');
Expand Down
14 changes: 13 additions & 1 deletion scripts/check-changeset-no-major.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,19 @@
* (17 package entries between them) during the 17.x line — enough to publish
* 39 packages as 18.0.0 against an `@objectstack` still on 17. The rule was
* already written down; nothing executed it, and no workflow even looked at
* `.changeset/**` (both `ci.yml` and `lint.yml` list it under `paths-ignore`).
* `.changeset/**` (at the time `ci.yml` and `lint.yml` both listed it under
* `paths-ignore` on their `pull_request` trigger, so a changeset-only PR started
* nothing at all).
*
* That parenthetical is history, not today's shape: objectui#3523 step 2 deleted
* `paths-ignore` from those two `pull_request` triggers and it remains ONLY on
* `push`, so such a PR now starts both workflows and produces their contexts.
* What skips is the expensive work inside them — the `Decide whether this change
* needs a full run` step excludes markdown and `.changeset/**` and skips every
* step below itself. So no gate in either workflow reads the changeset either
* way, and this one, run by `.github/workflows/changeset-guard.yml` outside that
* in-job switch, is still the only thing that judges such a PR. The conclusion
* outlived its premise; objectui#3857 pinned the correction.
*
* The one legitimate major is the synchronized bump that follows objectstack
* across ITS major. Set `OBJECTUI_ALLOW_MAJOR=1` for that release, and only
Expand Down
Loading