@fuzdev/fuz_gitops 0.78.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 (137) hide show
  1. package/README.md +20 -0
  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.map +1 -1
  11. package/dist/PullRequestsDetail.svelte +25 -17
  12. package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
  13. package/dist/PullRequestsPage.svelte +3 -3
  14. package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
  15. package/dist/ReposTable.svelte +24 -15
  16. package/dist/ReposTable.svelte.d.ts.map +1 -1
  17. package/dist/ReposTree.svelte +8 -6
  18. package/dist/ReposTree.svelte.d.ts.map +1 -1
  19. package/dist/ReposTreeNav.svelte +10 -11
  20. package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
  21. package/dist/TablePage.svelte +2 -2
  22. package/dist/TablePage.svelte.d.ts.map +1 -1
  23. package/dist/TreeItemPage.svelte +2 -2
  24. package/dist/TreeItemPage.svelte.d.ts.map +1 -1
  25. package/dist/TreePage.svelte +2 -2
  26. package/dist/TreePage.svelte.d.ts.map +1 -1
  27. package/dist/changeset_generator.d.ts.map +1 -1
  28. package/dist/changeset_generator.js +2 -2
  29. package/dist/changeset_reader.d.ts.map +1 -1
  30. package/dist/changeset_reader.js +3 -3
  31. package/dist/config_reconcile.d.ts.map +1 -1
  32. package/dist/config_reconcile.js +6 -2
  33. package/dist/dependency_graph.d.ts.map +1 -1
  34. package/dist/dependency_graph.js +5 -5
  35. package/dist/dependency_updater.d.ts.map +1 -1
  36. package/dist/dependency_updater.js +8 -8
  37. package/dist/fetch_repo_data.d.ts.map +1 -1
  38. package/dist/fetch_repo_data.js +3 -3
  39. package/dist/fs_fetch_value_cache.d.ts.map +1 -1
  40. package/dist/fs_fetch_value_cache.js +2 -2
  41. package/dist/git_operations.d.ts.map +1 -1
  42. package/dist/git_operations.js +1 -1
  43. package/dist/github.d.ts.map +1 -1
  44. package/dist/github.js +6 -6
  45. package/dist/github_helpers.d.ts.map +1 -1
  46. package/dist/gitops_analyze.task.d.ts.map +1 -1
  47. package/dist/gitops_analyze.task.js +7 -7
  48. package/dist/gitops_config.d.ts.map +1 -1
  49. package/dist/gitops_config.js +4 -4
  50. package/dist/gitops_plan.task.d.ts.map +1 -1
  51. package/dist/gitops_plan.task.js +8 -8
  52. package/dist/gitops_publish.task.d.ts.map +1 -1
  53. package/dist/gitops_publish.task.js +15 -12
  54. package/dist/gitops_run.task.d.ts.map +1 -1
  55. package/dist/gitops_run.task.js +8 -8
  56. package/dist/gitops_sync.task.d.ts.map +1 -1
  57. package/dist/gitops_sync.task.js +11 -9
  58. package/dist/gitops_task_helpers.d.ts.map +1 -1
  59. package/dist/gitops_task_helpers.js +3 -3
  60. package/dist/gitops_validate.task.d.ts.map +1 -1
  61. package/dist/gitops_validate.task.js +14 -14
  62. package/dist/graph_validation.d.ts.map +1 -1
  63. package/dist/graph_validation.js +2 -2
  64. package/dist/local_repo.d.ts +4 -4
  65. package/dist/local_repo.d.ts.map +1 -1
  66. package/dist/local_repo.js +13 -13
  67. package/dist/log_helpers.d.ts.map +1 -1
  68. package/dist/multi_repo_publisher.d.ts.map +1 -1
  69. package/dist/multi_repo_publisher.js +19 -19
  70. package/dist/npm_registry.d.ts.map +1 -1
  71. package/dist/npm_registry.js +2 -2
  72. package/dist/operations.d.ts.map +1 -1
  73. package/dist/operations_defaults.d.ts.map +1 -1
  74. package/dist/operations_defaults.js +12 -12
  75. package/dist/output_helpers.d.ts.map +1 -1
  76. package/dist/preflight_checks.d.ts +1 -1
  77. package/dist/preflight_checks.d.ts.map +1 -1
  78. package/dist/preflight_checks.js +4 -4
  79. package/dist/publish_gate.d.ts.map +1 -1
  80. package/dist/publish_steps.d.ts.map +1 -1
  81. package/dist/publish_steps.js +3 -3
  82. package/dist/publishing_event.d.ts.map +1 -1
  83. package/dist/publishing_event.js +16 -14
  84. package/dist/publishing_event_handler.d.ts.map +1 -1
  85. package/dist/publishing_event_handler.js +6 -6
  86. package/dist/publishing_plan.d.ts.map +1 -1
  87. package/dist/publishing_plan.js +14 -14
  88. package/dist/publishing_plan_helpers.d.ts.map +1 -1
  89. package/dist/publishing_plan_helpers.js +3 -3
  90. package/dist/publishing_plan_logging.d.ts.map +1 -1
  91. package/dist/publishing_plan_logging.js +2 -2
  92. package/dist/repo.svelte.d.ts.map +1 -1
  93. package/dist/repo_ops.js +2 -2
  94. package/dist/resolved_gitops_config.d.ts.map +1 -1
  95. package/dist/resolved_gitops_config.js +1 -1
  96. package/dist/version_utils.js +1 -1
  97. package/package.json +16 -15
  98. package/src/lib/cargo_toml.ts +3 -3
  99. package/src/lib/changeset_generator.ts +19 -19
  100. package/src/lib/changeset_reader.ts +18 -18
  101. package/src/lib/ci_reconcile.ts +5 -5
  102. package/src/lib/config_reconcile.ts +8 -4
  103. package/src/lib/dependency_graph.ts +26 -26
  104. package/src/lib/dependency_updater.ts +29 -29
  105. package/src/lib/fetch_repo_data.ts +11 -11
  106. package/src/lib/fs_fetch_value_cache.ts +14 -10
  107. package/src/lib/git_operations.ts +30 -30
  108. package/src/lib/github.ts +19 -19
  109. package/src/lib/github_helpers.ts +6 -6
  110. package/src/lib/gitops_analyze.task.ts +40 -40
  111. package/src/lib/gitops_config.ts +14 -14
  112. package/src/lib/gitops_plan.task.ts +31 -31
  113. package/src/lib/gitops_publish.task.ts +51 -48
  114. package/src/lib/gitops_run.task.ts +29 -29
  115. package/src/lib/gitops_sync.task.ts +39 -30
  116. package/src/lib/gitops_task_helpers.ts +21 -21
  117. package/src/lib/gitops_validate.task.ts +37 -37
  118. package/src/lib/graph_validation.ts +13 -13
  119. package/src/lib/local_repo.ts +70 -70
  120. package/src/lib/log_helpers.ts +15 -15
  121. package/src/lib/multi_repo_publisher.ts +67 -70
  122. package/src/lib/npm_registry.ts +13 -13
  123. package/src/lib/operations.ts +49 -38
  124. package/src/lib/operations_defaults.ts +106 -104
  125. package/src/lib/output_helpers.ts +4 -4
  126. package/src/lib/preflight_checks.ts +26 -26
  127. package/src/lib/publish_gate.ts +7 -9
  128. package/src/lib/publish_steps.ts +15 -15
  129. package/src/lib/publishing_event.ts +22 -20
  130. package/src/lib/publishing_event_handler.ts +8 -8
  131. package/src/lib/publishing_plan.ts +55 -55
  132. package/src/lib/publishing_plan_helpers.ts +16 -12
  133. package/src/lib/publishing_plan_logging.ts +22 -22
  134. package/src/lib/repo.svelte.ts +8 -8
  135. package/src/lib/repo_ops.ts +12 -12
  136. package/src/lib/resolved_gitops_config.ts +5 -5
  137. package/src/lib/version_utils.ts +3 -3
@@ -1,37 +1,37 @@
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.ts';
6
- import {analyze_repos, type DependencyAnalysis} from './graph_validation.ts';
5
+ import { get_gitops_ready } from './gitops_task_helpers.ts';
6
+ import { analyze_repos, type DependencyAnalysis } from './graph_validation.ts';
7
7
  import {
8
8
  generate_publishing_plan,
9
9
  log_publishing_plan,
10
- type PublishingPlan,
10
+ type PublishingPlan
11
11
  } from './publishing_plan.ts';
12
- import {execute_publishing_plan, type PublishingOptions} from './multi_repo_publisher.ts';
13
- import {log_dependency_analysis} from './log_helpers.ts';
14
- import {GITOPS_CONFIG_PATH_DEFAULT} from './gitops_constants.ts';
15
- import {reconcile_ci, repo_has_workflows} from './ci_reconcile.ts';
12
+ import { execute_publishing_plan, type PublishingOptions } from './multi_repo_publisher.ts';
13
+ import { log_dependency_analysis } from './log_helpers.ts';
14
+ import { GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.ts';
15
+ import { reconcile_ci, repo_has_workflows } from './ci_reconcile.ts';
16
16
 
17
17
  /** @nodocs */
18
18
  export const Args = z.strictObject({
19
19
  config: z
20
20
  .string()
21
- .meta({description: 'path to the gitops config file, absolute or relative to the cwd'})
21
+ .meta({ description: 'path to the gitops config file, absolute or relative to the cwd' })
22
22
  .default(GITOPS_CONFIG_PATH_DEFAULT),
23
23
  dir: z
24
24
  .string()
25
- .meta({description: 'path containing the repos, defaults to the parent of the config dir'})
25
+ .meta({ description: 'path containing the repos, defaults to the parent of the config dir' })
26
26
  .optional(),
27
- verbose: z.boolean().meta({description: 'show additional details'}).default(false),
27
+ verbose: z.boolean().meta({ description: 'show additional details' }).default(false),
28
28
  sync: z
29
29
  .boolean()
30
30
  .meta({
31
31
  description:
32
- 'sync repos (switch branch, pull, install) before validating instead of reading the working tree as-is',
32
+ 'sync repos (switch branch, pull, install) before validating instead of reading the working tree as-is'
33
33
  })
34
- .default(false),
34
+ .default(false)
35
35
  });
36
36
  export type Args = z.infer<typeof Args>;
37
37
 
@@ -40,8 +40,8 @@ export const task: Task<Args> = {
40
40
  Args,
41
41
  summary:
42
42
  'validate gitops configuration by running all read-only commands and checking for issues',
43
- run: async ({args, log}) => {
44
- const {config, dir, verbose, sync} = args;
43
+ run: async ({ args, log }) => {
44
+ const { config, dir, verbose, sync } = args;
45
45
 
46
46
  log.info(st('cyan', 'Running Gitops Validation Suite'));
47
47
  log.info(st('dim', 'This runs all read-only commands and checks for consistency.'));
@@ -61,7 +61,7 @@ export const task: Task<Args> = {
61
61
 
62
62
  // Load repos once (shared by all commands); read the working tree as-is unless `--sync`
63
63
  log.info(st('dim', 'Loading repositories...'));
64
- const {local_repos} = await get_gitops_ready({config, dir, download: false, sync, log});
64
+ const { local_repos } = await get_gitops_ready({ config, dir, download: false, sync, log });
65
65
  log.info(st('dim', ` Found ${local_repos.length} local repos`));
66
66
 
67
67
  // 1. Run gitops_analyze
@@ -69,7 +69,7 @@ export const task: Task<Args> = {
69
69
  const analyze_start = Date.now();
70
70
  try {
71
71
  // Build dependency graph and analyze cycles/wildcards (tolerating cycles)
72
- const {analysis} = analyze_repos(local_repos);
72
+ const { analysis } = analyze_repos(local_repos);
73
73
 
74
74
  const analyze_duration = Date.now() - analyze_start;
75
75
 
@@ -93,7 +93,7 @@ export const task: Task<Args> = {
93
93
  duration: analyze_duration,
94
94
  warning_details,
95
95
  info_details,
96
- analysis,
96
+ analysis
97
97
  });
98
98
 
99
99
  log.info(st('green', ` ✓ gitops_analyze completed in ${analyze_duration}ms`));
@@ -111,7 +111,7 @@ export const task: Task<Args> = {
111
111
  success: false,
112
112
  warnings: 0,
113
113
  errors: 1,
114
- duration: analyze_duration,
114
+ duration: analyze_duration
115
115
  });
116
116
  log.error(st('red', ` ✗ gitops_analyze failed: ${error}`));
117
117
  }
@@ -121,7 +121,7 @@ export const task: Task<Args> = {
121
121
  log.info(st('yellow', 'Running gitops_plan...'));
122
122
  const plan_start = Date.now();
123
123
  try {
124
- const plan = await generate_publishing_plan(local_repos, {verbose});
124
+ const plan = await generate_publishing_plan(local_repos, { verbose });
125
125
  publishing_plan = plan;
126
126
  const plan_duration = Date.now() - plan_start;
127
127
 
@@ -133,12 +133,12 @@ export const task: Task<Args> = {
133
133
  success: errors === 0,
134
134
  warnings,
135
135
  errors,
136
- duration: plan_duration,
136
+ duration: plan_duration
137
137
  });
138
138
 
139
139
  log.info(st('green', ` ✓ gitops_plan completed in ${plan_duration}ms`));
140
140
  if (verbose) {
141
- log_publishing_plan(plan, log, {verbose});
141
+ log_publishing_plan(plan, log, { verbose });
142
142
  }
143
143
  if (warnings > 0) {
144
144
  log.warn(st('yellow', ` ⚠️ Found ${warnings} warning(s)`));
@@ -153,7 +153,7 @@ export const task: Task<Args> = {
153
153
  success: false,
154
154
  warnings: 0,
155
155
  errors: 1,
156
- duration: plan_duration,
156
+ duration: plan_duration
157
157
  });
158
158
  log.error(st('red', ` ✗ gitops_plan failed: ${error}`));
159
159
  }
@@ -164,14 +164,14 @@ export const task: Task<Args> = {
164
164
  try {
165
165
  const options: PublishingOptions = {
166
166
  wetrun: false,
167
- log: undefined, // Silent for validation
167
+ log: undefined // Silent for validation
168
168
  };
169
169
 
170
170
  // Reuse the plan from step 2 (regenerate only if that step failed to produce one).
171
171
  const result = await execute_publishing_plan(
172
172
  local_repos,
173
- publishing_plan ?? (await generate_publishing_plan(local_repos, {verbose})),
174
- options,
173
+ publishing_plan ?? (await generate_publishing_plan(local_repos, { verbose })),
174
+ options
175
175
  );
176
176
  const dry_duration = Date.now() - dry_start;
177
177
 
@@ -184,7 +184,7 @@ export const task: Task<Args> = {
184
184
  success: result.ok,
185
185
  warnings: 0,
186
186
  errors,
187
- duration: dry_duration,
187
+ duration: dry_duration
188
188
  });
189
189
 
190
190
  log.info(st('green', ` ✓ gitops_publish (dry run) completed in ${dry_duration}ms`));
@@ -198,7 +198,7 @@ export const task: Task<Args> = {
198
198
  success: false,
199
199
  warnings: 0,
200
200
  errors: 1,
201
- duration: dry_duration,
201
+ duration: dry_duration
202
202
  });
203
203
  log.error(st('red', ` ✗ gitops_publish (dry run) failed: ${error}`));
204
204
  }
@@ -217,21 +217,21 @@ export const task: Task<Args> = {
217
217
  // always `true` today. The gate exists for a future caller that loads a
218
218
  // partial set; until then the skip path is inert and untested.
219
219
  checkable: true,
220
- archived: r.repo_config.archived,
221
- })),
220
+ archived: r.repo_config.archived
221
+ }))
222
222
  );
223
223
  const ci_duration = Date.now() - ci_start;
224
224
  const drift_details = ci_drift.map((d) =>
225
225
  d.kind === 'missing_ci'
226
226
  ? `${d.repo_url}: ci=true but no workflow files`
227
- : `${d.repo_url}: ci=false but workflow files present`,
227
+ : `${d.repo_url}: ci=false but workflow files present`
228
228
  );
229
229
  results.push({
230
230
  command: 'ci_reconcile',
231
231
  success: ci_drift.length === 0,
232
232
  warnings: 0,
233
233
  errors: ci_drift.length,
234
- duration: ci_duration,
234
+ duration: ci_duration
235
235
  });
236
236
  if (ci_drift.length === 0) {
237
237
  log.info(st('green', ` ✓ ci_reconcile completed in ${ci_duration}ms`));
@@ -248,7 +248,7 @@ export const task: Task<Args> = {
248
248
  success: false,
249
249
  warnings: 0,
250
250
  errors: 1,
251
- duration: ci_duration,
251
+ duration: ci_duration
252
252
  });
253
253
  log.error(st('red', ` ✗ ci_reconcile failed: ${error}`));
254
254
  }
@@ -295,7 +295,7 @@ export const task: Task<Args> = {
295
295
  log.info(st('green', '✓ All validation checks passed'));
296
296
  if (total_warnings > 0) {
297
297
  log.warn(
298
- st('yellow', `⚠️ Note: ${total_warnings} warning(s) found - review output above.`),
298
+ st('yellow', `⚠️ Note: ${total_warnings} warning(s) found - review output above.`)
299
299
  );
300
300
  }
301
301
  } else {
@@ -305,5 +305,5 @@ export const task: Task<Args> = {
305
305
  log.error(st('red', '❌ Validation failed - review the errors above.'));
306
306
  throw new Error('Validation failed');
307
307
  }
308
- },
308
+ }
309
309
  };
@@ -13,12 +13,12 @@
13
13
  * @module
14
14
  */
15
15
 
16
- import type {Logger} from '@fuzdev/fuz_util/log.ts';
17
- import {TaskError} from '@fuzdev/gro';
18
- import {styleText as st} from 'node:util';
16
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
17
+ import { TaskError } from '@fuzdev/gro';
18
+ import { styleText as st } from 'node:util';
19
19
 
20
- import {DependencyGraph, DependencyGraphBuilder} from './dependency_graph.ts';
21
- import {repo_is_npm, type LocalRepo} from './local_repo.ts';
20
+ import { DependencyGraph, DependencyGraphBuilder } from './dependency_graph.ts';
21
+ import { repo_is_npm, type LocalRepo } from './local_repo.ts';
22
22
 
23
23
  export interface GraphValidationResult {
24
24
  graph: DependencyGraph;
@@ -45,9 +45,9 @@ export const validate_dependency_graph = (
45
45
  throw_on_prod_cycles?: boolean;
46
46
  log_cycles?: boolean;
47
47
  log_order?: boolean;
48
- } = {},
48
+ } = {}
49
49
  ): GraphValidationResult => {
50
- const {log, throw_on_prod_cycles = true, log_cycles = true, log_order = true} = options;
50
+ const { log, throw_on_prod_cycles = true, log_cycles = true, log_order = true } = options;
51
51
 
52
52
  // Build dependency graph
53
53
  log?.info('📊 Analyzing dependencies...');
@@ -55,7 +55,7 @@ export const validate_dependency_graph = (
55
55
  const graph = builder.build_from_repos(repos);
56
56
 
57
57
  // Check for cycles
58
- const {production_cycles, dev_cycles} = graph.detect_cycles_by_type();
58
+ const { production_cycles, dev_cycles } = graph.detect_cycles_by_type();
59
59
 
60
60
  // Log production cycles
61
61
  if (production_cycles.length > 0 && log_cycles) {
@@ -67,7 +67,7 @@ export const validate_dependency_graph = (
67
67
  if (throw_on_prod_cycles) {
68
68
  throw new TaskError(
69
69
  `Cannot publish with production/peer dependency cycles. ` +
70
- `These must be resolved before publishing.`,
70
+ `These must be resolved before publishing.`
71
71
  );
72
72
  }
73
73
  }
@@ -106,7 +106,7 @@ export const validate_dependency_graph = (
106
106
  publishing_order,
107
107
  production_cycles,
108
108
  dev_cycles,
109
- sort_error,
109
+ sort_error
110
110
  };
111
111
  };
112
112
 
@@ -128,11 +128,11 @@ export interface RepoAnalysis {
128
128
  */
129
129
  export const analyze_repos = (repos: Array<LocalRepo>): RepoAnalysis => {
130
130
  // Only npm packages form the dependency graph; non-npm repos (e.g. cargo) are excluded.
131
- const {graph, publishing_order: order} = validate_dependency_graph(repos.filter(repo_is_npm), {
131
+ const { graph, publishing_order: order } = validate_dependency_graph(repos.filter(repo_is_npm), {
132
132
  throw_on_prod_cycles: false, // report, don't throw
133
133
  log_cycles: false, // callers format their own cycle output
134
- log_order: false,
134
+ log_order: false
135
135
  });
136
136
  const analysis = new DependencyGraphBuilder().analyze(graph);
137
- return {graph, analysis, publishing_order: order.length > 0 ? order : null};
137
+ return { graph, analysis, publishing_order: order.length > 0 ? order : null };
138
138
  };
@@ -1,22 +1,22 @@
1
- import {strip_end} from '@fuzdev/fuz_util/string.ts';
2
- import {to_error_message} from '@fuzdev/fuz_util/error.ts';
3
- import {library_json_from_modules, type LibraryJson} from '@fuzdev/fuz_util/library_json.ts';
4
- import type {PackageJson} from '@fuzdev/fuz_util/package_json.ts';
5
- import {Library} from '@fuzdev/fuz_ui/library.svelte.ts';
6
- import {existsSync} from 'node:fs';
7
- import {join} from 'node:path';
8
- import {TaskError} from '@fuzdev/gro';
9
- import {library_load_from_repo} from '@fuzdev/gro/library_load.ts';
10
- import type {Logger} from '@fuzdev/fuz_util/log.ts';
11
- import {spawn_out} from '@fuzdev/fuz_util/process.ts';
12
- import {map_concurrent_settled} from '@fuzdev/fuz_util/async.ts';
13
- import type {GitOperations, NpmOperations} from './operations.ts';
14
- import {default_git_operations, default_npm_operations} from './operations_defaults.ts';
15
-
16
- import type {GitopsConfig, GitopsRepoConfig} from './gitops_config.ts';
17
- import type {ResolvedGitopsConfig} from './resolved_gitops_config.ts';
18
- import {GITOPS_CONCURRENCY_DEFAULT} from './gitops_constants.ts';
19
- import {cargo_toml_load} from './cargo_toml.ts';
1
+ import { strip_end } from '@fuzdev/fuz_util/string.ts';
2
+ import { to_error_message } from '@fuzdev/fuz_util/error.ts';
3
+ import { library_json_from_modules, type LibraryJson } from '@fuzdev/fuz_util/library_json.ts';
4
+ import type { PackageJson } from '@fuzdev/fuz_util/package_json.ts';
5
+ import { Library } from '@fuzdev/fuz_ui/library.svelte.ts';
6
+ import { existsSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { TaskError } from '@fuzdev/gro';
9
+ import { library_load_from_repo } from '@fuzdev/gro/library_load.ts';
10
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
11
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
12
+ import { map_concurrent_settled } from '@fuzdev/fuz_util/async.ts';
13
+ import type { GitOperations, NpmOperations } from './operations.ts';
14
+ import { default_git_operations, default_npm_operations } from './operations_defaults.ts';
15
+
16
+ import type { GitopsConfig, GitopsRepoConfig } from './gitops_config.ts';
17
+ import type { ResolvedGitopsConfig } from './resolved_gitops_config.ts';
18
+ import { GITOPS_CONCURRENCY_DEFAULT } from './gitops_constants.ts';
19
+ import { cargo_toml_load } from './cargo_toml.ts';
20
20
 
21
21
  /**
22
22
  * Fully loaded local repo with `Library` and extracted dependency data.
@@ -97,7 +97,7 @@ export const local_repo_load = async ({
97
97
  git_ops = default_git_operations,
98
98
  npm_ops = default_npm_operations,
99
99
  sync = true,
100
- allow_dirty = false,
100
+ allow_dirty = false
101
101
  }: {
102
102
  local_repo_path: LocalRepoPath;
103
103
  log?: Logger;
@@ -106,20 +106,20 @@ export const local_repo_load = async ({
106
106
  sync?: boolean;
107
107
  allow_dirty?: boolean;
108
108
  }): Promise<LocalRepo> => {
109
- const {repo_config, repo_dir, repo_name, repo_git_ssh_url} = local_repo_path;
109
+ const { repo_config, repo_dir, repo_name, repo_git_ssh_url } = local_repo_path;
110
110
 
111
111
  if (sync) {
112
112
  // Record commit hash before any changes
113
- const commit_before_result = await git_ops.current_commit_hash({cwd: repo_dir});
113
+ const commit_before_result = await git_ops.current_commit_hash({ cwd: repo_dir });
114
114
  if (!commit_before_result.ok) {
115
115
  throw new TaskError(
116
- `Failed to get commit hash in ${repo_dir}: ${commit_before_result.message}`,
116
+ `Failed to get commit hash in ${repo_dir}: ${commit_before_result.message}`
117
117
  );
118
118
  }
119
119
  const commit_before = commit_before_result.value;
120
120
 
121
121
  // Switch to target branch if needed
122
- const branch_result = await git_ops.current_branch_name({cwd: repo_dir});
122
+ const branch_result = await git_ops.current_branch_name({ cwd: repo_dir });
123
123
  if (!branch_result.ok) {
124
124
  throw new TaskError(`Failed to get current branch in ${repo_dir}: ${branch_result.message}`);
125
125
  }
@@ -129,28 +129,28 @@ export const local_repo_load = async ({
129
129
  // Guard the switch on a clean workspace unless the caller opts into `allow_dirty`,
130
130
  // in which case we let `git checkout` itself fail loudly if it can't proceed.
131
131
  if (!allow_dirty) {
132
- const clean_result = await git_ops.check_clean_workspace({cwd: repo_dir});
132
+ const clean_result = await git_ops.check_clean_workspace({ cwd: repo_dir });
133
133
  if (!clean_result.ok) {
134
134
  throw new TaskError(`Failed to check workspace in ${repo_dir}: ${clean_result.message}`);
135
135
  }
136
136
 
137
137
  if (!clean_result.value) {
138
138
  throw new TaskError(
139
- `Repo ${repo_dir} is not on branch "${repo_config.branch}" and the workspace is unclean, blocking switch`,
139
+ `Repo ${repo_dir} is not on branch "${repo_config.branch}" and the workspace is unclean, blocking switch`
140
140
  );
141
141
  }
142
142
  }
143
143
 
144
- const checkout_result = await git_ops.checkout({branch: repo_config.branch, cwd: repo_dir});
144
+ const checkout_result = await git_ops.checkout({ branch: repo_config.branch, cwd: repo_dir });
145
145
  if (!checkout_result.ok) {
146
146
  throw new TaskError(
147
- `Failed to checkout branch "${repo_config.branch}" in ${repo_dir}: ${checkout_result.message}`,
147
+ `Failed to checkout branch "${repo_config.branch}" in ${repo_dir}: ${checkout_result.message}`
148
148
  );
149
149
  }
150
150
  }
151
151
 
152
152
  // Only pull if remote exists (skip for local-only repos, test fixtures)
153
- const origin_result = await git_ops.has_remote({remote: 'origin', cwd: repo_dir});
153
+ const origin_result = await git_ops.has_remote({ remote: 'origin', cwd: repo_dir });
154
154
  if (!origin_result.ok) {
155
155
  throw new TaskError(`Failed to check for remote in ${repo_dir}: ${origin_result.message}`);
156
156
  }
@@ -159,7 +159,7 @@ export const local_repo_load = async ({
159
159
  // Pull the configured branch explicitly. Without a branch, `git pull origin`
160
160
  // targets the remote's default branch (origin/HEAD), which for a repo checked
161
161
  // out on a non-default branch rebases the wrong branch onto it.
162
- const pull_result = await git_ops.pull({branch: repo_config.branch, cwd: repo_dir});
162
+ const pull_result = await git_ops.pull({ branch: repo_config.branch, cwd: repo_dir });
163
163
  if (!pull_result.ok) {
164
164
  throw new TaskError(`Failed to pull in ${repo_dir}: ${pull_result.message}`);
165
165
  }
@@ -168,25 +168,25 @@ export const local_repo_load = async ({
168
168
  // Check clean workspace after pull to ensure we're in a good state
169
169
  // (skipped when `allow_dirty`, since uncommitted changes are expected then)
170
170
  if (!allow_dirty) {
171
- const clean_after_result = await git_ops.check_clean_workspace({cwd: repo_dir});
171
+ const clean_after_result = await git_ops.check_clean_workspace({ cwd: repo_dir });
172
172
  if (!clean_after_result.ok) {
173
173
  throw new TaskError(
174
- `Failed to check workspace in ${repo_dir}: ${clean_after_result.message}`,
174
+ `Failed to check workspace in ${repo_dir}: ${clean_after_result.message}`
175
175
  );
176
176
  }
177
177
 
178
178
  if (!clean_after_result.value) {
179
179
  throw new TaskError(
180
- `Workspace ${repo_dir} is unclean after pulling branch "${repo_config.branch}"`,
180
+ `Workspace ${repo_dir} is unclean after pulling branch "${repo_config.branch}"`
181
181
  );
182
182
  }
183
183
  }
184
184
 
185
185
  // Record commit hash after pull
186
- const commit_after_result = await git_ops.current_commit_hash({cwd: repo_dir});
186
+ const commit_after_result = await git_ops.current_commit_hash({ cwd: repo_dir });
187
187
  if (!commit_after_result.ok) {
188
188
  throw new TaskError(
189
- `Failed to get commit hash in ${repo_dir}: ${commit_after_result.message}`,
189
+ `Failed to get commit hash in ${repo_dir}: ${commit_after_result.message}`
190
190
  );
191
191
  }
192
192
  const commit_after = commit_after_result.value;
@@ -200,20 +200,20 @@ export const local_repo_load = async ({
200
200
  from_commit: commit_before,
201
201
  to_commit: commit_after,
202
202
  file_path: 'package.json',
203
- cwd: repo_dir,
203
+ cwd: repo_dir
204
204
  });
205
205
 
206
206
  if (!changed_result.ok) {
207
207
  throw new TaskError(
208
- `Failed to check if package.json changed in ${repo_dir}: ${changed_result.message}`,
208
+ `Failed to check if package.json changed in ${repo_dir}: ${changed_result.message}`
209
209
  );
210
210
  }
211
211
 
212
212
  if (changed_result.value) {
213
- const install_result = await npm_ops.install({cwd: repo_dir});
213
+ const install_result = await npm_ops.install({ cwd: repo_dir });
214
214
  if (!install_result.ok) {
215
215
  throw new TaskError(
216
- `Failed to install dependencies in ${repo_dir}: ${install_result.message}${install_result.stderr ? `\n${install_result.stderr}` : ''}`,
216
+ `Failed to install dependencies in ${repo_dir}: ${install_result.message}${install_result.stderr ? `\n${install_result.stderr}` : ''}`
217
217
  );
218
218
  }
219
219
  }
@@ -225,21 +225,21 @@ export const local_repo_load = async ({
225
225
  // publishing/analysis skips. Anything else falls through to the npm loader below, whose
226
226
  // error covers a genuinely missing or unreadable manifest.
227
227
  if (!existsSync(join(repo_dir, 'package.json')) && existsSync(join(repo_dir, 'Cargo.toml'))) {
228
- return local_repo_load_cargo({local_repo_path});
228
+ return local_repo_load_cargo({ local_repo_path });
229
229
  }
230
230
 
231
231
  // Load library metadata via svelte-docinfo analysis (cached under `.gro/library.json`).
232
232
  let library_json: LibraryJson;
233
233
  let package_json: PackageJson;
234
234
  try {
235
- ({library_json, package_json} = await library_load_from_repo(repo_dir, {log: _log}));
235
+ ({ library_json, package_json } = await library_load_from_repo(repo_dir, { log: _log }));
236
236
  } catch (err) {
237
237
  const message = to_error_message(err);
238
238
  _log?.warn(
239
- `Failed to load library metadata for repo "${repo_name}" in ${repo_dir}: ${message}`,
239
+ `Failed to load library metadata for repo "${repo_name}" in ${repo_dir}: ${message}`
240
240
  );
241
241
  throw new TaskError(
242
- `Failed to load library metadata for repo "${repo_name}" in ${repo_dir}: ${message}`,
242
+ `Failed to load library metadata for repo "${repo_name}" in ${repo_dir}: ${message}`
243
243
  );
244
244
  }
245
245
  const library = new Library(library_json);
@@ -250,7 +250,7 @@ export const local_repo_load = async ({
250
250
  package_json,
251
251
  repo_dir,
252
252
  repo_git_ssh_url,
253
- repo_config,
253
+ repo_config
254
254
  };
255
255
 
256
256
  // Extract dependencies from the full package_json
@@ -284,11 +284,11 @@ export const repo_is_npm = (repo: LocalRepo): boolean => repo.kind === 'npm';
284
284
  * analysis paths skip it (see `repo_is_npm`).
285
285
  */
286
286
  const local_repo_load_cargo = async ({
287
- local_repo_path,
287
+ local_repo_path
288
288
  }: {
289
289
  local_repo_path: LocalRepoPath;
290
290
  }): Promise<LocalRepo> => {
291
- const {repo_config, repo_dir, repo_name, repo_url, repo_git_ssh_url} = local_repo_path;
291
+ const { repo_config, repo_dir, repo_name, repo_url, repo_git_ssh_url } = local_repo_path;
292
292
 
293
293
  const cargo = await cargo_toml_load(repo_dir);
294
294
 
@@ -299,7 +299,7 @@ const local_repo_load_cargo = async ({
299
299
  version: cargo?.version ?? '0.0.0',
300
300
  repository: cargo?.repository ?? repo_url,
301
301
  private: true,
302
- ...(cargo?.description ? {description: cargo.description} : null),
302
+ ...(cargo?.description ? { description: cargo.description } : null)
303
303
  };
304
304
 
305
305
  const library = new Library(library_json_from_modules(package_json, []));
@@ -310,7 +310,7 @@ const local_repo_load_cargo = async ({
310
310
  package_json,
311
311
  repo_dir,
312
312
  repo_git_ssh_url,
313
- repo_config,
313
+ repo_config
314
314
  };
315
315
  };
316
316
 
@@ -320,7 +320,7 @@ export const local_repos_ensure = async ({
320
320
  gitops_config,
321
321
  download,
322
322
  log,
323
- npm_ops = default_npm_operations,
323
+ npm_ops = default_npm_operations
324
324
  }: {
325
325
  resolved_config: ResolvedGitopsConfig;
326
326
  repos_dir: string;
@@ -339,19 +339,19 @@ export const local_repos_ensure = async ({
339
339
  repos_dir,
340
340
  local_repos_missing: resolved_config.local_repos_missing,
341
341
  log,
342
- npm_ops,
342
+ npm_ops
343
343
  });
344
344
  local_repo_paths = (resolved_config.local_repo_paths ?? [])
345
345
  .concat(downloaded)
346
346
  .sort(
347
347
  (a, b) =>
348
348
  gitops_config.repos.findIndex((r) => r.repo_url === a.repo_url) -
349
- gitops_config.repos.findIndex((r) => r.repo_url === b.repo_url),
349
+ gitops_config.repos.findIndex((r) => r.repo_url === b.repo_url)
350
350
  );
351
351
  } else {
352
352
  log?.error(
353
353
  `Failed to resolve local repos in ${repos_dir} - do you need to pass \`--download\` or configure the directory?`, // TODO leaking task impl details
354
- resolved_config.local_repos_missing.map((r) => r.repo_url),
354
+ resolved_config.local_repos_missing.map((r) => r.repo_url)
355
355
  );
356
356
  throw new TaskError('Failed to resolve local configs');
357
357
  }
@@ -372,7 +372,7 @@ export const local_repos_load = async ({
372
372
  parallel = true,
373
373
  concurrency = GITOPS_CONCURRENCY_DEFAULT,
374
374
  sync = true,
375
- allow_dirty = false,
375
+ allow_dirty = false
376
376
  }: {
377
377
  local_repo_paths: Array<LocalRepoPath>;
378
378
  log?: Logger;
@@ -388,7 +388,7 @@ export const local_repos_load = async ({
388
388
  const loaded: Array<LocalRepo> = [];
389
389
  for (const local_repo_path of local_repo_paths) {
390
390
  loaded.push(
391
- await local_repo_load({local_repo_path, log, git_ops, npm_ops, sync, allow_dirty}),
391
+ await local_repo_load({ local_repo_path, log, git_ops, npm_ops, sync, allow_dirty })
392
392
  );
393
393
  }
394
394
  return loaded;
@@ -399,13 +399,13 @@ export const local_repos_load = async ({
399
399
  local_repo_paths,
400
400
  concurrency,
401
401
  async (local_repo_path) => {
402
- return local_repo_load({local_repo_path, log, git_ops, npm_ops, sync, allow_dirty});
403
- },
402
+ return local_repo_load({ local_repo_path, log, git_ops, npm_ops, sync, allow_dirty });
403
+ }
404
404
  );
405
405
 
406
406
  // Check for failures and collect successes
407
407
  const loaded: Array<LocalRepo> = [];
408
- const errors: Array<{repo_name: string; error: string}> = [];
408
+ const errors: Array<{ repo_name: string; error: string }> = [];
409
409
 
410
410
  for (let i = 0; i < results.length; i++) {
411
411
  const result = results[i]!;
@@ -415,7 +415,7 @@ export const local_repos_load = async ({
415
415
  const repo_path = local_repo_paths[i]!;
416
416
  errors.push({
417
417
  repo_name: repo_path.repo_name,
418
- error: String(result.reason),
418
+ error: String(result.reason)
419
419
  });
420
420
  }
421
421
  }
@@ -431,12 +431,12 @@ export const local_repos_load = async ({
431
431
 
432
432
  export const local_repo_locate = ({
433
433
  repo_config,
434
- repos_dir,
434
+ repos_dir
435
435
  }: {
436
436
  repo_config: GitopsRepoConfig;
437
437
  repos_dir: string;
438
438
  }): LocalRepoPath | LocalRepoMissing => {
439
- const {repo_url} = repo_config;
439
+ const { repo_url } = repo_config;
440
440
  const repo_name = strip_end(repo_url, '/').split('/').at(-1);
441
441
  if (!repo_name) throw Error('Invalid `repo_config.repo_url` ' + repo_url);
442
442
 
@@ -444,7 +444,7 @@ export const local_repo_locate = ({
444
444
 
445
445
  const repo_dir = repo_config.repo_dir ?? join(repos_dir, repo_name);
446
446
  if (!existsSync(repo_dir)) {
447
- return {type: 'local_repo_missing', repo_name, repo_url, repo_git_ssh_url, repo_config};
447
+ return { type: 'local_repo_missing', repo_name, repo_url, repo_git_ssh_url, repo_config };
448
448
  }
449
449
 
450
450
  return {
@@ -453,7 +453,7 @@ export const local_repo_locate = ({
453
453
  repo_dir,
454
454
  repo_url,
455
455
  repo_git_ssh_url,
456
- repo_config,
456
+ repo_config
457
457
  };
458
458
  };
459
459
 
@@ -466,7 +466,7 @@ const download_repos = async ({
466
466
  repos_dir,
467
467
  local_repos_missing,
468
468
  log,
469
- npm_ops = default_npm_operations,
469
+ npm_ops = default_npm_operations
470
470
  }: {
471
471
  repos_dir: string;
472
472
  local_repos_missing: Array<LocalRepoMissing>;
@@ -474,26 +474,26 @@ const download_repos = async ({
474
474
  npm_ops?: NpmOperations;
475
475
  }): Promise<Array<LocalRepoPath>> => {
476
476
  const resolved: Array<LocalRepoPath> = [];
477
- for (const {repo_config, repo_git_ssh_url} of local_repos_missing) {
477
+ for (const { repo_config, repo_git_ssh_url } of local_repos_missing) {
478
478
  log?.info(`cloning repo ${repo_git_ssh_url} to ${repos_dir}`);
479
- const clone_result = await spawn_out('git', ['clone', repo_git_ssh_url], {cwd: repos_dir});
479
+ const clone_result = await spawn_out('git', ['clone', repo_git_ssh_url], { cwd: repos_dir });
480
480
  if (!clone_result.result.ok) {
481
481
  throw new TaskError(
482
- `Failed to clone repo ${repo_git_ssh_url} to ${repos_dir}${clone_result.stderr ? ': ' + clone_result.stderr.trim() : ''}`,
482
+ `Failed to clone repo ${repo_git_ssh_url} to ${repos_dir}${clone_result.stderr ? ': ' + clone_result.stderr.trim() : ''}`
483
483
  );
484
484
  }
485
- const local_repo = local_repo_locate({repo_config, repos_dir});
485
+ const local_repo = local_repo_locate({ repo_config, repos_dir });
486
486
  if (local_repo.type === 'local_repo_missing') {
487
487
  throw new TaskError(
488
- `Failed to clone repo ${repo_git_ssh_url} to ${repos_dir}: directory not found after clone`,
488
+ `Failed to clone repo ${repo_git_ssh_url} to ${repos_dir}: directory not found after clone`
489
489
  );
490
490
  }
491
491
  // Always install dependencies after cloning
492
492
  log?.info(`installing dependencies for newly cloned repo ${local_repo.repo_dir}`);
493
- const install_result = await npm_ops.install({cwd: local_repo.repo_dir});
493
+ const install_result = await npm_ops.install({ cwd: local_repo.repo_dir });
494
494
  if (!install_result.ok) {
495
495
  throw new TaskError(
496
- `Failed to install dependencies in ${local_repo.repo_dir}: ${install_result.message}${install_result.stderr ? `\n${install_result.stderr}` : ''}`,
496
+ `Failed to install dependencies in ${local_repo.repo_dir}: ${install_result.message}${install_result.stderr ? `\n${install_result.stderr}` : ''}`
497
497
  );
498
498
  }
499
499
  resolved.push(local_repo);