auklet 0.0.26 → 0.0.28

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 CHANGED
@@ -122,10 +122,28 @@ auklet CLI overrides.
122
122
  Publish controls stay on CLI flags:
123
123
 
124
124
  ```bash
125
+ auk publish
125
126
  auk publish --filter @scope/ui
126
127
  auk publish --version patch --dry-run
127
128
  auk publish --no-format
128
129
  auk publish --otp 123456
130
+ auk owner add alice
131
+ auk owner add alice --filter @scope/ui --otp 123456
132
+ ```
133
+
134
+ Target selection:
135
+
136
+ ```text
137
+ auk publish
138
+ ├─ --filter <pattern> publish matching workspace packages
139
+ └─ no --filter publish the current package
140
+ └─ private monorepo root -> fail; use --filter
141
+
142
+ auk owner add <user...>
143
+ ├─ --filter <pattern> add owners to matching workspace packages
144
+ ├─ --package <name> add owners to explicit npm packages
145
+ └─ no selector add owners to the current package
146
+ └─ private package -> fail
129
147
  ```
130
148
 
131
149
  `--no-format` disables auklet's publish output formatter for that run. It is not
@@ -134,7 +152,8 @@ Before writing versions, auklet checks npm authentication from each target
134
152
  package directory. Package-local `.npmrc` files and
135
153
  `package.json#publishConfig.registry` are respected.
136
154
  `--otp` is forwarded to `pnpm publish` for npm accounts or organizations that
137
- require publish 2FA. In CI, prefer an npm automation token.
155
+ require publish 2FA, and to `pnpm owner add` for owner management 2FA. In CI,
156
+ prefer an npm automation token.
138
157
 
139
158
  ## Configuration
140
159
 
@@ -10,7 +10,7 @@ export async function isGitRepository(cwd) {
10
10
  return !result.exitCode && result.stdout.trim() === 'true';
11
11
  }
12
12
  export async function getGitShortHash(cwd) {
13
- const result = await runGit(['rev-parse', '--short=6', 'HEAD'], cwd);
13
+ const result = await runGit(['rev-parse', '--short=7', 'HEAD'], cwd);
14
14
  if (result.exitCode)
15
15
  return null;
16
16
  return result.stdout.trim() || null;
@@ -1,7 +1,11 @@
1
1
  import type { WorkspacePackage } from '#auklet/publish/types';
2
2
  export declare class NpmPublishAuthenticationError extends Error {
3
+ readonly packageRoot: string;
3
4
  constructor(packageRoot: string);
4
5
  }
6
+ export declare class NpmPackageVersionExistsError extends Error {
7
+ constructor(packageName: string, version: string, registry?: string);
8
+ }
5
9
  export declare function ensurePnpm(): Promise<string>;
6
10
  export declare function readPnpmWorkspacePackages(root: string): Promise<WorkspacePackage[]>;
7
11
  export declare function runPnpmBuild(packageRoot: string): Promise<void>;
@@ -10,6 +14,9 @@ export declare function runPnpmWhoami(packageRoot: string, options?: {
10
14
  packageName?: string;
11
15
  registry?: string;
12
16
  }): Promise<string>;
17
+ export declare function hasPublishedPackageVersion(packageRoot: string, packageName: string, version: string, options?: {
18
+ registry?: string;
19
+ }): Promise<boolean>;
13
20
  export declare function runPnpmOwnerAdd(packageName: string, user: string, options: {
14
21
  cwd: string;
15
22
  otp?: string;
@@ -4,9 +4,16 @@ import semver from 'semver';
4
4
  import { readPnpmWorkspacePackageInfo } from '#auklet/workspace/packages';
5
5
  const supportedPnpmRange = '>=10.0.0';
6
6
  export class NpmPublishAuthenticationError extends Error {
7
+ packageRoot;
7
8
  constructor(packageRoot) {
8
- super(`[publish] pnpm publish failed at ${packageRoot}: ` +
9
- `npm publish requires additional authentication.`);
9
+ super('npm publish requires additional authentication.');
10
+ this.packageRoot = packageRoot;
11
+ }
12
+ }
13
+ export class NpmPackageVersionExistsError extends Error {
14
+ constructor(packageName, version, registry) {
15
+ const location = registry ? ` at ${registry}` : '';
16
+ super(`[publish] package ${packageName}@${version}${location} already exists.`);
10
17
  }
11
18
  }
12
19
  const runPnpm = async (args, options = {}) => {
@@ -64,7 +71,7 @@ export async function runPnpmPublish(packageRoot, args) {
64
71
  if (hasNpmAuthChallenge(result)) {
65
72
  throw new NpmPublishAuthenticationError(packageRoot);
66
73
  }
67
- throw new Error(`[publish] pnpm publish failed at ${packageRoot}.`);
74
+ throw new Error('pnpm publish failed.');
68
75
  }
69
76
  }
70
77
  export async function runPnpmWhoami(packageRoot, options = {}) {
@@ -82,6 +89,19 @@ export async function runPnpmWhoami(packageRoot, options = {}) {
82
89
  }
83
90
  return String(result.stdout ?? '').trim();
84
91
  }
92
+ export async function hasPublishedPackageVersion(packageRoot, packageName, version, options = {}) {
93
+ const args = ['view', `${packageName}@${version}`, 'version'];
94
+ if (options.registry)
95
+ args.push('--registry', options.registry);
96
+ const result = await runPnpm(args, {
97
+ cwd: packageRoot,
98
+ });
99
+ if (!result.exitCode)
100
+ return String(result.stdout ?? '').trim() === version;
101
+ if (isPackageNotFound(result))
102
+ return false;
103
+ throw new Error(`[publish] failed to check published version for ${packageName}@${version}.`);
104
+ }
85
105
  export async function runPnpmOwnerAdd(packageName, user, options) {
86
106
  const args = ['owner', 'add', user, packageName];
87
107
  if (options.otp)
@@ -120,9 +140,12 @@ const writeProcessOutput = (result) => {
120
140
  const stdout = String(result.stdout ?? '');
121
141
  const stderr = String(result.stderr ?? '');
122
142
  if (stdout)
123
- process.stdout.write(stdout);
143
+ process.stdout.write(withTrailingLineBreak(stdout));
124
144
  if (stderr)
125
- process.stderr.write(stderr);
145
+ process.stderr.write(withTrailingLineBreak(stderr));
146
+ };
147
+ const withTrailingLineBreak = (value) => {
148
+ return value.endsWith('\n') ? value : `${value}\n`;
126
149
  };
127
150
  const isNpmAuthChallenge = (output) => {
128
151
  return [
@@ -133,3 +156,14 @@ const isNpmAuthChallenge = (output) => {
133
156
  'ENEEDAUTH',
134
157
  ].some((text) => output.includes(text));
135
158
  };
159
+ const isPackageNotFound = (result) => {
160
+ const output = [result.stdout, result.stderr]
161
+ .map((value) => String(value ?? ''))
162
+ .join('\n');
163
+ return [
164
+ 'E404',
165
+ '404 Not Found',
166
+ 'is not in this registry',
167
+ 'No match found for version',
168
+ ].some((text) => output.includes(text));
169
+ };
@@ -3,8 +3,8 @@ type RunPublishHookOptions = {
3
3
  status: HookStatus;
4
4
  plan: PublishPlan;
5
5
  result?: HookResult;
6
- failedTarget?: PublishTarget;
7
- error?: unknown;
6
+ failedTarget?: PublishTarget | null;
7
+ error?: unknown | null;
8
8
  };
9
9
  export declare function runPublishHook(options: RunPublishHookOptions): Promise<void>;
10
10
  export {};
@@ -36,8 +36,8 @@ export async function runPublishCli(args) {
36
36
  dryRun: argv['dry-run'] === true,
37
37
  format: argv.format !== false,
38
38
  otp: stringOption(argv.otp),
39
- ignoreScripts: argv['ignore-scripts'] === true,
40
39
  allowDirty: argv['allow-dirty'] === true,
40
+ ignoreScripts: argv['ignore-scripts'] === true,
41
41
  }).run();
42
42
  }
43
43
  export async function runOwnerCli(args) {
@@ -5,11 +5,9 @@ export declare class PublishRunner {
5
5
  private readonly preflight;
6
6
  private readonly versions;
7
7
  private readonly logger;
8
- private readonly summaryLogger;
9
8
  private readonly options;
10
9
  constructor(options: PublishOptions);
11
10
  run(): Promise<void>;
12
- private preparePlan;
13
11
  private publishWithPlan;
14
12
  private handleFailure;
15
13
  private runAfterPublishSuccess;
@@ -1,4 +1,4 @@
1
- import { createAukletLogger, createScopedAukletLogger } from '#auklet/logger';
1
+ import { createScopedAukletLogger } from '#auklet/logger';
2
2
  import { runPublishHook } from '#auklet/publish/api/publishHookApi';
3
3
  import { runPackageBuilds, validateBuildScript, } from '#auklet/publish/runner/packageBuilder';
4
4
  import { formatPublishOutputs } from '#auklet/publish/runner/publishOutputFormatter';
@@ -16,21 +16,23 @@ export class PublishRunner {
16
16
  preflight;
17
17
  versions;
18
18
  logger;
19
- summaryLogger;
20
19
  options;
21
20
  constructor(options) {
22
21
  this.options = options;
23
22
  this.logger = createScopedAukletLogger('publish');
24
- this.summaryLogger = createAukletLogger();
25
23
  this.git = new ReleaseGitController(this.options, this.logger);
26
24
  this.publisher = new PackagePublisher(this.options, this.logger);
27
25
  this.preflight = new PublishPreflight(this.options, this.logger);
28
26
  this.versions = new VersionWriter(this.options, this.logger);
29
27
  }
30
28
  async run() {
31
- const plan = await this.preparePlan();
29
+ const plan = await resolvePublishPlan(this.options, this.logger);
32
30
  let failureHookEnabled = false;
33
31
  try {
32
+ validateBuildScript(plan.targets);
33
+ await this.git.checkBeforePublish(plan);
34
+ await this.preflight.verifyBeforeBuild(plan);
35
+ this.versions.logDryRunPlan(plan);
34
36
  await runPublishHook({ status: 'beforeBuild', plan });
35
37
  failureHookEnabled = true;
36
38
  this.versions.writeBeforeBuild(plan);
@@ -42,7 +44,7 @@ export class PublishRunner {
42
44
  }
43
45
  catch (error) {
44
46
  if (!failureHookEnabled) {
45
- reportPublishSummary(this.summaryLogger, {
47
+ reportPublishSummary({
46
48
  plan,
47
49
  status: 'failure',
48
50
  error,
@@ -53,14 +55,6 @@ export class PublishRunner {
53
55
  }
54
56
  await this.runAfterPublishSuccess(plan);
55
57
  }
56
- async preparePlan() {
57
- const plan = await resolvePublishPlan(this.options, this.logger);
58
- validateBuildScript(plan.targets);
59
- await this.git.checkBeforePublish(plan);
60
- await this.preflight.verifyAuthentication(plan);
61
- this.versions.logDryRunPlan(plan);
62
- return plan;
63
- }
64
58
  async publishWithPlan(plan) {
65
59
  if (plan.dryRun) {
66
60
  await this.preflight.run(plan);
@@ -71,7 +65,7 @@ export class PublishRunner {
71
65
  await this.publisher.run(plan);
72
66
  }
73
67
  async handleFailure(plan, error) {
74
- const failedTarget = error instanceof PublishTargetError ? error.target : undefined;
68
+ const failedTarget = error instanceof PublishTargetError ? error.target : null;
75
69
  try {
76
70
  await runPublishHook({
77
71
  status: 'afterPublish',
@@ -85,9 +79,9 @@ export class PublishRunner {
85
79
  this.logger.error?.(hookError);
86
80
  }
87
81
  if (error instanceof PublishTargetError) {
88
- reportPublishFailure(error, plan.version, this.logger);
82
+ reportPublishFailure(error, plan.version);
89
83
  }
90
- reportPublishSummary(this.summaryLogger, {
84
+ reportPublishSummary({
91
85
  plan,
92
86
  status: 'failure',
93
87
  error,
@@ -101,9 +95,10 @@ export class PublishRunner {
101
95
  plan,
102
96
  result: 'success',
103
97
  });
104
- reportPublishSummary(this.summaryLogger, {
98
+ reportPublishSummary({
105
99
  plan,
106
100
  status: 'success',
101
+ error: null,
107
102
  });
108
103
  }
109
104
  }
@@ -27,6 +27,6 @@ export function logAuthenticationError(logger, error) {
27
27
  if (!(error instanceof NpmPublishAuthenticationError))
28
28
  return;
29
29
  logger.error('npm publish requires additional authentication.');
30
- logger.error('If publish 2FA is enabled, retry with `auk publish --otp <code>`.');
30
+ logger.error('If publish 2FA is enabled, retry with `--otp <code>`.');
31
31
  logger.error('For CI, use an npm automation token.');
32
32
  }
@@ -1,3 +1,2 @@
1
1
  import { PublishTargetError } from '#auklet/publish/runner/publishTargetError';
2
- import type { AukletLogger } from '#auklet/logger';
3
- export declare function reportPublishFailure(error: PublishTargetError, version: string, logger: AukletLogger): void;
2
+ export declare function reportPublishFailure(error: PublishTargetError, version: string): void;
@@ -1,14 +1,16 @@
1
- export function reportPublishFailure(error, version, logger) {
2
- if (error.phase === 'publish' && error.publishedTargets.length) {
3
- logger.error('partial publish detected');
4
- logger.error('published packages:');
5
- for (const target of error.publishedTargets) {
6
- logger.error(formatPublishedTarget(logger, target.packageName, version));
7
- }
8
- }
9
- logger.error('failed package:');
10
- logger.error(formatPublishedTarget(logger, error.target.packageName, version));
1
+ import { createAukletLogger } from '#auklet/logger';
2
+ export function reportPublishFailure(error, version) {
3
+ const logger = createAukletLogger();
4
+ const noteBody = logger.colors.rgb(184, 140, 40);
5
+ const body = [
6
+ noteBody(' Some packages were already published before the failure.'),
7
+ '',
8
+ ...error.publishedTargets.map((target) => noteBody(` published ${target.packageName}@${version}`)),
9
+ noteBody(` failed ${error.target.packageName}@${version}`),
10
+ ];
11
+ logger.newline();
12
+ logger.note({
13
+ title: logger.colors.yellow(logger.colors.bold('Partial publish detected')),
14
+ body,
15
+ });
11
16
  }
12
- const formatPublishedTarget = (logger, packageName, version) => {
13
- return ['- ', logger.package(packageName), '@', logger.version(version)];
14
- };
@@ -6,6 +6,9 @@ export declare class PublishPreflight {
6
6
  private readonly pnpm;
7
7
  constructor(options: PublishOptions, logger: AukletLogger);
8
8
  run(plan: PublishPlan): Promise<void>;
9
- verifyAuthentication(plan: PublishPlan): Promise<void>;
9
+ verifyBeforeBuild(plan: PublishPlan): Promise<void>;
10
+ private verifyAuthentication;
10
11
  private verifyPnpmPublishDryRun;
12
+ private verifyPackageVersions;
13
+ private logExistingVersion;
11
14
  }
@@ -1,6 +1,6 @@
1
1
  import { isPlainObject, isString } from 'aidly';
2
2
  import { PnpmPublishApi } from '#auklet/publish/api/pnpmPublishApi';
3
- import { runPnpmWhoami } from '#auklet/publish/api/pnpmApi';
3
+ import { hasPublishedPackageVersion, NpmPackageVersionExistsError, runPnpmWhoami, } from '#auklet/publish/api/pnpmApi';
4
4
  import { logAuthenticationError } from '#auklet/publish/runner/packagePublisher';
5
5
  import { PublishTargetError } from '#auklet/publish/runner/publishTargetError';
6
6
  export class PublishPreflight {
@@ -14,9 +14,13 @@ export class PublishPreflight {
14
14
  async run(plan) {
15
15
  await this.verifyPnpmPublishDryRun(plan);
16
16
  }
17
- async verifyAuthentication(plan) {
17
+ async verifyBeforeBuild(plan) {
18
18
  if (plan.dryRun)
19
19
  return;
20
+ await this.verifyAuthentication(plan);
21
+ await this.verifyPackageVersions(plan);
22
+ }
23
+ async verifyAuthentication(plan) {
20
24
  const checked = new Set();
21
25
  for (const target of plan.targets) {
22
26
  const registry = getPublishRegistry(target.packageJson.publishConfig);
@@ -45,6 +49,22 @@ export class PublishPreflight {
45
49
  }
46
50
  }
47
51
  }
52
+ async verifyPackageVersions(plan) {
53
+ for (const target of plan.targets) {
54
+ const registry = getPublishRegistry(target.packageJson.publishConfig);
55
+ const exists = await hasPublishedPackageVersion(target.packageRoot, target.packageName, target.publishVersion, { registry });
56
+ if (!exists)
57
+ continue;
58
+ this.logExistingVersion(target, registry);
59
+ throw new PublishTargetError(target, 'preflight', new NpmPackageVersionExistsError(target.packageName, target.publishVersion, registry), []);
60
+ }
61
+ }
62
+ logExistingVersion(target, registry) {
63
+ this.logger.error('package version already exists: ', this.logger.package(target.packageName), '@', this.logger.version(target.publishVersion));
64
+ if (registry) {
65
+ this.logger.error('registry: ', this.logger.url(registry));
66
+ }
67
+ }
48
68
  }
49
69
  const getPublishRegistry = (publishConfig) => {
50
70
  if (!isPlainObject(publishConfig))
@@ -1,10 +1,30 @@
1
- import type { AukletLogger } from '#auklet/logger';
2
1
  import type { PublishPlan } from '#auklet/publish/types';
3
2
  type PublishSummaryStatus = 'success' | 'failure';
4
- type PublishSummaryOptions = {
3
+ export type PublishSummaryOptions = {
5
4
  plan: PublishPlan;
6
5
  status: PublishSummaryStatus;
7
- error?: unknown;
6
+ error: unknown | null;
8
7
  };
9
- export declare function reportPublishSummary(logger: AukletLogger, options: PublishSummaryOptions): void;
8
+ export declare function reportPublishSummary(options: PublishSummaryOptions): void;
9
+ export declare class PublishSummaryReporter {
10
+ private readonly options;
11
+ private readonly logger;
12
+ private publishedCount;
13
+ private failedTarget;
14
+ private publishError;
15
+ private publishedTargets;
16
+ private publishedTargetRoots;
17
+ constructor(options: PublishSummaryOptions);
18
+ report(): void;
19
+ private getSummaryTitle;
20
+ private getSummaryBody;
21
+ private getFailureReasonLine;
22
+ private getFailureMessage;
23
+ private getSummaryDetails;
24
+ private getVersionChangeTasks;
25
+ private getVersionChangeTaskStatus;
26
+ private getTargetKey;
27
+ private formatVersionChange;
28
+ private formatSummaryValue;
29
+ }
10
30
  export {};
@@ -1,85 +1,130 @@
1
+ import { createAukletLogger } from '#auklet/logger';
1
2
  import { PublishTargetError } from '#auklet/publish/runner/publishTargetError';
2
- export function reportPublishSummary(logger, options) {
3
- const publishError = options.error instanceof PublishTargetError ? options.error : undefined;
4
- const failedTarget = publishError?.target;
5
- const publishedTargets = publishError?.publishedTargets ?? [];
6
- const publishedTargetRoots = new Set(publishedTargets.map((target) => getTargetKey(target)));
7
- const publishedCount = options.status === 'success' && !options.plan.dryRun
8
- ? options.plan.targets.length
9
- : publishedTargets.length;
10
- logger.newline();
11
- logger.raw(logger.colors.gray('-'.repeat(56)));
12
- logger.newline();
13
- logger.result({
14
- title: logger.colors.bold(getSummaryTitle(options.status, options.plan)),
15
- status: options.status === 'success' ? 'success' : 'error',
16
- body: getSummaryBody(options.status, options.plan, failedTarget),
17
- details: {
18
- mode: formatSummaryValue(logger, options.plan.dryRun ? 'dry-run' : 'publish'),
19
- packages: formatSummaryValue(logger, options.plan.targets.length),
20
- published: formatSummaryValue(logger, publishedCount),
21
- version: logger.version(options.plan.version),
22
- },
23
- });
24
- logger.newline();
25
- logger.tasks({
26
- tasks: getVersionChangeTasks(logger, {
27
- targets: options.plan.targets,
28
- status: options.status,
29
- dryRun: options.plan.dryRun,
30
- failedTarget,
31
- publishedTargetRoots,
32
- }),
33
- });
34
- logger.newline();
3
+ export function reportPublishSummary(options) {
4
+ new PublishSummaryReporter(options).report();
35
5
  }
36
- const getSummaryTitle = (status, plan) => {
37
- if (status === 'failure')
38
- return 'Publish failed';
39
- return plan.dryRun ? 'Publish dry-run complete' : 'Publish complete';
40
- };
41
- const getSummaryBody = (status, plan, failedTarget) => {
42
- if (status === 'success') {
6
+ export class PublishSummaryReporter {
7
+ options;
8
+ logger;
9
+ publishedCount = 0;
10
+ failedTarget;
11
+ publishError;
12
+ publishedTargets = [];
13
+ publishedTargetRoots = new Set();
14
+ constructor(options) {
15
+ this.options = options;
16
+ this.logger = createAukletLogger();
17
+ this.publishError =
18
+ options.error instanceof PublishTargetError ? options.error : null;
19
+ this.publishedTargets = this.publishError
20
+ ? this.publishError.publishedTargets
21
+ : [];
22
+ this.failedTarget = this.publishError ? this.publishError.target : null;
23
+ this.publishedTargetRoots = new Set(this.publishedTargets.map((target) => this.getTargetKey(target)));
24
+ this.publishedCount =
25
+ options.status === 'success' && !options.plan.dryRun
26
+ ? options.plan.targets.length
27
+ : this.publishedTargets.length;
28
+ }
29
+ report() {
30
+ this.logger.newline();
31
+ this.logger.raw(this.logger.colors.gray('-'.repeat(56)));
32
+ this.logger.newline();
33
+ this.logger.result({
34
+ title: this.logger.colors.bold(this.getSummaryTitle()),
35
+ status: this.options.status === 'success' ? 'success' : 'error',
36
+ body: this.getSummaryBody(),
37
+ details: this.getSummaryDetails(),
38
+ });
39
+ this.logger.newline();
40
+ this.logger.tasks({
41
+ tasks: this.getVersionChangeTasks(),
42
+ });
43
+ this.logger.newline();
44
+ }
45
+ getSummaryTitle() {
46
+ if (this.options.status === 'failure')
47
+ return 'Publish failed';
48
+ return this.options.plan.dryRun
49
+ ? 'Publish dry-run complete'
50
+ : 'Publish complete';
51
+ }
52
+ getSummaryBody() {
53
+ if (this.options.status === 'success') {
54
+ return [
55
+ this.options.plan.dryRun
56
+ ? 'Preflight completed without publishing packages.'
57
+ : 'All selected packages were published.',
58
+ ];
59
+ }
60
+ if (this.failedTarget) {
61
+ return [
62
+ ['Failed at ', this.logger.package(this.failedTarget.packageName), '.'],
63
+ ...this.getFailureReasonLine(),
64
+ ];
65
+ }
43
66
  return [
44
- plan.dryRun
45
- ? 'Preflight completed without publishing packages.'
46
- : 'All selected packages were published.',
67
+ 'Publish stopped before package publishing completed.',
68
+ ...this.getFailureReasonLine(),
47
69
  ];
48
70
  }
49
- if (failedTarget) {
50
- return [['Failed at ', failedTarget.packageName, '. Check logs above.']];
71
+ getFailureReasonLine() {
72
+ const message = this.getFailureMessage();
73
+ if (!message)
74
+ return [];
75
+ return [
76
+ [this.logger.colors.bold(this.logger.colors.red(`Reason: ${message}`))],
77
+ ];
78
+ }
79
+ getFailureMessage() {
80
+ const error = this.publishError
81
+ ? this.publishError.originalError
82
+ : this.options.error;
83
+ return error instanceof Error ? error.message : null;
84
+ }
85
+ getSummaryDetails() {
86
+ return {
87
+ mode: this.formatSummaryValue(this.options.plan.dryRun ? 'dry-run' : 'publish'),
88
+ packages: this.formatSummaryValue(this.options.plan.targets.length),
89
+ published: this.formatSummaryValue(this.publishedCount),
90
+ version: this.logger.version(this.options.plan.version),
91
+ };
51
92
  }
52
- return ['Publish stopped before package publishing completed.'];
53
- };
54
- const getVersionChangeTasks = (logger, options) => {
55
- return options.targets.map((target) => ({
56
- title: [
57
- logger.package(target.packageName),
58
- ' ',
59
- ...formatVersionChange(logger, target.version, target.publishVersion),
60
- ],
61
- status: getVersionChangeTaskStatus(target, options),
62
- }));
63
- };
64
- const getVersionChangeTaskStatus = (target, options) => {
65
- if (options.dryRun)
93
+ getVersionChangeTasks() {
94
+ return this.options.plan.targets.map((target) => ({
95
+ title: [
96
+ this.logger.package(target.packageName),
97
+ ' ',
98
+ ...this.formatVersionChange(target.version, target.publishVersion),
99
+ ],
100
+ status: this.getVersionChangeTaskStatus(target),
101
+ }));
102
+ }
103
+ getVersionChangeTaskStatus(target) {
104
+ if (this.options.plan.dryRun)
105
+ return 'skipped';
106
+ if (this.options.status === 'success')
107
+ return 'success';
108
+ if (this.failedTarget &&
109
+ this.getTargetKey(target) === this.getTargetKey(this.failedTarget)) {
110
+ return 'error';
111
+ }
112
+ if (this.publishedTargetRoots.has(this.getTargetKey(target))) {
113
+ return 'success';
114
+ }
66
115
  return 'skipped';
67
- if (options.status === 'success')
68
- return 'success';
69
- if (options.failedTarget &&
70
- getTargetKey(target) === getTargetKey(options.failedTarget)) {
71
- return 'error';
72
116
  }
73
- if (options.publishedTargetRoots.has(getTargetKey(target)))
74
- return 'success';
75
- return 'skipped';
76
- };
77
- const getTargetKey = (target) => {
78
- return `${target.packageRoot}:${target.packageName}`;
79
- };
80
- const formatVersionChange = (logger, from, to) => {
81
- return [logger.version(from), logger.colors.gray(' -> '), logger.version(to)];
82
- };
83
- const formatSummaryValue = (logger, value) => {
84
- return logger.colors.bold(logger.colors.cyan(String(value)));
85
- };
117
+ getTargetKey(target) {
118
+ return `${target.packageRoot}:${target.packageName}`;
119
+ }
120
+ formatVersionChange(from, to) {
121
+ return [
122
+ this.logger.version(from),
123
+ this.logger.colors.gray(' -> '),
124
+ this.logger.version(to),
125
+ ];
126
+ }
127
+ formatSummaryValue(value) {
128
+ return this.logger.colors.bold(this.logger.colors.cyan(String(value)));
129
+ }
130
+ }
@@ -5,7 +5,7 @@ export class PublishTargetError extends Error {
5
5
  originalError;
6
6
  publishedTargets;
7
7
  constructor(target, phase, originalError, publishedTargets) {
8
- super(`[publish] ${phase} failed for ${target.packageName} at ${path.relative(process.cwd(), target.packageRoot) || target.packageRoot}.`);
8
+ super(`${phase} failed for ${target.packageName} at ${path.relative(process.cwd(), target.packageRoot) || target.packageRoot}.`);
9
9
  this.target = target;
10
10
  this.phase = phase;
11
11
  this.originalError = originalError;
@@ -1,4 +1,5 @@
1
1
  import { readPackageJson, writePackageJson, } from '#auklet/publish/api/packageJsonApi';
2
+ import { createAukletLogger } from '#auklet/logger';
2
3
  export class VersionWriter {
3
4
  options;
4
5
  logger;
@@ -48,7 +49,19 @@ export class VersionWriter {
48
49
  }
49
50
  logWrittenVersionFailure(plan) {
50
51
  if (!plan.dryRun && this.options.version) {
51
- this.logger.error('package.json versions may have been written. Auklet will not roll them back; check publish output before retrying.');
52
+ const logger = createAukletLogger();
53
+ const noteBody = logger.colors.rgb(184, 140, 40);
54
+ logger.newline();
55
+ logger.note({
56
+ title: logger.colors.yellow(logger.colors.bold('Version files may have changed')),
57
+ body: [
58
+ [noteBody(' package.json versions may have been written.')],
59
+ [
60
+ noteBody(' Auklet will not roll them back; check publish output before retrying.'),
61
+ ],
62
+ ],
63
+ });
64
+ logger.newline();
52
65
  }
53
66
  }
54
67
  writeVersions(plan) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auklet",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "type": "module",
5
5
  "author": "chentao.arthur",
6
6
  "description": "Build utilities for TypeScript packages and module CSS output.",