Skip to content

nx-affected releases: stop plugin-only changes releasing agent-team - #236

Draft
jack-nsheaps[bot] wants to merge 2 commits into
mainfrom
claude/zealous-newton-1b9u9g
Draft

nx-affected releases: stop plugin-only changes releasing agent-team#236
jack-nsheaps[bot] wants to merge 2 commits into
mainfrom
claude/zealous-newton-1b9u9g

Conversation

@jack-nsheaps

@jack-nsheaps jack-nsheaps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Problem

release.yaml ran on every push to main with no path filter, so a
plugins/**-only change cut a repo-wide release-it GitHub release and opened
an agent-team / claude-team Homebrew formula bump PR. Those formulas ship only
bin/** scripts (bin/claude-team, bin/ct, bin/agent-launch.ts, bin/lib/*),
so a plugins change produced a release that installs byte-identical binaries —
pure churn.

Approach — lean into the nx monorepo pattern

Releases are now affected-driven, mirroring the existing nx run-many fan-out:

  • Per-module release target (nx run-script), defined only on modules that
    actually publish:
    • rootrelease-it --ci (version + tag + GitHub release + Homebrew).
    • @nsheaps/agents-pluginsplugins/release.sh (per-plugin version bump +
      marketplace.json, self-contained commit/push, lifted from cd.yaml's old main job).
  • nx.json: release dependsOn: ["build", "test", "lint", "^release"] — a module
    builds/tests/lints (and upstream deps release) before it releases.
  • release.yaml: resolve base = floating last-released tag (fallback HEAD~1),
    compute nx show projects --affected --withTarget=release, run root's release first
    (release-it can't tolerate main advancing under it) then
    nx affected --target=release --exclude=root, open the Homebrew PR only when root cut
    a new v* tag
    , and on success move last-released to the released commit.
  • cd.yaml → PR-preview-only (the main bump job moved into the plugins release
    target). Retires the cd/last-release tag in favor of last-released.
  • Docs: docs/MONOREPO.md documents the release pipeline.

Net effect

Change Affected Result
plugins/** only ["@nsheaps/agents-plugins"] marketplace/version bump only — no agent-team release, no Homebrew PR
bin/** ["root"] release-it + Homebrew
both both both (root first)

Verified locally

  • nx show projects --affected --withTarget=release --files=… returns the table above.
  • nx recognizes both release targets with the dependsOn graph; --exclude=root and
    root:release resolve; JSON/YAML parse; markdown + shell lint clean.

Needs CI / review (not exercisable in the sandbox — no GitHub API / cross-repo)

  • The real release-it GitHub release, the cross-repo Homebrew formula PR, the
    last-released tag move, and the serialized concurrent-push behavior.

Plan: .claude/plans/nx-affected-release-pipeline.md.


🤖 Opened by an AI agent (jack-nsheaps[bot]) on behalf of @nsheaps.

claude added 2 commits June 9, 2026 20:17
…elease agent-team

release.yaml ran on every push to main, cutting a repo-wide release-it GitHub
release + Homebrew formula PR even for plugins/**-only changes. The agent-team /
claude-team formulas ship only bin/** scripts, so those releases installed
byte-identical binaries — pure churn.

Lean into the nx monorepo pattern instead:

- Add a per-module `release` target (nx run-script). Only modules that actually
  release define one: root -> `release-it --ci`; @nsheaps/agents-plugins ->
  plugins/release.sh (version bump + marketplace.json, self-contained commit/push,
  lifted from cd.yaml's main job).
- nx.json: `release` targetDefault with dependsOn [build, test, lint, ^release].
- release.yaml: resolve base = floating `last-released` tag (fallback HEAD~1),
  run `nx affected --target=release --parallel=1`, open the Homebrew PR only when
  root actually cut a new v* tag, then move `last-released` to the released commit.
- cd.yaml: now PR-preview-only; its main bump job moved into the plugins release
  target. Retire the `cd/last-release` tag in favor of `last-released`.
- Docs: document the release pipeline in docs/MONOREPO.md.

Net: plugins-only change -> only the plugins module releases (verified locally via
`nx show projects --affected --withTarget=release`). bin/** change -> root releases.
release-it (root) pushes a commit to main and can't tolerate main advancing
under it; the other modules' release scripts resync + retry. When a single
merge affects both, run root:release first, then nx affected --exclude=root for
the resilient rest.
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Plugin Version Preview

Preview only — plugin versions and marketplace.json are bumped automatically on merge to main, not in this PR. Manual bumps to higher versions are preserved. See the file annotations for the pending change on each plugin.json.

Plugin Base Current Action

@jack-nsheaps jack-nsheaps Bot added the request-review Force an AI code review on a draft PR (open non-draft PRs review automatically) label Jun 10, 2026
@jack-nsheaps

jack-nsheaps Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Code review (fallback self-review)

The CI review bot (Henry via dispatch-review.yaml) could not run — the automation-nsheaps[bot] App installation on this repo is missing Checks: write, so the dispatch failed at "Post pending check" (Resource not accessible by integration, run 27297261251). This is a fallback review by the PR author bot — lower independence than a real reviewer. Granting the automation App Checks: write on nsheaps/agents would restore the bot.

Verdict: 🟢 sound and achieves the goal. One P1 to address-or-consciously-accept; rest are minor.

P1 — partial-failure drops the Homebrew update non-self-healingly

In release.yaml, Resolve root release info (which sets released/tag) and Move last-released tag run after the combined Run affected releases step. If root:release (release-it) succeeds and pushes its v* tag, but the subsequent nx affected … --exclude=root (plugins) step fails, then:

  • release-info is skipped → released is empty → update-homebrew is skipped;
  • last-released is not moved.

Because release-it's commit is [skip ci], nothing re-triggers automatically. A manual re-run sees the base unchanged and root affected, but release-it finds no new version-worthy commitsreleased=false → Homebrew is permanently skipped for that version. Suggest decoupling "did root cut a new tag?" from the combined step (capture pre/post tag around root:release specifically, gate Homebrew on that), so a plugins failure can't strand the root release.

P2 — release is now gated on repo-wide lint (and test)

release dependsOn: ["build","test","lint",…], and nx run root:release runs root lint = prettier --check "**/*.md" + shell-syntax over the whole repo. Pre-existing markdown/shell drift on main (e.g. from a bot commit) would now block all releases, where previously release.yaml ran release-it directly with no lint gate. Likely acceptable (don't release a broken tree), but it's a new release-availability coupling — worth being explicit about.

P2 — doc vs. impl mismatch

docs/MONOREPO.md Releases §4 says the Homebrew PR opens "only when root is affected". The code is stricter: it opens only when root actually cut a new v* tag (released == 'true'). Tighten the doc to match.

P2 — leftover redundant guard

cd.yaml's version-preview job keeps if: github.event_name == 'pull_request', but the workflow now triggers only on pull_request, so the guard is always true. Harmless; can drop for clarity.

P2 — release-it changelog still repo-wide

Already captured as a follow-up in the plan: root's release-it scans repo-wide commits, so a root release's changelog can include unrelated (e.g. plugin) commit subjects. Out of scope for this PR.

✅ Verified / good

  • Affected discrimination is correct (--withTarget=release): plugins/**[plugins], bin/**[root], both→both. This is the core fix.
  • Root-first ordering avoids the stale-push race (release-it can't tolerate main advancing; plugins resyncs).
  • [skip ci] on both release commits prevents a release→push→release loop; tag-push doesn't re-trigger (on: push: branches: [main]).
  • plugins/release.sh faithfully lifts cd.yaml's resilient sync+retry; stages only its own slice.
  • nx graph picks up both release targets with the dependsOn; nx run root:release and --exclude=root resolve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

request-review Force an AI code review on a draft PR (open non-draft PRs review automatically)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant