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