Repository navigation
test(publish): add non-dry-run publish e2e coverage - #588
Merged
Merged
Conversation
Contributor
|
Standing release PR: #582 · v0.41.1 queued (4 packages) · open 2h 10m · ✅ ready to merge Release Preview — v0.41.0 → v0.41.1
These changes will be added to the release PR (#582) when merged: Changelogmonorepo 0.41.0 → 0.41.1
After merge — predicted release
Updated automatically by ReleaseKit |
Every existing layer bypasses the real publish path: Examples Smoke runs --dry-run (auth is dry-run-exempt), the Action harness sets SKIP_PUBLISH, and unit specs mock the registries. That gap let #578 (cargo auth demanded on a crateless repo) ship despite a green suite. Add a vitest integration spec that drives the real runPipeline with dryRun:false. npm publishes to an in-process verdaccio-style registry so npm publish + npm view + token auth run for real without hitting npmjs; cargo's publish exec is stubbed on PATH (the value is auth/discovery/ ordering, not the upload). Covers: enabled-but-empty stages no-op without demanding credentials (the #578 class), idempotent re-publish skip on a partial-failure re-run, per-registry auth detection, and post-publish tag + GitHub-Release creation. The mock registry sends Cache-Control: no-store so npm re-queries on each npm view (else heuristic freshness can serve a stale pre-publish 404 and defeat the idempotency skip). The lightweight guards run in the default gate (no network); the heavier real-npm-publish cases are opt-in via RELEASEKIT_PUBLISH_E2E=1. Closes #580 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BT6fVBZrmExXZj7vQ29881
goosewobbler
force-pushed
the
test/publish-non-dry-run-e2e
branch
from
July 19, 2026 23:17
9c7e262 to
3484337
Compare
Merged
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
packages/publish/test/integration/publish-e2e.spec.ts— end-to-end coverage of the non-dry-run publish pipeline, the path every existing test layer bypasses (Examples Smoke uses--dry-run, the Action harness setsSKIP_PUBLISH, unit specs mock the registries). That blind spot is exactly why #578 shipped despite a green suite.The spec drives the real
runPipelinewithdryRun: false:npm publish+npm view+ Bearer-token auth run without touching npmjs. The registry is serviced asynchronously (the pipeline shells out via asyncexecFile, so the event loop stays free) and sendsCache-Control: no-storeso npm re-queries on eachnpm viewinstead of serving a stale heuristic-fresh pre-publish 404.cargo publishexec stubbed onPATH; the value under test is auth + discovery + ordering, not the upload.gh release createis stubbed.Scenarios covered:
gh release create, asserted end to end).Test-harness robustness: the real-
npm publishcases run the publish subprocess with a hermetic environment — everynpm_config_*key is stripped andHOME/npm_config_globalconfig/npm_config_cacheare pinned to temp paths. Without this, running underpnpm --filter … test(the CI path) leaks an env-levelnpm_config_registrythat outranks the pipeline's userconfig in npm's precedence, sonpm publishwould target npmjs.org andENEEDAUTH.afterEachrestores the full env.Test plan
pnpm turbo run lint typecheck test— green (32/32); publish shows 288 passed + 3 skipped (the gated e2e is skipped by default so the default gate stays fast/no-network).pnpm lint— exit 0.RELEASEKIT_PUBLISH_E2E=1 pnpm --filter @releasekit/publish test— 291/291, run 3× consecutively, 0 failed (verified by the orchestrator). A dedicated CI job can set that flag to run the real-publish scenarios on demand.Harness choice
A vitest integration test (not the shell harness): the existing publish integration specs and the real-tool gated
cargo-lock-sync.spec.tsare all vitest, and drivingrunPipelinein-process lets the test stand up an in-process registry,PATHstubs, and a local bare git remote while reusing the existingdescribe.skipIfgating idiom. The shell harness exercises the Action/CLI wrapper and always setsSKIP_PUBLISH, so it's the wrong layer for the publish internals.Closes #580
🤖 Generated with Claude Code
https://claude.ai/code/session_01BT6fVBZrmExXZj7vQ29881
Greptile Summary
This PR adds
publish-e2e.spec.ts, a new integration spec that drivesrunPipelinewithdryRun: falseto close the coverage gap that let #578 (cargo auth demanded on a crate-less repo) ship with a green suite. The two previous review concerns —putCount()being incremented before the version-conflict check and the absence of a version-specificGET /<pkg>/<ver>handler — are both addressed in the submitted code.RELEASEKIT_PUBLISH_E2E=1): runnpm publishagainst an in-process registry with hermetic env stripping to prevent pnpm-injectednpm_config_registryfrom leaking, assert idempotent re-publish skip, and stubcargo publishon PATH to verify auth + ordering without touching crates.io.Confidence Score: 5/5
Safe to merge — adds test coverage only, no production code changes.
The change is purely additive test code. Both issues flagged in prior review threads are resolved:
putCount()is incremented after the conflict check, and the registry handles the version-specific GET endpoint. The harness design is solid with hermetic env stripping, local bare git remote,describe.skipIfgating, and properafterEachenv restore.No files require special attention.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant T as Test participant P as runPipeline participant R as LocalRegistry (in-process) participant N as npm CLI (subprocess) participant C as cargo stub (PATH) participant G as gh stub (PATH) participant BG as bare git remote Note over T,BG: Lightweight guards (default gate — no network) T->>P: dryRun:false, cargo+pub enabled, no crates/pkgs P-->>T: resolve (publishSucceeded:true, cargo:[], pub:[]) T->>P: dryRun:false, npm enabled, no NPM_TOKEN P-->>T: reject (failedStage:npm-publish, /authentication/) T->>P: dryRun:false, cargo enabled + crate present, no CARGO_REGISTRY_TOKEN P-->>T: reject (failedStage:cargo-publish, /CARGO_REGISTRY_TOKEN/) Note over T,BG: E2E (RELEASEKIT_PUBLISH_E2E=1) T->>R: startLocalRegistry() R-->>T: url + putCount() T->>P: dryRun:false, npm token auth, real npm client P->>N: npm publish (Bearer token) N->>R: PUT /pkg (Bearer: token) R-->>N: 201 ok N-->>P: exit 0 P->>G: gh release create v1.0.1 G-->>P: exit 0 (stubbed) P->>BG: git push origin main --tags P-->>T: resolve (npm[0].success:true, putCount:1) T->>P: re-run same version (idempotency) P->>N: "npm view pkg@ver" N->>R: GET /pkg R-->>N: 200 packument (Cache-Control:no-store) N-->>P: version already published P-->>T: resolve (skipped:true, putCount still 1) T->>P: cargo, CARGO_REGISTRY_TOKEN present P->>C: cargo publish (stubbed) C-->>P: exit 0 P-->>T: resolve (cargo[0].success:true)%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant T as Test participant P as runPipeline participant R as LocalRegistry (in-process) participant N as npm CLI (subprocess) participant C as cargo stub (PATH) participant G as gh stub (PATH) participant BG as bare git remote Note over T,BG: Lightweight guards (default gate — no network) T->>P: dryRun:false, cargo+pub enabled, no crates/pkgs P-->>T: resolve (publishSucceeded:true, cargo:[], pub:[]) T->>P: dryRun:false, npm enabled, no NPM_TOKEN P-->>T: reject (failedStage:npm-publish, /authentication/) T->>P: dryRun:false, cargo enabled + crate present, no CARGO_REGISTRY_TOKEN P-->>T: reject (failedStage:cargo-publish, /CARGO_REGISTRY_TOKEN/) Note over T,BG: E2E (RELEASEKIT_PUBLISH_E2E=1) T->>R: startLocalRegistry() R-->>T: url + putCount() T->>P: dryRun:false, npm token auth, real npm client P->>N: npm publish (Bearer token) N->>R: PUT /pkg (Bearer: token) R-->>N: 201 ok N-->>P: exit 0 P->>G: gh release create v1.0.1 G-->>P: exit 0 (stubbed) P->>BG: git push origin main --tags P-->>T: resolve (npm[0].success:true, putCount:1) T->>P: re-run same version (idempotency) P->>N: "npm view pkg@ver" N->>R: GET /pkg R-->>N: 200 packument (Cache-Control:no-store) N-->>P: version already published P-->>T: resolve (skipped:true, putCount still 1) T->>P: cargo, CARGO_REGISTRY_TOKEN present P->>C: cargo publish (stubbed) C-->>P: exit 0 P-->>T: resolve (cargo[0].success:true)Reviews (2): Last reviewed commit: "test(publish): add non-dry-run publish e..." | Re-trigger Greptile