@fuzdev/fuz_gitops 0.77.0 → 0.78.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +25 -5
  2. package/dist/ModulesDetail.svelte +14 -12
  3. package/dist/ModulesDetail.svelte.d.ts.map +1 -1
  4. package/dist/ModulesNav.svelte +6 -6
  5. package/dist/ModulesNav.svelte.d.ts.map +1 -1
  6. package/dist/ModulesPage.svelte +2 -2
  7. package/dist/ModulesPage.svelte.d.ts.map +1 -1
  8. package/dist/PageFooter.svelte +2 -2
  9. package/dist/PageHeader.svelte +5 -5
  10. package/dist/PageHeader.svelte.d.ts +1 -1
  11. package/dist/PageHeader.svelte.d.ts.map +1 -1
  12. package/dist/PullRequestsDetail.svelte +25 -17
  13. package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
  14. package/dist/PullRequestsPage.svelte +3 -3
  15. package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
  16. package/dist/ReposTable.svelte +24 -15
  17. package/dist/ReposTable.svelte.d.ts.map +1 -1
  18. package/dist/ReposTree.svelte +8 -6
  19. package/dist/ReposTree.svelte.d.ts.map +1 -1
  20. package/dist/ReposTreeNav.svelte +10 -11
  21. package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
  22. package/dist/TablePage.svelte +2 -2
  23. package/dist/TablePage.svelte.d.ts.map +1 -1
  24. package/dist/TreeItemPage.svelte +2 -2
  25. package/dist/TreeItemPage.svelte.d.ts.map +1 -1
  26. package/dist/TreePage.svelte +2 -2
  27. package/dist/TreePage.svelte.d.ts.map +1 -1
  28. package/dist/cargo_toml.d.ts +33 -0
  29. package/dist/cargo_toml.d.ts.map +1 -0
  30. package/dist/cargo_toml.js +74 -0
  31. package/dist/changeset_generator.d.ts +1 -1
  32. package/dist/changeset_generator.d.ts.map +1 -1
  33. package/dist/changeset_generator.js +2 -2
  34. package/dist/changeset_reader.d.ts +1 -1
  35. package/dist/changeset_reader.d.ts.map +1 -1
  36. package/dist/changeset_reader.js +3 -3
  37. package/dist/config_reconcile.d.ts.map +1 -1
  38. package/dist/config_reconcile.js +6 -2
  39. package/dist/dependency_graph.d.ts +2 -2
  40. package/dist/dependency_graph.d.ts.map +1 -1
  41. package/dist/dependency_graph.js +9 -9
  42. package/dist/dependency_updater.d.ts +1 -1
  43. package/dist/dependency_updater.d.ts.map +1 -1
  44. package/dist/dependency_updater.js +8 -8
  45. package/dist/fetch_repo_data.d.ts +2 -2
  46. package/dist/fetch_repo_data.d.ts.map +1 -1
  47. package/dist/fetch_repo_data.js +4 -4
  48. package/dist/fs_fetch_value_cache.d.ts +1 -1
  49. package/dist/fs_fetch_value_cache.d.ts.map +1 -1
  50. package/dist/fs_fetch_value_cache.js +5 -5
  51. package/dist/git_operations.d.ts +1 -1
  52. package/dist/git_operations.d.ts.map +1 -1
  53. package/dist/git_operations.js +2 -2
  54. package/dist/github.d.ts +2 -2
  55. package/dist/github.d.ts.map +1 -1
  56. package/dist/github.js +7 -7
  57. package/dist/github_helpers.d.ts.map +1 -1
  58. package/dist/github_helpers.js +1 -1
  59. package/dist/gitops_analyze.task.d.ts.map +1 -1
  60. package/dist/gitops_analyze.task.js +21 -14
  61. package/dist/gitops_config.d.ts +2 -2
  62. package/dist/gitops_config.d.ts.map +1 -1
  63. package/dist/gitops_config.js +5 -5
  64. package/dist/gitops_plan.task.d.ts.map +1 -1
  65. package/dist/gitops_plan.task.js +8 -8
  66. package/dist/gitops_publish.task.d.ts.map +1 -1
  67. package/dist/gitops_publish.task.js +15 -12
  68. package/dist/gitops_run.task.d.ts.map +1 -1
  69. package/dist/gitops_run.task.js +10 -10
  70. package/dist/gitops_sync.task.d.ts.map +1 -1
  71. package/dist/gitops_sync.task.js +15 -13
  72. package/dist/gitops_task_helpers.d.ts +1 -1
  73. package/dist/gitops_task_helpers.d.ts.map +1 -1
  74. package/dist/gitops_task_helpers.js +4 -4
  75. package/dist/gitops_validate.task.d.ts.map +1 -1
  76. package/dist/gitops_validate.task.js +14 -14
  77. package/dist/graph_validation.d.ts +2 -2
  78. package/dist/graph_validation.d.ts.map +1 -1
  79. package/dist/graph_validation.js +5 -3
  80. package/dist/local_repo.d.ts +21 -7
  81. package/dist/local_repo.d.ts.map +1 -1
  82. package/dist/local_repo.js +64 -16
  83. package/dist/log_helpers.d.ts +1 -1
  84. package/dist/log_helpers.d.ts.map +1 -1
  85. package/dist/multi_repo_publisher.d.ts +3 -3
  86. package/dist/multi_repo_publisher.d.ts.map +1 -1
  87. package/dist/multi_repo_publisher.js +24 -20
  88. package/dist/npm_registry.d.ts +1 -1
  89. package/dist/npm_registry.d.ts.map +1 -1
  90. package/dist/npm_registry.js +4 -4
  91. package/dist/operations.d.ts +4 -4
  92. package/dist/operations.d.ts.map +1 -1
  93. package/dist/operations_defaults.d.ts.map +1 -1
  94. package/dist/operations_defaults.js +16 -16
  95. package/dist/output_helpers.d.ts +1 -1
  96. package/dist/output_helpers.d.ts.map +1 -1
  97. package/dist/preflight_checks.d.ts +2 -2
  98. package/dist/preflight_checks.d.ts.map +1 -1
  99. package/dist/preflight_checks.js +5 -5
  100. package/dist/publish_gate.d.ts.map +1 -1
  101. package/dist/publish_steps.d.ts.map +1 -1
  102. package/dist/publish_steps.js +4 -4
  103. package/dist/publishing_event.d.ts.map +1 -1
  104. package/dist/publishing_event.js +16 -14
  105. package/dist/publishing_event_handler.d.ts.map +1 -1
  106. package/dist/publishing_event_handler.js +6 -6
  107. package/dist/publishing_plan.d.ts +3 -3
  108. package/dist/publishing_plan.d.ts.map +1 -1
  109. package/dist/publishing_plan.js +25 -15
  110. package/dist/publishing_plan_helpers.d.ts.map +1 -1
  111. package/dist/publishing_plan_helpers.js +3 -3
  112. package/dist/publishing_plan_logging.d.ts +1 -1
  113. package/dist/publishing_plan_logging.d.ts.map +1 -1
  114. package/dist/publishing_plan_logging.js +2 -2
  115. package/dist/repo.svelte.d.ts +5 -5
  116. package/dist/repo.svelte.d.ts.map +1 -1
  117. package/dist/repo.svelte.js +2 -2
  118. package/dist/repo_ops.js +2 -2
  119. package/dist/resolved_gitops_config.d.ts.map +1 -1
  120. package/dist/resolved_gitops_config.js +1 -1
  121. package/dist/version_utils.js +1 -1
  122. package/package.json +16 -15
  123. package/src/lib/cargo_toml.ts +82 -0
  124. package/src/lib/changeset_generator.ts +20 -20
  125. package/src/lib/changeset_reader.ts +18 -18
  126. package/src/lib/ci_reconcile.ts +5 -5
  127. package/src/lib/config_reconcile.ts +8 -4
  128. package/src/lib/dependency_graph.ts +28 -28
  129. package/src/lib/dependency_updater.ts +30 -30
  130. package/src/lib/fetch_repo_data.ts +11 -11
  131. package/src/lib/fs_fetch_value_cache.ts +14 -10
  132. package/src/lib/git_operations.ts +31 -31
  133. package/src/lib/github.ts +19 -19
  134. package/src/lib/github_helpers.ts +6 -6
  135. package/src/lib/gitops_analyze.task.ts +56 -48
  136. package/src/lib/gitops_config.ts +14 -14
  137. package/src/lib/gitops_plan.task.ts +32 -32
  138. package/src/lib/gitops_publish.task.ts +52 -49
  139. package/src/lib/gitops_run.task.ts +29 -29
  140. package/src/lib/gitops_sync.task.ts +39 -30
  141. package/src/lib/gitops_task_helpers.ts +21 -21
  142. package/src/lib/gitops_validate.task.ts +38 -38
  143. package/src/lib/graph_validation.ts +14 -13
  144. package/src/lib/local_repo.ts +130 -64
  145. package/src/lib/log_helpers.ts +15 -15
  146. package/src/lib/multi_repo_publisher.ts +75 -74
  147. package/src/lib/npm_registry.ts +13 -13
  148. package/src/lib/operations.ts +50 -39
  149. package/src/lib/operations_defaults.ts +108 -106
  150. package/src/lib/output_helpers.ts +4 -4
  151. package/src/lib/preflight_checks.ts +28 -28
  152. package/src/lib/publish_gate.ts +7 -9
  153. package/src/lib/publish_steps.ts +15 -15
  154. package/src/lib/publishing_event.ts +22 -20
  155. package/src/lib/publishing_event_handler.ts +8 -8
  156. package/src/lib/publishing_plan.ts +69 -57
  157. package/src/lib/publishing_plan_helpers.ts +16 -12
  158. package/src/lib/publishing_plan_logging.ts +23 -23
  159. package/src/lib/repo.svelte.ts +8 -8
  160. package/src/lib/repo_ops.ts +12 -12
  161. package/src/lib/resolved_gitops_config.ts +5 -5
  162. package/src/lib/version_utils.ts +3 -3
@@ -1,40 +1,40 @@
1
- import type {Task} from '@fuzdev/gro';
2
- import {z} from 'zod';
3
- import {styleText as st} from 'node:util';
1
+ import type { Task } from '@fuzdev/gro';
2
+ import { z } from 'zod';
3
+ import { styleText as st } from 'node:util';
4
4
 
5
- import {get_gitops_ready} from './gitops_task_helpers.js';
5
+ import { get_gitops_ready } from './gitops_task_helpers.ts';
6
6
  import {
7
7
  generate_publishing_plan,
8
8
  log_publishing_plan,
9
9
  type PublishingPlan,
10
- type LogPlanOptions,
11
- } from './publishing_plan.js';
12
- import {format_and_output, type OutputFormatters} from './output_helpers.js';
13
- import {GITOPS_CONFIG_PATH_DEFAULT} from './gitops_constants.js';
10
+ type LogPlanOptions
11
+ } from './publishing_plan.ts';
12
+ import { format_and_output, type OutputFormatters } from './output_helpers.ts';
13
+ import { GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.ts';
14
14
 
15
15
  /** @nodocs */
16
16
  export const Args = z.strictObject({
17
17
  config: z
18
18
  .string()
19
- .meta({description: 'path to the gitops config file, absolute or relative to the cwd'})
19
+ .meta({ description: 'path to the gitops config file, absolute or relative to the cwd' })
20
20
  .default(GITOPS_CONFIG_PATH_DEFAULT),
21
21
  dir: z
22
22
  .string()
23
- .meta({description: 'path containing the repos, defaults to the parent of the config dir'})
23
+ .meta({ description: 'path containing the repos, defaults to the parent of the config dir' })
24
24
  .optional(),
25
25
  format: z
26
26
  .enum(['stdout', 'json', 'markdown'])
27
- .meta({description: 'output format'})
27
+ .meta({ description: 'output format' })
28
28
  .default('stdout'),
29
- outfile: z.string().meta({description: 'write output to file instead of logging'}).optional(),
30
- verbose: z.boolean().meta({description: 'show additional details'}).default(false),
29
+ outfile: z.string().meta({ description: 'write output to file instead of logging' }).optional(),
30
+ verbose: z.boolean().meta({ description: 'show additional details' }).default(false),
31
31
  sync: z
32
32
  .boolean()
33
33
  .meta({
34
34
  description:
35
- 'sync repos (switch branch, pull, install) before planning instead of reading the working tree as-is',
35
+ 'sync repos (switch branch, pull, install) before planning instead of reading the working tree as-is'
36
36
  })
37
- .default(false),
37
+ .default(false)
38
38
  });
39
39
  export type Args = z.infer<typeof Args>;
40
40
 
@@ -52,18 +52,18 @@ export type Args = z.infer<typeof Args>;
52
52
  export const task: Task<Args> = {
53
53
  summary: 'generate a publishing plan based on changesets',
54
54
  Args,
55
- run: async ({args, log}): Promise<void> => {
56
- const {dir, config, format, outfile, verbose, sync} = args;
55
+ run: async ({ args, log }): Promise<void> => {
56
+ const { dir, config, format, outfile, verbose, sync } = args;
57
57
 
58
58
  log.info(st('cyan', 'Generating multi-repo publishing plan...'));
59
59
 
60
60
  // Load local repos; read the working tree as-is unless `--sync`
61
- const {local_repos} = await get_gitops_ready({
61
+ const { local_repos } = await get_gitops_ready({
62
62
  config,
63
63
  dir,
64
64
  download: false, // Don't download if missing
65
65
  sync,
66
- log,
66
+ log
67
67
  });
68
68
 
69
69
  if (local_repos.length === 0) {
@@ -74,20 +74,20 @@ export const task: Task<Args> = {
74
74
  log.info(` Found ${local_repos.length} local repos`);
75
75
 
76
76
  // Generate publishing plan
77
- const plan = await generate_publishing_plan(local_repos, {log, verbose});
77
+ const plan = await generate_publishing_plan(local_repos, { log, verbose });
78
78
 
79
79
  // Format and output using output_helpers
80
- await format_and_output(plan, create_plan_formatters({verbose}), {format, outfile, log});
80
+ await format_and_output(plan, create_plan_formatters({ verbose }), { format, outfile, log });
81
81
 
82
82
  // Exit with error if there are blocking issues
83
83
  if (plan.errors.length > 0) {
84
84
  throw new Error('Publishing plan found errors that would block publishing');
85
85
  }
86
- },
86
+ }
87
87
  };
88
88
 
89
89
  const create_plan_formatters = (
90
- options: LogPlanOptions = {},
90
+ options: LogPlanOptions = {}
91
91
  ): OutputFormatters<PublishingPlan> => ({
92
92
  json: (plan) => {
93
93
  const output = {
@@ -97,12 +97,12 @@ const create_plan_formatters = (
97
97
  breaking_cascades: Object.fromEntries(plan.breaking_cascades),
98
98
  warnings: plan.warnings,
99
99
  info: plan.info,
100
- errors: plan.errors,
100
+ errors: plan.errors
101
101
  };
102
102
  return JSON.stringify(output, null, 2);
103
103
  },
104
104
  markdown: (plan) => format_plan_as_markdown(plan),
105
- stdout: (plan, log) => log_publishing_plan(plan, log, options),
105
+ stdout: (plan, log) => log_publishing_plan(plan, log, options)
106
106
  });
107
107
 
108
108
  const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
@@ -114,7 +114,7 @@ const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
114
114
  breaking_cascades,
115
115
  warnings,
116
116
  info,
117
- errors,
117
+ errors
118
118
  } = plan;
119
119
 
120
120
  lines.push('# Publishing Plan');
@@ -141,7 +141,7 @@ const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
141
141
  // Version changes
142
142
  if (version_changes.length > 0) {
143
143
  const with_changesets = version_changes.filter(
144
- (vc) => vc.has_changesets && !vc.needs_bump_escalation,
144
+ (vc) => vc.has_changesets && !vc.needs_bump_escalation
145
145
  );
146
146
  const with_escalation = version_changes.filter((vc) => vc.needs_bump_escalation);
147
147
  const with_auto_changesets = version_changes.filter((vc) => vc.will_generate_changeset);
@@ -154,7 +154,7 @@ const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
154
154
  for (const change of with_changesets) {
155
155
  const is_major = change.bump_type === 'major' ? '💥 Yes' : 'No';
156
156
  lines.push(
157
- `| \`${change.package_name}\` | ${change.from} | ${change.to} | ${change.bump_type} | ${is_major} |`,
157
+ `| \`${change.package_name}\` | ${change.from} | ${change.to} | ${change.bump_type} | ${is_major} |`
158
158
  );
159
159
  }
160
160
  lines.push('');
@@ -168,12 +168,12 @@ const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
168
168
  for (const change of with_escalation) {
169
169
  const is_major = change.bump_type === 'major' ? '💥 Yes' : 'No';
170
170
  lines.push(
171
- `| \`${change.package_name}\` | ${change.from} | ${change.to} | ${change.existing_bump} | ${change.required_bump} | ${is_major} |`,
171
+ `| \`${change.package_name}\` | ${change.from} | ${change.to} | ${change.existing_bump} | ${change.required_bump} | ${is_major} |`
172
172
  );
173
173
  }
174
174
  lines.push('');
175
175
  lines.push(
176
- '> ⬆️ These packages have changesets, but dependencies require a larger version bump.',
176
+ '> ⬆️ These packages have changesets, but dependencies require a larger version bump.'
177
177
  );
178
178
  lines.push('');
179
179
  }
@@ -186,7 +186,7 @@ const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
186
186
  for (const change of with_auto_changesets) {
187
187
  const is_major = change.bump_type === 'major' ? '💥 Yes' : 'No';
188
188
  lines.push(
189
- `| \`${change.package_name}\` | ${change.from} | ${change.to} | ${change.bump_type} | ${is_major} |`,
189
+ `| \`${change.package_name}\` | ${change.from} | ${change.to} | ${change.bump_type} | ${is_major} |`
190
190
  );
191
191
  }
192
192
  lines.push('');
@@ -234,7 +234,7 @@ const format_plan_as_markdown = (plan: PublishingPlan): Array<string> => {
234
234
  ? 'peer'
235
235
  : 'dev';
236
236
  lines.push(
237
- `- "${update.updated_dependency}": "${update.current_version}" # ${type_label}`,
237
+ `- "${update.updated_dependency}": "${update.current_version}" # ${type_label}`
238
238
  );
239
239
  lines.push(`+ "${update.updated_dependency}": "${update.new_version}" # ${type_label}`);
240
240
  }
@@ -1,67 +1,70 @@
1
- import type {Task} from '@fuzdev/gro';
2
- import type {Logger} from '@fuzdev/fuz_util/log.js';
3
- import {z} from 'zod';
4
- import {createInterface} from 'node:readline/promises';
5
- import {styleText as st} from 'node:util';
1
+ import type { Task } from '@fuzdev/gro';
2
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
3
+ import { z } from 'zod';
4
+ import { createInterface } from 'node:readline/promises';
5
+ import { styleText as st } from 'node:util';
6
6
 
7
- import {get_gitops_ready} from './gitops_task_helpers.js';
7
+ import { get_gitops_ready } from './gitops_task_helpers.ts';
8
8
  import {
9
9
  execute_publishing_plan,
10
10
  type PublishingOptions,
11
- type PublishingResult,
12
- } from './multi_repo_publisher.js';
13
- import {stdout_handler} from './publishing_event_handler.js';
14
- import {generate_publishing_plan, log_publishing_plan} from './publishing_plan.js';
15
- import {derive_publish_steps, format_publish_steps, type PublishStep} from './publish_steps.js';
16
- import {decide_publish_gate, publish_run_failed} from './publish_gate.js';
17
- import {format_and_output, type OutputFormatters} from './output_helpers.js';
18
- import {GITOPS_CONFIG_PATH_DEFAULT, GITOPS_NPM_WAIT_TIMEOUT_DEFAULT} from './gitops_constants.js';
11
+ type PublishingResult
12
+ } from './multi_repo_publisher.ts';
13
+ import { stdout_handler } from './publishing_event_handler.ts';
14
+ import { generate_publishing_plan, log_publishing_plan } from './publishing_plan.ts';
15
+ import { derive_publish_steps, format_publish_steps, type PublishStep } from './publish_steps.ts';
16
+ import { decide_publish_gate, publish_run_failed } from './publish_gate.ts';
17
+ import { format_and_output, type OutputFormatters } from './output_helpers.ts';
18
+ import { GITOPS_CONFIG_PATH_DEFAULT, GITOPS_NPM_WAIT_TIMEOUT_DEFAULT } from './gitops_constants.ts';
19
19
 
20
20
  /** @nodocs */
21
21
  export const Args = z.strictObject({
22
22
  config: z
23
23
  .string()
24
- .meta({description: 'path to the gitops config file, absolute or relative to the cwd'})
24
+ .meta({ description: 'path to the gitops config file, absolute or relative to the cwd' })
25
25
  .default(GITOPS_CONFIG_PATH_DEFAULT),
26
26
  dir: z
27
27
  .string()
28
- .meta({description: 'path containing the repos, defaults to the parent of the config dir'})
28
+ .meta({ description: 'path containing the repos, defaults to the parent of the config dir' })
29
29
  .optional(),
30
30
  peer_strategy: z
31
31
  .enum(['exact', 'caret', 'tilde'])
32
- .meta({description: 'version strategy for peer dependencies'})
32
+ .meta({ description: 'version strategy for peer dependencies' })
33
33
  .default('caret' as const),
34
- wetrun: z.boolean().meta({description: 'actually publish (default is dry run)'}).default(false),
34
+ wetrun: z.boolean().meta({ description: 'actually publish (default is dry run)' }).default(false),
35
35
  format: z
36
36
  .enum(['stdout', 'json', 'markdown'])
37
- .meta({description: 'output format'})
37
+ .meta({ description: 'output format' })
38
38
  .default('stdout'),
39
- deploy: z.boolean().meta({description: 'deploy all repos after publishing'}).default(false),
39
+ deploy: z.boolean().meta({ description: 'deploy all repos after publishing' }).default(false),
40
40
  plan: z
41
41
  .boolean()
42
- .meta({description: 'show the plan and confirm before publishing; --no-plan to skip'})
42
+ .meta({ description: 'show the plan and confirm before publishing; --no-plan to skip' })
43
43
  .default(true),
44
44
  max_wait: z
45
45
  .number()
46
- .meta({description: 'max time to wait for npm propagation in ms'})
46
+ .meta({ description: 'max time to wait for npm propagation in ms' })
47
47
  .default(GITOPS_NPM_WAIT_TIMEOUT_DEFAULT),
48
48
  emit_json: z
49
49
  .boolean()
50
- .meta({description: 'stream structured publishing events as JSON-lines to stdout'})
50
+ .meta({ description: 'stream structured publishing events as JSON-lines to stdout' })
51
+ .default(false),
52
+ outfile: z.string().meta({ description: 'write output to file instead of logging' }).optional(),
53
+ verbose: z
54
+ .boolean()
55
+ .meta({ description: 'show additional details in plan output' })
51
56
  .default(false),
52
- outfile: z.string().meta({description: 'write output to file instead of logging'}).optional(),
53
- verbose: z.boolean().meta({description: 'show additional details in plan output'}).default(false),
54
57
  sync: z
55
58
  .boolean()
56
59
  .meta({
57
60
  description:
58
- 'sync repos (switch branch, pull, install) before the dry run instead of reading the working tree as-is; always on for --wetrun',
61
+ 'sync repos (switch branch, pull, install) before the dry run instead of reading the working tree as-is; always on for --wetrun'
59
62
  })
60
63
  .default(false),
61
64
  preview: z
62
65
  .boolean()
63
- .meta({description: 'show the ordered side-effects a --wetrun would perform'})
64
- .default(false),
66
+ .meta({ description: 'show the ordered side-effects a --wetrun would perform' })
67
+ .default(false)
65
68
  });
66
69
  export type Args = z.infer<typeof Args>;
67
70
 
@@ -69,7 +72,7 @@ export type Args = z.infer<typeof Args>;
69
72
  export const task: Task<Args> = {
70
73
  summary: 'publish all repos in dependency order',
71
74
  Args,
72
- run: async ({args, log}): Promise<void> => {
75
+ run: async ({ args, log }): Promise<void> => {
73
76
  const {
74
77
  config,
75
78
  dir,
@@ -83,32 +86,32 @@ export const task: Task<Args> = {
83
86
  outfile,
84
87
  verbose,
85
88
  sync,
86
- preview,
89
+ preview
87
90
  } = args;
88
91
 
89
92
  // Load repos. A dry run reads the working tree as-is unless `--sync`;
90
93
  // a real publish (`--wetrun`) always syncs so preflight sees the canonical branches.
91
- const {local_repos: repos} = await get_gitops_ready({
94
+ const { local_repos: repos } = await get_gitops_ready({
92
95
  config,
93
96
  dir,
94
97
  download: false, // Don't download if missing
95
98
  sync: sync || wetrun,
96
- log,
99
+ log
97
100
  });
98
101
 
99
102
  // Generate the plan once; the executor consumes this exact plan (no second pass).
100
- const publishing_plan = await generate_publishing_plan(repos, {verbose});
101
- const preview_steps = preview ? derive_publish_steps(publishing_plan, {deploy}) : null;
103
+ const publishing_plan = await generate_publishing_plan(repos, { verbose });
104
+ const preview_steps = preview ? derive_publish_steps(publishing_plan, { deploy }) : null;
102
105
 
103
106
  // Decide whether to show the plan + confirm, block, or proceed (the decision table lives
104
107
  // in `decide_publish_gate`; readline + exit stay here at the edge).
105
- const gate = decide_publish_gate({wetrun, show_plan: plan, plan: publishing_plan});
108
+ const gate = decide_publish_gate({ wetrun, show_plan: plan, plan: publishing_plan });
106
109
 
107
110
  // A real publish that shows its plan prints it first — including before a `blocked` throw,
108
111
  // so the operator sees the errors that blocked it.
109
112
  if (gate.action !== 'proceed') {
110
113
  log.info(st('cyan', 'Publishing Plan'));
111
- log_publishing_plan(publishing_plan, log, {verbose});
114
+ log_publishing_plan(publishing_plan, log, { verbose });
112
115
  }
113
116
 
114
117
  if (gate.action === 'blocked') {
@@ -139,7 +142,7 @@ export const task: Task<Args> = {
139
142
  max_wait,
140
143
  log,
141
144
  // Live JSON-lines stream when requested; events also surface on the result.
142
- events: emit_json ? stdout_handler() : undefined,
145
+ events: emit_json ? stdout_handler() : undefined
143
146
  };
144
147
 
145
148
  // Execute publishing (may throw on fatal errors like circular dependencies)
@@ -155,22 +158,22 @@ export const task: Task<Args> = {
155
158
  ok: false,
156
159
  published: [],
157
160
  // Note: FATAL_ERROR is a placeholder - only fatal_error.message is displayed in output
158
- failed: [{name: 'FATAL_ERROR', error: fatal_error}],
161
+ failed: [{ name: 'FATAL_ERROR', error: fatal_error }],
159
162
  duration: 0,
160
163
  events: [],
161
- summary: {total: 0, published: 0, failed: 1, skipped: 0, duration: 0},
164
+ summary: { total: 0, published: 0, failed: 1, skipped: 0, duration: 0 },
162
165
  plan_errors: publishing_plan.errors,
163
- plan_warnings: publishing_plan.warnings,
166
+ plan_warnings: publishing_plan.warnings
164
167
  };
165
168
  }
166
169
 
167
170
  // Format and output result (always runs, even on fatal errors)
168
171
  // Note: stdout format is handled by the executor's logging
169
172
  if (format !== 'stdout') {
170
- await format_and_output({result, fatal_error, preview_steps}, create_publish_formatters(), {
173
+ await format_and_output({ result, fatal_error, preview_steps }, create_publish_formatters(), {
171
174
  format,
172
175
  outfile,
173
- log,
176
+ log
174
177
  });
175
178
  }
176
179
 
@@ -178,7 +181,7 @@ export const task: Task<Args> = {
178
181
  if (publish_run_failed(result, fatal_error)) {
179
182
  process.exit(1);
180
183
  }
181
- },
184
+ }
182
185
  };
183
186
 
184
187
  interface PublishResultData {
@@ -190,15 +193,15 @@ interface PublishResultData {
190
193
  const create_publish_formatters = (): OutputFormatters<PublishResultData> => ({
191
194
  json: (data) =>
192
195
  JSON.stringify(
193
- data.preview_steps ? {...data.result, preview: data.preview_steps} : data.result,
196
+ data.preview_steps ? { ...data.result, preview: data.preview_steps } : data.result,
194
197
  null,
195
- 2,
198
+ 2
196
199
  ),
197
200
  markdown: (data) => format_result_markdown(data.result, data.fatal_error, data.preview_steps),
198
201
  stdout: () => {
199
202
  // stdout format is handled by the executor's logging
200
203
  // This should never be called due to early return in task
201
- },
204
+ }
202
205
  });
203
206
 
204
207
  /** Logs the ordered side-effect preview to stdout. */
@@ -213,7 +216,7 @@ const log_preview = (steps: Array<PublishStep>, log: Logger): void => {
213
216
  const format_result_markdown = (
214
217
  result: PublishingResult,
215
218
  fatal_error: Error | null,
216
- preview_steps: Array<PublishStep> | null,
219
+ preview_steps: Array<PublishStep> | null
217
220
  ): Array<string> => {
218
221
  const lines: Array<string> = [];
219
222
 
@@ -252,7 +255,7 @@ const format_result_markdown = (
252
255
  lines.push('');
253
256
  lines.push('## Failed Packages');
254
257
  lines.push('');
255
- for (const {name, error} of result.failed) {
258
+ for (const { name, error } of result.failed) {
256
259
  lines.push(`- \`${name}\`: ${error.message}`);
257
260
  }
258
261
  }
@@ -290,7 +293,7 @@ const format_result_markdown = (
290
293
  const prompt_for_confirmation = async (): Promise<boolean> => {
291
294
  const rl = createInterface({
292
295
  input: process.stdin,
293
- output: process.stdout,
296
+ output: process.stdout
294
297
  });
295
298
 
296
299
  const answer = await rl.question('');
@@ -1,33 +1,33 @@
1
- import {TaskError, type Task} from '@fuzdev/gro';
2
- import {z} from 'zod';
3
- import {map_concurrent_settled} from '@fuzdev/fuz_util/async.js';
4
- import {spawn_out} from '@fuzdev/fuz_util/process.js';
5
- import {writeFile} from 'node:fs/promises';
6
- import {styleText as st} from 'node:util';
7
- import {resolve} from 'node:path';
1
+ import { TaskError, type Task } from '@fuzdev/gro';
2
+ import { z } from 'zod';
3
+ import { map_concurrent_settled } from '@fuzdev/fuz_util/async.ts';
4
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
5
+ import { writeFile } from 'node:fs/promises';
6
+ import { styleText as st } from 'node:util';
7
+ import { resolve } from 'node:path';
8
8
 
9
- import {get_repo_paths} from './repo_ops.js';
10
- import {GITOPS_CONCURRENCY_DEFAULT, GITOPS_CONFIG_PATH_DEFAULT} from './gitops_constants.js';
9
+ import { get_repo_paths } from './repo_ops.ts';
10
+ import { GITOPS_CONCURRENCY_DEFAULT, GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.ts';
11
11
 
12
12
  export const Args = z.strictObject({
13
13
  // Positional rest args (gro convention) so `gro gitops_run "npm test"` works;
14
14
  // joined with spaces and passed to `sh -c`, so quote commands that contain flags.
15
- _: z.array(z.string()).meta({description: 'shell command to run in each repo'}).default([]),
15
+ _: z.array(z.string()).meta({ description: 'shell command to run in each repo' }).default([]),
16
16
  config: z
17
17
  .string()
18
- .meta({description: 'path to the gitops config file'})
18
+ .meta({ description: 'path to the gitops config file' })
19
19
  .default(GITOPS_CONFIG_PATH_DEFAULT),
20
20
  concurrency: z
21
21
  .number()
22
22
  .int()
23
23
  .min(1)
24
- .meta({description: 'maximum number of repos to run in parallel'})
24
+ .meta({ description: 'maximum number of repos to run in parallel' })
25
25
  .default(GITOPS_CONCURRENCY_DEFAULT),
26
- format: z.enum(['text', 'json']).meta({description: 'output format'}).default('text'),
26
+ format: z.enum(['text', 'json']).meta({ description: 'output format' }).default('text'),
27
27
  outfile: z
28
28
  .string()
29
- .meta({description: 'with --format json, write clean JSON to this file instead of stdout'})
30
- .optional(),
29
+ .meta({ description: 'with --format json, write clean JSON to this file instead of stdout' })
30
+ .optional()
31
31
  });
32
32
  export type Args = z.infer<typeof Args>;
33
33
 
@@ -45,8 +45,8 @@ interface RunResult {
45
45
  export const task: Task<Args> = {
46
46
  Args,
47
47
  summary: 'run a shell command across all repos in parallel',
48
- run: async ({args, log}) => {
49
- const {_, config, concurrency, format, outfile} = args;
48
+ run: async ({ args, log }) => {
49
+ const { _, config, concurrency, format, outfile } = args;
50
50
 
51
51
  const command = _.join(' ').trim();
52
52
  if (!command) {
@@ -62,7 +62,7 @@ export const task: Task<Args> = {
62
62
  }
63
63
 
64
64
  log.info(
65
- `Running ${st('cyan', command)} across ${repos.length} repos (concurrency: ${concurrency})`,
65
+ `Running ${st('cyan', command)} across ${repos.length} repos (concurrency: ${concurrency})`
66
66
  );
67
67
 
68
68
  const start_time = performance.now();
@@ -77,7 +77,7 @@ export const task: Task<Args> = {
77
77
  // Parse command into cmd + args for spawn
78
78
  // For now, we use shell mode to support pipes/redirects/etc
79
79
  const spawned = await spawn_out('sh', ['-c', command], {
80
- cwd: repo_dir,
80
+ cwd: repo_dir
81
81
  });
82
82
 
83
83
  const duration_ms = performance.now() - repo_start;
@@ -90,7 +90,7 @@ export const task: Task<Args> = {
90
90
  exit_code: spawned.result.kind === 'exited' ? spawned.result.code : 0,
91
91
  stdout: spawned.stdout || '',
92
92
  stderr: spawned.stderr || '',
93
- duration_ms,
93
+ duration_ms
94
94
  };
95
95
 
96
96
  return result;
@@ -104,7 +104,7 @@ export const task: Task<Args> = {
104
104
  stdout: '',
105
105
  stderr: '',
106
106
  duration_ms,
107
- error: String(error),
107
+ error: String(error)
108
108
  };
109
109
  }
110
110
  });
@@ -134,7 +134,7 @@ export const task: Task<Args> = {
134
134
  stdout: '',
135
135
  stderr: '',
136
136
  duration_ms: 0,
137
- error: String(result.reason),
137
+ error: String(result.reason)
138
138
  });
139
139
  }
140
140
  }
@@ -149,8 +149,8 @@ export const task: Task<Args> = {
149
149
  total: repos.length,
150
150
  success: successes.length,
151
151
  failure: failures.length,
152
- duration_ms: Math.round(total_duration_ms),
153
- },
152
+ duration_ms: Math.round(total_duration_ms)
153
+ }
154
154
  };
155
155
  const json = JSON.stringify(json_output, null, 2);
156
156
  if (outfile) {
@@ -225,15 +225,15 @@ export const task: Task<Args> = {
225
225
  log.info(
226
226
  st(
227
227
  'green',
228
- `✓ All ${total} repos succeeded in ${duration} (${success_rate}% success rate)`,
229
- ),
228
+ `✓ All ${total} repos succeeded in ${duration} (${success_rate}% success rate)`
229
+ )
230
230
  );
231
231
  } else {
232
232
  log.info(
233
233
  st(
234
234
  'yellow',
235
- `⚠ ${successes.length}/${total} repos succeeded in ${duration} (${success_rate}% success rate)`,
236
- ),
235
+ `⚠ ${successes.length}/${total} repos succeeded in ${duration} (${success_rate}% success rate)`
236
+ )
237
237
  );
238
238
  }
239
239
  }
@@ -242,5 +242,5 @@ export const task: Task<Args> = {
242
242
  if (failures.length > 0) {
243
243
  throw new TaskError(`${failures.length} repos failed`);
244
244
  }
245
- },
245
+ }
246
246
  };