@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.
- package/README.md +20 -0
- package/dist/ModulesDetail.svelte +14 -12
- package/dist/ModulesDetail.svelte.d.ts.map +1 -1
- package/dist/ModulesNav.svelte +6 -6
- package/dist/ModulesNav.svelte.d.ts.map +1 -1
- package/dist/ModulesPage.svelte +2 -2
- package/dist/ModulesPage.svelte.d.ts.map +1 -1
- package/dist/PageFooter.svelte +2 -2
- package/dist/PageHeader.svelte +5 -5
- package/dist/PageHeader.svelte.d.ts.map +1 -1
- package/dist/PullRequestsDetail.svelte +25 -17
- package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
- package/dist/PullRequestsPage.svelte +3 -3
- package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
- package/dist/ReposTable.svelte +24 -15
- package/dist/ReposTable.svelte.d.ts.map +1 -1
- package/dist/ReposTree.svelte +8 -6
- package/dist/ReposTree.svelte.d.ts.map +1 -1
- package/dist/ReposTreeNav.svelte +10 -11
- package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
- package/dist/TablePage.svelte +2 -2
- package/dist/TablePage.svelte.d.ts.map +1 -1
- package/dist/TreeItemPage.svelte +2 -2
- package/dist/TreeItemPage.svelte.d.ts.map +1 -1
- package/dist/TreePage.svelte +2 -2
- package/dist/TreePage.svelte.d.ts.map +1 -1
- package/dist/changeset_generator.d.ts.map +1 -1
- package/dist/changeset_generator.js +2 -2
- package/dist/changeset_reader.d.ts.map +1 -1
- package/dist/changeset_reader.js +3 -3
- package/dist/config_reconcile.d.ts.map +1 -1
- package/dist/config_reconcile.js +6 -2
- package/dist/dependency_graph.d.ts.map +1 -1
- package/dist/dependency_graph.js +5 -5
- package/dist/dependency_updater.d.ts.map +1 -1
- package/dist/dependency_updater.js +8 -8
- package/dist/fetch_repo_data.d.ts.map +1 -1
- package/dist/fetch_repo_data.js +3 -3
- package/dist/fs_fetch_value_cache.d.ts.map +1 -1
- package/dist/fs_fetch_value_cache.js +2 -2
- package/dist/git_operations.d.ts.map +1 -1
- package/dist/git_operations.js +1 -1
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +6 -6
- package/dist/github_helpers.d.ts.map +1 -1
- package/dist/gitops_analyze.task.d.ts.map +1 -1
- package/dist/gitops_analyze.task.js +7 -7
- package/dist/gitops_config.d.ts.map +1 -1
- package/dist/gitops_config.js +4 -4
- package/dist/gitops_plan.task.d.ts.map +1 -1
- package/dist/gitops_plan.task.js +8 -8
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +15 -12
- package/dist/gitops_run.task.d.ts.map +1 -1
- package/dist/gitops_run.task.js +8 -8
- package/dist/gitops_sync.task.d.ts.map +1 -1
- package/dist/gitops_sync.task.js +11 -9
- package/dist/gitops_task_helpers.d.ts.map +1 -1
- package/dist/gitops_task_helpers.js +3 -3
- package/dist/gitops_validate.task.d.ts.map +1 -1
- package/dist/gitops_validate.task.js +14 -14
- package/dist/graph_validation.d.ts.map +1 -1
- package/dist/graph_validation.js +2 -2
- package/dist/local_repo.d.ts +4 -4
- package/dist/local_repo.d.ts.map +1 -1
- package/dist/local_repo.js +13 -13
- package/dist/log_helpers.d.ts.map +1 -1
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +19 -19
- package/dist/npm_registry.d.ts.map +1 -1
- package/dist/npm_registry.js +2 -2
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations_defaults.d.ts.map +1 -1
- package/dist/operations_defaults.js +12 -12
- package/dist/output_helpers.d.ts.map +1 -1
- package/dist/preflight_checks.d.ts +1 -1
- package/dist/preflight_checks.d.ts.map +1 -1
- package/dist/preflight_checks.js +4 -4
- package/dist/publish_gate.d.ts.map +1 -1
- package/dist/publish_steps.d.ts.map +1 -1
- package/dist/publish_steps.js +3 -3
- package/dist/publishing_event.d.ts.map +1 -1
- package/dist/publishing_event.js +16 -14
- package/dist/publishing_event_handler.d.ts.map +1 -1
- package/dist/publishing_event_handler.js +6 -6
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +14 -14
- package/dist/publishing_plan_helpers.d.ts.map +1 -1
- package/dist/publishing_plan_helpers.js +3 -3
- package/dist/publishing_plan_logging.d.ts.map +1 -1
- package/dist/publishing_plan_logging.js +2 -2
- package/dist/repo.svelte.d.ts.map +1 -1
- package/dist/repo_ops.js +2 -2
- package/dist/resolved_gitops_config.d.ts.map +1 -1
- package/dist/resolved_gitops_config.js +1 -1
- package/dist/version_utils.js +1 -1
- package/package.json +16 -15
- package/src/lib/cargo_toml.ts +3 -3
- package/src/lib/changeset_generator.ts +19 -19
- package/src/lib/changeset_reader.ts +18 -18
- package/src/lib/ci_reconcile.ts +5 -5
- package/src/lib/config_reconcile.ts +8 -4
- package/src/lib/dependency_graph.ts +26 -26
- package/src/lib/dependency_updater.ts +29 -29
- package/src/lib/fetch_repo_data.ts +11 -11
- package/src/lib/fs_fetch_value_cache.ts +14 -10
- package/src/lib/git_operations.ts +30 -30
- package/src/lib/github.ts +19 -19
- package/src/lib/github_helpers.ts +6 -6
- package/src/lib/gitops_analyze.task.ts +40 -40
- package/src/lib/gitops_config.ts +14 -14
- package/src/lib/gitops_plan.task.ts +31 -31
- package/src/lib/gitops_publish.task.ts +51 -48
- package/src/lib/gitops_run.task.ts +29 -29
- package/src/lib/gitops_sync.task.ts +39 -30
- package/src/lib/gitops_task_helpers.ts +21 -21
- package/src/lib/gitops_validate.task.ts +37 -37
- package/src/lib/graph_validation.ts +13 -13
- package/src/lib/local_repo.ts +70 -70
- package/src/lib/log_helpers.ts +15 -15
- package/src/lib/multi_repo_publisher.ts +67 -70
- package/src/lib/npm_registry.ts +13 -13
- package/src/lib/operations.ts +49 -38
- package/src/lib/operations_defaults.ts +106 -104
- package/src/lib/output_helpers.ts +4 -4
- package/src/lib/preflight_checks.ts +26 -26
- package/src/lib/publish_gate.ts +7 -9
- package/src/lib/publish_steps.ts +15 -15
- package/src/lib/publishing_event.ts +22 -20
- package/src/lib/publishing_event_handler.ts +8 -8
- package/src/lib/publishing_plan.ts +55 -55
- package/src/lib/publishing_plan_helpers.ts +16 -12
- package/src/lib/publishing_plan_logging.ts +22 -22
- package/src/lib/repo.svelte.ts +8 -8
- package/src/lib/repo_ops.ts +12 -12
- package/src/lib/resolved_gitops_config.ts +5 -5
- 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
|
|
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
|
};
|
package/src/lib/local_repo.ts
CHANGED
|
@@ -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);
|