@fuzdev/fuz_gitops 0.78.0 → 0.79.0
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 +91 -17
- package/dist/ModulesDetail.svelte +22 -27
- package/dist/ModulesDetail.svelte.d.ts.map +1 -1
- package/dist/ModulesNav.svelte +8 -5
- package/dist/ModulesNav.svelte.d.ts.map +1 -1
- package/dist/ModulesPage.svelte +3 -5
- package/dist/ModulesPage.svelte.d.ts.map +1 -1
- package/dist/PageFooter.svelte +2 -2
- package/dist/PageHeader.svelte +6 -6
- package/dist/PageHeader.svelte.d.ts +0 -3
- package/dist/PageHeader.svelte.d.ts.map +1 -1
- package/dist/PullRequestsDetail.svelte +29 -20
- package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
- package/dist/PullRequestsPage.svelte +4 -6
- package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
- package/dist/ReposTable.svelte +43 -55
- package/dist/ReposTable.svelte.d.ts.map +1 -1
- package/dist/ReposTree.svelte +9 -21
- package/dist/ReposTree.svelte.d.ts.map +1 -1
- package/dist/ReposTreeNav.svelte +9 -12
- package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
- package/dist/TablePage.svelte +3 -5
- package/dist/TablePage.svelte.d.ts.map +1 -1
- package/dist/TreeItemPage.svelte +3 -5
- package/dist/TreeItemPage.svelte.d.ts.map +1 -1
- package/dist/TreePage.svelte +3 -5
- 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/ci_reconcile.d.ts +6 -10
- package/dist/ci_reconcile.d.ts.map +1 -1
- package/dist/ci_reconcile.js +6 -8
- package/dist/dependency_graph.d.ts +26 -49
- package/dist/dependency_graph.d.ts.map +1 -1
- package/dist/dependency_graph.js +40 -83
- package/dist/dependency_updater.d.ts +1 -1
- package/dist/dependency_updater.d.ts.map +1 -1
- package/dist/dependency_updater.js +14 -9
- package/dist/fetch_repo_data.d.ts +34 -8
- package/dist/fetch_repo_data.d.ts.map +1 -1
- package/dist/fetch_repo_data.js +44 -22
- package/dist/fs_fetch_value_cache.d.ts +1 -1
- package/dist/fs_fetch_value_cache.d.ts.map +1 -1
- package/dist/fs_fetch_value_cache.js +3 -3
- package/dist/git_operations.d.ts +6 -49
- package/dist/git_operations.d.ts.map +1 -1
- package/dist/git_operations.js +13 -126
- package/dist/github.d.ts +17 -2
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +17 -8
- package/dist/github_helpers.d.ts.map +1 -1
- package/dist/github_helpers.js +3 -11
- package/dist/gitops_analyze.task.d.ts +24 -2
- package/dist/gitops_analyze.task.d.ts.map +1 -1
- package/dist/gitops_analyze.task.js +47 -34
- package/dist/gitops_config.d.ts +34 -79
- package/dist/gitops_config.d.ts.map +1 -1
- package/dist/gitops_config.js +76 -53
- package/dist/gitops_constants.d.ts +6 -4
- package/dist/gitops_constants.d.ts.map +1 -1
- package/dist/gitops_constants.js +6 -4
- package/dist/gitops_plan.task.d.ts +29 -3
- package/dist/gitops_plan.task.d.ts.map +1 -1
- package/dist/gitops_plan.task.js +83 -61
- package/dist/gitops_publish.task.d.ts +62 -2
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +193 -105
- package/dist/gitops_run.task.d.ts +74 -0
- package/dist/gitops_run.task.d.ts.map +1 -1
- package/dist/gitops_run.task.js +176 -162
- package/dist/gitops_sync.task.d.ts +65 -3
- package/dist/gitops_sync.task.d.ts.map +1 -1
- package/dist/gitops_sync.task.js +163 -37
- package/dist/gitops_task_helpers.d.ts +86 -59
- package/dist/gitops_task_helpers.d.ts.map +1 -1
- package/dist/gitops_task_helpers.js +120 -79
- package/dist/gitops_validate.task.d.ts +1 -2
- package/dist/gitops_validate.task.d.ts.map +1 -1
- package/dist/gitops_validate.task.js +25 -32
- package/dist/graph_validation.d.ts +16 -27
- package/dist/graph_validation.d.ts.map +1 -1
- package/dist/graph_validation.js +24 -65
- package/dist/local_repo.d.ts +50 -62
- package/dist/local_repo.d.ts.map +1 -1
- package/dist/local_repo.js +83 -196
- package/dist/log_helpers.d.ts +8 -8
- package/dist/log_helpers.d.ts.map +1 -1
- package/dist/multi_repo_publisher.d.ts +10 -0
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +125 -61
- package/dist/npm_registry.d.ts +23 -19
- package/dist/npm_registry.d.ts.map +1 -1
- package/dist/npm_registry.js +21 -48
- package/dist/operations.d.ts +75 -180
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +15 -7
- package/dist/operations_defaults.d.ts +17 -2
- package/dist/operations_defaults.d.ts.map +1 -1
- package/dist/operations_defaults.js +111 -128
- package/dist/output_helpers.d.ts +36 -0
- package/dist/output_helpers.d.ts.map +1 -1
- package/dist/output_helpers.js +37 -3
- package/dist/preflight_checks.d.ts +20 -27
- package/dist/preflight_checks.d.ts.map +1 -1
- package/dist/preflight_checks.js +37 -126
- package/dist/publish_gate.d.ts.map +1 -1
- package/dist/publish_steps.d.ts +2 -4
- package/dist/publish_steps.d.ts.map +1 -1
- package/dist/publish_steps.js +4 -8
- package/dist/publishing_event.d.ts +2 -8
- package/dist/publishing_event.d.ts.map +1 -1
- package/dist/publishing_event.js +20 -17
- package/dist/publishing_event_handler.d.ts +10 -8
- package/dist/publishing_event_handler.d.ts.map +1 -1
- package/dist/publishing_event_handler.js +19 -17
- package/dist/publishing_plan.d.ts +16 -1
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +332 -254
- 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 +1 -1
- package/dist/publishing_plan_logging.d.ts.map +1 -1
- package/dist/publishing_plan_logging.js +22 -15
- package/dist/repo.svelte.d.ts +7 -0
- package/dist/repo.svelte.d.ts.map +1 -1
- package/dist/repo.svelte.js +3 -0
- package/dist/repo_readiness.d.ts +210 -0
- package/dist/repo_readiness.d.ts.map +1 -0
- package/dist/repo_readiness.js +516 -0
- package/dist/repos_status.d.ts +3340 -0
- package/dist/repos_status.d.ts.map +1 -0
- package/dist/repos_status.js +555 -0
- package/dist/repos_status_load.d.ts +65 -0
- package/dist/repos_status_load.d.ts.map +1 -0
- package/dist/repos_status_load.js +131 -0
- package/dist/version_utils.js +1 -1
- package/package.json +15 -34
- 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 +12 -16
- package/src/lib/dependency_graph.ts +61 -113
- package/src/lib/dependency_updater.ts +36 -30
- package/src/lib/fetch_repo_data.ts +71 -34
- package/src/lib/fs_fetch_value_cache.ts +15 -11
- package/src/lib/git_operations.ts +22 -194
- package/src/lib/github.ts +33 -21
- package/src/lib/github_helpers.ts +9 -16
- package/src/lib/gitops_analyze.task.ts +104 -66
- package/src/lib/gitops_config.ts +90 -139
- package/src/lib/gitops_constants.ts +6 -4
- package/src/lib/gitops_plan.task.ts +128 -76
- package/src/lib/gitops_publish.task.ts +280 -144
- package/src/lib/gitops_run.task.ts +265 -193
- package/src/lib/gitops_sync.task.ts +236 -52
- package/src/lib/gitops_task_helpers.ts +170 -114
- package/src/lib/gitops_validate.task.ts +44 -54
- package/src/lib/graph_validation.ts +28 -89
- package/src/lib/local_repo.ts +128 -335
- package/src/lib/log_helpers.ts +18 -28
- package/src/lib/multi_repo_publisher.ts +192 -110
- package/src/lib/npm_registry.ts +42 -67
- package/src/lib/operations.ts +99 -160
- package/src/lib/operations_defaults.ts +157 -201
- package/src/lib/output_helpers.ts +58 -6
- package/src/lib/preflight_checks.ts +52 -188
- package/src/lib/publish_gate.ts +7 -9
- package/src/lib/publish_steps.ts +27 -25
- package/src/lib/publishing_event.ts +26 -23
- package/src/lib/publishing_event_handler.ts +24 -22
- package/src/lib/publishing_plan.ts +474 -310
- package/src/lib/publishing_plan_helpers.ts +16 -12
- package/src/lib/publishing_plan_logging.ts +53 -44
- package/src/lib/repo.svelte.ts +16 -8
- package/src/lib/repo_readiness.ts +647 -0
- package/src/lib/repos_status.ts +671 -0
- package/src/lib/repos_status_load.ts +173 -0
- package/src/lib/version_utils.ts +3 -3
- package/dist/config_reconcile.d.ts +0 -46
- package/dist/config_reconcile.d.ts.map +0 -1
- package/dist/config_reconcile.js +0 -60
- package/dist/paths.d.ts +0 -7
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js +0 -6
- package/dist/repo_ops.d.ts +0 -59
- package/dist/repo_ops.d.ts.map +0 -1
- package/dist/repo_ops.js +0 -170
- package/dist/resolved_gitops_config.d.ts +0 -9
- package/dist/resolved_gitops_config.d.ts.map +0 -1
- package/dist/resolved_gitops_config.js +0 -12
- package/src/lib/config_reconcile.ts +0 -94
- package/src/lib/paths.ts +0 -6
- package/src/lib/repo_ops.ts +0 -216
- package/src/lib/resolved_gitops_config.ts +0 -27
package/dist/gitops_run.task.js
CHANGED
|
@@ -2,11 +2,14 @@ import { TaskError } from '@fuzdev/gro';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { map_concurrent_settled } from '@fuzdev/fuz_util/async.ts';
|
|
4
4
|
import { spawn_out } from '@fuzdev/fuz_util/process.ts';
|
|
5
|
+
import { to_error_message } from '@fuzdev/fuz_util/error.ts';
|
|
5
6
|
import { writeFile } from 'node:fs/promises';
|
|
6
7
|
import { styleText as st } from 'node:util';
|
|
7
|
-
import {
|
|
8
|
-
import { get_repo_paths } from './repo_ops.js';
|
|
8
|
+
import { resolve_gitops_repos } from './gitops_task_helpers.js';
|
|
9
9
|
import { GITOPS_CONCURRENCY_DEFAULT, GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.js';
|
|
10
|
+
import { default_repos_operations } from './operations_defaults.js';
|
|
11
|
+
import { output_is_machine, route_human_output } from './output_helpers.js';
|
|
12
|
+
/** @nodocs */
|
|
10
13
|
export const Args = z.strictObject({
|
|
11
14
|
// Positional rest args (gro convention) so `gro gitops_run "npm test"` works;
|
|
12
15
|
// joined with spaces and passed to `sh -c`, so quote commands that contain flags.
|
|
@@ -15,6 +18,12 @@ export const Args = z.strictObject({
|
|
|
15
18
|
.string()
|
|
16
19
|
.meta({ description: 'path to the gitops config file' })
|
|
17
20
|
.default(GITOPS_CONFIG_PATH_DEFAULT),
|
|
21
|
+
registry: z
|
|
22
|
+
.string()
|
|
23
|
+
.meta({
|
|
24
|
+
description: 'path to the repos.toml registry, when `repos` would not find it walking up from the cwd'
|
|
25
|
+
})
|
|
26
|
+
.optional(),
|
|
18
27
|
concurrency: z
|
|
19
28
|
.number()
|
|
20
29
|
.int()
|
|
@@ -25,182 +34,187 @@ export const Args = z.strictObject({
|
|
|
25
34
|
outfile: z
|
|
26
35
|
.string()
|
|
27
36
|
.meta({ description: 'with --format json, write clean JSON to this file instead of stdout' })
|
|
28
|
-
.optional()
|
|
37
|
+
.optional()
|
|
29
38
|
});
|
|
39
|
+
const default_gitops_run_deps = {
|
|
40
|
+
repos_ops: default_repos_operations,
|
|
41
|
+
run_command: async ({ command, cwd }) => {
|
|
42
|
+
// through a shell, so pipes, redirects, and globs work
|
|
43
|
+
const { result, stdout, stderr } = await spawn_out('sh', ['-c', command], { cwd });
|
|
44
|
+
const outcome = result.kind === 'exited'
|
|
45
|
+
? { kind: 'exited', code: result.code }
|
|
46
|
+
: result.kind === 'signaled'
|
|
47
|
+
? { kind: 'signaled', signal: result.signal }
|
|
48
|
+
: { kind: 'error', message: to_error_message(result.error) };
|
|
49
|
+
return { outcome, stdout: stdout ?? '', stderr: stderr ?? '' };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/** @nodocs */
|
|
30
53
|
export const task = {
|
|
31
54
|
Args,
|
|
32
55
|
summary: 'run a shell command across all repos in parallel',
|
|
33
56
|
run: async ({ args, log }) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
57
|
+
await run_gitops_run(args, log);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Runs `gro gitops_run`: resolves the config's repos through `repos status`,
|
|
62
|
+
* refusing a missing one, runs the command in each, `concurrency` at a time,
|
|
63
|
+
* and reports every result. Under `--format json` without `--outfile`, the log
|
|
64
|
+
* goes to stderr and stdout carries the JSON alone (`route_human_output`).
|
|
65
|
+
*
|
|
66
|
+
* @throws {TaskError} when no command is given, resolving the repos fails, or the command fails in any repo (after reporting)
|
|
67
|
+
* @nodocs
|
|
68
|
+
*/
|
|
69
|
+
export const run_gitops_run = async (args, log, deps = {}) => {
|
|
70
|
+
const { repos_ops, run_command } = { ...default_gitops_run_deps, ...deps };
|
|
71
|
+
const { _, config, registry, concurrency, format, outfile } = args;
|
|
72
|
+
const write_stdout = route_human_output(log, output_is_machine(format, outfile));
|
|
73
|
+
const command = _.join(' ').trim();
|
|
74
|
+
if (!command) {
|
|
75
|
+
throw new TaskError('No command provided, e.g. `gro gitops_run "npm test"`');
|
|
76
|
+
}
|
|
77
|
+
// Resolve repo paths through `repos status` (no library-metadata loading needed);
|
|
78
|
+
// a configured repo that's missing or not a repo fails the run, naming it
|
|
79
|
+
const { local_repo_paths: repos } = await resolve_gitops_repos({
|
|
80
|
+
config,
|
|
81
|
+
registry,
|
|
82
|
+
log,
|
|
83
|
+
repos_ops
|
|
84
|
+
});
|
|
85
|
+
log.info(`Running ${st('cyan', command)} across ${repos.length} repos (concurrency: ${concurrency})`);
|
|
86
|
+
const start_time = performance.now();
|
|
87
|
+
const settled = await map_concurrent_settled(repos, concurrency, async ({ repo_name, repo_dir }) => {
|
|
88
|
+
const repo_start = performance.now();
|
|
89
|
+
const { outcome, stdout, stderr } = await run_command({ command, cwd: repo_dir });
|
|
90
|
+
return {
|
|
91
|
+
repo_name,
|
|
92
|
+
repo_dir,
|
|
93
|
+
status: outcome.kind === 'exited' && outcome.code === 0 ? 'success' : 'failure',
|
|
94
|
+
exit_code: outcome.kind === 'exited' ? outcome.code : null,
|
|
95
|
+
signal: outcome.kind === 'signaled' ? outcome.signal : null,
|
|
96
|
+
stdout,
|
|
97
|
+
stderr,
|
|
98
|
+
duration_ms: performance.now() - repo_start,
|
|
99
|
+
...(outcome.kind === 'error' && { error: outcome.message })
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
const total_duration_ms = performance.now() - start_time;
|
|
103
|
+
// Process results; a rejection is `run_command` throwing, which the default never does
|
|
104
|
+
const successes = [];
|
|
105
|
+
const failures = [];
|
|
106
|
+
settled.forEach((result, i) => {
|
|
107
|
+
if (result.status === 'fulfilled') {
|
|
108
|
+
(result.value.status === 'success' ? successes : failures).push(result.value);
|
|
38
109
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
110
|
+
else {
|
|
111
|
+
const { repo_name, repo_dir } = repos[i];
|
|
112
|
+
failures.push({
|
|
113
|
+
repo_name,
|
|
114
|
+
repo_dir,
|
|
115
|
+
status: 'failure',
|
|
116
|
+
exit_code: null,
|
|
117
|
+
signal: null,
|
|
118
|
+
stdout: '',
|
|
119
|
+
stderr: '',
|
|
120
|
+
duration_ms: 0,
|
|
121
|
+
error: to_error_message(result.reason)
|
|
122
|
+
});
|
|
44
123
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
});
|
|
58
|
-
const duration_ms = performance.now() - repo_start;
|
|
59
|
-
const success = spawned.result.ok;
|
|
60
|
-
const result = {
|
|
61
|
-
repo_name,
|
|
62
|
-
repo_dir,
|
|
63
|
-
status: success ? 'success' : 'failure',
|
|
64
|
-
exit_code: spawned.result.kind === 'exited' ? spawned.result.code : 0,
|
|
65
|
-
stdout: spawned.stdout || '',
|
|
66
|
-
stderr: spawned.stderr || '',
|
|
67
|
-
duration_ms,
|
|
68
|
-
};
|
|
69
|
-
return result;
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
const duration_ms = performance.now() - repo_start;
|
|
73
|
-
return {
|
|
74
|
-
repo_name,
|
|
75
|
-
repo_dir,
|
|
76
|
-
status: 'failure',
|
|
77
|
-
exit_code: -1,
|
|
78
|
-
stdout: '',
|
|
79
|
-
stderr: '',
|
|
80
|
-
duration_ms,
|
|
81
|
-
error: String(error),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
const total_duration_ms = performance.now() - start_time;
|
|
86
|
-
// Process results
|
|
87
|
-
const successes = [];
|
|
88
|
-
const failures = [];
|
|
89
|
-
for (const result of results) {
|
|
90
|
-
if (result.status === 'fulfilled') {
|
|
91
|
-
const run_result = result.value;
|
|
92
|
-
if (run_result.status === 'success') {
|
|
93
|
-
successes.push(run_result);
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
failures.push(run_result);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
// This shouldn't happen since we catch errors in the task fn
|
|
101
|
-
// but handle it anyway
|
|
102
|
-
failures.push({
|
|
103
|
-
repo_name: 'unknown',
|
|
104
|
-
repo_dir: 'unknown',
|
|
105
|
-
status: 'failure',
|
|
106
|
-
exit_code: -1,
|
|
107
|
-
stdout: '',
|
|
108
|
-
stderr: '',
|
|
109
|
-
duration_ms: 0,
|
|
110
|
-
error: String(result.reason),
|
|
111
|
-
});
|
|
124
|
+
});
|
|
125
|
+
// Output results based on format
|
|
126
|
+
if (format === 'json') {
|
|
127
|
+
const json_output = {
|
|
128
|
+
command,
|
|
129
|
+
concurrency,
|
|
130
|
+
repos: [...successes, ...failures],
|
|
131
|
+
summary: {
|
|
132
|
+
total: repos.length,
|
|
133
|
+
success: successes.length,
|
|
134
|
+
failure: failures.length,
|
|
135
|
+
duration_ms: Math.round(total_duration_ms)
|
|
112
136
|
}
|
|
137
|
+
};
|
|
138
|
+
const json = JSON.stringify(json_output, null, 2);
|
|
139
|
+
if (outfile) {
|
|
140
|
+
// Clean machine-readable output, free of gro's logging prefixes.
|
|
141
|
+
await writeFile(outfile, json);
|
|
142
|
+
log.info(`wrote JSON output to ${outfile}`);
|
|
113
143
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
144
|
+
else {
|
|
145
|
+
write_stdout(json);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
log_text_results({ successes, failures, total: repos.length, total_duration_ms }, log);
|
|
150
|
+
}
|
|
151
|
+
// Exit with error if any failures (so CI fails)
|
|
152
|
+
if (failures.length > 0) {
|
|
153
|
+
throw new TaskError(`${failures.length} repos failed`);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const log_text_results = (data, log) => {
|
|
157
|
+
const { successes, failures, total, total_duration_ms } = data;
|
|
158
|
+
log.info(''); // blank line
|
|
159
|
+
// Show successes, including the command's output so read-only commands
|
|
160
|
+
// (`git rev-parse`, `cat package.json`, …) are useful without `--format json`.
|
|
161
|
+
if (successes.length > 0) {
|
|
162
|
+
log.info(st('green', `✓ ${successes.length} succeeded:`));
|
|
163
|
+
for (const result of successes) {
|
|
164
|
+
const duration = st('blue', `(${Math.round(result.duration_ms)}ms)`);
|
|
165
|
+
const label = st('gray', ` ${result.repo_name}`);
|
|
166
|
+
const out = result.stdout.trim();
|
|
167
|
+
const out_lines = out ? out.split('\n') : [];
|
|
168
|
+
if (out_lines.length <= 1) {
|
|
169
|
+
// single-line (or empty) output inline after the repo name
|
|
170
|
+
log.info(out ? `${label} ${out} ${duration}` : `${label} ${duration}`);
|
|
132
171
|
}
|
|
133
172
|
else {
|
|
134
|
-
//
|
|
135
|
-
|
|
173
|
+
// multi-line output indented under the repo
|
|
174
|
+
log.info(`${label} ${duration}`);
|
|
175
|
+
for (const line of out_lines) {
|
|
176
|
+
log.info(st('gray', ` ${line}`));
|
|
177
|
+
}
|
|
136
178
|
}
|
|
137
179
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const out = result.stdout.trim();
|
|
149
|
-
const out_lines = out ? out.split('\n') : [];
|
|
150
|
-
if (out_lines.length <= 1) {
|
|
151
|
-
// single-line (or empty) output inline after the repo name
|
|
152
|
-
log.info(out ? `${label} ${out} ${duration}` : `${label} ${duration}`);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
// multi-line output indented under the repo
|
|
156
|
-
log.info(`${label} ${duration}`);
|
|
157
|
-
for (const line of out_lines) {
|
|
158
|
-
log.info(st('gray', ` ${line}`));
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
180
|
+
}
|
|
181
|
+
// Show failures with details
|
|
182
|
+
if (failures.length > 0) {
|
|
183
|
+
log.info(''); // blank line
|
|
184
|
+
log.error(st('red', `✗ ${failures.length} failed:`));
|
|
185
|
+
for (const result of failures) {
|
|
186
|
+
const duration = `${Math.round(result.duration_ms)}ms`;
|
|
187
|
+
log.error(st('gray', ` ${result.repo_name} ${st('blue', `(${duration})`)}`));
|
|
188
|
+
if (result.error) {
|
|
189
|
+
log.error(st('gray', ` Error: ${result.error}`));
|
|
162
190
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
log.info(''); // blank line
|
|
166
|
-
log.error(st('red', `✗ ${failures.length} failed:`));
|
|
167
|
-
for (const result of failures) {
|
|
168
|
-
const duration = `${Math.round(result.duration_ms)}ms`;
|
|
169
|
-
log.error(st('gray', ` ${result.repo_name} ${st('blue', `(${duration})`)}`));
|
|
170
|
-
if (result.error) {
|
|
171
|
-
log.error(st('gray', ` Error: ${result.error}`));
|
|
172
|
-
}
|
|
173
|
-
else if (result.exit_code !== 0) {
|
|
174
|
-
log.error(st('gray', ` Exit code: ${result.exit_code}`));
|
|
175
|
-
}
|
|
176
|
-
if (result.stderr) {
|
|
177
|
-
// Show first few lines of stderr
|
|
178
|
-
const stderr_lines = result.stderr.trim().split('\n');
|
|
179
|
-
const preview_lines = stderr_lines.slice(0, 3);
|
|
180
|
-
for (const line of preview_lines) {
|
|
181
|
-
log.error(st('gray', ` ${line}`));
|
|
182
|
-
}
|
|
183
|
-
if (stderr_lines.length > 3) {
|
|
184
|
-
log.error(st('gray', ` ... (${stderr_lines.length - 3} more lines)`));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
191
|
+
else if (result.signal) {
|
|
192
|
+
log.error(st('gray', ` Killed by ${result.signal}`));
|
|
188
193
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const total = repos.length;
|
|
192
|
-
const success_rate = ((successes.length / total) * 100).toFixed(0);
|
|
193
|
-
const duration = `${Math.round(total_duration_ms)}ms`;
|
|
194
|
-
if (failures.length === 0) {
|
|
195
|
-
log.info(st('green', `✓ All ${total} repos succeeded in ${duration} (${success_rate}% success rate)`));
|
|
194
|
+
else if (result.exit_code !== null) {
|
|
195
|
+
log.error(st('gray', ` Exit code: ${result.exit_code}`));
|
|
196
196
|
}
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
if (result.stderr) {
|
|
198
|
+
// Show first few lines of stderr
|
|
199
|
+
const stderr_lines = result.stderr.trim().split('\n');
|
|
200
|
+
const preview_lines = stderr_lines.slice(0, 3);
|
|
201
|
+
for (const line of preview_lines) {
|
|
202
|
+
log.error(st('gray', ` ${line}`));
|
|
203
|
+
}
|
|
204
|
+
if (stderr_lines.length > 3) {
|
|
205
|
+
log.error(st('gray', ` ... (${stderr_lines.length - 3} more lines)`));
|
|
206
|
+
}
|
|
199
207
|
}
|
|
200
208
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
209
|
+
}
|
|
210
|
+
// Summary
|
|
211
|
+
log.info(''); // blank line
|
|
212
|
+
const success_rate = ((successes.length / total) * 100).toFixed(0);
|
|
213
|
+
const duration = `${Math.round(total_duration_ms)}ms`;
|
|
214
|
+
if (failures.length === 0) {
|
|
215
|
+
log.info(st('green', `✓ All ${total} repos succeeded in ${duration} (${success_rate}% success rate)`));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
log.info(st('yellow', `⚠ ${successes.length}/${total} repos succeeded in ${duration} (${success_rate}% success rate)`));
|
|
219
|
+
}
|
|
206
220
|
};
|
|
@@ -1,19 +1,81 @@
|
|
|
1
1
|
import { type Task } from '@fuzdev/gro';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
4
|
+
import { type LocalRepo, type LocalRepoPath } from './local_repo.js';
|
|
5
|
+
import type { ReposOperations } from './operations.js';
|
|
3
6
|
/** @nodocs */
|
|
4
7
|
export declare const Args: z.ZodObject<{
|
|
5
8
|
config: z.ZodDefault<z.ZodString>;
|
|
6
|
-
|
|
9
|
+
registry: z.ZodOptional<z.ZodString>;
|
|
7
10
|
outdir: z.ZodOptional<z.ZodString>;
|
|
8
|
-
download: z.ZodDefault<z.ZodBoolean>;
|
|
9
11
|
check: z.ZodDefault<z.ZodBoolean>;
|
|
10
12
|
allow_dirty: z.ZodDefault<z.ZodBoolean>;
|
|
11
13
|
}, z.core.$strict>;
|
|
12
14
|
export type Args = z.infer<typeof Args>;
|
|
13
15
|
/**
|
|
14
|
-
*
|
|
16
|
+
* Generates the dashboard's site data (`repos.json` and `repos.ts`) from each
|
|
17
|
+
* configured repo's working tree and its GitHub CI status and pull requests.
|
|
18
|
+
* It never moves a repo: see `prepare_gitops_sync` for what it reads and
|
|
19
|
+
* refuses. This is a task not a `.gen.` file because it makes network calls.
|
|
15
20
|
*
|
|
16
21
|
* @nodocs
|
|
17
22
|
*/
|
|
18
23
|
export declare const task: Task<Args>;
|
|
24
|
+
/**
|
|
25
|
+
* The side effects `prepare_gitops_sync` reaches through, injectable for tests.
|
|
26
|
+
*
|
|
27
|
+
* @nodocs
|
|
28
|
+
*/
|
|
29
|
+
export interface GitopsSyncDeps {
|
|
30
|
+
/** Runs `repos status`. */
|
|
31
|
+
repos_ops: ReposOperations;
|
|
32
|
+
/** Loads each resolved repo's library as it sits (`local_repos_load`). */
|
|
33
|
+
load_repos: (options: {
|
|
34
|
+
local_repo_paths: Array<LocalRepoPath>;
|
|
35
|
+
log?: Logger;
|
|
36
|
+
}) => Promise<Array<LocalRepo>>;
|
|
37
|
+
/** Reads `SECRET_GITHUB_API_TOKEN`; `undefined` when it isn't set. */
|
|
38
|
+
load_token: () => string | undefined;
|
|
39
|
+
/** Whether a path exists, for the analysis-setup warning. */
|
|
40
|
+
exists: (path: string) => boolean;
|
|
41
|
+
/** Reads a file as UTF-8, for the analysis-setup warning. */
|
|
42
|
+
read_file: (path: string) => string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Everything `gitops_sync` does before it fetches from GitHub, in order:
|
|
46
|
+
*
|
|
47
|
+
* 1. resolves the config's repos from `repos status <keys…> --json` (local
|
|
48
|
+
* refs), refusing a private repo when the host package is public
|
|
49
|
+
* 2. checks each repo is ready to generate from (`check_gen_readiness`): on
|
|
50
|
+
* its registry branch, clean, and idle, unless `allow_dirty` — refusing
|
|
51
|
+
* before any network. With `check`, that report is the whole run: its
|
|
52
|
+
* warnings are logged, and it throws when a real run would refuse
|
|
53
|
+
* 3. reads `SECRET_GITHUB_API_TOKEN`
|
|
54
|
+
* 4. fetches the repos from origin (`repos status <keys…> --fetch --json`,
|
|
55
|
+
* which writes remote-tracking refs and nothing else) and checks them
|
|
56
|
+
* again, warning on a followed branch not in sync with origin and a
|
|
57
|
+
* failed fetch
|
|
58
|
+
* 5. warns on each npm repo the library analysis can't fully read: no
|
|
59
|
+
* `node_modules`, or no `.svelte-kit/tsconfig.json` when its tsconfig
|
|
60
|
+
* extends it (external types then read as `any`) — it installs nothing
|
|
61
|
+
* 6. loads each repo's library as it sits
|
|
62
|
+
*
|
|
63
|
+
* @returns the loaded repos and the token, or `null` when `check` passed
|
|
64
|
+
* @throws {TaskError} if resolving fails, a repo isn't ready, or the token is missing
|
|
65
|
+
* @nodocs
|
|
66
|
+
*/
|
|
67
|
+
export declare const prepare_gitops_sync: (options: {
|
|
68
|
+
config: string;
|
|
69
|
+
registry?: string;
|
|
70
|
+
host?: {
|
|
71
|
+
name: string;
|
|
72
|
+
private: boolean;
|
|
73
|
+
};
|
|
74
|
+
check?: boolean;
|
|
75
|
+
allow_dirty?: boolean;
|
|
76
|
+
log: Logger;
|
|
77
|
+
}, deps?: Partial<GitopsSyncDeps>) => Promise<{
|
|
78
|
+
local_repos: Array<LocalRepo>;
|
|
79
|
+
token: string;
|
|
80
|
+
} | null>;
|
|
19
81
|
//# sourceMappingURL=gitops_sync.task.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_sync.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_sync.task.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"gitops_sync.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_sync.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAOtD,OAAO,EAGN,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKvD,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;kBA8Bf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CA8F3B,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,2BAA2B;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,0EAA0E;IAC1E,UAAU,EAAE,CAAC,OAAO,EAAE;QACrB,gBAAgB,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACvC,GAAG,CAAC,EAAE,MAAM,CAAC;KACb,KAAK,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IAChC,sEAAsE;IACtE,UAAU,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACrC,6DAA6D;IAC7D,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,6DAA6D;IAC7D,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC;AAWD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,mBAAmB,GAC/B,SAAS;IACR,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACZ,EACD,OAAM,OAAO,CAAC,cAAc,CAAM,KAChC,OAAO,CAAC;IAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAmEjE,CAAC"}
|