Skip to content

fix(ci): stop publishing on paths that cannot reach a consumer - #3098

Merged
mfal merged 2 commits into
mainfrom
claude/title-driven-release-gate
Sep 15, 2026
Merged

mfal merged 2 commits into
mainfrom
claude/title-driven-release-gate

Conversation

@mfal

@mfal mfal commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

The release denylist knew only repo-root prefixes, matched with startsWith, so everything under packages/** counted as publish-relevant wholesale:

Version Trigger Reaches a consumer?
1.0.14 #3010 — packages/components/.storybook/preview.tsx alone No
1.0.12 #3006 — a scripts-only package manifest, a package-local CONTRIBUTE.md, dev/cross-version/**, src/tests/visual/** No

Package-local denylist entries, segment-exact under packages/<name>/ — e2e-helpers/ is not e2e/:

  • .storybook/**, e2e/**, src/tests/**, dev/cross-version/**, dev/vitest/**
  • the package's CONTRIBUTE.md (no package lists it in files)
  • Dockerfile and .dockerignore — the Storybook preview image, built by CI from dev/ and .github/. ci: build the preview apps in CI and let the image only package them #3008 pushed both and nothing else under packages/
  • *.stories.tsx and *.test.* anywhere — .test. is not always the last extension (*.browser.test.remote.tsx)

A package's root-level Markdown is judged against that package's files, not by path — nothing builds one, so it reaches a consumer exactly if it is published. flow-react-components lists AGENTS.md, MIGRATION.md and USAGE.md; remote-react-components lists only USAGE.md, so ITS AGENTS.md reaches nobody. Markdown deeper in a package keeps its path-level relevance: codemods/src/migrations/*/entry.md is a generator input, not documentation.

packages/*/dev/** is deliberately not denylisted wholesale: in components and codemods that directory is the build — dev/vite/* holds the plugins vite.build.config.ts imports, dev/createDocPropertiesJson.ts writes the shipped dist/assets/doc-properties.json, dev/remote-components-generator/** generates view.ts and src/auto-generated/**, and codemods' build script is tsx dev/generateCli.ts && ….

The criterion is no consumer effect, not "not in the tarball": a tarball carries the package's scripts, yet nothing a consumer installs reads them.

The key-diff refinement applies to every packages/*/package.json, not just the root one — a scripts-only diff cannot reach a consumer. publish.yml therefore snapshots each changed manifest into MANIFEST_SNAPSHOT_DIR instead of the two ROOT_MANIFEST_* files. A failed fetch leaves the snapshot missing, which the classifier still reads as "relevant" — the behaviour before, and what an added or deleted manifest gets.

isPublishRelevant is now a wrapper around classifyPath, which also returns the rule that decided — that is what the skip notice prints.

Verified

docs/release-workflow.md is cut back to the mechanics: what the classifier excludes and what it judges by content.

Split out of this PR

This PR was three changes; each now has its own line, all rebased onto current main.

A title-driven variant of the release gate ([release] / [no-release] tags in the PR title) was built and withdrawn — the tag puts the decision in a hand-written token while the paths answer the question directly. The branch name still carries that withdrawn approach; the PR number is kept for its review history.

Part of #3023 — the path half.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Coverage Report for ./packages/components/

Status Category Percentage Covered / Total
🔵 Lines 78.68% 779 / 990
🔵 Statements 78.59% 797 / 1014
🔵 Functions 79.82% 178 / 223
🔵 Branches 70.62% 404 / 572
File CoverageNo changed files found.
Generated in workflow #6755 for commit 006823e by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

Preview environments are ready:

Type URL
docs pr-3098.docs.review.flow-components.de
storybook pr-3098.storybook.review.flow-components.de

Images:

  • docs: ghcr.io/mittwald/flow/docs:pr-3098
  • storybook: ghcr.io/mittwald/flow/storybook:pr-3098

@mfal mfal changed the title fix(ci): decide releases from the PR title and verify them against the paths (fixes #3023) fix(ci): stop publishing on paths that cannot reach a consumer (fixes #3023) Sep 2, 2026
@mfal
mfal marked this pull request as ready for review September 2, 2026 14:16
@mfal
mfal requested a review from a team September 2, 2026 14:16
@mfal
mfal marked this pull request as draft September 4, 2026 06:43
The release denylist knew only repo-ROOT prefixes, matched with `startsWith`,
so everything under `packages/**` counted as publish-relevant wholesale. 1.0.14
came from `packages/components/.storybook/preview.tsx` alone (#3010); 1.0.12
from a `scripts`-only package manifest, a package-local `CONTRIBUTE.md`,
`dev/cross-version/**` and `src/tests/visual/**` (#3006). Neither reaches a
consumer.

Package-local denylist entries, segment-exact under `packages/<name>/` —
`e2e-helpers/` is not `e2e/`:

- `.storybook/**`, `e2e/**`, `src/tests/**`, `dev/cross-version/**`,
  `dev/vitest/**`
- `Dockerfile` and `.dockerignore` — the Storybook preview image (#3008)
- `*.stories.tsx` and `*.test.*` anywhere: `.test.` is not always the last
  extension (`*.browser.test.remote.tsx`)

A package's root-level Markdown is judged against that package's `files`
instead of by path — nothing builds one, so it reaches a consumer exactly if it
is published. `flow-react-components` lists `AGENTS.md`, `MIGRATION.md` and
`USAGE.md`; `remote-react-components` lists only `USAGE.md`, so ITS `AGENTS.md`
reaches nobody. Markdown deeper in a package keeps its path-level relevance —
`codemods/src/migrations/*/entry.md` is a generator input, not documentation.

`packages/*/dev/**` is deliberately NOT denylisted wholesale: in `components`
and `codemods` that directory IS the build. `dev/vite/*` holds the plugins
`vite.build.config.ts` imports, `dev/createDocPropertiesJson.ts` writes the
shipped `dist/assets/doc-properties.json`, `dev/remote-components-generator/**`
generates `view.ts` and `src/auto-generated/**`, and `codemods`' build script
is `tsx dev/generateCli.ts && …`.

The key-diff refinement now applies to every `packages/*/package.json`, not
just the root one: a `scripts`-only diff cannot reach a consumer. `publish.yml`
therefore snapshots each changed manifest into `MANIFEST_SNAPSHOT_DIR` rather
than the two `ROOT_MANIFEST_*` files. A failed fetch leaves the snapshot
missing, which the classifier still reads as "relevant" — the behaviour before,
and what an added or deleted manifest gets.

The criterion is NO CONSUMER EFFECT, not "not in the tarball": a tarball
carries the package's `scripts`, yet nothing a consumer installs reads them.

`isPublishRelevant` is now a wrapper around `classifyPath`, which also returns
the RULE that decided — that is what the skip notice prints.

Verified: 35 classifier tests, run by the `decide` job before it classifies.
Replayed every non-release commit on `main` since #2933 through the changed
classifier — #3010 and #3008 flip to no-publish, and no commit that produced a
legitimate release flips with them. `next` stays symmetric: docs-only
`chore(sync):` merges produce no `-next.N` bump.

Part of #3023 — the path half; the type half is a sibling PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mfal
mfal force-pushed the claude/title-driven-release-gate branch from 9ab9101 to bd2307d Compare September 8, 2026 14:05
@mfal mfal changed the title fix(ci): stop publishing on paths that cannot reach a consumer (fixes #3023) fix(ci): stop publishing on paths that cannot reach a consumer Sep 8, 2026
@mfal
mfal marked this pull request as ready for review September 8, 2026 14:06
@mfal
mfal enabled auto-merge (squash) September 8, 2026 14:13
@mfal
mfal requested a review from ins0 September 8, 2026 14:20
@mfal

mfal commented Sep 15, 2026

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

…elease-gate

# Conflicts:
#	docs/release-workflow.md

Co-authored-by: mfal <4696750+mfal@users.noreply.github.com>
auto-merge was automatically disabled September 15, 2026 08:01

Head branch was pushed to by a user without write access

Copilot AI commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Addressed in 006823e by merging main into this branch, resolving the docs/release-workflow.md conflict, and re-running the targeted release-workflow tests.

@mfal
mfal enabled auto-merge (squash) September 15, 2026 08:45
@mfal
mfal merged commit 1534239 into main Sep 15, 2026
22 checks passed
@mfal
mfal deleted the claude/title-driven-release-gate branch September 15, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants