@detergent-software/atk 8.9.0-dev.3 → 8.9.0-dev.30
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 +204 -0
- package/README.md +22 -12
- package/build/cli.js +18 -6
- package/build/cli.js.map +1 -1
- package/build/command-manifest.json +1507 -0
- package/build/commands/_app.d.ts.map +1 -1
- package/build/commands/_app.js +8 -4
- package/build/commands/_app.js.map +1 -1
- package/build/commands/audit.d.ts.map +1 -1
- package/build/commands/audit.js +1 -1
- package/build/commands/audit.js.map +1 -1
- package/build/commands/browse.js +2 -2
- package/build/commands/browse.js.map +1 -1
- package/build/commands/cache.d.ts +1 -1
- package/build/commands/cache.d.ts.map +1 -1
- package/build/commands/cache.js +1 -16
- package/build/commands/cache.js.map +1 -1
- package/build/commands/config.d.ts.map +1 -1
- package/build/commands/config.js +1 -1
- package/build/commands/config.js.map +1 -1
- package/build/commands/diff.d.ts.map +1 -1
- package/build/commands/diff.js +4 -0
- package/build/commands/diff.js.map +1 -1
- package/build/commands/drift.d.ts.map +1 -1
- package/build/commands/drift.js +4 -0
- package/build/commands/drift.js.map +1 -1
- package/build/commands/index.d.ts.map +1 -1
- package/build/commands/index.js +5 -40
- package/build/commands/index.js.map +1 -1
- package/build/commands/info.d.ts.map +1 -1
- package/build/commands/info.js +50 -33
- package/build/commands/info.js.map +1 -1
- package/build/commands/init.d.ts.map +1 -1
- package/build/commands/init.js +4 -2
- package/build/commands/init.js.map +1 -1
- package/build/commands/install.d.ts.map +1 -1
- package/build/commands/install.js +28 -7
- package/build/commands/install.js.map +1 -1
- package/build/commands/list.js +2 -2
- package/build/commands/list.js.map +1 -1
- package/build/commands/login.d.ts.map +1 -1
- package/build/commands/login.js +12 -2
- package/build/commands/login.js.map +1 -1
- package/build/commands/logout.d.ts.map +1 -1
- package/build/commands/logout.js +9 -1
- package/build/commands/logout.js.map +1 -1
- package/build/commands/outdated.js +1 -1
- package/build/commands/outdated.js.map +1 -1
- package/build/commands/prune.d.ts.map +1 -1
- package/build/commands/prune.js +4 -2
- package/build/commands/prune.js.map +1 -1
- package/build/commands/publish.d.ts +1 -1
- package/build/commands/publish.d.ts.map +1 -1
- package/build/commands/publish.js +31 -36
- package/build/commands/publish.js.map +1 -1
- package/build/commands/release-notes.d.ts.map +1 -1
- package/build/commands/release-notes.js +4 -0
- package/build/commands/release-notes.js.map +1 -1
- package/build/commands/schema.d.ts +3 -3
- package/build/commands/search.js +1 -1
- package/build/commands/search.js.map +1 -1
- package/build/commands/sync.d.ts +1 -1
- package/build/commands/sync.d.ts.map +1 -1
- package/build/commands/sync.js +27 -12
- package/build/commands/sync.js.map +1 -1
- package/build/commands/update.d.ts.map +1 -1
- package/build/commands/update.js +58 -9
- package/build/commands/update.js.map +1 -1
- package/build/commands/whoami.d.ts.map +1 -1
- package/build/commands/whoami.js +16 -4
- package/build/commands/whoami.js.map +1 -1
- package/build/commands/why.js +3 -4
- package/build/commands/why.js.map +1 -1
- package/build/components/Header.d.ts +2 -3
- package/build/components/Header.d.ts.map +1 -1
- package/build/components/Header.js +2 -9
- package/build/components/Header.js.map +1 -1
- package/build/components/LocalEditsHint.d.ts +16 -0
- package/build/components/LocalEditsHint.d.ts.map +1 -0
- package/build/components/LocalEditsHint.js +18 -0
- package/build/components/LocalEditsHint.js.map +1 -0
- package/build/components/SyncAllInSync.d.ts +5 -1
- package/build/components/SyncAllInSync.d.ts.map +1 -1
- package/build/components/SyncAllInSync.js +2 -2
- package/build/components/SyncAllInSync.js.map +1 -1
- package/build/components/header-art.d.ts +7 -0
- package/build/components/header-art.d.ts.map +1 -0
- package/build/components/header-art.js +14 -0
- package/build/components/header-art.js.map +1 -0
- package/build/components/index.d.ts +1 -0
- package/build/components/index.d.ts.map +1 -1
- package/build/components/index.js +1 -0
- package/build/components/index.js.map +1 -1
- package/build/hooks/useListActions.d.ts.map +1 -1
- package/build/hooks/useListActions.js +4 -0
- package/build/hooks/useListActions.js.map +1 -1
- package/build/hooks/usePruneState.d.ts +1 -7
- package/build/hooks/usePruneState.d.ts.map +1 -1
- package/build/hooks/usePruneState.js +18 -62
- package/build/hooks/usePruneState.js.map +1 -1
- package/build/hooks/usePublishState.d.ts +43 -8
- package/build/hooks/usePublishState.d.ts.map +1 -1
- package/build/hooks/usePublishState.js +82 -565
- package/build/hooks/usePublishState.js.map +1 -1
- package/build/lib/adapter.d.ts +10 -1
- package/build/lib/adapter.d.ts.map +1 -1
- package/build/lib/adapter.js +46 -3
- package/build/lib/adapter.js.map +1 -1
- package/build/lib/api-client.d.ts +9 -5
- package/build/lib/api-client.d.ts.map +1 -1
- package/build/lib/api-client.js +35 -8
- package/build/lib/api-client.js.map +1 -1
- package/build/lib/atk-api/generated/types.gen.d.ts +4 -4
- package/build/lib/auth.d.ts +12 -2
- package/build/lib/auth.d.ts.map +1 -1
- package/build/lib/auth.js +38 -3
- package/build/lib/auth.js.map +1 -1
- package/build/lib/checksum.d.ts +40 -14
- package/build/lib/checksum.d.ts.map +1 -1
- package/build/lib/checksum.js +110 -57
- package/build/lib/checksum.js.map +1 -1
- package/build/lib/config.d.ts +4 -4
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +31 -8
- package/build/lib/config.js.map +1 -1
- package/build/lib/diagnostics.d.ts.map +1 -1
- package/build/lib/diagnostics.js +10 -7
- package/build/lib/diagnostics.js.map +1 -1
- package/build/lib/diff-command.js +1 -1
- package/build/lib/diff-command.js.map +1 -1
- package/build/lib/errors.d.ts +4 -1
- package/build/lib/errors.d.ts.map +1 -1
- package/build/lib/errors.js.map +1 -1
- package/build/lib/format-age.d.ts +3 -0
- package/build/lib/format-age.d.ts.map +1 -0
- package/build/lib/format-age.js +18 -0
- package/build/lib/format-age.js.map +1 -0
- package/build/lib/installer.d.ts +8 -11
- package/build/lib/installer.d.ts.map +1 -1
- package/build/lib/installer.js +83 -28
- package/build/lib/installer.js.map +1 -1
- package/build/lib/local-edits.d.ts +72 -0
- package/build/lib/local-edits.d.ts.map +1 -0
- package/build/lib/local-edits.js +145 -0
- package/build/lib/local-edits.js.map +1 -0
- package/build/lib/lockfile.d.ts +12 -8
- package/build/lib/lockfile.d.ts.map +1 -1
- package/build/lib/lockfile.js +217 -54
- package/build/lib/lockfile.js.map +1 -1
- package/build/lib/mover.d.ts.map +1 -1
- package/build/lib/mover.js +11 -12
- package/build/lib/mover.js.map +1 -1
- package/build/lib/multi-tool-install.d.ts +4 -2
- package/build/lib/multi-tool-install.d.ts.map +1 -1
- package/build/lib/multi-tool-install.js +12 -2
- package/build/lib/multi-tool-install.js.map +1 -1
- package/build/lib/offline.d.ts +19 -0
- package/build/lib/offline.d.ts.map +1 -0
- package/build/lib/offline.js +26 -0
- package/build/lib/offline.js.map +1 -0
- package/build/lib/owned-paths.d.ts +7 -4
- package/build/lib/owned-paths.d.ts.map +1 -1
- package/build/lib/owned-paths.js +23 -8
- package/build/lib/owned-paths.js.map +1 -1
- package/build/lib/parse-json.d.ts +12 -0
- package/build/lib/parse-json.d.ts.map +1 -1
- package/build/lib/parse-json.js +15 -2
- package/build/lib/parse-json.js.map +1 -1
- package/build/lib/pastel/commander-specs.d.ts +7 -0
- package/build/lib/pastel/commander-specs.d.ts.map +1 -0
- package/build/lib/pastel/commander-specs.js +50 -0
- package/build/lib/pastel/commander-specs.js.map +1 -0
- package/build/lib/pastel/generate-arguments.d.ts +3 -3
- package/build/lib/pastel/generate-arguments.d.ts.map +1 -1
- package/build/lib/pastel/generate-arguments.js +25 -22
- package/build/lib/pastel/generate-arguments.js.map +1 -1
- package/build/lib/pastel/generate-command.d.ts +7 -5
- package/build/lib/pastel/generate-command.d.ts.map +1 -1
- package/build/lib/pastel/generate-command.js +32 -67
- package/build/lib/pastel/generate-command.js.map +1 -1
- package/build/lib/pastel/generate-commands.d.ts +3 -5
- package/build/lib/pastel/generate-commands.d.ts.map +1 -1
- package/build/lib/pastel/generate-commands.js +6 -10
- package/build/lib/pastel/generate-commands.js.map +1 -1
- package/build/lib/pastel/generate-options.d.ts +3 -3
- package/build/lib/pastel/generate-options.d.ts.map +1 -1
- package/build/lib/pastel/generate-options.js +16 -13
- package/build/lib/pastel/generate-options.js.map +1 -1
- package/build/lib/pastel/index.d.ts +26 -4
- package/build/lib/pastel/index.d.ts.map +1 -1
- package/build/lib/pastel/index.js +104 -18
- package/build/lib/pastel/index.js.map +1 -1
- package/build/lib/pastel/internal-types.d.ts +39 -8
- package/build/lib/pastel/internal-types.d.ts.map +1 -1
- package/build/lib/pastel/manifest.d.ts +8 -0
- package/build/lib/pastel/manifest.d.ts.map +1 -0
- package/build/lib/pastel/manifest.js +7 -0
- package/build/lib/pastel/manifest.js.map +1 -0
- package/build/lib/pastel/read-commands.d.ts +7 -2
- package/build/lib/pastel/read-commands.d.ts.map +1 -1
- package/build/lib/pastel/read-commands.js +51 -30
- package/build/lib/pastel/read-commands.js.map +1 -1
- package/build/lib/pastel/render-command.d.ts +13 -0
- package/build/lib/pastel/render-command.d.ts.map +1 -0
- package/build/lib/pastel/render-command.js +56 -0
- package/build/lib/pastel/render-command.js.map +1 -0
- package/build/lib/pruner.d.ts +26 -0
- package/build/lib/pruner.d.ts.map +1 -0
- package/build/lib/pruner.js +42 -0
- package/build/lib/pruner.js.map +1 -0
- package/build/lib/publish-flow.d.ts +7 -15
- package/build/lib/publish-flow.d.ts.map +1 -1
- package/build/lib/publish-flow.js +634 -178
- package/build/lib/publish-flow.js.map +1 -1
- package/build/lib/publish-run.d.ts +55 -0
- package/build/lib/publish-run.d.ts.map +1 -0
- package/build/lib/publish-run.js +169 -0
- package/build/lib/publish-run.js.map +1 -0
- package/build/lib/publisher.d.ts +23 -16
- package/build/lib/publisher.d.ts.map +1 -1
- package/build/lib/publisher.js +34 -35
- package/build/lib/publisher.js.map +1 -1
- package/build/lib/registrar.d.ts.map +1 -1
- package/build/lib/registrar.js +2 -2
- package/build/lib/registrar.js.map +1 -1
- package/build/lib/registry.d.ts +18 -7
- package/build/lib/registry.d.ts.map +1 -1
- package/build/lib/registry.js +113 -32
- package/build/lib/registry.js.map +1 -1
- package/build/lib/root-path.d.ts +11 -0
- package/build/lib/root-path.d.ts.map +1 -1
- package/build/lib/root-path.js +15 -1
- package/build/lib/root-path.js.map +1 -1
- package/build/lib/schemas/config.d.ts +3 -1
- package/build/lib/schemas/config.d.ts.map +1 -1
- package/build/lib/schemas/config.js +1 -1
- package/build/lib/schemas/config.js.map +1 -1
- package/build/lib/schemas/lockfile.d.ts +156 -23
- package/build/lib/schemas/lockfile.d.ts.map +1 -1
- package/build/lib/schemas/lockfile.js +100 -79
- package/build/lib/schemas/lockfile.js.map +1 -1
- package/build/lib/setup.d.ts.map +1 -1
- package/build/lib/setup.js +53 -48
- package/build/lib/setup.js.map +1 -1
- package/build/lib/sync.d.ts +22 -6
- package/build/lib/sync.d.ts.map +1 -1
- package/build/lib/sync.js +59 -7
- package/build/lib/sync.js.map +1 -1
- package/build/lib/uninstaller.d.ts.map +1 -1
- package/build/lib/uninstaller.js +8 -5
- package/build/lib/uninstaller.js.map +1 -1
- package/build/lib/update-check.d.ts +4 -0
- package/build/lib/update-check.d.ts.map +1 -1
- package/build/lib/update-check.js +55 -56
- package/build/lib/update-check.js.map +1 -1
- package/build/lib/updater.d.ts +31 -1
- package/build/lib/updater.d.ts.map +1 -1
- package/build/lib/updater.js +143 -4
- package/build/lib/updater.js.map +1 -1
- package/build/lib/usage-error.d.ts +20 -0
- package/build/lib/usage-error.d.ts.map +1 -0
- package/build/lib/usage-error.js +41 -0
- package/build/lib/usage-error.js.map +1 -0
- package/build/lib/user-setup.d.ts.map +1 -1
- package/build/lib/user-setup.js +62 -59
- package/build/lib/user-setup.js.map +1 -1
- package/build/lib/write-file.d.ts +5 -0
- package/build/lib/write-file.d.ts.map +1 -1
- package/build/lib/write-file.js +10 -7
- package/build/lib/write-file.js.map +1 -1
- package/package.json +81 -81
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { writeFile } from 'node:fs/promises';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
|
+
import { compare as semverCompare, valid as semverValid } from 'semver';
|
|
3
4
|
import { loadAllAdapters, resolveInstalledPaths } from './adapter.js';
|
|
4
5
|
import { isApiError } from './api-client.js';
|
|
5
6
|
import { getCredential } from './auth.js';
|
|
6
|
-
import { hashFile } from './checksum.js';
|
|
7
7
|
import { errorGuidance, errorMessage } from './errors.js';
|
|
8
|
-
import { detectCompatibleTools, getSignedInUserName } from './init.js';
|
|
9
|
-
import {
|
|
8
|
+
import { detectCompatibleTools, getEntrypointName, getSignedInUserName } from './init.js';
|
|
9
|
+
import { findInstalledAsset, readLockfile } from './lockfile.js';
|
|
10
10
|
import { diffManifests, fetchExistingManifest } from './manifest-diff.js';
|
|
11
11
|
import { parseOrgFromName } from './org.js';
|
|
12
12
|
import { findProjectRoot } from './paths.js';
|
|
13
|
-
import { buildPublishPlan, buildStagingArea, checkRegistryVersion, detectAssetFromPath, detectPublishType, executePublish, findSiblingDependencies, loadPublishBatch, loadPublishEntries, mapPublishError, missingDependencies, resolvePlanDependencies, unknownToolsError, updateManifestField, updateManifestVersion, validatePublishTarget, } from './publisher.js';
|
|
14
|
-
import { clearCache,
|
|
13
|
+
import { buildPublishPlan, buildStagingArea, bumpVersion, checkRegistryVersion, detectAssetFromPath, detectPublishType, executePublish, filledManifestFields, findSiblingDependencies, isOrgScopedTarget, loadPublishBatch, loadPublishEntries, mapPublishError, missingDependencies, readManifestFile, resolvePlanDependencies, unknownToolsError, updateManifestField, updateManifestVersion, validatePublishTarget, } from './publisher.js';
|
|
14
|
+
import { clearCache, fetchAssetFileBytes, fetchAssetReadme, fetchRegistry, findAsset } from './registry.js';
|
|
15
15
|
import { parseReviewersInput, validateGithubUsername } from './reviewers.js';
|
|
16
16
|
import { stageInstalledFiles } from './staging.js';
|
|
17
17
|
import { resolveTools } from './tool-resolver.js';
|
|
@@ -63,7 +63,6 @@ export function createInitialState(flags) {
|
|
|
63
63
|
target: undefined,
|
|
64
64
|
token: undefined,
|
|
65
65
|
toolAdapters: [],
|
|
66
|
-
toolCursorIndex: 0,
|
|
67
66
|
toolsDetected: [],
|
|
68
67
|
validation: undefined,
|
|
69
68
|
versionCheck: undefined,
|
|
@@ -163,6 +162,64 @@ async function firstFailure(edits) {
|
|
|
163
162
|
}
|
|
164
163
|
return undefined;
|
|
165
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* The metadata step of a raw publish, for a raw folder or an installed asset, whose `source`
|
|
167
|
+
* gives its org and any description of its own: the signed-in author, the description from
|
|
168
|
+
* --description or the source, the tags from --tags, and the tools from --tools or detection.
|
|
169
|
+
* An interactive run goes on to ask for what is missing; a non-interactive one stages the
|
|
170
|
+
* manifest now, or fails without a description or tools.
|
|
171
|
+
*/
|
|
172
|
+
async function gatherRawMetadata(state, ctx, detection, source) {
|
|
173
|
+
const [signedIn, tools] = await Promise.all([
|
|
174
|
+
getSignedInUserName(),
|
|
175
|
+
state.flags.toolsFlag ? splitList(state.flags.toolsFlag) : detectCompatibleTools(detection.assetType),
|
|
176
|
+
]);
|
|
177
|
+
if (ctx.cancelled())
|
|
178
|
+
return;
|
|
179
|
+
const author = signedIn ?? '';
|
|
180
|
+
const description = state.flags.descriptionFlag?.trim() || source.description;
|
|
181
|
+
if (!state.nonInteractive) {
|
|
182
|
+
ctx.dispatch({
|
|
183
|
+
authorValue: author,
|
|
184
|
+
...(description ? { description } : {}),
|
|
185
|
+
orgValue: source.org ?? '',
|
|
186
|
+
rawDetection: detection,
|
|
187
|
+
toolsDetected: tools,
|
|
188
|
+
type: 'RAW_DETECT_DONE',
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (!description) {
|
|
193
|
+
ctx.dispatch({
|
|
194
|
+
message: state.flags.fromInstalled
|
|
195
|
+
? `description required: provide --description (the lockfile has none for '${detection.name}')`
|
|
196
|
+
: 'description required: provide --description or include in manifest.json',
|
|
197
|
+
type: 'ERROR',
|
|
198
|
+
});
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (tools.length === 0) {
|
|
202
|
+
ctx.dispatch({
|
|
203
|
+
message: `--tools <comma-separated> required: no tools detected for type ${detection.assetType}`,
|
|
204
|
+
type: 'ERROR',
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const stagingDir = await buildStagingArea(detection, {
|
|
209
|
+
author,
|
|
210
|
+
description,
|
|
211
|
+
...(source.org ? { org: source.org } : {}),
|
|
212
|
+
tags: splitList(state.flags.tagsFlag),
|
|
213
|
+
tools,
|
|
214
|
+
});
|
|
215
|
+
ctx.stage(stagingDir);
|
|
216
|
+
if (ctx.cancelled())
|
|
217
|
+
return;
|
|
218
|
+
const detected = await detectPublishType(stagingDir);
|
|
219
|
+
if (ctx.cancelled())
|
|
220
|
+
return;
|
|
221
|
+
ctx.dispatch({ rawDetection: detection, target: detected, type: 'RAW_DETECT_DONE_NON_INTERACTIVE' });
|
|
222
|
+
}
|
|
166
223
|
function stepFor(state) {
|
|
167
224
|
switch (state.phase) {
|
|
168
225
|
case 'building-plan':
|
|
@@ -175,8 +232,6 @@ function stepFor(state) {
|
|
|
175
232
|
return detecting;
|
|
176
233
|
case 'gathering-metadata':
|
|
177
234
|
return state.metadataSubPhase === 'building-staging' ? buildingStaging : undefined;
|
|
178
|
-
case 'installing':
|
|
179
|
-
return installing;
|
|
180
235
|
case 'loading-tools':
|
|
181
236
|
return loadingTools;
|
|
182
237
|
case 'publishing':
|
|
@@ -229,10 +284,10 @@ function toErrorAction(err, override) {
|
|
|
229
284
|
}
|
|
230
285
|
/**
|
|
231
286
|
* Write what the run changed in memory to the manifests on disk: the root's bump and each
|
|
232
|
-
* entry's, and the tags and tools the
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* other files are still written.
|
|
287
|
+
* entry's, and the tags and tools the publish sent on top of the root's manifest (from flags,
|
|
288
|
+
* prompts or detection). Only once the publish has opened its PR, so a cancelled or failed one
|
|
289
|
+
* leaves every manifest as it was. A file whose write fails takes none of its later edits and
|
|
290
|
+
* comes back as one warning naming the fields it lacks; the other files are still written.
|
|
236
291
|
*/
|
|
237
292
|
async function writeManifestEdits(state) {
|
|
238
293
|
const target = state.target;
|
|
@@ -244,19 +299,14 @@ async function writeManifestEdits(state) {
|
|
|
244
299
|
files.set(path, [...(files.get(path) ?? []), { field, value, write }]);
|
|
245
300
|
};
|
|
246
301
|
const version = (dir, file, value) => edit(dir, file, 'version', value, () => updateManifestVersion(dir, file, value));
|
|
247
|
-
const
|
|
302
|
+
const manifestFile = target.type === 'asset' ? 'manifest.json' : 'bundle.json';
|
|
248
303
|
if (state.versionCheck?.status === 'needs-bump' && state.resolvedVersion) {
|
|
249
|
-
version(target.sourceDir,
|
|
304
|
+
version(target.sourceDir, manifestFile, state.resolvedVersion);
|
|
250
305
|
}
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
field('tags', tags);
|
|
256
|
-
}
|
|
257
|
-
if (state.selectedPromptTools.length > 0) {
|
|
258
|
-
field('tools', tools);
|
|
259
|
-
}
|
|
306
|
+
// A manifest that can't be read now takes no field edits; its version edit, if any, warns.
|
|
307
|
+
const written = await readManifestFile(target).catch(() => undefined);
|
|
308
|
+
for (const [name, value] of Object.entries(written ? filledManifestFields(written, target) : {})) {
|
|
309
|
+
edit(target.sourceDir, manifestFile, name, value, () => updateManifestField(target.sourceDir, manifestFile, name, value));
|
|
260
310
|
}
|
|
261
311
|
for (const entry of state.entries) {
|
|
262
312
|
if (entry.versionCheck?.status === 'needs-bump' && entry.resolvedVersion) {
|
|
@@ -269,7 +319,7 @@ async function writeManifestEdits(state) {
|
|
|
269
319
|
if (!failed)
|
|
270
320
|
continue;
|
|
271
321
|
const missing = edits.slice(failed.index);
|
|
272
|
-
// Only the version matters to the next publish: it
|
|
322
|
+
// Only the version matters to the next publish: it fills missing tags and tools again.
|
|
273
323
|
const again = missing.some((e) => e.field === 'version') ? ' before you publish it again' : '';
|
|
274
324
|
unwritten.push(`The PR is open, but ${path} wasn't updated (${errorMessage(failed.error)}): set ${missing.map((e) => `"${e.field}" to ${JSON.stringify(e.value)}`).join(', ')}${again}.`);
|
|
275
325
|
}
|
|
@@ -278,29 +328,45 @@ async function writeManifestEdits(state) {
|
|
|
278
328
|
// ---------------------------------------------------------------------------
|
|
279
329
|
// Steps, one per phase that waits on work
|
|
280
330
|
// ---------------------------------------------------------------------------
|
|
331
|
+
/**
|
|
332
|
+
* The installed asset's files, at their source paths, through a raw publish's metadata step,
|
|
333
|
+
* with the version, entrypoint, dependencies, org and description its lockfile entry records.
|
|
334
|
+
*/
|
|
281
335
|
const resolvingInstalled = {
|
|
282
336
|
async run(state, ctx) {
|
|
283
337
|
const source = await findInstalledSource(state, ctx);
|
|
284
338
|
if (!source)
|
|
285
339
|
return;
|
|
286
340
|
const { adapter, installed, projectRoot } = source;
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
341
|
+
const { files } = resolveInstalledPaths(installed, adapter, projectRoot);
|
|
342
|
+
// An older lockfile entry has no entrypoint: the type's usual one when it was installed, else its first file.
|
|
343
|
+
const usual = getEntrypointName(installed.type, installed.name);
|
|
344
|
+
const entrypoint = installed.entrypoint ?? (files.some((file) => file.sourcePath === usual) ? usual : files[0]?.sourcePath);
|
|
345
|
+
const dependencies = (installed.dependencies ?? []).map(({ name, type, version }) => ({
|
|
346
|
+
name,
|
|
347
|
+
type,
|
|
348
|
+
...(version ? { version } : {}),
|
|
349
|
+
}));
|
|
350
|
+
const detection = {
|
|
351
|
+
assetType: installed.type,
|
|
352
|
+
...(dependencies.length > 0 ? { dependencies } : {}),
|
|
353
|
+
...(entrypoint ? { entrypoint } : {}),
|
|
354
|
+
files: files.map((file) => ({
|
|
355
|
+
absolutePath: join(projectRoot, file.installedPath),
|
|
356
|
+
relativePath: file.sourcePath,
|
|
357
|
+
})),
|
|
297
358
|
name: installed.name,
|
|
298
|
-
|
|
299
|
-
type: installed.type,
|
|
359
|
+
sourceDir: projectRoot,
|
|
300
360
|
version: installed.version,
|
|
301
361
|
};
|
|
302
|
-
|
|
303
|
-
|
|
362
|
+
// A --with folder that is missing, a bundle or a repeat fails here, before any prompt, as in detecting.
|
|
363
|
+
if (state.flags.withPaths?.length) {
|
|
364
|
+
const entries = await loadPublishEntries(state.flags.withPaths, projectRoot);
|
|
365
|
+
if (ctx.cancelled())
|
|
366
|
+
return;
|
|
367
|
+
ctx.dispatch({ entries, type: 'ENTRIES_LOADED' });
|
|
368
|
+
}
|
|
369
|
+
await gatherRawMetadata(state, ctx, detection, { description: installed.description, org: installed.org });
|
|
304
370
|
},
|
|
305
371
|
};
|
|
306
372
|
const resolvingUpdate = {
|
|
@@ -310,21 +376,35 @@ const resolvingUpdate = {
|
|
|
310
376
|
return;
|
|
311
377
|
const { adapter, installed, org, projectRoot } = source;
|
|
312
378
|
const assetName = state.flags.rawPath;
|
|
313
|
-
// Fetch the registry to find the latest version
|
|
379
|
+
// Fetch the registry to find the latest version. An installed entry is always an asset.
|
|
314
380
|
const registry = await fetchRegistry({ force: state.flags.refresh });
|
|
315
381
|
if (ctx.cancelled())
|
|
316
382
|
return;
|
|
317
|
-
// Look up the asset in the registry: try findAsset first, then findBundle
|
|
318
383
|
const resolvedAsset = findAsset(registry, installed.name, installed.type, undefined, installed.org ?? org);
|
|
319
|
-
|
|
320
|
-
if (!resolvedAsset && !resolvedBundle) {
|
|
384
|
+
if (!resolvedAsset) {
|
|
321
385
|
ctx.dispatch({ message: `Asset '${assetName}' not found in the registry.`, type: 'ERROR' });
|
|
322
386
|
return;
|
|
323
387
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
388
|
+
// The installed files go out on top of the latest's manifest, so they must not be older
|
|
389
|
+
// than it: they would publish the next version without the changes made since.
|
|
390
|
+
const latestVersion = resolvedAsset.version;
|
|
391
|
+
if (!semverValid(installed.version) || semverCompare(installed.version, latestVersion) < 0) {
|
|
392
|
+
ctx.dispatch({
|
|
393
|
+
command: `atk diff ${assetName}`,
|
|
394
|
+
hint: `See what changed since v${installed.version} with \`atk diff ${assetName}\`, get the latest into a folder with \`atk checkout ${assetName}\`, carry your edits into it, and publish that folder.`,
|
|
395
|
+
message: `'${assetName}' is installed at v${installed.version}, but the registry's latest is v${latestVersion}. --update would publish your copy, built on v${installed.version}, as the next version and undo the changes made since.`,
|
|
396
|
+
type: 'ERROR',
|
|
397
|
+
});
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
// The latest's manifest as the registry has it, byte for byte, so a field this CLI's schema
|
|
401
|
+
// doesn't know (from a newer publisher) is published again; and its README, if any.
|
|
402
|
+
const { org: assetOrg, type } = resolvedAsset.asset;
|
|
403
|
+
const ref = { name: installed.name, ...(assetOrg ? { org: assetOrg } : {}), type };
|
|
404
|
+
const [manifest, readme] = await Promise.all([
|
|
405
|
+
fetchAssetFileBytes(ref, latestVersion, 'manifest.json'),
|
|
406
|
+
fetchAssetReadme(ref, latestVersion),
|
|
407
|
+
]);
|
|
328
408
|
if (ctx.cancelled())
|
|
329
409
|
return;
|
|
330
410
|
// Copy the user's locally modified files into a temp staging directory
|
|
@@ -332,13 +412,9 @@ const resolvingUpdate = {
|
|
|
332
412
|
ctx.stage(tempDir);
|
|
333
413
|
if (ctx.cancelled())
|
|
334
414
|
return;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
await writeFile(join(tempDir, fetched.manifestFileName), fetched.manifestContent, 'utf-8');
|
|
339
|
-
// Write README if present
|
|
340
|
-
if (fetched.readmeContent) {
|
|
341
|
-
await writeFile(join(tempDir, 'README.md'), fetched.readmeContent, 'utf-8');
|
|
415
|
+
await writeFile(join(tempDir, 'manifest.json'), manifest);
|
|
416
|
+
if (readme) {
|
|
417
|
+
await writeFile(join(tempDir, 'README.md'), readme, 'utf-8');
|
|
342
418
|
}
|
|
343
419
|
ctx.dispatch({ resolvedPath: tempDir, type: 'RESOLVED_UPDATE' });
|
|
344
420
|
},
|
|
@@ -389,66 +465,11 @@ const detecting = {
|
|
|
389
465
|
const detection = await detectAssetFromPath(state.resolvedPath, adapter, projectRoot);
|
|
390
466
|
if (ctx.cancelled())
|
|
391
467
|
return;
|
|
392
|
-
//
|
|
393
|
-
const author = (await getSignedInUserName()) ?? '';
|
|
394
|
-
if (ctx.cancelled())
|
|
395
|
-
return;
|
|
468
|
+
// No manifest exists yet, so the project's org and the flags and prompts give the metadata.
|
|
396
469
|
const lockfile = await readLockfile(projectRoot);
|
|
397
470
|
if (ctx.cancelled())
|
|
398
471
|
return;
|
|
399
|
-
|
|
400
|
-
if (ctx.cancelled())
|
|
401
|
-
return;
|
|
402
|
-
// Non-interactive mode (raw publish — no manifest exists yet, so the only
|
|
403
|
-
// sources for description are --description flag or exit-1; tags come from
|
|
404
|
-
// --tags or default to empty). Tool detection runs for both modes above.
|
|
405
|
-
if (!state.nonInteractive) {
|
|
406
|
-
// Interactive mode — gather metadata from the user
|
|
407
|
-
ctx.dispatch({
|
|
408
|
-
authorValue: author,
|
|
409
|
-
orgValue: lockfile.org ?? '',
|
|
410
|
-
rawDetection: detection,
|
|
411
|
-
toolsDetected: tools,
|
|
412
|
-
type: 'RAW_DETECT_DONE',
|
|
413
|
-
});
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
if (!state.flags.descriptionFlag) {
|
|
417
|
-
ctx.dispatch({
|
|
418
|
-
message: 'description required: provide --description or include in manifest.json',
|
|
419
|
-
type: 'ERROR',
|
|
420
|
-
});
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
// Tools resolution: --tools flag -> detected (already populated above)
|
|
424
|
-
let toolsList;
|
|
425
|
-
if (state.flags.toolsFlag) {
|
|
426
|
-
toolsList = splitList(state.flags.toolsFlag);
|
|
427
|
-
}
|
|
428
|
-
else if (tools.length > 0) {
|
|
429
|
-
toolsList = tools;
|
|
430
|
-
}
|
|
431
|
-
else {
|
|
432
|
-
ctx.dispatch({
|
|
433
|
-
message: `--tools <comma-separated> required: no tools detected for type ${detection.assetType}`,
|
|
434
|
-
type: 'ERROR',
|
|
435
|
-
});
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
const stagingDir = await buildStagingArea(detection, {
|
|
439
|
-
author,
|
|
440
|
-
description: state.flags.descriptionFlag,
|
|
441
|
-
...(lockfile.org ? { org: lockfile.org } : {}),
|
|
442
|
-
tags: splitList(state.flags.tagsFlag),
|
|
443
|
-
tools: toolsList,
|
|
444
|
-
});
|
|
445
|
-
ctx.stage(stagingDir);
|
|
446
|
-
if (ctx.cancelled())
|
|
447
|
-
return;
|
|
448
|
-
const detected = await detectPublishType(stagingDir);
|
|
449
|
-
if (ctx.cancelled())
|
|
450
|
-
return;
|
|
451
|
-
ctx.dispatch({ rawDetection: detection, target: detected, type: 'RAW_DETECT_DONE_NON_INTERACTIVE' });
|
|
472
|
+
await gatherRawMetadata(state, ctx, detection, { org: lockfile.org });
|
|
452
473
|
},
|
|
453
474
|
};
|
|
454
475
|
/** The `building-staging` sub-phase of `gathering-metadata`: the manifest from the prompts' answers. */
|
|
@@ -529,14 +550,13 @@ const validating = {
|
|
|
529
550
|
},
|
|
530
551
|
};
|
|
531
552
|
/**
|
|
532
|
-
* In interactive mode, loads adapters for the multi-select prompt.
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
* checking-registry.
|
|
553
|
+
* In interactive mode without --tools, loads adapters for the multi-select prompt. Otherwise
|
|
554
|
+
* resolves tools via manifest -> --tools flag -> detectCompatibleTools(assetType) -> exit 1,
|
|
555
|
+
* then dispatches RESOLVE_TOOLS_NONINTERACTIVE to advance past the prompt.
|
|
536
556
|
*/
|
|
537
557
|
const loadingTools = {
|
|
538
558
|
async run(state, ctx) {
|
|
539
|
-
if (!state.nonInteractive) {
|
|
559
|
+
if (!state.nonInteractive && !state.flags.toolsFlag) {
|
|
540
560
|
const adapters = await loadAllAdapters();
|
|
541
561
|
if (ctx.cancelled())
|
|
542
562
|
return;
|
|
@@ -690,8 +710,8 @@ const buildingPlan = {
|
|
|
690
710
|
const localPlan = await buildPublishPlan(currentTarget, currentVersion, state.isUpdate, state.flags.message, reviewers, entries, ...(isBatch(state.flags) ? [state.flags.rawPath] : []));
|
|
691
711
|
if (ctx.cancelled())
|
|
692
712
|
return;
|
|
693
|
-
//
|
|
694
|
-
//
|
|
713
|
+
// Ask the API for its plan now, so the preview and --dry-run show its dependencies
|
|
714
|
+
// and reviewers, and anything it rejects stops before the confirm prompt.
|
|
695
715
|
const publishPlan = await resolvePlanDependencies(localPlan);
|
|
696
716
|
if (ctx.cancelled())
|
|
697
717
|
return;
|
|
@@ -728,75 +748,511 @@ const publishing = {
|
|
|
728
748
|
catch {
|
|
729
749
|
// Best-effort — don't fail publish over cache
|
|
730
750
|
}
|
|
731
|
-
//
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
751
|
+
// The lockfile is left as it was, even for an installed asset or a raw folder: the registry
|
|
752
|
+
// has the new version only once the PR merges, and a fresh clone installs the version the
|
|
753
|
+
// lockfile names (ATK-592). `atk update` (or `atk install`) records it after the merge.
|
|
754
|
+
if (ctx.cancelled())
|
|
755
|
+
return;
|
|
756
|
+
ctx.dispatch({ result, type: 'PUBLISH_DONE' });
|
|
757
|
+
},
|
|
758
|
+
};
|
|
759
|
+
// ---------------------------------------------------------------------------
|
|
760
|
+
// Reducer
|
|
761
|
+
// ---------------------------------------------------------------------------
|
|
762
|
+
export function publishReducer(state, action) {
|
|
763
|
+
switch (action.type) {
|
|
764
|
+
case 'BUMP_DONE': {
|
|
765
|
+
const bumped = {
|
|
766
|
+
...state,
|
|
767
|
+
errorMessage: action.message ? action.message : state.errorMessage,
|
|
768
|
+
resolvedVersion: action.version,
|
|
769
|
+
target: action.updatedTarget,
|
|
770
|
+
};
|
|
771
|
+
return action.message ? { ...bumped, phase: 'error' } : advanceToPlan(bumped);
|
|
772
|
+
}
|
|
773
|
+
case 'CONFIRM_PROMPT_TOOLS': {
|
|
774
|
+
if (action.tools.length === 0)
|
|
775
|
+
return state;
|
|
776
|
+
const updatedToolsTarget = state.target
|
|
777
|
+
? {
|
|
778
|
+
...state.target,
|
|
779
|
+
data: { ...state.target.data, tools: action.tools },
|
|
780
|
+
}
|
|
781
|
+
: undefined;
|
|
782
|
+
return {
|
|
783
|
+
...state,
|
|
784
|
+
phase: phaseAfterMetadata(updatedToolsTarget),
|
|
785
|
+
selectedPromptTools: action.tools,
|
|
786
|
+
target: updatedToolsTarget,
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
case 'DETECT_DONE':
|
|
790
|
+
if (action.target.type === 'bundle' && state.entries.length > 0) {
|
|
791
|
+
return {
|
|
792
|
+
...state,
|
|
793
|
+
errorMessage: 'A bundle is published on its own. Remove --with, and publish its new assets first.',
|
|
794
|
+
phase: 'error',
|
|
795
|
+
target: action.target,
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
return {
|
|
799
|
+
...state,
|
|
800
|
+
phase: 'validating',
|
|
801
|
+
target: action.target,
|
|
802
|
+
};
|
|
803
|
+
case 'ENTRIES_CHECKED':
|
|
804
|
+
return advanceToPlan({ ...state, entries: action.entries });
|
|
805
|
+
case 'ENTRIES_LOADED':
|
|
806
|
+
return { ...state, entries: action.entries };
|
|
807
|
+
case 'ERROR':
|
|
808
|
+
return {
|
|
809
|
+
...state,
|
|
810
|
+
errorCode: action.code,
|
|
811
|
+
errorCommand: action.command,
|
|
812
|
+
errorHint: action.hint,
|
|
813
|
+
errorMessage: action.message,
|
|
814
|
+
phase: 'error',
|
|
815
|
+
};
|
|
816
|
+
case 'PLAN_DONE': {
|
|
817
|
+
// dry-run always shows the dry-run result; --yes / non-TTY skip the confirm prompt
|
|
818
|
+
// and proceed directly to publishing.
|
|
819
|
+
let nextPhase;
|
|
820
|
+
if (state.flags.dryRun) {
|
|
821
|
+
nextPhase = 'dry-run-result';
|
|
822
|
+
}
|
|
823
|
+
else if (state.nonInteractive) {
|
|
824
|
+
nextPhase = 'publishing';
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
nextPhase = 'confirm-publish';
|
|
828
|
+
}
|
|
829
|
+
return {
|
|
830
|
+
...state,
|
|
831
|
+
manifestDiff: action.manifestDiff,
|
|
832
|
+
phase: nextPhase,
|
|
833
|
+
plan: action.plan,
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
case 'PUBLISH_DONE':
|
|
837
|
+
return { ...state, phase: 'done', publishResult: action.result };
|
|
838
|
+
case 'PUBLISH_PROGRESS':
|
|
839
|
+
return { ...state, progressMessage: action.message };
|
|
840
|
+
case 'RAW_DETECT_DONE':
|
|
841
|
+
// Ask only for what neither a flag nor the installed asset gave.
|
|
842
|
+
return {
|
|
843
|
+
...state,
|
|
844
|
+
authorValue: action.authorValue,
|
|
845
|
+
descriptionValue: action.description ?? '',
|
|
846
|
+
isRawPublish: !state.flags.fromInstalled,
|
|
847
|
+
metadataSubPhase: action.description === undefined ? 'description' : metadataAfterDescription(state),
|
|
848
|
+
orgValue: action.orgValue,
|
|
849
|
+
phase: 'gathering-metadata',
|
|
850
|
+
rawDetection: action.rawDetection,
|
|
851
|
+
tagsValue: state.flags.tagsFlag ?? '',
|
|
852
|
+
toolsDetected: action.toolsDetected,
|
|
853
|
+
};
|
|
854
|
+
case 'RAW_DETECT_DONE_NON_INTERACTIVE':
|
|
855
|
+
return {
|
|
856
|
+
...state,
|
|
857
|
+
isRawPublish: !state.flags.fromInstalled,
|
|
858
|
+
phase: 'validating',
|
|
859
|
+
rawDetection: action.rawDetection,
|
|
860
|
+
target: action.target,
|
|
861
|
+
};
|
|
862
|
+
case 'REGISTRY_CHECK_DONE': {
|
|
863
|
+
const { isUpdate, resolvedVersion, token, versionCheck } = action;
|
|
864
|
+
let nextPhase;
|
|
865
|
+
let errorMessage = state.errorMessage;
|
|
866
|
+
let bumpedVersion = resolvedVersion;
|
|
867
|
+
let bumpedTarget = state.target;
|
|
868
|
+
if (versionCheck.status === 'new-asset') {
|
|
869
|
+
nextPhase = 'building-plan';
|
|
870
|
+
}
|
|
871
|
+
else if (versionCheck.status === 'version-already-bumped') {
|
|
872
|
+
// --yes / non-TTY implicitly confirm the update
|
|
873
|
+
nextPhase = state.nonInteractive ? 'building-plan' : 'confirm-update';
|
|
874
|
+
}
|
|
875
|
+
else {
|
|
876
|
+
// needs-bump
|
|
877
|
+
if (state.flags.bump && state.target) {
|
|
878
|
+
// --bump applies in any run; a successful publish writes it to the manifest
|
|
879
|
+
try {
|
|
880
|
+
bumpedVersion = bumpVersion(versionCheck.latestVersion, state.flags.bump);
|
|
881
|
+
bumpedTarget = {
|
|
882
|
+
...state.target,
|
|
883
|
+
data: { ...state.target.data, version: bumpedVersion },
|
|
884
|
+
};
|
|
885
|
+
nextPhase = 'building-plan';
|
|
886
|
+
}
|
|
887
|
+
catch {
|
|
888
|
+
errorMessage = 'Failed to compute bumped version.';
|
|
889
|
+
nextPhase = 'error';
|
|
753
890
|
}
|
|
891
|
+
}
|
|
892
|
+
else if (!state.nonInteractive) {
|
|
893
|
+
nextPhase = 'bump-prompt';
|
|
894
|
+
}
|
|
895
|
+
else if (isBatch(state.flags)) {
|
|
896
|
+
// advanceToPlan lists every asset of the batch that needs --bump, once the entries are checked.
|
|
897
|
+
nextPhase = 'building-plan';
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
errorMessage = `--bump <patch|minor|major> required: registry has v${versionCheck.latestVersion} but manifest is not newer`;
|
|
901
|
+
nextPhase = 'error';
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
const checked = {
|
|
905
|
+
...state,
|
|
906
|
+
errorMessage,
|
|
907
|
+
isUpdate,
|
|
908
|
+
phase: nextPhase,
|
|
909
|
+
resolvedVersion: bumpedVersion,
|
|
910
|
+
target: bumpedTarget,
|
|
911
|
+
token,
|
|
912
|
+
versionCheck,
|
|
913
|
+
};
|
|
914
|
+
return nextPhase === 'building-plan' ? advanceToPlan(checked) : checked;
|
|
915
|
+
}
|
|
916
|
+
case 'RESOLVE_TOOLS_NONINTERACTIVE': {
|
|
917
|
+
const updatedTarget = state.target
|
|
918
|
+
? {
|
|
919
|
+
...state.target,
|
|
920
|
+
data: { ...state.target.data, tools: action.tools },
|
|
921
|
+
}
|
|
922
|
+
: undefined;
|
|
923
|
+
return {
|
|
924
|
+
...state,
|
|
925
|
+
// An interactive run's --tools stood in for the tools prompt; the reviewer prompt may still follow.
|
|
926
|
+
phase: state.nonInteractive ? 'checking-registry' : phaseAfterMetadata(updatedTarget),
|
|
927
|
+
target: updatedTarget,
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
case 'RESOLVED_UPDATE':
|
|
931
|
+
return {
|
|
932
|
+
...state,
|
|
933
|
+
phase: 'detecting',
|
|
934
|
+
resolvedPath: action.resolvedPath,
|
|
935
|
+
};
|
|
936
|
+
case 'SET_BUMP_SELECTION':
|
|
937
|
+
return { ...state, bumpSelection: action.value };
|
|
938
|
+
case 'SET_CONFIRM_VALUE':
|
|
939
|
+
return { ...state, confirmValue: action.value };
|
|
940
|
+
case 'SET_DESCRIPTION':
|
|
941
|
+
return { ...state, descriptionValue: action.value };
|
|
942
|
+
case 'SET_PROMPT_TAGS':
|
|
943
|
+
return { ...state, promptTagsValue: action.value };
|
|
944
|
+
case 'SET_PUBLISH_CONFIRM_VALUE':
|
|
945
|
+
return { ...state, publishConfirmValue: action.value };
|
|
946
|
+
case 'SET_REVIEWER':
|
|
947
|
+
return { ...state, reviewerValue: action.value };
|
|
948
|
+
case 'SET_TAGS':
|
|
949
|
+
return { ...state, tagsValue: action.value };
|
|
950
|
+
case 'SET_WITH_CONFIRM_VALUE':
|
|
951
|
+
return { ...state, withConfirmValue: action.value };
|
|
952
|
+
case 'STAGING_DONE':
|
|
953
|
+
return {
|
|
954
|
+
...state,
|
|
955
|
+
phase: 'validating',
|
|
956
|
+
target: action.target,
|
|
957
|
+
};
|
|
958
|
+
case 'SUBMIT_BUMP': {
|
|
959
|
+
const trimmed = state.bumpSelection.trim().toLowerCase();
|
|
960
|
+
if (trimmed !== 'patch' && trimmed !== 'minor' && trimmed !== 'major') {
|
|
961
|
+
return state; // Ignore invalid input
|
|
962
|
+
}
|
|
963
|
+
// The prompt is for an entry: bump it, then on to the next pending bump or the plan.
|
|
964
|
+
if (state.bumpEntry !== undefined) {
|
|
965
|
+
const entry = state.entries[state.bumpEntry];
|
|
966
|
+
if (entry?.versionCheck?.status !== 'needs-bump')
|
|
967
|
+
return state;
|
|
968
|
+
return bumpEntryAt({ ...state, bumpSelection: '' }, state.bumpEntry, trimmed);
|
|
969
|
+
}
|
|
970
|
+
if (!state.target || !state.versionCheck || state.versionCheck.status !== 'needs-bump') {
|
|
971
|
+
return state;
|
|
972
|
+
}
|
|
973
|
+
// Compute the bumped version in the reducer (pure, synchronous)
|
|
974
|
+
const bumpType = trimmed;
|
|
975
|
+
try {
|
|
976
|
+
const newVersion = bumpVersion(state.versionCheck.latestVersion, bumpType);
|
|
977
|
+
// The bump is only on the target until the publish succeeds, which writes it to
|
|
978
|
+
// the manifest; entries still to check or bump come first.
|
|
979
|
+
return advanceToPlan({
|
|
980
|
+
...state,
|
|
981
|
+
bumpSelection: '',
|
|
982
|
+
resolvedVersion: newVersion,
|
|
983
|
+
target: { ...state.target, data: { ...state.target.data, version: newVersion } },
|
|
754
984
|
});
|
|
755
985
|
}
|
|
756
986
|
catch {
|
|
757
|
-
|
|
987
|
+
return {
|
|
988
|
+
...state,
|
|
989
|
+
errorMessage: 'Failed to compute bumped version.',
|
|
990
|
+
phase: 'error',
|
|
991
|
+
};
|
|
758
992
|
}
|
|
759
993
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
994
|
+
case 'SUBMIT_CONFIRM': {
|
|
995
|
+
const trimmed = state.confirmValue.trim().toLowerCase();
|
|
996
|
+
if (trimmed === 'y' || trimmed === 'yes') {
|
|
997
|
+
return advanceToPlan(state);
|
|
998
|
+
}
|
|
999
|
+
else if (trimmed === 'n' || trimmed === 'no') {
|
|
1000
|
+
return { ...state, errorMessage: 'Publish cancelled.', phase: 'error' };
|
|
1001
|
+
}
|
|
1002
|
+
// Otherwise ignore (wait for valid input)
|
|
1003
|
+
return state;
|
|
1004
|
+
}
|
|
1005
|
+
case 'SUBMIT_DESCRIPTION': {
|
|
1006
|
+
const trimmed = state.descriptionValue.trim();
|
|
1007
|
+
if (!trimmed)
|
|
1008
|
+
return state; // Don't allow empty description
|
|
1009
|
+
return {
|
|
1010
|
+
...state,
|
|
1011
|
+
descriptionValue: trimmed,
|
|
1012
|
+
metadataSubPhase: metadataAfterDescription(state),
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
case 'SUBMIT_PROMPT_TAGS': {
|
|
1016
|
+
const parsedTags = splitList(state.promptTagsValue);
|
|
1017
|
+
// Update the target's data with the new tags
|
|
1018
|
+
const updatedTagsTarget = state.target
|
|
1019
|
+
? {
|
|
1020
|
+
...state.target,
|
|
1021
|
+
data: { ...state.target.data, tags: parsedTags.length > 0 ? parsedTags : undefined },
|
|
781
1022
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1023
|
+
: undefined;
|
|
1024
|
+
// Check if tools are also missing (only for assets)
|
|
1025
|
+
const needsToolsPrompt = updatedTagsTarget?.type === 'asset' &&
|
|
1026
|
+
(!('tools' in updatedTagsTarget.data) ||
|
|
1027
|
+
!Array.isArray(updatedTagsTarget.data.tools) ||
|
|
1028
|
+
(updatedTagsTarget.data.tools?.length ?? 0) === 0);
|
|
1029
|
+
const nextTagsPhase = needsToolsPrompt ? 'loading-tools' : phaseAfterMetadata(updatedTagsTarget);
|
|
1030
|
+
return {
|
|
1031
|
+
...state,
|
|
1032
|
+
phase: nextTagsPhase,
|
|
1033
|
+
target: updatedTagsTarget,
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
case 'SUBMIT_PUBLISH_CONFIRM': {
|
|
1037
|
+
const trimmed = state.publishConfirmValue.trim().toLowerCase();
|
|
1038
|
+
if (trimmed === 'y' || trimmed === 'yes') {
|
|
1039
|
+
return { ...state, phase: 'publishing' };
|
|
1040
|
+
}
|
|
1041
|
+
else if (trimmed === 'n' || trimmed === 'no') {
|
|
1042
|
+
return { ...state, errorMessage: 'Publish cancelled.', phase: 'error' };
|
|
1043
|
+
}
|
|
1044
|
+
// Otherwise ignore (wait for valid input)
|
|
1045
|
+
return state;
|
|
1046
|
+
}
|
|
1047
|
+
case 'SUBMIT_REVIEWER':
|
|
1048
|
+
return { ...state, phase: 'checking-registry' };
|
|
1049
|
+
case 'SUBMIT_TAGS':
|
|
1050
|
+
return {
|
|
1051
|
+
...state,
|
|
1052
|
+
metadataSubPhase: 'building-staging',
|
|
1053
|
+
};
|
|
1054
|
+
case 'SUBMIT_WITH_CONFIRM': {
|
|
1055
|
+
const trimmed = state.withConfirmValue.trim().toLowerCase();
|
|
1056
|
+
if (trimmed === 'y' || trimmed === 'yes') {
|
|
1057
|
+
return advanceToPlan({
|
|
1058
|
+
...state,
|
|
1059
|
+
entries: [...state.entries, ...state.suggestedEntries],
|
|
1060
|
+
missingDependencies: [],
|
|
1061
|
+
pendingError: undefined,
|
|
1062
|
+
suggestedEntries: [],
|
|
1063
|
+
withConfirmValue: '',
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
if ((trimmed === 'n' || trimmed === 'no') && state.pendingError) {
|
|
1067
|
+
return publishReducer({ ...state, suggestedEntries: [], withConfirmValue: '' }, state.pendingError);
|
|
1068
|
+
}
|
|
1069
|
+
return state;
|
|
1070
|
+
}
|
|
1071
|
+
case 'SUGGEST_ENTRIES':
|
|
1072
|
+
return {
|
|
1073
|
+
...state,
|
|
1074
|
+
missingDependencies: action.missing,
|
|
1075
|
+
pendingError: action.error,
|
|
1076
|
+
phase: 'confirm-with',
|
|
1077
|
+
suggestedEntries: action.suggested,
|
|
1078
|
+
withConfirmValue: '',
|
|
1079
|
+
};
|
|
1080
|
+
case 'TOOLS_LOADED':
|
|
1081
|
+
return {
|
|
1082
|
+
...state,
|
|
1083
|
+
phase: 'prompting-tools',
|
|
1084
|
+
toolAdapters: action.adapters,
|
|
1085
|
+
};
|
|
1086
|
+
case 'VALIDATE_DONE': {
|
|
1087
|
+
if (!action.validation.valid) {
|
|
1088
|
+
return {
|
|
1089
|
+
...state,
|
|
1090
|
+
errorMessage: `Validation failed:\n${action.validation.errors.map((e) => ` - ${e}`).join('\n')}`,
|
|
1091
|
+
phase: 'error',
|
|
1092
|
+
validation: action.validation,
|
|
790
1093
|
};
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1094
|
+
}
|
|
1095
|
+
// Seed the reviewers field: the --reviewer flag wins over the project's
|
|
1096
|
+
// lockfile-configured default (org.ts's CLI-flag > lockfile priority chain).
|
|
1097
|
+
const reviewerValue = state.flags.reviewerFlag ?? (action.lockfileOrgReviewers ?? []).join(', ');
|
|
1098
|
+
// Determine next phase based on missing tags/tools. A batch asks for neither: as for
|
|
1099
|
+
// a --with entry, a missing one is only a warning.
|
|
1100
|
+
const batch = isBatch(state.flags);
|
|
1101
|
+
const manifest = state.target?.data;
|
|
1102
|
+
const hasTags = batch || (manifest && 'tags' in manifest && Array.isArray(manifest.tags) && manifest.tags.length > 0);
|
|
1103
|
+
const hasTools = batch ||
|
|
1104
|
+
// Only assets have tools; bundles skip the tools prompt
|
|
1105
|
+
state.target?.type !== 'asset' ||
|
|
1106
|
+
(manifest && 'tools' in manifest && Array.isArray(manifest.tools) && manifest.tools.length > 0);
|
|
1107
|
+
const isOrgScoped = batch
|
|
1108
|
+
? [state.target, ...state.entries.map((entry) => entry.target)].some((t) => t && isOrgScopedTarget(t))
|
|
1109
|
+
: Boolean(state.target && isOrgScopedTarget(state.target));
|
|
1110
|
+
// Reviewers only apply to org-scoped assets (non-org PRs always go to the registry
|
|
1111
|
+
// maintainer) — fail fast rather than silently ignoring the flag.
|
|
1112
|
+
if (!isOrgScoped && state.flags.reviewerFlag && parseReviewersInput(state.flags.reviewerFlag).length > 0) {
|
|
1113
|
+
return {
|
|
1114
|
+
...state,
|
|
1115
|
+
errorMessage: 'The --reviewer flag only applies to org-scoped assets. Remove the flag to publish this asset.',
|
|
1116
|
+
phase: 'error',
|
|
1117
|
+
validation: action.validation,
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
// A manifest without tags takes them from --tags right here, in any run: a non-interactive
|
|
1121
|
+
// one without the flag publishes none, an interactive one asks. Manifest tags always win.
|
|
1122
|
+
const tagsFromFlag = !hasTags && (state.nonInteractive || state.flags.tagsFlag !== undefined);
|
|
1123
|
+
let nextTarget = state.target;
|
|
1124
|
+
if (tagsFromFlag && nextTarget) {
|
|
1125
|
+
const flagTags = splitList(state.flags.tagsFlag);
|
|
1126
|
+
nextTarget = {
|
|
1127
|
+
...nextTarget,
|
|
1128
|
+
data: { ...nextTarget.data, tags: flagTags.length > 0 ? flagTags : undefined },
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
// Non-interactive path: either route to loading-tools (effect resolves tools async) or
|
|
1132
|
+
// directly to checking-registry. The reviewer prompt never applies here — non-interactive
|
|
1133
|
+
// mode always skips it.
|
|
1134
|
+
if (state.nonInteractive) {
|
|
1135
|
+
let nextPhase;
|
|
1136
|
+
if (!hasTools) {
|
|
1137
|
+
// The loading-tools effect detects whether we're non-interactive and
|
|
1138
|
+
// either resolves tools from the manifest/flag/inference or errors out.
|
|
1139
|
+
nextPhase = 'loading-tools';
|
|
1140
|
+
}
|
|
1141
|
+
else {
|
|
1142
|
+
nextPhase = 'checking-registry';
|
|
1143
|
+
}
|
|
1144
|
+
return {
|
|
1145
|
+
...state,
|
|
1146
|
+
phase: nextPhase,
|
|
1147
|
+
reviewerValue,
|
|
1148
|
+
target: nextTarget,
|
|
1149
|
+
validation: action.validation,
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
let nextPhase;
|
|
1153
|
+
if (!hasTags && !tagsFromFlag) {
|
|
1154
|
+
nextPhase = 'prompting-tags';
|
|
1155
|
+
}
|
|
1156
|
+
else if (!hasTools) {
|
|
1157
|
+
nextPhase = 'loading-tools';
|
|
1158
|
+
}
|
|
1159
|
+
else {
|
|
1160
|
+
nextPhase = isOrgScoped ? 'prompting-reviewer' : 'checking-registry';
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
...state,
|
|
1164
|
+
phase: nextPhase,
|
|
1165
|
+
reviewerValue,
|
|
1166
|
+
target: nextTarget,
|
|
1167
|
+
validation: action.validation,
|
|
1168
|
+
};
|
|
795
1169
|
}
|
|
796
|
-
|
|
797
|
-
|
|
1170
|
+
default:
|
|
1171
|
+
return state;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* The step before `building-plan`, once the root asset's own checks are done:
|
|
1176
|
+
* check the entries not yet checked, then settle each entry that needs a bump
|
|
1177
|
+
* (`--bump`; without it, the bump prompt, or an error when non-interactive), then plan.
|
|
1178
|
+
*/
|
|
1179
|
+
function advanceToPlan(state) {
|
|
1180
|
+
if (state.entries.some((entry) => !entry.versionCheck)) {
|
|
1181
|
+
return { ...state, bumpEntry: undefined, phase: 'checking-entries' };
|
|
1182
|
+
}
|
|
1183
|
+
// A batch without --bump names every asset that needs one, not just the first.
|
|
1184
|
+
if (isBatch(state.flags) && state.nonInteractive && !state.flags.bump) {
|
|
1185
|
+
const pending = [
|
|
1186
|
+
...(state.target && state.versionCheck?.status === 'needs-bump' && !state.resolvedVersion
|
|
1187
|
+
? [{ label: state.flags.rawPath, latestVersion: state.versionCheck.latestVersion, target: state.target }]
|
|
1188
|
+
: []),
|
|
1189
|
+
...state.entries.flatMap((entry) => entry.versionCheck?.status === 'needs-bump' && entry.resolvedVersion === undefined
|
|
1190
|
+
? [{ label: entry.label, latestVersion: entry.versionCheck.latestVersion, target: entry.target }]
|
|
1191
|
+
: []),
|
|
1192
|
+
];
|
|
1193
|
+
if (pending.length > 0) {
|
|
1194
|
+
const lines = pending.map((p) => ` ${p.label}: ${p.target.assetType}:${p.target.data.name} v${p.target.data.version}, registry has v${p.latestVersion}`);
|
|
1195
|
+
return {
|
|
1196
|
+
...state,
|
|
1197
|
+
errorMessage: `--bump <patch|minor|major> required: these manifests are not newer than the registry:\n${lines.join('\n')}`,
|
|
1198
|
+
phase: 'error',
|
|
1199
|
+
};
|
|
798
1200
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1201
|
+
}
|
|
1202
|
+
const index = state.entries.findIndex((entry) => entry.versionCheck?.status === 'needs-bump' && entry.resolvedVersion === undefined);
|
|
1203
|
+
const entry = state.entries[index];
|
|
1204
|
+
if (entry?.versionCheck?.status !== 'needs-bump') {
|
|
1205
|
+
return { ...state, bumpEntry: undefined, phase: 'building-plan' };
|
|
1206
|
+
}
|
|
1207
|
+
if (state.flags.bump) {
|
|
1208
|
+
return bumpEntryAt(state, index, state.flags.bump);
|
|
1209
|
+
}
|
|
1210
|
+
if (!state.nonInteractive) {
|
|
1211
|
+
return { ...state, bumpEntry: index, bumpSelection: '', phase: 'bump-prompt' };
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
...state,
|
|
1215
|
+
errorMessage: `--bump <patch|minor|major> required: registry has v${entry.versionCheck.latestVersion} of ${entry.target.assetType}:${entry.target.data.name} (from ${entry.label}) but its manifest is not newer`,
|
|
1216
|
+
phase: 'error',
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Bump the entry at `index` from its registry version, then go on toward the
|
|
1221
|
+
* plan; an error state, as for the root, when the version can't be bumped.
|
|
1222
|
+
*/
|
|
1223
|
+
function bumpEntryAt(state, index, bump) {
|
|
1224
|
+
const entry = state.entries[index];
|
|
1225
|
+
if (entry?.versionCheck?.status !== 'needs-bump')
|
|
1226
|
+
return state;
|
|
1227
|
+
let version;
|
|
1228
|
+
try {
|
|
1229
|
+
version = bumpVersion(entry.versionCheck.latestVersion, bump);
|
|
1230
|
+
}
|
|
1231
|
+
catch {
|
|
1232
|
+
return { ...state, errorMessage: `Failed to compute bumped version for ${entry.label}.`, phase: 'error' };
|
|
1233
|
+
}
|
|
1234
|
+
return advanceToPlan({ ...state, entries: replaceEntry(state.entries, index, withVersion(entry, version)) });
|
|
1235
|
+
}
|
|
1236
|
+
/** A raw publish's step after its description: the tags prompt, unless --tags answered it. */
|
|
1237
|
+
function metadataAfterDescription(state) {
|
|
1238
|
+
return state.flags.tagsFlag === undefined ? 'tags' : 'building-staging';
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Phase to enter once the tags/tools metadata prompts are resolved: org-scoped
|
|
1242
|
+
* targets get the reviewer prompt, everything else proceeds to the registry check.
|
|
1243
|
+
*/
|
|
1244
|
+
function phaseAfterMetadata(target) {
|
|
1245
|
+
return target && isOrgScopedTarget(target) ? 'prompting-reviewer' : 'checking-registry';
|
|
1246
|
+
}
|
|
1247
|
+
function replaceEntry(entries, index, entry) {
|
|
1248
|
+
return entries.map((current, i) => (i === index ? entry : current));
|
|
1249
|
+
}
|
|
1250
|
+
/** The entry published at `version`; a successful publish writes it to the entry's manifest. */
|
|
1251
|
+
function withVersion(entry, version) {
|
|
1252
|
+
return {
|
|
1253
|
+
...entry,
|
|
1254
|
+
resolvedVersion: version,
|
|
1255
|
+
target: { ...entry.target, data: { ...entry.target.data, version } },
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
802
1258
|
//# sourceMappingURL=publish-flow.js.map
|