rman 2.11.0 → 2.11.1

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.
@@ -43,6 +43,11 @@ export declare namespace PublishService {
43
43
  * goes green" is the most important sentence in the plan when it applies.
44
44
  */
45
45
  staged?: boolean;
46
+ /** Subdirectory to publish from, relative to the package's own directory - only consulted when
47
+ * the package doesn't already declare its own `package.json` `publishConfig.directory` (npm's
48
+ * native mechanism for this, which always wins when present). A plan option, because the
49
+ * manifest in that directory is what the plan decides from. */
50
+ contents?: string;
46
51
  }
47
52
  interface ApplyOptions extends Options {
48
53
  packageManager?: CiService.PackageManager;
@@ -50,10 +55,6 @@ export declare namespace PublishService {
50
55
  access?: 'public' | 'restricted';
51
56
  /** `npm publish --otp <otp>` - a 2FA one-time password, for registries that require it. */
52
57
  otp?: string;
53
- /** Subdirectory to publish from, relative to the package's own directory - only consulted when
54
- * the package doesn't already declare its own `package.json` `publishConfig.directory` (npm's
55
- * native mechanism for this, which always wins when present). */
56
- contents?: string;
57
58
  }
58
59
  /** One package's outcome in a publish plan - see `getPlan`. */
59
60
  interface Entry {
@@ -101,7 +102,11 @@ export declare namespace PublishService {
101
102
  * queries it to decide, so it's safe to call any time, including as the plan a bare `rman
102
103
  * publish` shows before asking for confirmation.
103
104
  *
104
- * A `private: true` package is always `'skip'`ped outright. Each remaining package's **dist-tag**
105
+ * **Whether a package is private is read from the manifest that would be published** - the one in
106
+ * its build directory when it publishes from one, its own otherwise. A build directory with no
107
+ * `package.json` is an `'error'`: nothing has been built to publish. A package `private` in its
108
+ * source with no `publishConfig` is skipped before that is asked, since it stays private in any
109
+ * manifest derived from it. Each remaining package's **dist-tag**
105
110
  * is settled next (`distTagFor`): usually derived from the version itself, `'error'` in the two
106
111
  * cases with nothing to derive - that one is about the invocation rather than the package, so it
107
112
  * is answered before anything touches the network. A package with uncommitted local changes is
@@ -72,21 +72,19 @@ function preparePublishManifest(pkg, publishDir, packagesByName) {
72
72
  * builds a native module on install. The rest (`build`, `test`, `prepare`, ...) never reach the
73
73
  * consumer - `prepare` runs for a git dependency, which builds from the repository, not from this
74
74
  * tarball.
75
- * - `private` - it is a statement about the **source tree**, not about the artifact derived from it,
76
- * and a manifest being published is by definition not private. rman's own gate normally stops a
77
- * private package before this runs, so the line looks unreachable; it is not, because `private`
78
- * is also how a repository keeps a stray `npm publish` out of the package directory while
79
- * publishing `build/` on purpose. That is a real configuration - this repository ran it until
80
- * `rman publish` became its own release path and the gate started refusing the thing it ships.
81
- * A narrower guard (`prepublishOnly`, which never reaches a consumer either) says the same thing
82
- * without claiming the artifact is unpublishable.
75
+ * - `private` - **only when the package declares a `publishConfig`**. A package configured to be
76
+ * published that is also `private` is guarding its source tree against a stray `npm publish`,
77
+ * not refusing to ship; one with no `publishConfig` means it, and keeps the flag. `getPlan`
78
+ * decides from the manifest this produces, so the rule here *is* the publish rule - a preset
79
+ * writing the build directory's manifest must apply the same one.
83
80
  * - `publishConfig.directory` - it pointed *here*; kept, it would point one level deeper again.
84
81
  */
85
82
  function derivePublishManifest(pkg, packagesByName) {
86
83
  const json = structuredClone(pkg.manifest.raw);
87
84
  resolveWorkspaceRanges(json, packagesByName);
88
85
  delete json.devDependencies;
89
- delete json.private;
86
+ if (json.publishConfig)
87
+ delete json.private;
90
88
  if (json.scripts) {
91
89
  const kept = Object.fromEntries(Object.entries(json.scripts).filter(([name]) => CONSUMER_SCRIPTS.has(name)));
92
90
  if (Object.keys(kept).length)
@@ -129,7 +127,11 @@ export var PublishService;
129
127
  * queries it to decide, so it's safe to call any time, including as the plan a bare `rman
130
128
  * publish` shows before asking for confirmation.
131
129
  *
132
- * A `private: true` package is always `'skip'`ped outright. Each remaining package's **dist-tag**
130
+ * **Whether a package is private is read from the manifest that would be published** - the one in
131
+ * its build directory when it publishes from one, its own otherwise. A build directory with no
132
+ * `package.json` is an `'error'`: nothing has been built to publish. A package `private` in its
133
+ * source with no `publishConfig` is skipped before that is asked, since it stays private in any
134
+ * manifest derived from it. Each remaining package's **dist-tag**
133
135
  * is settled next (`distTagFor`): usually derived from the version itself, `'error'` in the two
134
136
  * cases with nothing to derive - that one is about the invocation rather than the package, so it
135
137
  * is answered before anything touches the network. A package with uncommitted local changes is
@@ -187,7 +189,19 @@ export var PublishService;
187
189
  reason: 'excluded via .rmanrc "publish.skip"',
188
190
  });
189
191
  }
190
- else if (pkg.isPrivate) {
192
+ else if (privateBySource(pkg)) {
193
+ entries.set(pkg.name, { package: pkg, version: pkg.version, status: 'skip', reason: 'private package' });
194
+ }
195
+ else if (!fs.existsSync(path.join(resolvePublishDir(pkg, options.contents), 'package.json'))) {
196
+ const dir = path.relative(pkg.dirname, resolvePublishDir(pkg, options.contents)) || '.';
197
+ entries.set(pkg.name, {
198
+ package: pkg,
199
+ version: pkg.version,
200
+ status: 'error',
201
+ reason: `nothing to publish in "${dir}" - it has no package.json; build the package first`,
202
+ });
203
+ }
204
+ else if (publishedManifestOf(pkg, options.contents).private) {
191
205
  entries.set(pkg.name, { package: pkg, version: pkg.version, status: 'skip', reason: 'private package' });
192
206
  }
193
207
  else if (distTag.error) {
@@ -310,6 +324,27 @@ function resolvePublishDir(pkg, contentsOverride) {
310
324
  const rel = (typeof native === 'string' && native) || configured || contentsOverride;
311
325
  return rel ? path.resolve(pkg.dirname, rel) : pkg.dirname;
312
326
  }
327
+ /** The manifest `npm publish` will read for `pkg` - its build directory's, or its own when it
328
+ * publishes in place. */
329
+ /* **Decided from the artifact, not the source**, because the two disagree about `private` and only
330
+ * one of them is published. Read before any build, the plan answered `skip - private package` for a
331
+ * single-package repository whose source carries `private: true` as a guard against a stray
332
+ * `npm publish` - while `derivePublishManifest` was removing that very flag from what it ships.
333
+ * Reported from `postgrejs-kysely`: version, tag and GitHub release all went through, and the
334
+ * registry got nothing. */
335
+ function publishedManifestOf(pkg, contentsOverride) {
336
+ const dir = resolvePublishDir(pkg, contentsOverride);
337
+ if (path.resolve(dir) === path.resolve(pkg.dirname))
338
+ return pkg.manifest.raw;
339
+ return JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
340
+ }
341
+ /** `private` in the source with no `publishConfig` - private in every manifest derived from it too,
342
+ * so it is known without a build. */
343
+ /* Asked first so an unbuilt private package is skipped rather than reported as unbuilt: opra's
344
+ * examples inherit `publish.npm.directory` from the shared preset and skip their build. */
345
+ function privateBySource(pkg) {
346
+ return !!pkg.manifest.raw.private && !pkg.manifest.raw.publishConfig;
347
+ }
313
348
  /**
314
349
  * Which registry a package's own version is asked about, and published to.
315
350
  *
@@ -84,7 +84,6 @@ export class NpmPublishTarget {
84
84
  packageManager: ctx.args.packageManager,
85
85
  access: ctx.args.access,
86
86
  otp: ctx.args.otp,
87
- contents: ctx.args.contents,
88
87
  });
89
88
  }
90
89
  /** The shared filters plus the two flags both halves need - read here rather than in the
@@ -103,6 +102,9 @@ export class NpmPublishTarget {
103
102
  * flag was not given, so each package's own `publish.npm.staged` still decides - `false`
104
103
  * here would mean `--no-staged` and silently overrule the config. */
105
104
  staged: ctx.args.staged,
105
+ /** The plan decides from the manifest in the directory being published, so it has to know
106
+ * which directory that is. */
107
+ contents: ctx.args.contents,
106
108
  };
107
109
  }
108
110
  }
package/constants.js CHANGED
@@ -1 +1 @@
1
- export const version = '2.11.0';
1
+ export const version = '2.11.1';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rman",
3
3
  "description": "Repository manager",
4
- "version": "2.11.0",
4
+ "version": "2.11.1",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
7
7
  "dependencies": {