rvlib-shipkit 0.35.4 → 0.35.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.35.5
4
+
5
+ - **The `TaskDef.inputs` doc comment stated only half the safety rule.** It said undeclared means never cached, so forgetting costs speed and never correctness, which is true for forgetting a whole task and false for the mistake that actually ships a false green: a list MISSING a path the command reads. The key cannot move when that path changes, so the answer replays over a tree it no longer describes. Observed twice in the field in one day. The comment now carries the asymmetry, names `['.']` as the declaration that cannot under declare, and says that a task carries no code closure, so the script it runs belongs in `inputs` too.
6
+ - **`shipkit release` scopes its dirt check exactly like `shipkit bump`.** `bump` examined the released unit plus every package.json and lockfile a version commit can touch; `release` examined the WHOLE worktree, refused, and then named `shipkit release` as the fix, which refuses identically. Several agents share one checkout here, so a neighbour editing an unrelated package was enough to wedge a release with no way forward that the message described. The reason to refuse at all is unchanged and still applies inside the scope: `npm publish` packs the WORKING TREE rather than the commit, so a half written file inside the unit ships under a tag that describes something else. Dirt in another unit reaches neither the tarball nor the tag, and the refusal now says what it examined.
7
+
3
8
  ## 0.35.4
4
9
 
5
10
  - **The imports refusal did not follow tsconfig `extends`, so a correctly configured repo went red and was told to add a key it already had.** Inheriting `paths` from a base config is the more common way to carry them, and only `references` was handled. `extends` is now followed (relative and node-resolved, chains and cycles included), and a mapping counts only when its TARGET is on disk: `"src/*": ["./packages/core/src/*"]` maps the prefix and resolves nothing. A package prefix is no longer accepted on the package DIRECTORY existing either, since a stale installed copy missing the file is the same false green one level up. `baseUrl` is no longer proof at all: tsc follows one, but rollup, esbuild and vite do not resolve a bare specifier through it, and the field failure this guard exists for was a rollup one. A multi-segment root (`packages/core`) is named as itself rather than as `packages`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rvlib-shipkit",
3
- "version": "0.35.4",
3
+ "version": "0.35.5",
4
4
  "description": "All-in-one repo companion: ci gate (task DAG), auto-discovered health checks, release-contract fulfillness, asks queue, md-wiki tools, asset atelier, live tui",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,8 +32,14 @@ export type TaskDef = {
32
32
  timeoutMs?: number
33
33
  /** CONTENT population: the repo-relative paths this task reads. Declaring
34
34
  * them is what makes the task keyable (ledger/git-key.ts). Undeclared is
35
- * the DEFAULT and means never cached, so forgetting costs speed and never
36
- * correctness. Declaring both this and `ttl` is a registration failure. */
35
+ * the DEFAULT and means never cached, so forgetting a whole task costs
36
+ * speed and never correctness. A list MISSING a path the command reads is
37
+ * the one that costs correctness: the key cannot move when that path
38
+ * changes, so the answer replays over a tree it no longer describes. Over
39
+ * declaring costs a re-run, under declaring is a false green, and `['.']`
40
+ * is the whole work tree and cannot under declare. A task carries no code
41
+ * closure, so the script it runs belongs in here too.
42
+ * Declaring both this and `ttl` is a registration failure. */
37
43
  inputs?: string[]
38
44
  /** WORLD population: this task reads the network, a keychain, $PATH or the
39
45
  * clock, so nothing on disk describes its answer and a clean pass is
@@ -11,6 +11,7 @@ import { join } from 'path'
11
11
  import { runCi } from '../core/run-ci.ts'
12
12
  import { extractChangelogSection } from './changelog.ts'
13
13
  import { deriveRemote, dirtyPaths, git, remoteTagState, tagExistsLocally, type RemoteTagState } from './git-facts.ts'
14
+ import { releaseScope } from './release-scope.ts'
14
15
  import { npmPublishArgv, unitBlockers } from './unit-gate.ts'
15
16
  import { formatUnitError, resolveUnits, unitById, type ReleaseUnit } from './units.ts'
16
17
  import type { RepoConfig } from '../repo-config.ts'
@@ -172,9 +173,23 @@ export async function releaseUnit(root: string, config: RepoConfig, unit: Releas
172
173
  if (cur.code !== 0) blockers.push('not a git repository')
173
174
  else if (cur.out !== branch) blockers.push(`releases ship from '${branch}', HEAD is on '${cur.out}'`)
174
175
 
175
- const dirty = dirtyPaths(root, config)
176
- if (dirty !== '' && o.allowDirty !== true)
177
- blockers.push(`working tree not clean (--allow-dirty overrides):\n${dirty.split('\n').slice(0, 10).join('\n')}`)
176
+ // scoped exactly like `bump`, and for the same reason: `npm publish` packs
177
+ // the WORKING TREE rather than the commit, so dirt INSIDE what ships can
178
+ // put a half written file under a tag that describes something else. Dirt
179
+ // in another unit reaches neither this tarball nor this tag. Checking the
180
+ // whole tree here made `release` refuse what `bump` allows, and then name
181
+ // `shipkit release` as the fix, which refuses identically: several agents
182
+ // share this checkout, so a neighbour editing an unrelated package was
183
+ // enough to wedge a release with no way forward that the message named.
184
+ // the sibling units matter to the SCOPE: a version write rewrites the
185
+ // rvlib range in every dependent's package.json, so those paths are inside
186
+ // this release even though they are outside this unit
187
+ const scope = releaseScope(root, resolveUnits(root, config).units, [unit])
188
+ const dirty = dirtyPaths(root, config, scope.specs ?? undefined)
189
+ if (dirty !== '' && o.allowDirty !== true) {
190
+ blockers.push(`uncommitted changes in ${scope.describe} (--allow-dirty overrides):\n${dirty.split('\n').slice(0, 10).join('\n')}`)
191
+ if (scope.specs != null) blockers.push('dirt elsewhere in the worktree is deliberately ignored, it cannot reach this tarball or this tag')
192
+ }
178
193
  if (o.skipUnitGate !== true) blockers.push(...unitBlockers(root, config, unit))
179
194
 
180
195
  let alreadyPublished = false