rman 1.3.0 → 2.0.0-beta.3
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/README.md +65 -31
- package/builtins/platforms/node/augmentation/rmanrc.augmentation.d.ts +83 -0
- package/builtins/platforms/node/augmentation/system-info.augmentation.d.ts +26 -0
- package/builtins/platforms/node/augmentation/system-info.augmentation.js +79 -0
- package/builtins/platforms/node/commands/ci.command.d.ts +133 -0
- package/builtins/platforms/node/commands/ci.command.js +60 -0
- package/builtins/platforms/node/commands/clean.command.d.ts +185 -0
- package/builtins/platforms/node/commands/clean.command.js +74 -0
- package/builtins/platforms/node/index.d.ts +8 -0
- package/builtins/platforms/node/index.js +8 -0
- package/builtins/platforms/node/node-config.interface.d.ts +76 -0
- package/builtins/platforms/node/node-config.interface.js +7 -0
- package/builtins/platforms/node/node-manifest.provider.d.ts +68 -0
- package/builtins/platforms/node/node-manifest.provider.js +125 -0
- package/builtins/platforms/node/node.platform.d.ts +53 -0
- package/builtins/platforms/node/node.platform.js +134 -0
- package/builtins/platforms/node/services/ci.service.d.ts +47 -0
- package/builtins/platforms/node/services/ci.service.js +213 -0
- package/builtins/platforms/node/services/clean.service.d.ts +53 -0
- package/builtins/platforms/node/services/clean.service.js +237 -0
- package/builtins/platforms/node/services/publish.service.d.ts +114 -0
- package/builtins/platforms/node/services/publish.service.js +371 -0
- package/builtins/platforms/node/services/version-plan.service.d.ts +44 -0
- package/builtins/platforms/node/services/version-plan.service.js +58 -0
- package/builtins/platforms/node/utils/workspace-range.d.ts +26 -0
- package/builtins/platforms/node/utils/workspace-range.js +28 -0
- package/builtins/presets/index.d.ts +15 -0
- package/builtins/presets/index.js +57 -0
- package/builtins/presets/node.d.ts +16 -0
- package/builtins/presets/node.js +57 -0
- package/{services → builtins/publish-targets/docker}/docker-publish.service.d.ts +52 -31
- package/{services → builtins/publish-targets/docker}/docker-publish.service.js +49 -26
- package/builtins/publish-targets/docker/docker.target.d.ts +54 -0
- package/builtins/publish-targets/docker/docker.target.js +40 -0
- package/builtins/publish-targets/docker/index.d.ts +2 -0
- package/builtins/publish-targets/docker/index.js +2 -0
- package/builtins/publish-targets/npm/index.d.ts +2 -0
- package/builtins/publish-targets/npm/index.js +2 -0
- package/builtins/publish-targets/npm/npm-publish-target.d.ts +73 -0
- package/builtins/publish-targets/npm/npm-publish-target.js +95 -0
- package/builtins/publish-targets/npm/npm-view.d.ts +48 -0
- package/builtins/publish-targets/npm/npm-view.js +71 -0
- package/cli.d.ts +8 -0
- package/cli.js +228 -93
- package/commands/build.command.d.ts +177 -3
- package/commands/build.command.js +20 -10
- package/commands/changelog.command.d.ts +296 -3
- package/commands/changelog.command.js +127 -43
- package/commands/config.command.d.ts +44 -3
- package/commands/config.command.js +53 -24
- package/commands/diff.command.d.ts +37 -3
- package/commands/diff.command.js +25 -16
- package/commands/exec.command.d.ts +193 -3
- package/commands/exec.command.js +60 -58
- package/commands/github-release.command.d.ts +154 -3
- package/commands/github-release.command.js +67 -37
- package/commands/import.command.d.ts +36 -3
- package/commands/import.command.js +28 -20
- package/commands/info.command.d.ts +35 -7
- package/commands/info.command.js +36 -30
- package/commands/lint.command.d.ts +176 -0
- package/commands/lint.command.js +34 -0
- package/commands/list.command.d.ts +163 -3
- package/commands/list.command.js +109 -71
- package/commands/publish.command.d.ts +231 -0
- package/commands/publish.command.js +304 -0
- package/commands/run.command.d.ts +186 -6
- package/commands/run.command.js +26 -72
- package/commands/test.command.d.ts +173 -3
- package/commands/test.command.js +16 -10
- package/commands/version.command.d.ts +330 -3
- package/commands/version.command.js +292 -78
- package/commands.d.ts +32 -0
- package/commands.js +28 -0
- package/constants.js +1 -1
- package/core/application.d.ts +116 -0
- package/core/application.js +160 -0
- package/core/classes/package.d.ts +219 -0
- package/core/classes/package.js +214 -0
- package/core/classes/registry.d.ts +30 -0
- package/core/classes/registry.js +47 -0
- package/core/{repository.d.ts → classes/repository.d.ts} +69 -20
- package/core/{repository.js → classes/repository.js} +195 -75
- package/core/classes/service.d.ts +49 -0
- package/core/classes/service.js +40 -0
- package/core/{version-scheme.d.ts → classes/version-scheme.d.ts} +23 -1
- package/core/{version-scheme.js → classes/version-scheme.js} +29 -1
- package/core/classes/workspace.d.ts +275 -0
- package/core/classes/workspace.js +537 -0
- package/core/command-builder.d.ts +14 -0
- package/core/command-builder.js +94 -0
- package/core/config/config-file-scope.d.ts +107 -0
- package/core/config/config-file-scope.js +226 -0
- package/core/config/config-interpolator.d.ts +164 -0
- package/core/config/config-interpolator.js +577 -0
- package/core/config/config-paths.d.ts +65 -0
- package/core/config/config-paths.js +78 -0
- package/core/config/config-reader.d.ts +192 -0
- package/core/config/config-reader.js +727 -0
- package/core/{merge-config.d.ts → config/merge-config.d.ts} +33 -34
- package/core/config/merge-config.js +260 -0
- package/core/{resolve-target.d.ts → config/resolve-config-target.d.ts} +1 -1
- package/core/{resolve-target.js → config/resolve-config-target.js} +1 -1
- package/core/{custom-command.d.ts → interfaces/custom-command.d.ts} +46 -10
- package/core/{custom-command.js → interfaces/custom-command.js} +44 -17
- package/core/{manifest.d.ts → interfaces/manifest.d.ts} +49 -27
- package/core/interfaces/manifest.js +132 -0
- package/core/interfaces/plugin.d.ts +174 -0
- package/core/interfaces/plugin.js +124 -0
- package/core/interfaces/publish-target.d.ts +136 -0
- package/core/interfaces/publish-target.js +43 -0
- package/core/{run-step.d.ts → interfaces/run-step.d.ts} +4 -4
- package/core/interfaces/run-step.js +1 -0
- package/core/plugin-loader.d.ts +25 -0
- package/core/plugin-loader.js +53 -0
- package/index.d.ts +122 -24
- package/index.js +66 -16
- package/interfaces/config-scope.interface.d.ts +223 -0
- package/interfaces/config-scope.interface.js +1 -0
- package/interfaces/rman-config.interface.d.ts +821 -203
- package/interfaces/rman-config.interface.js +78 -1
- package/package.json +3 -1
- package/services/change-hash.service.d.ts +42 -8
- package/services/change-hash.service.js +92 -13
- package/services/changelog.service.d.ts +91 -52
- package/services/changelog.service.js +460 -74
- package/services/config-service.d.ts +8 -0
- package/services/config-service.js +3 -0
- package/services/exec.service.d.ts +23 -12
- package/services/exec.service.js +14 -9
- package/services/github-release.service.d.ts +45 -34
- package/services/github-release.service.js +15 -12
- package/services/import.service.d.ts +25 -14
- package/services/import.service.js +9 -5
- package/services/list.service.d.ts +67 -13
- package/services/list.service.js +62 -15
- package/services/run.service.d.ts +35 -22
- package/services/run.service.js +316 -233
- package/services/system-info.d.ts +1 -1
- package/services/version-plan.service.d.ts +35 -8
- package/services/version-plan.service.js +96 -36
- package/services/version.service.d.ts +34 -14
- package/services/version.service.js +35 -16
- package/services.d.ts +1 -1
- package/services.js +1 -1
- package/utils/bin-path.d.ts +6 -7
- package/utils/bin-path.js +7 -18
- package/utils/branch-guard.d.ts +30 -1
- package/utils/branch-guard.js +31 -0
- package/utils/color-yaml.d.ts +8 -0
- package/utils/color-yaml.js +86 -0
- package/utils/exec.d.ts +10 -0
- package/utils/exec.js +1 -1
- package/utils/git.d.ts +26 -0
- package/utils/git.js +65 -0
- package/utils/logger.d.ts +2 -2
- package/utils/logger.js +1 -1
- package/utils/package-filter.d.ts +135 -8
- package/utils/package-filter.js +204 -16
- package/utils/printable-config.d.ts +9 -1
- package/utils/printable-config.js +46 -1
- package/utils/progress-panel.d.ts +9 -0
- package/utils/progress-panel.js +23 -1
- package/utils/release-version.d.ts +1 -1
- package/utils/run-bin.d.ts +10 -0
- package/utils/run-bin.js +1 -1
- package/utils/run-options.d.ts +97 -0
- package/utils/run-options.js +81 -0
- package/utils/version-group.d.ts +31 -0
- package/utils/version-group.js +43 -0
- package/utils/version-stamp.d.ts +1 -1
- package/utils/version-stamp.js +1 -1
- package/commands/changed.command.d.ts +0 -3
- package/commands/changed.command.js +0 -29
- package/core/config.d.ts +0 -409
- package/core/config.js +0 -939
- package/core/extends-config.d.ts +0 -27
- package/core/extends-config.js +0 -89
- package/core/manifest.js +0 -150
- package/core/merge-config.js +0 -219
- package/core/package.d.ts +0 -83
- package/core/package.js +0 -106
- package/core/plugin.d.ts +0 -112
- package/core/plugin.js +0 -189
- package/core/workspace.d.ts +0 -68
- package/core/workspace.js +0 -83
- /package/{core/run-step.js → builtins/platforms/node/augmentation/rmanrc.augmentation.js} +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { definePlatform } from '../../core/interfaces/plugin.js';
|
|
2
|
+
import { defineConfig } from '../../interfaces/rman-config.interface.js';
|
|
3
|
+
import { augmentSystemInfo, ciCommand, cleanCommand, NodePlatform } from '../platforms/node/index.js';
|
|
4
|
+
import { NpmPublishTarget } from '../publish-targets/npm/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* **The `node` preset** - everything rman knows about the npm ecosystem, as a config.
|
|
7
|
+
*
|
|
8
|
+
* ```yaml
|
|
9
|
+
* # .rmanrc.yml
|
|
10
|
+
* extends: node
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* It contributes the technology (how a `package.json` is read, where `workspaces` point, how
|
|
14
|
+
* versions are planned), the two commands that are npm's alone (`clean`, `ci`), and the `npm`
|
|
15
|
+
* publish target. A polyglot repository names several: `extends: ['node', 'cargo']` holds both,
|
|
16
|
+
* because every key here appends.
|
|
17
|
+
*/
|
|
18
|
+
/* **A config rather than a plugin, and that is the whole shape of a preset.** `commands` and
|
|
19
|
+
* `publishTargets` were already config keys; `platforms` is one now, so a technology arrives the
|
|
20
|
+
* same way everything else does. What used to need a `Builtin` type, a name that looked like a glob
|
|
21
|
+
* and an expansion step is `extends` and nothing else.
|
|
22
|
+
*
|
|
23
|
+
* **A function, so nothing here happens until a repository asks for it.** `augmentSystemInfo()`
|
|
24
|
+
* mutates the core's own `SystemInfo` in place, so running it at import time would have `rman info`
|
|
25
|
+
* report npm's tooling in a Cargo repository that never named this preset. `extends` imports the
|
|
26
|
+
* module it names and calls this; a repository that names something else never reaches it. */
|
|
27
|
+
export function nodePreset() {
|
|
28
|
+
augmentSystemInfo();
|
|
29
|
+
return defineConfig({
|
|
30
|
+
platforms: [(nodePlatform ??= definePlatform(new NodePlatform()))],
|
|
31
|
+
commands: [ciCommand, cleanCommand],
|
|
32
|
+
publishTargets: [(npmTarget ??= new NpmPublishTarget())],
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export default nodePreset;
|
|
36
|
+
/**
|
|
37
|
+
* **One instance of each across every call, so calling this preset twice contributes one of each.**
|
|
38
|
+
*
|
|
39
|
+
* A repository writing `extends: 'rman:node'` is read *and* gets the same preset laid under it by
|
|
40
|
+
* default, which is ordinary rather than a mistake - the contribution keys append and drop a
|
|
41
|
+
* duplicate **by identity** (`appendList`). The two commands are module consts, so they dedup on
|
|
42
|
+
* their own; anything this factory `new`s does not, and both of these have been that at some point.
|
|
43
|
+
*
|
|
44
|
+
* - **The target announced itself loudly.** Two of them reached `publish`, which refuses two
|
|
45
|
+
* targets declaring one option name, and it died with `Publish targets "npm" and "npm" both
|
|
46
|
+
* declare an option named "packageManager"` - the guard working exactly as intended, on a
|
|
47
|
+
* collision with itself.
|
|
48
|
+
* - **The platform does not, and that is the one to watch.** `_addPlatform` dedups by *name*, so a
|
|
49
|
+
* second `node` platform never reaches `context.platforms` and nothing resolves differently. What
|
|
50
|
+
* it does is put the same technology in `config.platforms` twice - visible only in `rman config`
|
|
51
|
+
* and to whoever iterates the key - plus an `augmentSystemInfo()` and a `new NodePlatform()` per
|
|
52
|
+
* read. Caught by the identity spec in `docs-api.spec.ts` rather than by anything failing.
|
|
53
|
+
*
|
|
54
|
+
* **A new preset has to do the same for anything it constructs.**
|
|
55
|
+
*/
|
|
56
|
+
let npmTarget;
|
|
57
|
+
let nodePlatform;
|
|
@@ -1,31 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type
|
|
3
|
-
import { type PackageFilterOptions } from '
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
type ApplyOptions = Options;
|
|
19
|
-
/** One package's outcome in a docker-publish plan - see `getPlan`. */
|
|
20
|
-
interface Entry {
|
|
21
|
-
package: Package;
|
|
22
|
-
version: string;
|
|
23
|
-
status: 'publish' | 'skip' | 'up-to-date' | 'error';
|
|
24
|
-
/** The fully-qualified `<namespace>/<image>` this entry publishes to - unset only when the
|
|
25
|
-
* package's own `publish.docker.image` config is missing entirely (an `'error'` entry). */
|
|
26
|
-
image?: string;
|
|
27
|
-
reason?: string;
|
|
28
|
-
}
|
|
1
|
+
import { Service } from '../../../core/classes/service.js';
|
|
2
|
+
import { type PublishTarget } from '../../../core/interfaces/publish-target.js';
|
|
3
|
+
import { type PackageFilterOptions } from '../../../utils/package-filter.js';
|
|
4
|
+
/**
|
|
5
|
+
* The name this target answers to in `publish.target` and `--target`.
|
|
6
|
+
*
|
|
7
|
+
* Declared beside the implementation rather than in `publish-target.ts`: the seam is general and
|
|
8
|
+
* must not know any one target's name, and the adapter in `builtins/publish-targets/docker/docker.target.ts` reads it from
|
|
9
|
+
* here, which keeps the dependency pointing one way.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DOCKER_TARGET = "docker";
|
|
12
|
+
/**
|
|
13
|
+
* A service class - see `ListService` for the shape and `Service` for the three measured
|
|
14
|
+
* consequences a namespace had. `repository` left the signature because the application carries it.
|
|
15
|
+
*/
|
|
16
|
+
export declare class DockerPublishService extends Service {
|
|
29
17
|
/**
|
|
30
18
|
* Computes what `publish --target docker` *would* do. Unlike the npm side (opt-out via
|
|
31
19
|
* `"private"`), the docker target is opt-in: only packages whose own (cascaded) `.rmanrc
|
|
@@ -39,14 +27,47 @@ export declare namespace DockerPublishService {
|
|
|
39
27
|
* already exists on the registry (via `docker manifest inspect`, queried concurrently) decides
|
|
40
28
|
* the rest: `'up-to-date'` if so, `'publish'` if not.
|
|
41
29
|
*/
|
|
42
|
-
|
|
30
|
+
getPlan(options?: DockerPublishService.Options, deps?: DockerPublishService.Deps): Promise<DockerPublishService.Entry[]>;
|
|
43
31
|
/**
|
|
44
32
|
* Publishes every `'publish'` entry in `plan`: one `docker login` and one `docker buildx create`
|
|
45
33
|
* up front (each package's own build reuses them), then per package a single `docker buildx
|
|
46
|
-
* build --push` using that package's `publish.docker` config (
|
|
34
|
+
* build --push` using that package's `publish.docker` config (architectures, named build-contexts,
|
|
47
35
|
* build-args, an optional `cwd` override). A package's `publish.docker.readme` file (default
|
|
48
36
|
* `DOCKER_README.md`), if present, updates the DockerHub repo description afterward. A package's
|
|
49
37
|
* own failure doesn't stop unrelated packages elsewhere in the plan.
|
|
50
38
|
*/
|
|
51
|
-
|
|
39
|
+
applyPlan(plan: DockerPublishService.Entry[]): Promise<DockerPublishService.Entry[]>;
|
|
40
|
+
}
|
|
41
|
+
export declare namespace DockerPublishService {
|
|
42
|
+
/** Injectable "does this tag already exist" check - mainly for tests, so they don't depend on
|
|
43
|
+
* network access or a real Docker daemon. Same shape as `PublishService.Deps.npmViewVersion`. */
|
|
44
|
+
interface Deps {
|
|
45
|
+
imageExists?: (image: string, tag: string) => Promise<boolean>;
|
|
46
|
+
}
|
|
47
|
+
interface Options extends PackageFilterOptions {
|
|
48
|
+
/** A package with uncommitted local changes is excluded (status `'skip'`) instead of aborting
|
|
49
|
+
* the whole plan (status `'error'`) - same as `version`/`publish --target npm`'s own option. */
|
|
50
|
+
ignoreDirty?: boolean;
|
|
51
|
+
/** Prefixed onto a bare (no `/`) `publish.docker.image` - falls back to the
|
|
52
|
+
* `DOCKERHUB_NAMESPACE` environment variable. */
|
|
53
|
+
namespace?: string;
|
|
54
|
+
}
|
|
55
|
+
type ApplyOptions = Options;
|
|
56
|
+
/**
|
|
57
|
+
* One package's outcome in a docker-publish plan - see `getPlan`.
|
|
58
|
+
*
|
|
59
|
+
* A `PublishTarget.Entry` with one field of its own, which is the shape that interface expects: a
|
|
60
|
+
* target knows things about its own registry that no other target has a word for, and `detail` is
|
|
61
|
+
* where it puts whatever the command should print beside the package.
|
|
62
|
+
*/
|
|
63
|
+
interface Entry extends PublishTarget.Entry {
|
|
64
|
+
/** The fully-qualified `<namespace>/<image>` this entry publishes to - unset only when the
|
|
65
|
+
* package's own `publish.docker.image` config is missing entirely (an `'error'` entry). */
|
|
66
|
+
image?: string;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
declare module '../../../core/classes/service.js' {
|
|
70
|
+
interface ServiceMap {
|
|
71
|
+
dockerPublish: DockerPublishService;
|
|
72
|
+
}
|
|
52
73
|
}
|
|
@@ -2,11 +2,24 @@ import { execFile } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
import { Service } from '../../../core/classes/service.js';
|
|
6
|
+
import { targetsOf } from '../../../core/interfaces/publish-target.js';
|
|
7
|
+
import { exec } from '../../../utils/exec.js';
|
|
8
|
+
import { GitHelper } from '../../../utils/git.js';
|
|
9
|
+
import { filterPackages } from '../../../utils/package-filter.js';
|
|
10
|
+
/**
|
|
11
|
+
* The name this target answers to in `publish.target` and `--target`.
|
|
12
|
+
*
|
|
13
|
+
* Declared beside the implementation rather than in `publish-target.ts`: the seam is general and
|
|
14
|
+
* must not know any one target's name, and the adapter in `builtins/publish-targets/docker/docker.target.ts` reads it from
|
|
15
|
+
* here, which keeps the dependency pointing one way.
|
|
16
|
+
*/
|
|
17
|
+
export const DOCKER_TARGET = 'docker';
|
|
18
|
+
/**
|
|
19
|
+
* A service class - see `ListService` for the shape and `Service` for the three measured
|
|
20
|
+
* consequences a namespace had. `repository` left the signature because the application carries it.
|
|
21
|
+
*/
|
|
22
|
+
export class DockerPublishService extends Service {
|
|
10
23
|
/**
|
|
11
24
|
* Computes what `publish --target docker` *would* do. Unlike the npm side (opt-out via
|
|
12
25
|
* `"private"`), the docker target is opt-in: only packages whose own (cascaded) `.rmanrc
|
|
@@ -20,9 +33,14 @@ export var DockerPublishService;
|
|
|
20
33
|
* already exists on the registry (via `docker manifest inspect`, queried concurrently) decides
|
|
21
34
|
* the rest: `'up-to-date'` if so, `'publish'` if not.
|
|
22
35
|
*/
|
|
23
|
-
async
|
|
36
|
+
async getPlan(options = {}, deps = {}) {
|
|
37
|
+
const repository = this.repository;
|
|
24
38
|
const git = new GitHelper({ cwd: repository.dirname });
|
|
25
|
-
|
|
39
|
+
/** Which packages are the docker target's is the one question `PublishTarget` answers for every
|
|
40
|
+
* target alike (`publish.target`, or `claims` when a package declares none) - asked through
|
|
41
|
+
* `targetsOf` rather than re-read here, so `publish` and `list --json` cannot disagree about
|
|
42
|
+
* where a package ships. */
|
|
43
|
+
const packages = filterPackages(repository.getPackages({ toposort: true }), options).filter(pkg => targetsOf(this.app, pkg).some(t => t.name === DOCKER_TARGET) && !pkg.config.publish?.skip);
|
|
26
44
|
const dirtyFiles = await git.listDirtyFiles({ absolute: true });
|
|
27
45
|
const isDirty = (pkg) => dirtyFiles.some(f => !path.relative(pkg.dirname, f).startsWith('..'));
|
|
28
46
|
const imageExists = deps.imageExists ?? defaultImageExists;
|
|
@@ -52,6 +70,7 @@ export var DockerPublishService;
|
|
|
52
70
|
package: pkg,
|
|
53
71
|
version: pkg.version,
|
|
54
72
|
image,
|
|
73
|
+
detail: image,
|
|
55
74
|
status: options.ignoreDirty ? 'skip' : 'error',
|
|
56
75
|
reason: 'uncommitted local changes',
|
|
57
76
|
});
|
|
@@ -65,27 +84,33 @@ export var DockerPublishService;
|
|
|
65
84
|
package: pkg,
|
|
66
85
|
version: pkg.version,
|
|
67
86
|
image,
|
|
87
|
+
detail: image,
|
|
68
88
|
status: exists ? 'up-to-date' : 'publish',
|
|
69
89
|
reason: exists ? `registry already has ${image}:${pkg.version}` : 'never published',
|
|
70
90
|
});
|
|
71
91
|
}));
|
|
72
92
|
return packages.map(pkg => entries.get(pkg.name));
|
|
73
93
|
}
|
|
74
|
-
DockerPublishService.getPlan = getPlan;
|
|
75
94
|
/**
|
|
76
95
|
* Publishes every `'publish'` entry in `plan`: one `docker login` and one `docker buildx create`
|
|
77
96
|
* up front (each package's own build reuses them), then per package a single `docker buildx
|
|
78
|
-
* build --push` using that package's `publish.docker` config (
|
|
97
|
+
* build --push` using that package's `publish.docker` config (architectures, named build-contexts,
|
|
79
98
|
* build-args, an optional `cwd` override). A package's `publish.docker.readme` file (default
|
|
80
99
|
* `DOCKER_README.md`), if present, updates the DockerHub repo description afterward. A package's
|
|
81
100
|
* own failure doesn't stop unrelated packages elsewhere in the plan.
|
|
82
101
|
*/
|
|
83
|
-
async
|
|
102
|
+
async applyPlan(plan) {
|
|
103
|
+
const repository = this.repository;
|
|
84
104
|
const toPublish = plan.filter(e => e.status === 'publish');
|
|
85
105
|
if (!toPublish.length)
|
|
86
106
|
return plan;
|
|
87
|
-
await dockerLogin(repository.dirname);
|
|
88
|
-
await exec('docker buildx create --use', {
|
|
107
|
+
await dockerLogin(repository.app, repository.dirname);
|
|
108
|
+
await exec('docker buildx create --use', {
|
|
109
|
+
cwd: repository.dirname,
|
|
110
|
+
app: repository.app,
|
|
111
|
+
stdio: 'inherit',
|
|
112
|
+
throwOnError: false,
|
|
113
|
+
});
|
|
89
114
|
const result = [];
|
|
90
115
|
for (const entry of plan) {
|
|
91
116
|
if (entry.status !== 'publish') {
|
|
@@ -103,12 +128,11 @@ export var DockerPublishService;
|
|
|
103
128
|
}
|
|
104
129
|
return result;
|
|
105
130
|
}
|
|
106
|
-
|
|
107
|
-
})(DockerPublishService || (DockerPublishService = {}));
|
|
131
|
+
}
|
|
108
132
|
const execFileAsync = promisify(execFile);
|
|
109
133
|
/** `docker manifest inspect <image>:<tag>` - `false` for any failure (tag doesn't exist yet, no
|
|
110
|
-
* network, not logged in, ...), same catch-everything shape
|
|
111
|
-
*
|
|
134
|
+
* network, not logged in, ...), the same catch-everything shape every target's registry check has:
|
|
135
|
+
* "is this version out there" must never fail the run for a reason that is not an answer. */
|
|
112
136
|
async function defaultImageExists(image, tag) {
|
|
113
137
|
try {
|
|
114
138
|
await execFileAsync('docker', ['manifest', 'inspect', `${image}:${tag}`]);
|
|
@@ -118,11 +142,6 @@ async function defaultImageExists(image, tag) {
|
|
|
118
142
|
return false;
|
|
119
143
|
}
|
|
120
144
|
}
|
|
121
|
-
function targetsDocker(pkg) {
|
|
122
|
-
const target = pkg.config.publish?.target;
|
|
123
|
-
const targets = Array.isArray(target) ? target : target ? [target] : ['npm'];
|
|
124
|
-
return targets.includes('docker');
|
|
125
|
-
}
|
|
126
145
|
function resolveImageRef(image, namespaceOverride) {
|
|
127
146
|
if (image.includes('/'))
|
|
128
147
|
return image;
|
|
@@ -138,21 +157,25 @@ function expandEnvValue(value) {
|
|
|
138
157
|
const match = /^\$([A-Za-z_][A-Za-z0-9_]*)$/.exec(value);
|
|
139
158
|
return match ? (process.env[match[1]] ?? '') : value;
|
|
140
159
|
}
|
|
141
|
-
async function dockerLogin(cwd) {
|
|
160
|
+
async function dockerLogin(app, cwd) {
|
|
142
161
|
const username = process.env.DOCKERHUB_USERNAME;
|
|
143
162
|
const password = process.env.DOCKERHUB_PASSWORD;
|
|
144
163
|
if (!username || !password) {
|
|
145
164
|
throw new Error('DOCKERHUB_USERNAME/DOCKERHUB_PASSWORD environment variables are required to publish to Docker');
|
|
146
165
|
}
|
|
147
|
-
await exec(`echo "${password}" | docker login --username "${username}" --password-stdin`, {
|
|
166
|
+
await exec(`echo "${password}" | docker login --username "${username}" --password-stdin`, {
|
|
167
|
+
cwd,
|
|
168
|
+
app,
|
|
169
|
+
stdio: 'inherit',
|
|
170
|
+
});
|
|
148
171
|
}
|
|
149
172
|
async function buildAndPush(repository, entry) {
|
|
150
173
|
const pkg = entry.package;
|
|
151
174
|
const docker = pkg.config.publish.docker;
|
|
152
|
-
const
|
|
175
|
+
const architectures = docker.architectures?.length ? docker.architectures : ['linux/amd64'];
|
|
153
176
|
const dockerfile = path.resolve(pkg.dirname, docker.dockerfile || 'Dockerfile');
|
|
154
177
|
const cwd = docker.cwd ? path.resolve(repository.dirname, docker.cwd) : pkg.dirname;
|
|
155
|
-
const args = ['buildx', 'build', '--platform',
|
|
178
|
+
const args = ['buildx', 'build', '--platform', architectures.join(',')];
|
|
156
179
|
for (const [name, dir] of Object.entries(docker.buildContexts ?? {})) {
|
|
157
180
|
args.push('--build-context', `${name}="${path.resolve(pkg.dirname, dir)}"`);
|
|
158
181
|
}
|
|
@@ -160,7 +183,7 @@ async function buildAndPush(repository, entry) {
|
|
|
160
183
|
args.push('--build-arg', `${name}="${expandEnvValue(value)}"`);
|
|
161
184
|
}
|
|
162
185
|
args.push('-f', `"${dockerfile}"`, '-t', `"${entry.image}:${entry.version}"`, '-t', `"${entry.image}:latest"`, '--push', '.');
|
|
163
|
-
await exec(`docker ${args.join(' ')}`, { cwd, stdio: 'inherit' });
|
|
186
|
+
await exec(`docker ${args.join(' ')}`, { cwd, app: repository.app, stdio: 'inherit' });
|
|
164
187
|
}
|
|
165
188
|
async function updateDescription(entry) {
|
|
166
189
|
const pkg = entry.package;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { PublishTarget } from '../../../core/interfaces/publish-target.js';
|
|
2
|
+
import type { ConfigValue, ScopedVars } from '../../../interfaces/rman-config.interface.js';
|
|
3
|
+
/**
|
|
4
|
+
* **`publish.docker.*`** - this target's own config block, declared here rather than centrally.
|
|
5
|
+
*
|
|
6
|
+
* Reaches `RmanConfig` through the `PublishTargetConfigs` slot `publish.command.ts` exports, which
|
|
7
|
+
* is the same slot the `node` built-in declares `publish.npm.*` in. Whoever reads a key declares it: the
|
|
8
|
+
* only thing that reads these is `DockerPublishService`, two files away.
|
|
9
|
+
*
|
|
10
|
+
* Required once `"docker"` is one of a package's `publish.target`s - `publish --target docker`
|
|
11
|
+
* errors clearly on a package that opts in and leaves this out.
|
|
12
|
+
*/
|
|
13
|
+
export interface DockerPublishOptions extends DockerPublishOptionsKeys, ScopedVars {
|
|
14
|
+
}
|
|
15
|
+
/** Every key here is a **value**, so every one is a `ConfigValue` - this target declares no step,
|
|
16
|
+
* which is what makes the whole block uniform (see `VersionExtraKeys` for the interface where it
|
|
17
|
+
* is not). */
|
|
18
|
+
export interface DockerPublishOptionsKeys {
|
|
19
|
+
/** DockerHub image name/repository - bare (e.g. `"my-app"`) to be prefixed with
|
|
20
|
+
* `--docker-namespace`/`DOCKERHUB_NAMESPACE`, or already-namespaced (contains a `/`) to use
|
|
21
|
+
* verbatim. */
|
|
22
|
+
image: ConfigValue<string>;
|
|
23
|
+
/** Relative to the package's own directory. Default `"Dockerfile"`. */
|
|
24
|
+
dockerfile?: ConfigValue<string>;
|
|
25
|
+
/**
|
|
26
|
+
* The architectures to build for - `docker buildx build --platform`. Default `["linux/amd64"]`.
|
|
27
|
+
*/
|
|
28
|
+
architectures?: ConfigValue<string[]>;
|
|
29
|
+
/** Build `cwd` override, relative to the repository root - only needed when the Dockerfile's
|
|
30
|
+
* own `COPY`/`ADD` paths expect something other than the package's own directory (rare). */
|
|
31
|
+
cwd?: ConfigValue<string>;
|
|
32
|
+
/** Named `docker buildx build --build-context <name>=<path>` entries, keyed by name - each
|
|
33
|
+
* path is relative to the package's own directory (or absolute). */
|
|
34
|
+
buildContexts?: ConfigValue<Record<string, string>>;
|
|
35
|
+
/** `docker buildx build --build-arg <name>=<value>` entries - a value of exactly `"$NAME"`
|
|
36
|
+
* expands to `process.env.NAME` at build time (e.g. to pass a CI secret through). */
|
|
37
|
+
buildArgs?: ConfigValue<Record<string, string>>;
|
|
38
|
+
/** A file (relative to the package's own directory) whose contents become the DockerHub repo's
|
|
39
|
+
* full description, if present. Default `"DOCKER_README.md"`. */
|
|
40
|
+
readme?: ConfigValue<string>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* **Docker, as a publish target** - the core's own, and the reason `PublishTarget` is in the core
|
|
44
|
+
* rather than in a plugin.
|
|
45
|
+
*
|
|
46
|
+
* Any language's project can ship an image; nothing about `docker buildx build --push` is npm's, or
|
|
47
|
+
* Cargo's, or Maven's. It was already a core *service*, and could still only be reached through
|
|
48
|
+
* `rman-node`'s `publish` command - so a repository with no JavaScript in it had to install a Node
|
|
49
|
+
* plugin to push a container. This file is the ten lines that fix that.
|
|
50
|
+
*
|
|
51
|
+
* Opt-in, and therefore no `claims`: most packages in a repository are not images, so a package
|
|
52
|
+
* ships here only by naming `"docker"` in its own `publish.target`.
|
|
53
|
+
*/
|
|
54
|
+
export declare const dockerPublishTarget: PublishTarget;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DOCKER_TARGET } from './docker-publish.service.js';
|
|
2
|
+
/**
|
|
3
|
+
* **Docker, as a publish target** - the core's own, and the reason `PublishTarget` is in the core
|
|
4
|
+
* rather than in a plugin.
|
|
5
|
+
*
|
|
6
|
+
* Any language's project can ship an image; nothing about `docker buildx build --push` is npm's, or
|
|
7
|
+
* Cargo's, or Maven's. It was already a core *service*, and could still only be reached through
|
|
8
|
+
* `rman-node`'s `publish` command - so a repository with no JavaScript in it had to install a Node
|
|
9
|
+
* plugin to push a container. This file is the ten lines that fix that.
|
|
10
|
+
*
|
|
11
|
+
* Opt-in, and therefore no `claims`: most packages in a repository are not images, so a package
|
|
12
|
+
* ships here only by naming `"docker"` in its own `publish.target`.
|
|
13
|
+
*/
|
|
14
|
+
export const dockerPublishTarget = {
|
|
15
|
+
name: DOCKER_TARGET,
|
|
16
|
+
describe: 'Build and push a container image (docker buildx build --push)',
|
|
17
|
+
options: {
|
|
18
|
+
dockerNamespace: {
|
|
19
|
+
target: 'cli',
|
|
20
|
+
cliName: 'docker-namespace',
|
|
21
|
+
describe: 'Prefixed onto a bare (no "/") "publish.docker.image" - default: the DOCKERHUB_NAMESPACE ' +
|
|
22
|
+
'environment variable.',
|
|
23
|
+
type: 'string',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
getPlan(ctx) {
|
|
27
|
+
return ctx.app.getService('dockerPublish').getPlan(optionsOf(ctx));
|
|
28
|
+
},
|
|
29
|
+
applyPlan(ctx, plan) {
|
|
30
|
+
/** The entries are this target's own - `getPlan` produced them - so the cast reads back what
|
|
31
|
+
* was put in rather than claiming anything new. The command only ever passes a plan back to
|
|
32
|
+
* the target that made it. */
|
|
33
|
+
return ctx.app.getService('dockerPublish').applyPlan(plan);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/** The shared filters plus the one flag this target declared - read here rather than in the service,
|
|
37
|
+
* so the service keeps taking a plain options object and stays callable without a CLI. */
|
|
38
|
+
function optionsOf(ctx) {
|
|
39
|
+
return { ...ctx.options, namespace: ctx.args.dockerNamespace };
|
|
40
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { PublishTarget } from '../../../core/interfaces/publish-target.js';
|
|
2
|
+
import { PublishService } from '../../platforms/node/services/publish.service.js';
|
|
3
|
+
/** The name this target answers to in `publish.target` and `--target`. */
|
|
4
|
+
export declare const NPM_TARGET = "npm";
|
|
5
|
+
/**
|
|
6
|
+
* **npm, as a publish target** - what is left of the old `rman-node` `publish` command once the command
|
|
7
|
+
* itself went back to the core where it belonged.
|
|
8
|
+
*
|
|
9
|
+
* The split is worth stating, because it is the whole point of the move: everything about
|
|
10
|
+
* *publishing a repository* - which packages are candidates, dependency order, the plan/confirm/
|
|
11
|
+
* apply shape, `--dry-run`, the JSON a CI gate reads - is the core's and always was. What is npm's
|
|
12
|
+
* is this file: seven flags, one registry question, and one push. A Cargo or Maven target is the
|
|
13
|
+
* same size.
|
|
14
|
+
*
|
|
15
|
+
* **`claims` is the other half, and it fixes a real bug.** The core used to default a package with
|
|
16
|
+
* no `publish.target` to `['npm']`, which is a statement only an ecosystem can make - so a Cargo
|
|
17
|
+
* package beside a Node one was reported by `rman list --json` as shipping to npm, and treated by
|
|
18
|
+
* `publish` as an npm candidate. Asking `pkg.provider === 'node'` puts the answer where the
|
|
19
|
+
* knowledge is: this plugin read that manifest, so this plugin is the one that can say so.
|
|
20
|
+
*
|
|
21
|
+
* A class, like `NodePlugin` and `NodeManifestProvider`: a config declares it as
|
|
22
|
+
* `publishTargets: [new NpmPublishTarget()]`, which is one shape for everything a plugin package
|
|
23
|
+
* contributes rather than an object literal here and a class there.
|
|
24
|
+
*/
|
|
25
|
+
export declare class NpmPublishTarget implements PublishTarget {
|
|
26
|
+
name: string;
|
|
27
|
+
describe: string;
|
|
28
|
+
/** npm's alone: a package rman read through the `node` platform. */
|
|
29
|
+
platforms: string[];
|
|
30
|
+
options: {
|
|
31
|
+
packageManager: {
|
|
32
|
+
target: "cli";
|
|
33
|
+
cliName: string;
|
|
34
|
+
describe: string;
|
|
35
|
+
choices: readonly ["npm", "yarn", "pnpm", "bun"];
|
|
36
|
+
};
|
|
37
|
+
access: {
|
|
38
|
+
target: "cli";
|
|
39
|
+
describe: string;
|
|
40
|
+
choices: string[];
|
|
41
|
+
};
|
|
42
|
+
tag: {
|
|
43
|
+
target: "cli";
|
|
44
|
+
describe: string;
|
|
45
|
+
type: "string";
|
|
46
|
+
};
|
|
47
|
+
otp: {
|
|
48
|
+
target: "cli";
|
|
49
|
+
describe: string;
|
|
50
|
+
type: "string";
|
|
51
|
+
};
|
|
52
|
+
registry: {
|
|
53
|
+
target: "cli";
|
|
54
|
+
describe: string;
|
|
55
|
+
type: "string";
|
|
56
|
+
};
|
|
57
|
+
userconfig: {
|
|
58
|
+
target: "cli";
|
|
59
|
+
describe: string;
|
|
60
|
+
type: "string";
|
|
61
|
+
};
|
|
62
|
+
contents: {
|
|
63
|
+
target: "cli";
|
|
64
|
+
describe: string;
|
|
65
|
+
type: "string";
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
getPlan(ctx: PublishTarget.Context): Promise<PublishService.Entry[]>;
|
|
69
|
+
applyPlan(ctx: PublishTarget.Context, plan: PublishTarget.Entry[]): Promise<PublishService.Entry[]>;
|
|
70
|
+
/** The shared filters plus the two flags both halves need - read here rather than in the
|
|
71
|
+
* service, which keeps taking a plain options object and stays callable without a CLI. */
|
|
72
|
+
protected planOptions(ctx: PublishTarget.Context): PublishService.Options;
|
|
73
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { CiService } from '../../platforms/node/services/ci.service.js';
|
|
2
|
+
import { PublishService } from '../../platforms/node/services/publish.service.js';
|
|
3
|
+
/** The name this target answers to in `publish.target` and `--target`. */
|
|
4
|
+
export const NPM_TARGET = 'npm';
|
|
5
|
+
/**
|
|
6
|
+
* **npm, as a publish target** - what is left of the old `rman-node` `publish` command once the command
|
|
7
|
+
* itself went back to the core where it belonged.
|
|
8
|
+
*
|
|
9
|
+
* The split is worth stating, because it is the whole point of the move: everything about
|
|
10
|
+
* *publishing a repository* - which packages are candidates, dependency order, the plan/confirm/
|
|
11
|
+
* apply shape, `--dry-run`, the JSON a CI gate reads - is the core's and always was. What is npm's
|
|
12
|
+
* is this file: seven flags, one registry question, and one push. A Cargo or Maven target is the
|
|
13
|
+
* same size.
|
|
14
|
+
*
|
|
15
|
+
* **`claims` is the other half, and it fixes a real bug.** The core used to default a package with
|
|
16
|
+
* no `publish.target` to `['npm']`, which is a statement only an ecosystem can make - so a Cargo
|
|
17
|
+
* package beside a Node one was reported by `rman list --json` as shipping to npm, and treated by
|
|
18
|
+
* `publish` as an npm candidate. Asking `pkg.provider === 'node'` puts the answer where the
|
|
19
|
+
* knowledge is: this plugin read that manifest, so this plugin is the one that can say so.
|
|
20
|
+
*
|
|
21
|
+
* A class, like `NodePlugin` and `NodeManifestProvider`: a config declares it as
|
|
22
|
+
* `publishTargets: [new NpmPublishTarget()]`, which is one shape for everything a plugin package
|
|
23
|
+
* contributes rather than an object literal here and a class there.
|
|
24
|
+
*/
|
|
25
|
+
export class NpmPublishTarget {
|
|
26
|
+
name = NPM_TARGET;
|
|
27
|
+
describe = 'Publish to an npm registry (npm/yarn/pnpm/bun publish)';
|
|
28
|
+
/** npm's alone: a package rman read through the `node` platform. */
|
|
29
|
+
platforms = ['node'];
|
|
30
|
+
options = {
|
|
31
|
+
packageManager: {
|
|
32
|
+
target: 'cli',
|
|
33
|
+
cliName: 'package-manager',
|
|
34
|
+
describe: 'Package manager to publish with (default: npm, or .rmanrc "packageManager")',
|
|
35
|
+
choices: CiService.PACKAGE_MANAGERS,
|
|
36
|
+
},
|
|
37
|
+
access: {
|
|
38
|
+
target: 'cli',
|
|
39
|
+
describe: 'npm publish --access <public|restricted> - required by the registry for a new scoped package',
|
|
40
|
+
choices: ['public', 'restricted'],
|
|
41
|
+
},
|
|
42
|
+
tag: {
|
|
43
|
+
target: 'cli',
|
|
44
|
+
describe: 'npm publish --tag <tag> - overrides the dist-tag. A prerelease already publishes under its ' +
|
|
45
|
+
'own identifier (2.0.0-beta.1 -> "beta") and a release under "latest", so this is rarely needed',
|
|
46
|
+
type: 'string',
|
|
47
|
+
},
|
|
48
|
+
otp: {
|
|
49
|
+
target: 'cli',
|
|
50
|
+
describe: 'npm publish --otp <otp> - a 2FA one-time password, for registries that require it',
|
|
51
|
+
type: 'string',
|
|
52
|
+
},
|
|
53
|
+
registry: {
|
|
54
|
+
target: 'cli',
|
|
55
|
+
describe: 'Registry to check against and publish to (default: whatever .npmrc already configures)',
|
|
56
|
+
type: 'string',
|
|
57
|
+
},
|
|
58
|
+
userconfig: {
|
|
59
|
+
target: 'cli',
|
|
60
|
+
describe: 'Path to a custom .npmrc to use for both the registry check and the actual publish',
|
|
61
|
+
type: 'string',
|
|
62
|
+
},
|
|
63
|
+
contents: {
|
|
64
|
+
target: 'cli',
|
|
65
|
+
describe: "Subdirectory to publish from, relative to each package's own directory - only consulted when a " +
|
|
66
|
+
'package has no "publishConfig.directory" of its own (that always wins when present)',
|
|
67
|
+
type: 'string',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
getPlan(ctx) {
|
|
71
|
+
return PublishService.getPlan(ctx.repository, this.planOptions(ctx));
|
|
72
|
+
}
|
|
73
|
+
applyPlan(ctx, plan) {
|
|
74
|
+
return PublishService.applyPlan(ctx.repository, plan, {
|
|
75
|
+
...this.planOptions(ctx),
|
|
76
|
+
packageManager: ctx.args.packageManager,
|
|
77
|
+
access: ctx.args.access,
|
|
78
|
+
otp: ctx.args.otp,
|
|
79
|
+
contents: ctx.args.contents,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** The shared filters plus the two flags both halves need - read here rather than in the
|
|
83
|
+
* service, which keeps taking a plain options object and stays callable without a CLI. */
|
|
84
|
+
planOptions(ctx) {
|
|
85
|
+
return {
|
|
86
|
+
...ctx.options,
|
|
87
|
+
registry: ctx.args.registry,
|
|
88
|
+
userconfig: ctx.args.userconfig,
|
|
89
|
+
/** Read at *plan* time too, not only where the publish command is built: the plan is what
|
|
90
|
+
* decides the dist-tag and refuses the two cases with nothing to derive, so `--dry-run` and
|
|
91
|
+
* the JSON a pipeline gates on have to see the flag. */
|
|
92
|
+
tag: ctx.args.tag,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** What the registry knows about one package - the two halves `publish` needs, from one call. */
|
|
2
|
+
export interface NpmPackageView {
|
|
3
|
+
/** The version the **`latest` dist-tag** points at, which is what a bare `npm install <name>`
|
|
4
|
+
* resolves to. Not necessarily the highest: a prerelease published under its own tag, or a
|
|
5
|
+
* patch to an older line, leaves `latest` where it was. */
|
|
6
|
+
latest?: string;
|
|
7
|
+
/** Every version ever published, `latest` included. */
|
|
8
|
+
versions: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `npm view <name> version versions --json` - `undefined` for anything that is not an answer (never
|
|
12
|
+
* published, no network, private or restricted with no access). Catch-everything on purpose: every
|
|
13
|
+
* caller treats "no answer" as a legitimate state rather than a failure.
|
|
14
|
+
*
|
|
15
|
+
* **Two fields in one call, because the two questions are genuinely different and `publish` needs
|
|
16
|
+
* both.** Whether *this* version is already out there decides `up-to-date` vs `publish`, and only
|
|
17
|
+
* `versions` can answer it; what `latest` points at is what the plan *reports*, so a reader can see
|
|
18
|
+
* where the registry stands. Asking `latest` alone was the same approximation in both roles, and it
|
|
19
|
+
* is wrong in both directions: a prerelease on its own dist-tag never moves `latest`, so `publish`
|
|
20
|
+
* kept proposing an already-published version until npm answered 403; and a package whose local
|
|
21
|
+
* version is *behind* `latest` was proposed just as wrongly.
|
|
22
|
+
*
|
|
23
|
+
* **`versions` is normalized to an array defensively, and the reason is what happens if it is
|
|
24
|
+
* not.** `includes` exists on a string too, so a bare `"1.0.0"` would answer `versions.includes()`
|
|
25
|
+
* without any error at all - and answer it by substring, where `"1.0.10".includes("1.0.1")` is
|
|
26
|
+
* `true` (measured). npm's own `--json` output *is* a real array here on this npm (measured: a
|
|
27
|
+
* single-entry `maintainers` comes back as `[...]`, not unwrapped), so this guards a shape
|
|
28
|
+
* difference across npm versions rather than one I reproduced - but a silent wrong answer about
|
|
29
|
+
* whether a version is published is worth two lines.
|
|
30
|
+
*/
|
|
31
|
+
export declare function npmViewPackage(name: string, cwd: string, options?: {
|
|
32
|
+
registry?: string;
|
|
33
|
+
userconfig?: string;
|
|
34
|
+
}): Promise<NpmPackageView | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* `npm view <name> version` - the **`latest` dist-tag's** version, or `undefined` for anything that
|
|
37
|
+
* is not an answer.
|
|
38
|
+
*
|
|
39
|
+
* `packageJsonManifest.publishedVersion` asks this so that `detectChangeHash` can guess a tag name
|
|
40
|
+
* for a package with no release tag at all, and `latest` is the right question for it: it wants the
|
|
41
|
+
* one version the ecosystem considers current, not the set of everything ever published. It passes
|
|
42
|
+
* no options - a bare `npm view` already picks up the repository's own `.npmrc` from `cwd`, which
|
|
43
|
+
* is what that path wants. `publish` asks `npmViewPackage` instead; see there for why.
|
|
44
|
+
*/
|
|
45
|
+
export declare function npmViewVersion(name: string, cwd: string, options?: {
|
|
46
|
+
registry?: string;
|
|
47
|
+
userconfig?: string;
|
|
48
|
+
}): Promise<string | undefined>;
|