primo-cli 0.1.19 → 0.1.20

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.
@@ -479,18 +479,26 @@ async function wait_for_ready(url) {
479
479
  // Run the equivalent of `primo push` against the local workspace. push_site
480
480
  // resolves the server URL from server.yaml (which we just wrote), so no extra
481
481
  // flags are needed. We surface failures but don't re-throw — the deploy already
482
- // succeeded and the user can rerun push manually.
482
+ // succeeded and the user can rerun push manually. Only a fully clean push
483
+ // counts as success: a partial upload must not be reported as "complete".
483
484
  async function run_auto_push(inventory) {
484
485
  console.log('');
485
486
  console.log(chalk.cyan('Uploading your workspace...'));
486
487
  try {
487
- await push_site({ dir: inventory.root_dir });
488
+ const failed = await push_site({ dir: inventory.root_dir });
489
+ if (failed.length > 0) {
490
+ // push_site already printed the per-item errors, the summary, and
491
+ // set the exit code. The server itself is fine, so finish the
492
+ // deploy flow — just not as "complete".
493
+ return false;
494
+ }
488
495
  return true;
489
496
  }
490
497
  catch (error) {
491
498
  console.log('');
492
499
  console.log(chalk.yellow(`Auto-push failed: ${error instanceof Error ? error.message : error}`));
493
500
  console.log(chalk.dim(' Your server is live — rerun `primo push` once the issue is sorted.'));
501
+ process.exitCode = 1;
494
502
  return false;
495
503
  }
496
504
  }
@@ -7,5 +7,5 @@ interface PushOptions {
7
7
  preview?: boolean;
8
8
  dryRun?: boolean;
9
9
  }
10
- export declare function push_site(options: PushOptions): Promise<void>;
10
+ export declare function push_site(options: PushOptions): Promise<string[]>;
11
11
  export {};
@@ -39,6 +39,8 @@ async function resolve_group_name(site_dir, group_id) {
39
39
  }
40
40
  return undefined;
41
41
  }
42
+ // Returns the labels (site slugs / 'library') that failed to push so callers
43
+ // like `primo deploy` can tell a clean run from a partial one. Empty = success.
42
44
  export async function push_site(options) {
43
45
  const root_dir = path.resolve(options.dir);
44
46
  const has_site_yaml = await path_exists(get_site_config_path(root_dir));
@@ -61,17 +63,27 @@ export async function push_site(options) {
61
63
  : options;
62
64
  if (options.dryRun) {
63
65
  await print_push_dry_run(root_dir, has_site_yaml, has_server_yaml, effective_options);
64
- return;
66
+ return [];
65
67
  }
66
68
  // Server-folder mode: walk site subfolders + push library
67
69
  if (!has_site_yaml && has_server_yaml) {
68
- await push_server(root_dir, effective_options);
69
- return;
70
+ const failed = await push_server(root_dir, effective_options);
71
+ if (failed.length > 0) {
72
+ console.log('');
73
+ console.log(chalk.red(`Push incomplete — failed: ${failed.join(', ')}`));
74
+ console.log(chalk.dim(' Fix the errors above and rerun `primo push` (completed pushes are safe to repeat).'));
75
+ console.log('');
76
+ // exitCode (not process.exit) so an in-process caller like `primo
77
+ // deploy` can still finish its own reporting before the process ends.
78
+ process.exitCode = 1;
79
+ }
80
+ return failed;
70
81
  }
71
82
  // Single-site mode (cwd is a site folder, or --dir points at one)
72
83
  const spinner = ora('Reading local files...').start();
73
84
  try {
74
85
  await push_single_site(root_dir, effective_options, spinner);
86
+ return [];
75
87
  }
76
88
  catch (error) {
77
89
  spinner.fail(`Push failed: ${error instanceof Error ? error.message : error}`);
@@ -166,6 +178,9 @@ async function print_push_dry_run(root_dir, has_site_yaml, has_server_yaml, opti
166
178
  console.log(chalk.dim(' No requests sent. Run without --dry-run to push.'));
167
179
  console.log('');
168
180
  }
181
+ // Pushes every site folder plus the library, continuing past individual
182
+ // failures. Returns the labels that failed — the caller decides how loudly a
183
+ // partial push should fail.
169
184
  async function push_server(root_dir, options) {
170
185
  // Sites live under sites/<slug>/
171
186
  const sites_root = path.join(root_dir, 'sites');
@@ -204,9 +219,10 @@ async function push_server(root_dir, options) {
204
219
  print_auth_hint();
205
220
  process.exit(1);
206
221
  }
207
- return;
222
+ return [];
208
223
  }
209
224
  let saw_auth_error = false;
225
+ const failed = [];
210
226
  // Push each site
211
227
  for (const site_dir of site_dirs) {
212
228
  const spinner = ora(`Pushing ${chalk.cyan(path.basename(site_dir))}...`).start();
@@ -217,6 +233,7 @@ async function push_server(root_dir, options) {
217
233
  spinner.fail(`${path.basename(site_dir)}: ${error instanceof Error ? error.message : error}`);
218
234
  if (is_auth_error(error))
219
235
  saw_auth_error = true;
236
+ failed.push(path.basename(site_dir));
220
237
  // Continue to remaining sites rather than abort the whole push
221
238
  }
222
239
  }
@@ -231,10 +248,12 @@ async function push_server(root_dir, options) {
231
248
  spinner.fail(`library: ${error instanceof Error ? error.message : error}`);
232
249
  if (is_auth_error(error))
233
250
  saw_auth_error = true;
251
+ failed.push('library');
234
252
  }
235
253
  }
236
254
  if (saw_auth_error)
237
255
  print_auth_hint();
256
+ return failed;
238
257
  }
239
258
  async function push_single_site(site_dir, options, spinner) {
240
259
  let config = null;
package/dist/index.js CHANGED
@@ -95,7 +95,7 @@ ${chalk.bold('See also')}
95
95
  primo deploy Stand up a new hosted Primo server
96
96
  primo login Authenticate with a hosted Primo server
97
97
  `)
98
- .action((server, options) => push_site({ ...options, server: server || options.server }));
98
+ .action(async (server, options) => { await push_site({ ...options, server: server || options.server }); });
99
99
  program
100
100
  .command('pull [server] [dir]')
101
101
  .description('Pull entire server (all sites + library) to local files (defaults to ./<server-hostname>)')
@@ -169,4 +169,13 @@ program.on('command:*', (operands) => {
169
169
  console.error('');
170
170
  process.exit(1);
171
171
  });
172
- program.parse();
172
+ // parseAsync so async action handlers are awaited inside commander's
173
+ // lifecycle — with plain parse() a rejected handler becomes an unhandled
174
+ // rejection (ugly stack, engine-dependent exit) instead of the clean
175
+ // message + exit(1) below.
176
+ program.parseAsync().catch((error) => {
177
+ console.error('');
178
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
179
+ console.error('');
180
+ process.exit(1);
181
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primo-cli",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Local development CLI for Primo",
5
5
  "type": "module",
6
6
  "bin": {