@fuzdev/fuz_gitops 0.72.0 → 0.74.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 +15 -8
- package/dist/PageHeader.svelte +3 -3
- package/dist/PageHeader.svelte.d.ts +3 -3
- package/dist/PageHeader.svelte.d.ts.map +1 -1
- package/dist/changeset_generator.d.ts.map +1 -1
- package/dist/changeset_generator.js +2 -16
- package/dist/changeset_reader.d.ts +1 -1
- package/dist/changeset_reader.d.ts.map +1 -1
- package/dist/changeset_reader.js +1 -1
- package/dist/dependency_graph.d.ts.map +1 -1
- package/dist/dependency_graph.js +6 -6
- package/dist/fetch_repo_data.d.ts.map +1 -1
- package/dist/fetch_repo_data.js +3 -2
- package/dist/git_operations.d.ts +5 -0
- package/dist/git_operations.d.ts.map +1 -1
- package/dist/git_operations.js +5 -0
- package/dist/gitops_analyze.task.d.ts +1 -0
- package/dist/gitops_analyze.task.d.ts.map +1 -1
- package/dist/gitops_analyze.task.js +12 -17
- package/dist/gitops_plan.task.d.ts +1 -0
- package/dist/gitops_plan.task.d.ts.map +1 -1
- package/dist/gitops_plan.task.js +9 -2
- package/dist/gitops_publish.task.d.ts +2 -2
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +83 -28
- package/dist/gitops_run.task.d.ts +2 -1
- package/dist/gitops_run.task.d.ts.map +1 -1
- package/dist/gitops_run.task.js +40 -7
- package/dist/gitops_sync.task.d.ts +1 -0
- package/dist/gitops_sync.task.d.ts.map +1 -1
- package/dist/gitops_sync.task.js +16 -2
- package/dist/gitops_task_helpers.d.ts +16 -2
- package/dist/gitops_task_helpers.d.ts.map +1 -1
- package/dist/gitops_task_helpers.js +11 -3
- package/dist/gitops_validate.task.d.ts +1 -0
- package/dist/gitops_validate.task.d.ts.map +1 -1
- package/dist/gitops_validate.task.js +20 -20
- package/dist/graph_validation.d.ts +16 -1
- package/dist/graph_validation.d.ts.map +1 -1
- package/dist/graph_validation.js +15 -0
- package/dist/local_repo.d.ts +25 -12
- package/dist/local_repo.d.ts.map +1 -1
- package/dist/local_repo.js +99 -79
- package/dist/log_helpers.d.ts +0 -5
- package/dist/log_helpers.d.ts.map +1 -1
- package/dist/log_helpers.js +8 -19
- package/dist/multi_repo_publisher.d.ts +21 -2
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +279 -287
- package/dist/operations.d.ts +6 -26
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations_defaults.d.ts.map +1 -1
- package/dist/operations_defaults.js +4 -20
- package/dist/output_helpers.d.ts.map +1 -1
- package/dist/output_helpers.js +7 -6
- package/dist/paths.d.ts +0 -4
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +0 -4
- package/dist/publish_gate.d.ts +44 -0
- package/dist/publish_gate.d.ts.map +1 -0
- package/dist/publish_gate.js +32 -0
- package/dist/publish_steps.d.ts +60 -0
- package/dist/publish_steps.d.ts.map +1 -0
- package/dist/publish_steps.js +113 -0
- package/dist/publishing_event.d.ts +12 -19
- package/dist/publishing_event.d.ts.map +1 -1
- package/dist/publishing_event.js +16 -25
- package/dist/publishing_plan.d.ts +1 -2
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +21 -4
- package/dist/publishing_plan_helpers.d.ts +1 -1
- package/dist/publishing_plan_helpers.d.ts.map +1 -1
- package/dist/publishing_plan_helpers.js +2 -15
- package/dist/publishing_plan_logging.d.ts.map +1 -1
- package/dist/publishing_plan_logging.js +15 -23
- package/dist/repo.svelte.d.ts +10 -6
- package/dist/repo.svelte.d.ts.map +1 -1
- package/dist/repo.svelte.js +6 -14
- package/dist/version_utils.d.ts +17 -3
- package/dist/version_utils.d.ts.map +1 -1
- package/dist/version_utils.js +22 -0
- package/package.json +14 -15
- package/src/lib/changeset_generator.ts +10 -19
- package/src/lib/changeset_reader.ts +2 -3
- package/src/lib/dependency_graph.ts +6 -8
- package/src/lib/fetch_repo_data.ts +3 -2
- package/src/lib/git_operations.ts +5 -0
- package/src/lib/gitops_analyze.task.ts +18 -23
- package/src/lib/gitops_plan.task.ts +10 -2
- package/src/lib/gitops_publish.task.ts +92 -27
- package/src/lib/gitops_run.task.ts +39 -7
- package/src/lib/gitops_sync.task.ts +18 -3
- package/src/lib/gitops_task_helpers.ts +20 -3
- package/src/lib/gitops_validate.task.ts +30 -22
- package/src/lib/graph_validation.ts +26 -0
- package/src/lib/local_repo.ts +124 -88
- package/src/lib/log_helpers.ts +8 -26
- package/src/lib/multi_repo_publisher.ts +336 -353
- package/src/lib/operations.ts +6 -22
- package/src/lib/operations_defaults.ts +4 -20
- package/src/lib/output_helpers.ts +7 -6
- package/src/lib/paths.ts +0 -5
- package/src/lib/publish_gate.ts +53 -0
- package/src/lib/publish_steps.ts +149 -0
- package/src/lib/publishing_event.ts +16 -25
- package/src/lib/publishing_plan.ts +26 -6
- package/src/lib/publishing_plan_helpers.ts +5 -18
- package/src/lib/publishing_plan_logging.ts +19 -39
- package/src/lib/repo.svelte.ts +12 -15
- package/src/lib/version_utils.ts +30 -9
- package/dist/npm_install_helpers.d.ts +0 -23
- package/dist/npm_install_helpers.d.ts.map +0 -1
- package/dist/npm_install_helpers.js +0 -60
- package/dist/semver.d.ts +0 -26
- package/dist/semver.d.ts.map +0 -1
- package/dist/semver.js +0 -137
- package/dist/serialization_types.d.ts +0 -59
- package/dist/serialization_types.d.ts.map +0 -1
- package/dist/serialization_types.js +0 -42
- package/src/lib/npm_install_helpers.ts +0 -85
- package/src/lib/semver.ts +0 -170
- package/src/lib/serialization_types.ts +0 -92
package/dist/gitops_run.task.js
CHANGED
|
@@ -2,12 +2,15 @@ import { TaskError } from '@fuzdev/gro';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { map_concurrent_settled } from '@fuzdev/fuz_util/async.js';
|
|
4
4
|
import { spawn_out } from '@fuzdev/fuz_util/process.js';
|
|
5
|
+
import { writeFile } from 'node:fs/promises';
|
|
5
6
|
import { styleText as st } from 'node:util';
|
|
6
7
|
import { resolve } from 'node:path';
|
|
7
8
|
import { get_repo_paths } from './repo_ops.js';
|
|
8
9
|
import { GITOPS_CONCURRENCY_DEFAULT, GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.js';
|
|
9
10
|
export const Args = z.strictObject({
|
|
10
|
-
|
|
11
|
+
// Positional rest args (gro convention) so `gro gitops_run "npm test"` works;
|
|
12
|
+
// joined with spaces and passed to `sh -c`, so quote commands that contain flags.
|
|
13
|
+
_: z.array(z.string()).meta({ description: 'shell command to run in each repo' }).default([]),
|
|
11
14
|
config: z
|
|
12
15
|
.string()
|
|
13
16
|
.meta({ description: 'path to the gitops config file' })
|
|
@@ -19,12 +22,20 @@ export const Args = z.strictObject({
|
|
|
19
22
|
.meta({ description: 'maximum number of repos to run in parallel' })
|
|
20
23
|
.default(GITOPS_CONCURRENCY_DEFAULT),
|
|
21
24
|
format: z.enum(['text', 'json']).meta({ description: 'output format' }).default('text'),
|
|
25
|
+
outfile: z
|
|
26
|
+
.string()
|
|
27
|
+
.meta({ description: 'with --format json, write clean JSON to this file instead of stdout' })
|
|
28
|
+
.optional(),
|
|
22
29
|
});
|
|
23
30
|
export const task = {
|
|
24
31
|
Args,
|
|
25
32
|
summary: 'run a shell command across all repos in parallel',
|
|
26
33
|
run: async ({ args, log }) => {
|
|
27
|
-
const {
|
|
34
|
+
const { _, config, concurrency, format, outfile } = args;
|
|
35
|
+
const command = _.join(' ').trim();
|
|
36
|
+
if (!command) {
|
|
37
|
+
throw new TaskError('No command provided, e.g. `gro gitops_run "npm test"`');
|
|
38
|
+
}
|
|
28
39
|
// Get repo paths (lightweight, no library-metadata loading needed)
|
|
29
40
|
const config_path = resolve(config);
|
|
30
41
|
const repos = await get_repo_paths(config_path);
|
|
@@ -113,18 +124,40 @@ export const task = {
|
|
|
113
124
|
duration_ms: Math.round(total_duration_ms),
|
|
114
125
|
},
|
|
115
126
|
};
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
const json = JSON.stringify(json_output, null, 2);
|
|
128
|
+
if (outfile) {
|
|
129
|
+
// Clean machine-readable output, free of gro's logging prefixes.
|
|
130
|
+
await writeFile(outfile, json);
|
|
131
|
+
log.info(`wrote JSON output to ${outfile}`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// eslint-disable-next-line no-console
|
|
135
|
+
console.log(json);
|
|
136
|
+
}
|
|
118
137
|
}
|
|
119
138
|
else {
|
|
120
139
|
// Text format
|
|
121
140
|
log.info(''); // blank line
|
|
122
|
-
// Show successes
|
|
141
|
+
// Show successes, including the command's output so read-only commands
|
|
142
|
+
// (`git rev-parse`, `cat package.json`, …) are useful without `--format json`.
|
|
123
143
|
if (successes.length > 0) {
|
|
124
144
|
log.info(st('green', `✓ ${successes.length} succeeded:`));
|
|
125
145
|
for (const result of successes) {
|
|
126
|
-
const duration =
|
|
127
|
-
|
|
146
|
+
const duration = st('blue', `(${Math.round(result.duration_ms)}ms)`);
|
|
147
|
+
const label = st('gray', ` ${result.repo_name}`);
|
|
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
|
+
}
|
|
128
161
|
}
|
|
129
162
|
}
|
|
130
163
|
// Show failures with details
|
|
@@ -7,6 +7,7 @@ export declare const Args: z.ZodObject<{
|
|
|
7
7
|
outdir: z.ZodOptional<z.ZodString>;
|
|
8
8
|
download: z.ZodDefault<z.ZodBoolean>;
|
|
9
9
|
check: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
allow_dirty: z.ZodDefault<z.ZodBoolean>;
|
|
10
11
|
}, z.core.$strict>;
|
|
11
12
|
export type Args = z.infer<typeof Args>;
|
|
12
13
|
/**
|
|
@@ -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,EAAY,KAAK,IAAI,EAAC,MAAM,aAAa,CAAC;AACjD,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAiBtB,cAAc;AACd,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"gitops_sync.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_sync.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,IAAI,EAAC,MAAM,aAAa,CAAC;AACjD,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAiBtB,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;;kBAyBf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CA6F3B,CAAC"}
|
package/dist/gitops_sync.task.js
CHANGED
|
@@ -32,6 +32,12 @@ export const Args = z.strictObject({
|
|
|
32
32
|
.boolean()
|
|
33
33
|
.meta({ description: 'check repos are ready without fetching remote data' })
|
|
34
34
|
.default(false),
|
|
35
|
+
allow_dirty: z
|
|
36
|
+
.boolean()
|
|
37
|
+
.meta({
|
|
38
|
+
description: 'sync (switch branch, pull) tolerating uncommitted changes instead of failing on a dirty workspace',
|
|
39
|
+
})
|
|
40
|
+
.default(false),
|
|
35
41
|
});
|
|
36
42
|
/**
|
|
37
43
|
* This is a task not a `.gen.` file because it makes network calls.
|
|
@@ -42,8 +48,16 @@ export const task = {
|
|
|
42
48
|
Args,
|
|
43
49
|
summary: 'syncs local repos and generates UI data from repo metadata',
|
|
44
50
|
run: async ({ args, log, svelte_config, invoke_task }) => {
|
|
45
|
-
const { config, dir, outdir = svelte_config.routes_path, download, check } = args;
|
|
46
|
-
|
|
51
|
+
const { config, dir, outdir = svelte_config.routes_path, download, check, allow_dirty } = args;
|
|
52
|
+
// `gitops_sync` is the task whose job is to mutate working trees, so it always syncs.
|
|
53
|
+
const { local_repos } = await get_gitops_ready({
|
|
54
|
+
config,
|
|
55
|
+
dir,
|
|
56
|
+
download,
|
|
57
|
+
sync: true,
|
|
58
|
+
allow_dirty,
|
|
59
|
+
log,
|
|
60
|
+
});
|
|
47
61
|
const outfile_json = resolve(outdir, 'repos.json');
|
|
48
62
|
const outfile_ts = resolve(outdir, 'repos.ts');
|
|
49
63
|
// This searches the parent directory for the env var, so we don't use SvelteKit's $env imports
|
|
@@ -28,6 +28,14 @@ export interface GetGitopsReadyOptions {
|
|
|
28
28
|
npm_ops?: NpmOperations;
|
|
29
29
|
parallel?: boolean;
|
|
30
30
|
concurrency?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Sync each repo's working tree to its configured branch before loading
|
|
33
|
+
* (switch branch, pull, install). When `false`, repos load exactly as they
|
|
34
|
+
* sit on disk — the safe default for read-only diagnostics. Defaults to `true`.
|
|
35
|
+
*/
|
|
36
|
+
sync?: boolean;
|
|
37
|
+
/** When syncing, tolerate uncommitted changes instead of throwing. Defaults to `false`. */
|
|
38
|
+
allow_dirty?: boolean;
|
|
31
39
|
}
|
|
32
40
|
/**
|
|
33
41
|
* Central initialization function for all gitops tasks.
|
|
@@ -35,8 +43,12 @@ export interface GetGitopsReadyOptions {
|
|
|
35
43
|
* Initialization sequence:
|
|
36
44
|
* 1. Loads and normalizes config from `gitops.config.ts`
|
|
37
45
|
* 2. Resolves local repo paths (creates missing with `--download`)
|
|
38
|
-
* 3.
|
|
39
|
-
* 4.
|
|
46
|
+
* 3. If `sync`, switches branches and pulls latest changes (in parallel by default)
|
|
47
|
+
* 4. If `sync`, auto-installs deps if `package.json` changed during pull
|
|
48
|
+
*
|
|
49
|
+
* With `sync: false` (the default for read-only diagnostics), steps 3-4 are
|
|
50
|
+
* skipped and repos are loaded exactly as checked out — no branch switch, pull,
|
|
51
|
+
* install, or clean-workspace check.
|
|
40
52
|
*
|
|
41
53
|
* Priority for path resolution:
|
|
42
54
|
* - `dir` argument (explicit override)
|
|
@@ -47,6 +59,8 @@ export interface GetGitopsReadyOptions {
|
|
|
47
59
|
* @param options.npm_ops - for testing (defaults to real npm operations)
|
|
48
60
|
* @param options.parallel - whether to load repos in parallel (default: true)
|
|
49
61
|
* @param options.concurrency - max concurrent repo loads (default: 5)
|
|
62
|
+
* @param options.sync - sync working trees before loading (default: true)
|
|
63
|
+
* @param options.allow_dirty - when syncing, tolerate uncommitted changes (default: false)
|
|
50
64
|
* @returns initialized config and fully loaded repos ready for operations
|
|
51
65
|
* @throws {TaskError} if config loading or repo resolution fails
|
|
52
66
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_task_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_task_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAqB,KAAK,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAuC,KAAK,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAGrF,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"gitops_task_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_task_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAqB,KAAK,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAuC,KAAK,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAGrF,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2FAA2F;IAC3F,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,gBAAgB,GAC5B,SAAS,qBAAqB,KAC5B,OAAO,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,YAAY,CAAC;IAC5B,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC9B,CAwCA,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,oBAAoB,GAChC,SAAS,yBAAyB,KAChC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAczC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,YAAY,CAMpF,CAAC"}
|
|
@@ -29,8 +29,12 @@ import { DEFAULT_REPOS_DIR } from './paths.js';
|
|
|
29
29
|
* Initialization sequence:
|
|
30
30
|
* 1. Loads and normalizes config from `gitops.config.ts`
|
|
31
31
|
* 2. Resolves local repo paths (creates missing with `--download`)
|
|
32
|
-
* 3.
|
|
33
|
-
* 4.
|
|
32
|
+
* 3. If `sync`, switches branches and pulls latest changes (in parallel by default)
|
|
33
|
+
* 4. If `sync`, auto-installs deps if `package.json` changed during pull
|
|
34
|
+
*
|
|
35
|
+
* With `sync: false` (the default for read-only diagnostics), steps 3-4 are
|
|
36
|
+
* skipped and repos are loaded exactly as checked out — no branch switch, pull,
|
|
37
|
+
* install, or clean-workspace check.
|
|
34
38
|
*
|
|
35
39
|
* Priority for path resolution:
|
|
36
40
|
* - `dir` argument (explicit override)
|
|
@@ -41,11 +45,13 @@ import { DEFAULT_REPOS_DIR } from './paths.js';
|
|
|
41
45
|
* @param options.npm_ops - for testing (defaults to real npm operations)
|
|
42
46
|
* @param options.parallel - whether to load repos in parallel (default: true)
|
|
43
47
|
* @param options.concurrency - max concurrent repo loads (default: 5)
|
|
48
|
+
* @param options.sync - sync working trees before loading (default: true)
|
|
49
|
+
* @param options.allow_dirty - when syncing, tolerate uncommitted changes (default: false)
|
|
44
50
|
* @returns initialized config and fully loaded repos ready for operations
|
|
45
51
|
* @throws {TaskError} if config loading or repo resolution fails
|
|
46
52
|
*/
|
|
47
53
|
export const get_gitops_ready = async (options) => {
|
|
48
|
-
const { config, dir, download, log, git_ops, npm_ops, parallel, concurrency } = options;
|
|
54
|
+
const { config, dir, download, log, git_ops, npm_ops, parallel, concurrency, sync, allow_dirty } = options;
|
|
49
55
|
const config_path = resolve(config);
|
|
50
56
|
const gitops_config = await import_gitops_config(config_path);
|
|
51
57
|
// Priority: explicit dir arg → config repos_dir → default (two dirs up from config)
|
|
@@ -71,6 +77,8 @@ export const get_gitops_ready = async (options) => {
|
|
|
71
77
|
npm_ops,
|
|
72
78
|
parallel,
|
|
73
79
|
concurrency,
|
|
80
|
+
sync,
|
|
81
|
+
allow_dirty,
|
|
74
82
|
});
|
|
75
83
|
return { config_path, repos_dir, gitops_config, local_repos };
|
|
76
84
|
};
|
|
@@ -5,6 +5,7 @@ export declare const Args: z.ZodObject<{
|
|
|
5
5
|
config: z.ZodDefault<z.ZodString>;
|
|
6
6
|
dir: z.ZodOptional<z.ZodString>;
|
|
7
7
|
verbose: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
sync: z.ZodDefault<z.ZodBoolean>;
|
|
8
9
|
}, z.core.$strict>;
|
|
9
10
|
export type Args = z.infer<typeof Args>;
|
|
10
11
|
/** @nodocs */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_validate.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_validate.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"gitops_validate.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_validate.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AActB,cAAc;AACd,eAAO,MAAM,IAAI;;;;;kBAiBf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,cAAc;AACd,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CA2N3B,CAAC"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { styleText as st } from 'node:util';
|
|
3
3
|
import { get_gitops_ready } from './gitops_task_helpers.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { publish_repos } from './multi_repo_publisher.js';
|
|
4
|
+
import { analyze_repos } from './graph_validation.js';
|
|
5
|
+
import { generate_publishing_plan, log_publishing_plan, } from './publishing_plan.js';
|
|
6
|
+
import { execute_publishing_plan } from './multi_repo_publisher.js';
|
|
8
7
|
import { log_dependency_analysis } from './log_helpers.js';
|
|
9
8
|
import { GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.js';
|
|
10
9
|
/** @nodocs */
|
|
@@ -18,34 +17,33 @@ export const Args = z.strictObject({
|
|
|
18
17
|
.meta({ description: 'path containing the repos, defaults to the parent of the config dir' })
|
|
19
18
|
.optional(),
|
|
20
19
|
verbose: z.boolean().meta({ description: 'show additional details' }).default(false),
|
|
20
|
+
sync: z
|
|
21
|
+
.boolean()
|
|
22
|
+
.meta({
|
|
23
|
+
description: 'sync repos (switch branch, pull, install) before validating instead of reading the working tree as-is',
|
|
24
|
+
})
|
|
25
|
+
.default(false),
|
|
21
26
|
});
|
|
22
27
|
/** @nodocs */
|
|
23
28
|
export const task = {
|
|
24
29
|
Args,
|
|
25
30
|
summary: 'validate gitops configuration by running all read-only commands and checking for issues',
|
|
26
31
|
run: async ({ args, log }) => {
|
|
27
|
-
const { config, dir, verbose } = args;
|
|
32
|
+
const { config, dir, verbose, sync } = args;
|
|
28
33
|
log.info(st('cyan', 'Running Gitops Validation Suite'));
|
|
29
34
|
log.info(st('dim', 'This runs all read-only commands and checks for consistency.'));
|
|
30
35
|
const results = [];
|
|
31
36
|
const start_time = Date.now();
|
|
32
|
-
// Load repos once (shared by all commands)
|
|
37
|
+
// Load repos once (shared by all commands); read the working tree as-is unless `--sync`
|
|
33
38
|
log.info(st('dim', 'Loading repositories...'));
|
|
34
|
-
const { local_repos } = await get_gitops_ready({ config, dir, download: false, log });
|
|
39
|
+
const { local_repos } = await get_gitops_ready({ config, dir, download: false, sync, log });
|
|
35
40
|
log.info(st('dim', ` Found ${local_repos.length} local repos`));
|
|
36
41
|
// 1. Run gitops_analyze
|
|
37
42
|
log.info(st('yellow', 'Running gitops_analyze...'));
|
|
38
43
|
const analyze_start = Date.now();
|
|
39
44
|
try {
|
|
40
|
-
// Build dependency graph and
|
|
41
|
-
const {
|
|
42
|
-
throw_on_prod_cycles: false, // Analyze should report, not throw
|
|
43
|
-
log_cycles: false, // We'll collect our own statistics
|
|
44
|
-
log_order: false,
|
|
45
|
-
});
|
|
46
|
-
// Perform additional analysis
|
|
47
|
-
const builder = new DependencyGraphBuilder();
|
|
48
|
-
const analysis = builder.analyze(graph);
|
|
45
|
+
// Build dependency graph and analyze cycles/wildcards (tolerating cycles)
|
|
46
|
+
const { analysis } = analyze_repos(local_repos);
|
|
49
47
|
const analyze_duration = Date.now() - analyze_start;
|
|
50
48
|
// Collect warnings, info, and errors
|
|
51
49
|
const warning_details = [];
|
|
@@ -86,11 +84,13 @@ export const task = {
|
|
|
86
84
|
});
|
|
87
85
|
log.error(st('red', ` ✗ gitops_analyze failed: ${error}`));
|
|
88
86
|
}
|
|
89
|
-
// 2. Run gitops_plan
|
|
87
|
+
// 2. Run gitops_plan (generated once here and reused by the dry run below)
|
|
88
|
+
let publishing_plan;
|
|
90
89
|
log.info(st('yellow', 'Running gitops_plan...'));
|
|
91
90
|
const plan_start = Date.now();
|
|
92
91
|
try {
|
|
93
|
-
const plan = await generate_publishing_plan(local_repos, {
|
|
92
|
+
const plan = await generate_publishing_plan(local_repos, { verbose });
|
|
93
|
+
publishing_plan = plan;
|
|
94
94
|
const plan_duration = Date.now() - plan_start;
|
|
95
95
|
const warnings = plan.warnings.length;
|
|
96
96
|
const errors = plan.errors.length;
|
|
@@ -129,10 +129,10 @@ export const task = {
|
|
|
129
129
|
try {
|
|
130
130
|
const options = {
|
|
131
131
|
wetrun: false,
|
|
132
|
-
update_deps: true,
|
|
133
132
|
log: undefined, // Silent for validation
|
|
134
133
|
};
|
|
135
|
-
|
|
134
|
+
// Reuse the plan from step 2 (regenerate only if that step failed to produce one).
|
|
135
|
+
const result = await execute_publishing_plan(local_repos, publishing_plan ?? (await generate_publishing_plan(local_repos, { verbose })), options);
|
|
136
136
|
const dry_duration = Date.now() - dry_start;
|
|
137
137
|
// Dry run doesn't have warnings/errors in the same format
|
|
138
138
|
// We'll just check if it succeeded
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* @module
|
|
14
14
|
*/
|
|
15
15
|
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
16
|
-
import { DependencyGraph } from './dependency_graph.js';
|
|
16
|
+
import { DependencyGraph, DependencyGraphBuilder } from './dependency_graph.js';
|
|
17
17
|
import type { LocalRepo } from './local_repo.js';
|
|
18
18
|
export interface GraphValidationResult {
|
|
19
19
|
graph: DependencyGraph;
|
|
@@ -38,4 +38,19 @@ export declare const validate_dependency_graph: (repos: Array<LocalRepo>, option
|
|
|
38
38
|
log_cycles?: boolean;
|
|
39
39
|
log_order?: boolean;
|
|
40
40
|
}) => GraphValidationResult;
|
|
41
|
+
/** Cycles, wildcard deps, and missing peers produced by `DependencyGraphBuilder.analyze`. */
|
|
42
|
+
export type DependencyAnalysis = ReturnType<DependencyGraphBuilder['analyze']>;
|
|
43
|
+
export interface RepoAnalysis {
|
|
44
|
+
graph: DependencyGraph;
|
|
45
|
+
analysis: DependencyAnalysis;
|
|
46
|
+
/** Topological publishing order, or `null` when prod/peer cycles prevent ordering. */
|
|
47
|
+
publishing_order: Array<string> | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Builds the dependency graph and runs cycle/wildcard analysis, tolerating cycles
|
|
51
|
+
* (reports rather than throws). The shared core of `gitops_analyze` and
|
|
52
|
+
* `gitops_validate`, which format the result themselves — so this stays silent
|
|
53
|
+
* (no `log`) to avoid emitting a redundant "Analyzing dependencies" line.
|
|
54
|
+
*/
|
|
55
|
+
export declare const analyze_repos: (repos: Array<LocalRepo>) => RepoAnalysis;
|
|
41
56
|
//# sourceMappingURL=graph_validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph_validation.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/graph_validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAIpD,OAAO,EAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"graph_validation.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/graph_validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAIpD,OAAO,EAAC,eAAe,EAAE,sBAAsB,EAAC,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,eAAe,CAAC;IACvB,gBAAgB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChC,iBAAiB,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACrC,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,UAAS;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACf,KACJ,qBA8DF,CAAC;AAEF,6FAA6F;AAC7F,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,sFAAsF;IACtF,gBAAgB,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CACvC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,CAAC,SAAS,CAAC,KAAG,YAQvD,CAAC"}
|
package/dist/graph_validation.js
CHANGED
|
@@ -79,3 +79,18 @@ export const validate_dependency_graph = (repos, options = {}) => {
|
|
|
79
79
|
sort_error,
|
|
80
80
|
};
|
|
81
81
|
};
|
|
82
|
+
/**
|
|
83
|
+
* Builds the dependency graph and runs cycle/wildcard analysis, tolerating cycles
|
|
84
|
+
* (reports rather than throws). The shared core of `gitops_analyze` and
|
|
85
|
+
* `gitops_validate`, which format the result themselves — so this stays silent
|
|
86
|
+
* (no `log`) to avoid emitting a redundant "Analyzing dependencies" line.
|
|
87
|
+
*/
|
|
88
|
+
export const analyze_repos = (repos) => {
|
|
89
|
+
const { graph, publishing_order: order } = validate_dependency_graph(repos, {
|
|
90
|
+
throw_on_prod_cycles: false, // report, don't throw
|
|
91
|
+
log_cycles: false, // callers format their own cycle output
|
|
92
|
+
log_order: false,
|
|
93
|
+
});
|
|
94
|
+
const analysis = new DependencyGraphBuilder().analyze(graph);
|
|
95
|
+
return { graph, analysis, publishing_order: order.length > 0 ? order : null };
|
|
96
|
+
};
|
package/dist/local_repo.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PackageJson } from '@fuzdev/fuz_util/package_json.js';
|
|
2
2
|
import { Library } from '@fuzdev/fuz_ui/library.svelte.js';
|
|
3
3
|
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
4
4
|
import type { GitOperations, NpmOperations } from './operations.js';
|
|
@@ -10,7 +10,8 @@ import type { ResolvedGitopsConfig } from './resolved_gitops_config.js';
|
|
|
10
10
|
*/
|
|
11
11
|
export interface LocalRepo {
|
|
12
12
|
library: Library;
|
|
13
|
-
|
|
13
|
+
/** The repo's full `package.json` (with `dependencies`/`devDependencies`). */
|
|
14
|
+
package_json: PackageJson;
|
|
14
15
|
repo_dir: string;
|
|
15
16
|
repo_git_ssh_url: string;
|
|
16
17
|
repo_config: GitopsRepoConfig;
|
|
@@ -41,27 +42,37 @@ export interface LocalRepoMissing {
|
|
|
41
42
|
repo_config: GitopsRepoConfig;
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
|
-
* Loads repo data
|
|
45
|
+
* Loads repo data, optionally syncing the working tree first.
|
|
45
46
|
*
|
|
46
|
-
*
|
|
47
|
+
* When `sync` is `false` (the default for read-only diagnostics like
|
|
48
|
+
* `gitops_analyze`/`gitops_plan`), the repo is loaded exactly as it sits on
|
|
49
|
+
* disk — no branch switch, pull, install, or clean-workspace check. This makes
|
|
50
|
+
* those commands safe to run on an active workspace with uncommitted changes or
|
|
51
|
+
* feature branches checked out.
|
|
52
|
+
*
|
|
53
|
+
* When `sync` is `true` (used by `gitops_sync`), the working tree is brought in
|
|
54
|
+
* line with the configured branch first:
|
|
47
55
|
* 1. Records current commit hash (for detecting changes)
|
|
48
|
-
* 2. Switches to target branch if needed (requires clean workspace)
|
|
56
|
+
* 2. Switches to target branch if needed (requires clean workspace unless `allow_dirty`)
|
|
49
57
|
* 3. Pulls latest changes from remote (skipped for local-only repos)
|
|
50
|
-
* 4. Validates workspace is clean after pull
|
|
58
|
+
* 4. Validates workspace is clean after pull (skipped if `allow_dirty`)
|
|
51
59
|
* 5. Auto-installs dependencies if `package.json` changed
|
|
60
|
+
*
|
|
61
|
+
* Either way it then:
|
|
52
62
|
* 6. Loads `library_json` via `library_load_from_repo` (svelte-docinfo analysis)
|
|
53
63
|
* 7. Creates `Library` and extracts dependency maps
|
|
54
64
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @throws {TaskError} if workspace dirty, branch switch fails, install fails, or analysis fails
|
|
65
|
+
* @param sync - sync the working tree to the configured branch before loading (default `true`)
|
|
66
|
+
* @param allow_dirty - when syncing, tolerate uncommitted changes instead of throwing (default `false`)
|
|
67
|
+
* @throws {TaskError} if syncing fails (dirty workspace, branch switch, install) or analysis fails
|
|
59
68
|
*/
|
|
60
|
-
export declare const local_repo_load: ({ local_repo_path, log: _log, git_ops, npm_ops, }: {
|
|
69
|
+
export declare const local_repo_load: ({ local_repo_path, log: _log, git_ops, npm_ops, sync, allow_dirty, }: {
|
|
61
70
|
local_repo_path: LocalRepoPath;
|
|
62
71
|
log?: Logger;
|
|
63
72
|
git_ops?: GitOperations;
|
|
64
73
|
npm_ops?: NpmOperations;
|
|
74
|
+
sync?: boolean;
|
|
75
|
+
allow_dirty?: boolean;
|
|
65
76
|
}) => Promise<LocalRepo>;
|
|
66
77
|
export declare const local_repos_ensure: ({ resolved_config, repos_dir, gitops_config, download, log, npm_ops, }: {
|
|
67
78
|
resolved_config: ResolvedGitopsConfig;
|
|
@@ -71,13 +82,15 @@ export declare const local_repos_ensure: ({ resolved_config, repos_dir, gitops_c
|
|
|
71
82
|
log?: Logger;
|
|
72
83
|
npm_ops?: NpmOperations;
|
|
73
84
|
}) => Promise<Array<LocalRepoPath>>;
|
|
74
|
-
export declare const local_repos_load: ({ local_repo_paths, log, git_ops, npm_ops, parallel, concurrency, }: {
|
|
85
|
+
export declare const local_repos_load: ({ local_repo_paths, log, git_ops, npm_ops, parallel, concurrency, sync, allow_dirty, }: {
|
|
75
86
|
local_repo_paths: Array<LocalRepoPath>;
|
|
76
87
|
log?: Logger;
|
|
77
88
|
git_ops?: GitOperations;
|
|
78
89
|
npm_ops?: NpmOperations;
|
|
79
90
|
parallel?: boolean;
|
|
80
91
|
concurrency?: number;
|
|
92
|
+
sync?: boolean;
|
|
93
|
+
allow_dirty?: boolean;
|
|
81
94
|
}) => Promise<Array<LocalRepo>>;
|
|
82
95
|
export declare const local_repo_locate: ({ repo_config, repos_dir, }: {
|
|
83
96
|
repo_config: GitopsRepoConfig;
|
package/dist/local_repo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local_repo.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/local_repo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local_repo.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/local_repo.ts"],"names":[],"mappings":"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"}
|