From 5d18fe0f82396a455e26f6a9e590ab4702dc81ed Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 14 Aug 2026 17:07:44 +0200 Subject: [PATCH 1/2] chore(repo): fix release-pr skill step order and add a git-dep pre-flight check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lint:pub shells out to `pub publish -n`, which rejects a dirty tree, so it could never pass where step 4 ran it — before the release commit. Split it into step 5, after the commit and before the push. Add a pre-flight check for a git/path `stream_core_flutter` dependency. Both are rejected by pub.dev, and because `release_publish.yml` publishes in dependency order, the failure lands mid-run and half-publishes the version. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/skills/release-pr/SKILL.md | 33 ++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/.claude/skills/release-pr/SKILL.md b/.claude/skills/release-pr/SKILL.md index d7d40757ea..1eea394766 100644 --- a/.claude/skills/release-pr/SKILL.md +++ b/.claude/skills/release-pr/SKILL.md @@ -59,6 +59,16 @@ Run these checks. **If any fail, stop the skill, surface the failing check to th - `gh pr list --head release/v --state all --json number` returns `[]`. - Latest CI on the base-branch tip is green: `gh run list --branch --limit 5` — no failures on the most recent runs. +- No publishable package depends on `stream_core_flutter` by git ref or path — pub.dev rejects both, and + `release_publish.yml` publishes in dependency order, so the earlier packages go live and only + `stream_chat_flutter` fails, leaving the version half-published: + + ```bash + grep -n "stream-core-flutter.git\|path: .*stream_core_flutter" melos.yaml packages/*/pubspec.yaml + ``` + + Any hit is a hard stop: `stream_core_flutter` must be released to pub.dev first (its own repo has a `release-pr` + skill), then the pin swapped to a version constraint. Surface it and stop — don't pick the version yourself. ## Steps @@ -135,25 +145,36 @@ For each, **apply the first matching rule below** — it's a decision tree, not **Every package gets a `## ` header**, even if it's only a dep-bump line. Empty version sections and missing headers both fail pana. -### 4. Sanity-check +### 4. Analyze, then commit ```bash melos run analyze -melos run lint:pub ``` -If either fails, surface to the user and stop. - -### 5. Commit and push +If it fails, surface to the user and stop. ```bash git add -A git commit -m "chore(repo): release v" -git push -u origin release/v ``` Single commit. The message format is load-bearing: `release_tag.yml` parses `vX.Y.Z` from it after merge. +`melos run lint:pub` is deliberately *not* here: it shells out to `pub publish -n`, which fails any dirty tree with +"N checked-in files are modified in git". It can only pass once the release commit exists — hence step 5. + +### 5. Verify publishability, then push + +```bash +melos run lint:pub +``` + +If it fails, surface to the user and stop — don't push. + +```bash +git push -u origin release/v +``` + ### 6. Generate the PR body The body **must be exactly what GitHub's release UI produces when you click "Generate release notes"** — no template From d15e80cdee75e76029e6d178452bd92da7b21d7d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 17 Aug 2026 11:06:33 +0200 Subject: [PATCH 2/2] chore(repo): address review on the release-pr skill - Match the stream_core_flutter dependency key and its source rather than a URL spelling; `git:` also takes a scalar URL and need not end in `.git`. - Stage with `git add -u` instead of `-A`, so the untracked files pre-flight deliberately ignores can't ride into the release commit. - Note that release_tag.yml gates on the tip commit, so the PR must be squash-merged or the tag job never fires. - Document that `pub publish -f` bypasses warnings but not errors, so only error-level lint:pub findings block the release. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/skills/release-pr/SKILL.md | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.claude/skills/release-pr/SKILL.md b/.claude/skills/release-pr/SKILL.md index 1eea394766..923c908653 100644 --- a/.claude/skills/release-pr/SKILL.md +++ b/.claude/skills/release-pr/SKILL.md @@ -64,11 +64,13 @@ Run these checks. **If any fail, stop the skill, surface the failing check to th `stream_chat_flutter` fails, leaving the version half-published: ```bash - grep -n "stream-core-flutter.git\|path: .*stream_core_flutter" melos.yaml packages/*/pubspec.yaml + grep -n -A4 '^\s*stream_core_flutter:' melos.yaml packages/*/pubspec.yaml ``` - Any hit is a hard stop: `stream_core_flutter` must be released to pub.dev first (its own repo has a `release-pr` - skill), then the pin swapped to a version constraint. Surface it and stop — don't pick the version yourself. + Match on the dependency key and its source, not on a URL spelling — `git:` takes a scalar URL as well as a map, + and the URL need not end in `.git`. Anything other than a single-line version constraint is a hard stop: + `stream_core_flutter` must be released to pub.dev first (its own repo has a `release-pr` skill), then the pin + swapped to a version constraint. Surface it and stop — don't pick the version yourself. ## Steps @@ -154,11 +156,18 @@ melos run analyze If it fails, surface to the user and stop. ```bash -git add -A +git status --short # nothing untracked should be release material +git add -u # tracked modifications only git commit -m "chore(repo): release v" ``` -Single commit. The message format is load-bearing: `release_tag.yml` parses `vX.Y.Z` from it after merge. +`git add -u`, not `-A`: pre-flight's `git status --short -uno` ignores untracked files, so `-A` would sweep local +artifacts into the release commit. If a release ever does need a genuinely new tracked file, add it by path — the +`git diff --stat` comparison in step 2 is what catches the omission. + +Single commit. The message format is load-bearing: `release_tag.yml` parses `vX.Y.Z` from it after merge — and it +gates on the **tip** commit of `master`, so the PR must be **squash-merged**. A merge commit would leave +`Merge pull request #…` at the tip and the tag job would silently never fire. `melos run lint:pub` is deliberately *not* here: it shells out to `pub publish -n`, which fails any dirty tree with "N checked-in files are modified in git". It can only pass once the release commit exists — hence step 5. @@ -169,6 +178,17 @@ Single commit. The message format is load-bearing: `release_tag.yml` parses `vX. melos run lint:pub ``` +This is the real publish gate. Read failures carefully — pub reports two severities and only one blocks: + +- **"Package validation found the following error"** — blocks. `release_publish.yml` runs `pub publish -f`, and + `-f` does **not** bypass errors. Must be fixed before merge. +- **"potential issue" / "Package has N warnings"** — `-f` publishes through these. Worth fixing, not blocking. + +A common error is a `lib/` or `test/` file importing a package absent from that package's own `dependencies` / +`dev_dependencies`; it resolves locally through a transitive dep and only `pub publish` catches it. Fix at the +import (prefer the barrel the rest of the package already uses) or by declaring the dep, and tell the user the +release PR now carries a source change. + If it fails, surface to the user and stop — don't push. ```bash