@fuzdev/fuz_gitops 0.78.0 → 0.78.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/ModulesDetail.svelte +14 -12
- package/dist/ModulesDetail.svelte.d.ts.map +1 -1
- package/dist/ModulesNav.svelte +6 -6
- package/dist/ModulesNav.svelte.d.ts.map +1 -1
- package/dist/ModulesPage.svelte +2 -2
- package/dist/ModulesPage.svelte.d.ts.map +1 -1
- package/dist/PageFooter.svelte +2 -2
- package/dist/PageHeader.svelte +5 -5
- package/dist/PageHeader.svelte.d.ts.map +1 -1
- package/dist/PullRequestsDetail.svelte +25 -17
- package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
- package/dist/PullRequestsPage.svelte +3 -3
- package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
- package/dist/ReposTable.svelte +24 -15
- package/dist/ReposTable.svelte.d.ts.map +1 -1
- package/dist/ReposTree.svelte +8 -6
- package/dist/ReposTree.svelte.d.ts.map +1 -1
- package/dist/ReposTreeNav.svelte +10 -11
- package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
- package/dist/TablePage.svelte +2 -2
- package/dist/TablePage.svelte.d.ts.map +1 -1
- package/dist/TreeItemPage.svelte +2 -2
- package/dist/TreeItemPage.svelte.d.ts.map +1 -1
- package/dist/TreePage.svelte +2 -2
- package/dist/TreePage.svelte.d.ts.map +1 -1
- package/dist/changeset_generator.d.ts.map +1 -1
- package/dist/changeset_generator.js +2 -2
- package/dist/changeset_reader.d.ts.map +1 -1
- package/dist/changeset_reader.js +3 -3
- package/dist/config_reconcile.d.ts.map +1 -1
- package/dist/config_reconcile.js +6 -2
- package/dist/dependency_graph.d.ts.map +1 -1
- package/dist/dependency_graph.js +5 -5
- package/dist/dependency_updater.d.ts.map +1 -1
- package/dist/dependency_updater.js +8 -8
- package/dist/fetch_repo_data.d.ts.map +1 -1
- package/dist/fetch_repo_data.js +3 -3
- package/dist/fs_fetch_value_cache.d.ts.map +1 -1
- package/dist/fs_fetch_value_cache.js +2 -2
- package/dist/git_operations.d.ts.map +1 -1
- package/dist/git_operations.js +1 -1
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +6 -6
- package/dist/github_helpers.d.ts.map +1 -1
- package/dist/gitops_analyze.task.d.ts.map +1 -1
- package/dist/gitops_analyze.task.js +7 -7
- package/dist/gitops_config.d.ts.map +1 -1
- package/dist/gitops_config.js +4 -4
- package/dist/gitops_plan.task.d.ts.map +1 -1
- package/dist/gitops_plan.task.js +8 -8
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +15 -12
- package/dist/gitops_run.task.d.ts.map +1 -1
- package/dist/gitops_run.task.js +8 -8
- package/dist/gitops_sync.task.d.ts.map +1 -1
- package/dist/gitops_sync.task.js +11 -9
- package/dist/gitops_task_helpers.d.ts.map +1 -1
- package/dist/gitops_task_helpers.js +3 -3
- package/dist/gitops_validate.task.d.ts.map +1 -1
- package/dist/gitops_validate.task.js +14 -14
- package/dist/graph_validation.d.ts.map +1 -1
- package/dist/graph_validation.js +2 -2
- package/dist/local_repo.d.ts +4 -4
- package/dist/local_repo.d.ts.map +1 -1
- package/dist/local_repo.js +13 -13
- package/dist/log_helpers.d.ts.map +1 -1
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +19 -19
- package/dist/npm_registry.d.ts.map +1 -1
- package/dist/npm_registry.js +2 -2
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations_defaults.d.ts.map +1 -1
- package/dist/operations_defaults.js +12 -12
- package/dist/output_helpers.d.ts.map +1 -1
- package/dist/preflight_checks.d.ts +1 -1
- package/dist/preflight_checks.d.ts.map +1 -1
- package/dist/preflight_checks.js +4 -4
- package/dist/publish_gate.d.ts.map +1 -1
- package/dist/publish_steps.d.ts.map +1 -1
- package/dist/publish_steps.js +3 -3
- package/dist/publishing_event.d.ts.map +1 -1
- package/dist/publishing_event.js +16 -14
- package/dist/publishing_event_handler.d.ts.map +1 -1
- package/dist/publishing_event_handler.js +6 -6
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +14 -14
- package/dist/publishing_plan_helpers.d.ts.map +1 -1
- package/dist/publishing_plan_helpers.js +3 -3
- package/dist/publishing_plan_logging.d.ts.map +1 -1
- package/dist/publishing_plan_logging.js +2 -2
- package/dist/repo.svelte.d.ts.map +1 -1
- package/dist/repo_ops.js +2 -2
- package/dist/resolved_gitops_config.d.ts.map +1 -1
- package/dist/resolved_gitops_config.js +1 -1
- package/dist/version_utils.js +1 -1
- package/package.json +16 -15
- package/src/lib/cargo_toml.ts +3 -3
- package/src/lib/changeset_generator.ts +19 -19
- package/src/lib/changeset_reader.ts +18 -18
- package/src/lib/ci_reconcile.ts +5 -5
- package/src/lib/config_reconcile.ts +8 -4
- package/src/lib/dependency_graph.ts +26 -26
- package/src/lib/dependency_updater.ts +29 -29
- package/src/lib/fetch_repo_data.ts +11 -11
- package/src/lib/fs_fetch_value_cache.ts +14 -10
- package/src/lib/git_operations.ts +30 -30
- package/src/lib/github.ts +19 -19
- package/src/lib/github_helpers.ts +6 -6
- package/src/lib/gitops_analyze.task.ts +40 -40
- package/src/lib/gitops_config.ts +14 -14
- package/src/lib/gitops_plan.task.ts +31 -31
- package/src/lib/gitops_publish.task.ts +51 -48
- package/src/lib/gitops_run.task.ts +29 -29
- package/src/lib/gitops_sync.task.ts +39 -30
- package/src/lib/gitops_task_helpers.ts +21 -21
- package/src/lib/gitops_validate.task.ts +37 -37
- package/src/lib/graph_validation.ts +13 -13
- package/src/lib/local_repo.ts +70 -70
- package/src/lib/log_helpers.ts +15 -15
- package/src/lib/multi_repo_publisher.ts +67 -70
- package/src/lib/npm_registry.ts +13 -13
- package/src/lib/operations.ts +49 -38
- package/src/lib/operations_defaults.ts +106 -104
- package/src/lib/output_helpers.ts +4 -4
- package/src/lib/preflight_checks.ts +26 -26
- package/src/lib/publish_gate.ts +7 -9
- package/src/lib/publish_steps.ts +15 -15
- package/src/lib/publishing_event.ts +22 -20
- package/src/lib/publishing_event_handler.ts +8 -8
- package/src/lib/publishing_plan.ts +55 -55
- package/src/lib/publishing_plan_helpers.ts +16 -12
- package/src/lib/publishing_plan_logging.ts +22 -22
- package/src/lib/repo.svelte.ts +8 -8
- package/src/lib/repo_ops.ts +12 -12
- package/src/lib/resolved_gitops_config.ts +5 -5
- package/src/lib/version_utils.ts +3 -3
package/src/lib/log_helpers.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type {Logger} from '@fuzdev/fuz_util/log.ts';
|
|
2
|
-
import {styleText as st} from 'node:util';
|
|
1
|
+
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
2
|
+
import { styleText as st } from 'node:util';
|
|
3
3
|
|
|
4
|
-
import type {DependencyGraphBuilder} from './dependency_graph.ts';
|
|
4
|
+
import type { DependencyGraphBuilder } from './dependency_graph.ts';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Formats wildcard dependencies as styled strings.
|
|
8
8
|
* Returns array of lines for inclusion in output.
|
|
9
9
|
*/
|
|
10
10
|
export const format_wildcard_dependencies = (
|
|
11
|
-
analysis: ReturnType<DependencyGraphBuilder['analyze']
|
|
11
|
+
analysis: ReturnType<DependencyGraphBuilder['analyze']>
|
|
12
12
|
): Array<string> => {
|
|
13
13
|
if (analysis.wildcard_deps.length === 0) return [];
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ export const format_wildcard_dependencies = (
|
|
|
17
17
|
// a leading `\n` in the header would leave the header line unprefixed.
|
|
18
18
|
lines.push('');
|
|
19
19
|
lines.push(st('yellow', `⚠️ Found ${analysis.wildcard_deps.length} wildcard dependencies:`));
|
|
20
|
-
for (const {pkg, dep, version} of analysis.wildcard_deps) {
|
|
20
|
+
for (const { pkg, dep, version } of analysis.wildcard_deps) {
|
|
21
21
|
lines.push(` ${pkg} → ${dep} ${st('red', version)}`);
|
|
22
22
|
}
|
|
23
23
|
return lines;
|
|
@@ -28,7 +28,7 @@ export const format_wildcard_dependencies = (
|
|
|
28
28
|
* Returns array of lines for inclusion in output.
|
|
29
29
|
*/
|
|
30
30
|
export const format_dev_cycles = (
|
|
31
|
-
analysis: ReturnType<DependencyGraphBuilder['analyze']
|
|
31
|
+
analysis: ReturnType<DependencyGraphBuilder['analyze']>
|
|
32
32
|
): Array<string> => {
|
|
33
33
|
if (analysis.dev_cycles.length === 0) return [];
|
|
34
34
|
|
|
@@ -37,8 +37,8 @@ export const format_dev_cycles = (
|
|
|
37
37
|
lines.push(
|
|
38
38
|
st(
|
|
39
39
|
'dim',
|
|
40
|
-
`ℹ️ Found ${analysis.dev_cycles.length} dev circular dependencies (normal, non-blocking)
|
|
41
|
-
)
|
|
40
|
+
`ℹ️ Found ${analysis.dev_cycles.length} dev circular dependencies (normal, non-blocking):`
|
|
41
|
+
)
|
|
42
42
|
);
|
|
43
43
|
for (const cycle of analysis.dev_cycles) {
|
|
44
44
|
lines.push(st('dim', ` ${cycle.join(' → ')}`));
|
|
@@ -51,7 +51,7 @@ export const format_dev_cycles = (
|
|
|
51
51
|
* Returns array of lines for inclusion in output.
|
|
52
52
|
*/
|
|
53
53
|
export const format_production_cycles = (
|
|
54
|
-
analysis: ReturnType<DependencyGraphBuilder['analyze']
|
|
54
|
+
analysis: ReturnType<DependencyGraphBuilder['analyze']>
|
|
55
55
|
): Array<string> => {
|
|
56
56
|
if (analysis.production_cycles.length === 0) return [];
|
|
57
57
|
|
|
@@ -60,8 +60,8 @@ export const format_production_cycles = (
|
|
|
60
60
|
lines.push(
|
|
61
61
|
st(
|
|
62
62
|
'red',
|
|
63
|
-
`❌ Found ${analysis.production_cycles.length} production/peer circular dependencies (blocks publishing)
|
|
64
|
-
)
|
|
63
|
+
`❌ Found ${analysis.production_cycles.length} production/peer circular dependencies (blocks publishing):`
|
|
64
|
+
)
|
|
65
65
|
);
|
|
66
66
|
for (const cycle of analysis.production_cycles) {
|
|
67
67
|
lines.push(` ${st('red', cycle.join(' → '))}`);
|
|
@@ -76,7 +76,7 @@ export const format_production_cycles = (
|
|
|
76
76
|
export const log_wildcard_dependencies = (
|
|
77
77
|
analysis: ReturnType<DependencyGraphBuilder['analyze']>,
|
|
78
78
|
log: Logger,
|
|
79
|
-
indent = ''
|
|
79
|
+
indent = ''
|
|
80
80
|
): void => {
|
|
81
81
|
const lines = format_wildcard_dependencies(analysis);
|
|
82
82
|
for (const line of lines) {
|
|
@@ -91,7 +91,7 @@ export const log_wildcard_dependencies = (
|
|
|
91
91
|
export const log_dev_cycles = (
|
|
92
92
|
analysis: ReturnType<DependencyGraphBuilder['analyze']>,
|
|
93
93
|
log: Logger,
|
|
94
|
-
indent = ''
|
|
94
|
+
indent = ''
|
|
95
95
|
): void => {
|
|
96
96
|
const lines = format_dev_cycles(analysis);
|
|
97
97
|
for (const line of lines) {
|
|
@@ -106,7 +106,7 @@ export const log_dev_cycles = (
|
|
|
106
106
|
export const log_production_cycles = (
|
|
107
107
|
analysis: ReturnType<DependencyGraphBuilder['analyze']>,
|
|
108
108
|
log: Logger,
|
|
109
|
-
indent = ''
|
|
109
|
+
indent = ''
|
|
110
110
|
): void => {
|
|
111
111
|
const lines = format_production_cycles(analysis);
|
|
112
112
|
for (const line of lines) {
|
|
@@ -121,7 +121,7 @@ export const log_production_cycles = (
|
|
|
121
121
|
export const log_dependency_analysis = (
|
|
122
122
|
analysis: ReturnType<DependencyGraphBuilder['analyze']>,
|
|
123
123
|
log: Logger,
|
|
124
|
-
indent = ''
|
|
124
|
+
indent = ''
|
|
125
125
|
): void => {
|
|
126
126
|
log_wildcard_dependencies(analysis, log, indent);
|
|
127
127
|
log_production_cycles(analysis, log, indent);
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import type {Logger} from '@fuzdev/fuz_util/log.ts';
|
|
2
|
-
import {TaskError} from '@fuzdev/gro';
|
|
3
|
-
import {join} from 'node:path';
|
|
4
|
-
import {styleText as st} from 'node:util';
|
|
1
|
+
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
2
|
+
import { TaskError } from '@fuzdev/gro';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { styleText as st } from 'node:util';
|
|
5
5
|
|
|
6
|
-
import {repo_is_npm, type LocalRepo} from './local_repo.ts';
|
|
7
|
-
import {update_package_json, type VersionStrategy} from './dependency_updater.ts';
|
|
6
|
+
import { repo_is_npm, type LocalRepo } from './local_repo.ts';
|
|
7
|
+
import { update_package_json, type VersionStrategy } from './dependency_updater.ts';
|
|
8
8
|
import {
|
|
9
9
|
generate_publishing_plan,
|
|
10
10
|
type VersionChange,
|
|
11
11
|
type DependencyUpdate,
|
|
12
|
-
type PublishingPlan
|
|
12
|
+
type PublishingPlan
|
|
13
13
|
} from './publishing_plan.ts';
|
|
14
|
-
import type {PreflightOptions} from './preflight_checks.ts';
|
|
15
|
-
import type {GitopsOperations} from './operations.ts';
|
|
16
|
-
import {default_gitops_operations} from './operations_defaults.ts';
|
|
17
|
-
import {GITOPS_NPM_WAIT_TIMEOUT_DEFAULT} from './gitops_constants.ts';
|
|
14
|
+
import type { PreflightOptions } from './preflight_checks.ts';
|
|
15
|
+
import type { GitopsOperations } from './operations.ts';
|
|
16
|
+
import { default_gitops_operations } from './operations_defaults.ts';
|
|
17
|
+
import { GITOPS_NPM_WAIT_TIMEOUT_DEFAULT } from './gitops_constants.ts';
|
|
18
18
|
import {
|
|
19
19
|
type PublishingEvent,
|
|
20
20
|
type PublishingRunSummary,
|
|
21
|
-
summarize_events
|
|
21
|
+
summarize_events
|
|
22
22
|
} from './publishing_event.ts';
|
|
23
23
|
import {
|
|
24
24
|
type PublishingEventHandler,
|
|
25
25
|
capture_handler,
|
|
26
|
-
multi_handler
|
|
26
|
+
multi_handler
|
|
27
27
|
} from './publishing_event_handler.ts';
|
|
28
28
|
|
|
29
29
|
export interface PublishingOptions {
|
|
@@ -50,7 +50,7 @@ export interface PublishedVersion {
|
|
|
50
50
|
export interface PublishingResult {
|
|
51
51
|
ok: boolean;
|
|
52
52
|
published: Array<PublishedVersion>;
|
|
53
|
-
failed: Array<{name: string; error: Error}>;
|
|
53
|
+
failed: Array<{ name: string; error: Error }>;
|
|
54
54
|
duration: number;
|
|
55
55
|
/** The structured event stream for this run, in emission order. */
|
|
56
56
|
events: Array<PublishingEvent>;
|
|
@@ -64,13 +64,13 @@ export interface PublishingResult {
|
|
|
64
64
|
|
|
65
65
|
export const publish_repos = async (
|
|
66
66
|
repos: Array<LocalRepo>,
|
|
67
|
-
options: PublishingOptions
|
|
67
|
+
options: PublishingOptions
|
|
68
68
|
): Promise<PublishingResult> => {
|
|
69
|
-
const {log, ops = default_gitops_operations} = options;
|
|
69
|
+
const { log, ops = default_gitops_operations } = options;
|
|
70
70
|
// Convenience entry: generate the plan, then execute it. Callers that already hold a
|
|
71
71
|
// plan (e.g. to display and confirm it first) call `execute_publishing_plan` directly,
|
|
72
72
|
// so the plan is generated exactly once per command.
|
|
73
|
-
const plan = await generate_publishing_plan(repos, {log, ops: ops.changeset});
|
|
73
|
+
const plan = await generate_publishing_plan(repos, { log, ops: ops.changeset });
|
|
74
74
|
return execute_publishing_plan(repos, plan, options);
|
|
75
75
|
};
|
|
76
76
|
|
|
@@ -85,10 +85,10 @@ export const publish_repos = async (
|
|
|
85
85
|
export const execute_publishing_plan = async (
|
|
86
86
|
all_repos: Array<LocalRepo>,
|
|
87
87
|
plan: PublishingPlan,
|
|
88
|
-
options: PublishingOptions
|
|
88
|
+
options: PublishingOptions
|
|
89
89
|
): Promise<PublishingResult> => {
|
|
90
90
|
const start_time = Date.now();
|
|
91
|
-
const {wetrun, log, ops = default_gitops_operations} = options;
|
|
91
|
+
const { wetrun, log, ops = default_gitops_operations } = options;
|
|
92
92
|
|
|
93
93
|
// Only npm repos publish; drop any non-npm repos (e.g. cargo) so preflight and the
|
|
94
94
|
// executor's name lookup never touch them. The plan already excludes them too.
|
|
@@ -99,7 +99,7 @@ export const execute_publishing_plan = async (
|
|
|
99
99
|
// (no side effects) but the result is not ok (see the summary below).
|
|
100
100
|
if (wetrun && plan.errors.length > 0) {
|
|
101
101
|
throw new TaskError(
|
|
102
|
-
`Cannot publish — the plan has ${plan.errors.length} error(s):\n ${plan.errors.join('\n ')}
|
|
102
|
+
`Cannot publish — the plan has ${plan.errors.length} error(s):\n ${plan.errors.join('\n ')}`
|
|
103
103
|
);
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -115,7 +115,7 @@ export const execute_publishing_plan = async (
|
|
|
115
115
|
const preflight_options: PreflightOptions = {
|
|
116
116
|
skip_changesets: false, // Always check for changesets
|
|
117
117
|
required_branch: 'main',
|
|
118
|
-
log
|
|
118
|
+
log
|
|
119
119
|
};
|
|
120
120
|
const preflight = await ops.preflight.run_preflight_checks({
|
|
121
121
|
repos,
|
|
@@ -123,7 +123,7 @@ export const execute_publishing_plan = async (
|
|
|
123
123
|
git_ops: ops.git,
|
|
124
124
|
npm_ops: ops.npm,
|
|
125
125
|
build_ops: ops.build,
|
|
126
|
-
changeset_ops: ops.changeset
|
|
126
|
+
changeset_ops: ops.changeset
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
if (!preflight.ok) {
|
|
@@ -138,13 +138,13 @@ export const execute_publishing_plan = async (
|
|
|
138
138
|
// frozen topological order directly, re-deriving nothing.
|
|
139
139
|
const order = plan.publishing_order;
|
|
140
140
|
const plan_changes: Map<string, VersionChange> = new Map(
|
|
141
|
-
plan.version_changes.map((vc) => [vc.package_name, vc])
|
|
141
|
+
plan.version_changes.map((vc) => [vc.package_name, vc])
|
|
142
142
|
);
|
|
143
143
|
if (order.length > 0) {
|
|
144
144
|
log?.info(` Publishing order: ${order.join(' → ')}`);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
emit({event: 'run_started', wetrun, total: order.length});
|
|
147
|
+
emit({ event: 'run_started', wetrun, total: order.length });
|
|
148
148
|
|
|
149
149
|
const published: Map<string, PublishedVersion> = new Map();
|
|
150
150
|
const failed: Map<string, Error> = new Map();
|
|
@@ -165,7 +165,7 @@ export const execute_publishing_plan = async (
|
|
|
165
165
|
|
|
166
166
|
// Not in the plan = no changesets and no dependency updates = nothing to publish.
|
|
167
167
|
if (!planned) {
|
|
168
|
-
emit({event: 'package_skipped', name: pkg_name, reason: 'no changesets'});
|
|
168
|
+
emit({ event: 'package_skipped', name: pkg_name, reason: 'no changesets' });
|
|
169
169
|
log?.info(st('yellow', ` ⚠️ Skipping ${pkg_name} - no changesets`));
|
|
170
170
|
continue;
|
|
171
171
|
}
|
|
@@ -182,8 +182,8 @@ export const execute_publishing_plan = async (
|
|
|
182
182
|
log?.info(
|
|
183
183
|
st(
|
|
184
184
|
'dim',
|
|
185
|
-
` [${i + 1}/${order.length}] ${wetrun ? 'Publishing' : 'Would publish'} ${pkg_name}
|
|
186
|
-
)
|
|
185
|
+
` [${i + 1}/${order.length}] ${wetrun ? 'Publishing' : 'Would publish'} ${pkg_name}...`
|
|
186
|
+
)
|
|
187
187
|
);
|
|
188
188
|
const version = await publish_single_repo(repo, options, ops, planned);
|
|
189
189
|
|
|
@@ -194,10 +194,10 @@ export const execute_publishing_plan = async (
|
|
|
194
194
|
if (wetrun && version.new_version !== planned.to) {
|
|
195
195
|
const err = new Error(
|
|
196
196
|
`Plan drift for ${pkg_name}: published ${version.new_version} but the plan predicted ${planned.to}. ` +
|
|
197
|
-
`Aborting — re-run 'gro gitops_publish --wetrun' to re-plan from the current state
|
|
197
|
+
`Aborting — re-run 'gro gitops_publish --wetrun' to re-plan from the current state.`
|
|
198
198
|
);
|
|
199
199
|
failed.set(pkg_name, err);
|
|
200
|
-
emit({event: 'package_failed', name: pkg_name, error: err.message, code: 'drift'});
|
|
200
|
+
emit({ event: 'package_failed', name: pkg_name, error: err.message, code: 'drift' });
|
|
201
201
|
log?.error(st('red', ` ❌ ${err.message}`));
|
|
202
202
|
break;
|
|
203
203
|
}
|
|
@@ -212,12 +212,12 @@ export const execute_publishing_plan = async (
|
|
|
212
212
|
bump_type: version.bump_type,
|
|
213
213
|
breaking: version.breaking,
|
|
214
214
|
commit: version.commit,
|
|
215
|
-
tag: version.tag
|
|
215
|
+
tag: version.tag
|
|
216
216
|
});
|
|
217
217
|
log?.info(
|
|
218
218
|
wetrun
|
|
219
219
|
? st('green', ` ✅ Published ${pkg_name}@${version.new_version}`)
|
|
220
|
-
: st('cyan', ` ◇ Would publish ${pkg_name}@${version.new_version}`)
|
|
220
|
+
: st('cyan', ` ◇ Would publish ${pkg_name}@${version.new_version}`)
|
|
221
221
|
);
|
|
222
222
|
|
|
223
223
|
if (wetrun) {
|
|
@@ -230,9 +230,9 @@ export const execute_publishing_plan = async (
|
|
|
230
230
|
max_attempts: 30,
|
|
231
231
|
initial_delay: 1000,
|
|
232
232
|
max_delay: 60000,
|
|
233
|
-
timeout: options.max_wait ?? GITOPS_NPM_WAIT_TIMEOUT_DEFAULT
|
|
233
|
+
timeout: options.max_wait ?? GITOPS_NPM_WAIT_TIMEOUT_DEFAULT
|
|
234
234
|
},
|
|
235
|
-
log
|
|
235
|
+
log
|
|
236
236
|
});
|
|
237
237
|
|
|
238
238
|
if (!wait_result.ok) {
|
|
@@ -240,14 +240,14 @@ export const execute_publishing_plan = async (
|
|
|
240
240
|
// carries a typed `timeout` signal, so we know this is a network failure
|
|
241
241
|
// without sniffing the message.
|
|
242
242
|
const err = new Error(
|
|
243
|
-
`Failed to wait for package: ${wait_result.message}${wait_result.timeout ? ' (timeout)' : ''}
|
|
243
|
+
`Failed to wait for package: ${wait_result.message}${wait_result.timeout ? ' (timeout)' : ''}`
|
|
244
244
|
);
|
|
245
245
|
failed.set(pkg_name, err);
|
|
246
|
-
emit({event: 'package_failed', name: pkg_name, error: err.message, code: 'network'});
|
|
246
|
+
emit({ event: 'package_failed', name: pkg_name, error: err.message, code: 'network' });
|
|
247
247
|
log?.error(st('red', ` ❌ Failed to publish ${pkg_name}: ${err.message}`));
|
|
248
248
|
break; // fail fast
|
|
249
249
|
}
|
|
250
|
-
emit({event: 'npm_waited', name: pkg_name, version: version.new_version});
|
|
250
|
+
emit({ event: 'npm_waited', name: pkg_name, version: version.new_version });
|
|
251
251
|
|
|
252
252
|
// 3. Update every dependent the plan says has a prod/peer dep on this package.
|
|
253
253
|
// This rewrites their package.json ranges and creates their auto-changeset,
|
|
@@ -258,7 +258,7 @@ export const execute_publishing_plan = async (
|
|
|
258
258
|
published,
|
|
259
259
|
(update) =>
|
|
260
260
|
update.updated_dependency === pkg_name &&
|
|
261
|
-
(update.type === 'dependencies' || update.type === 'peerDependencies')
|
|
261
|
+
(update.type === 'dependencies' || update.type === 'peerDependencies')
|
|
262
262
|
);
|
|
263
263
|
for (const [dependent_name, updates] of dependent_updates) {
|
|
264
264
|
const dependent_repo = repo_by_name.get(dependent_name);
|
|
@@ -277,7 +277,7 @@ export const execute_publishing_plan = async (
|
|
|
277
277
|
dependency: dep_name,
|
|
278
278
|
version: dep_version,
|
|
279
279
|
dep_type: dependency_update_type(plan, dependent_name, dep_name),
|
|
280
|
-
creates_changeset: republishes
|
|
280
|
+
creates_changeset: republishes
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
283
|
changed_repos.add(dependent_name); // Mark as changed for deployment
|
|
@@ -287,7 +287,7 @@ export const execute_publishing_plan = async (
|
|
|
287
287
|
published_versions: published, // creates the auto-changeset
|
|
288
288
|
log,
|
|
289
289
|
git_ops: ops.git,
|
|
290
|
-
fs_ops: ops.fs
|
|
290
|
+
fs_ops: ops.fs
|
|
291
291
|
});
|
|
292
292
|
} else {
|
|
293
293
|
// update-only leaf: rewrite ranges + commit, no changeset (it won't republish)
|
|
@@ -295,7 +295,7 @@ export const execute_publishing_plan = async (
|
|
|
295
295
|
strategy: options.version_strategy || 'caret',
|
|
296
296
|
log,
|
|
297
297
|
git_ops: ops.git,
|
|
298
|
-
fs_ops: ops.fs
|
|
298
|
+
fs_ops: ops.fs
|
|
299
299
|
});
|
|
300
300
|
}
|
|
301
301
|
}
|
|
@@ -310,7 +310,7 @@ export const execute_publishing_plan = async (
|
|
|
310
310
|
// TODO: emit a precise code once the npm/process ops return typed errors —
|
|
311
311
|
// today a publish-step cause lives in unstructured stderr, so use the honest
|
|
312
312
|
// coarse bucket rather than guessing 'auth'/'network'/'build' from the message.
|
|
313
|
-
code: 'publish'
|
|
313
|
+
code: 'publish'
|
|
314
314
|
});
|
|
315
315
|
log?.error(st('red', ` ❌ Failed to publish ${pkg_name}: ${err.message}`));
|
|
316
316
|
break; // Always fail fast on error
|
|
@@ -327,7 +327,7 @@ export const execute_publishing_plan = async (
|
|
|
327
327
|
const dev_updates_by_repo = group_dependency_updates(
|
|
328
328
|
plan.dependency_updates,
|
|
329
329
|
published,
|
|
330
|
-
(update) => update.type === 'devDependencies'
|
|
330
|
+
(update) => update.type === 'devDependencies'
|
|
331
331
|
);
|
|
332
332
|
|
|
333
333
|
if (dev_updates_by_repo.size > 0) {
|
|
@@ -346,7 +346,7 @@ export const execute_publishing_plan = async (
|
|
|
346
346
|
dependency: dep_name,
|
|
347
347
|
version: dep_version,
|
|
348
348
|
dep_type: 'dev',
|
|
349
|
-
creates_changeset: false
|
|
349
|
+
creates_changeset: false // dev-dep updates redeploy without republishing
|
|
350
350
|
});
|
|
351
351
|
}
|
|
352
352
|
changed_repos.add(repo_name); // Mark as changed for deployment
|
|
@@ -357,7 +357,7 @@ export const execute_publishing_plan = async (
|
|
|
357
357
|
strategy: options.version_strategy || 'caret',
|
|
358
358
|
log,
|
|
359
359
|
git_ops: ops.git,
|
|
360
|
-
fs_ops: ops.fs
|
|
360
|
+
fs_ops: ops.fs
|
|
361
361
|
});
|
|
362
362
|
}
|
|
363
363
|
}
|
|
@@ -371,15 +371,12 @@ export const execute_publishing_plan = async (
|
|
|
371
371
|
.map((name) => repo_by_name.get(name))
|
|
372
372
|
.filter((r): r is LocalRepo => r !== undefined);
|
|
373
373
|
log?.info(
|
|
374
|
-
st(
|
|
375
|
-
'cyan',
|
|
376
|
-
`\n🚢 Deploying ${repos_to_deploy.length}/${repos.length} repos with changes...\n`,
|
|
377
|
-
),
|
|
374
|
+
st('cyan', `\n🚢 Deploying ${repos_to_deploy.length}/${repos.length} repos with changes...\n`)
|
|
378
375
|
);
|
|
379
376
|
|
|
380
377
|
for (const repo of repos_to_deploy) {
|
|
381
378
|
try {
|
|
382
|
-
emit({event: 'deploy_started', name: repo.library.name});
|
|
379
|
+
emit({ event: 'deploy_started', name: repo.library.name });
|
|
383
380
|
log?.info(` Deploying ${repo.library.name}...`);
|
|
384
381
|
// Build fresh (no --no-build): a deployed site bundles its dependencies, so it
|
|
385
382
|
// must be rebuilt against the versions this run just published — the preflight
|
|
@@ -387,19 +384,19 @@ export const execute_publishing_plan = async (
|
|
|
387
384
|
const deploy_result = await ops.process.spawn({
|
|
388
385
|
cmd: 'gro',
|
|
389
386
|
args: ['deploy'],
|
|
390
|
-
cwd: repo.repo_dir
|
|
387
|
+
cwd: repo.repo_dir
|
|
391
388
|
});
|
|
392
389
|
|
|
393
390
|
if (deploy_result.ok) {
|
|
394
|
-
emit({event: 'deploy_completed', name: repo.library.name});
|
|
391
|
+
emit({ event: 'deploy_completed', name: repo.library.name });
|
|
395
392
|
log?.info(st('green', ` ✅ Deployed ${repo.library.name}`));
|
|
396
393
|
} else {
|
|
397
|
-
emit({event: 'deploy_failed', name: repo.library.name, error: deploy_result.message});
|
|
394
|
+
emit({ event: 'deploy_failed', name: repo.library.name, error: deploy_result.message });
|
|
398
395
|
log?.warn(st('yellow', ` ⚠️ Failed to deploy ${repo.library.name}`));
|
|
399
396
|
}
|
|
400
397
|
} catch (error) {
|
|
401
398
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
402
|
-
emit({event: 'deploy_failed', name: repo.library.name, error: err.message});
|
|
399
|
+
emit({ event: 'deploy_failed', name: repo.library.name, error: err.message });
|
|
403
400
|
log?.error(st('red', ` ❌ Error deploying ${repo.library.name}: ${err.message}`));
|
|
404
401
|
}
|
|
405
402
|
}
|
|
@@ -435,8 +432,8 @@ export const execute_publishing_plan = async (
|
|
|
435
432
|
log?.info(
|
|
436
433
|
st(
|
|
437
434
|
'green',
|
|
438
|
-
`\n✨ Dry run complete — ${published.size} package(s) would be published. Re-run with --wetrun to publish
|
|
439
|
-
)
|
|
435
|
+
`\n✨ Dry run complete — ${published.size} package(s) would be published. Re-run with --wetrun to publish.`
|
|
436
|
+
)
|
|
440
437
|
);
|
|
441
438
|
// The dry run is driven by the same plan as `gro gitops_plan`, so this
|
|
442
439
|
// count includes bump escalations and auto-generated changesets — it
|
|
@@ -449,22 +446,22 @@ export const execute_publishing_plan = async (
|
|
|
449
446
|
'red',
|
|
450
447
|
wetrun
|
|
451
448
|
? '\n❌ Some packages failed to publish\n'
|
|
452
|
-
: '\n❌ Some packages failed during dry run\n'
|
|
453
|
-
)
|
|
449
|
+
: '\n❌ Some packages failed during dry run\n'
|
|
450
|
+
)
|
|
454
451
|
);
|
|
455
452
|
}
|
|
456
453
|
|
|
457
|
-
emit({event: 'run_finished', summary});
|
|
454
|
+
emit({ event: 'run_finished', summary });
|
|
458
455
|
|
|
459
456
|
return {
|
|
460
457
|
ok,
|
|
461
458
|
published: Array.from(published.values()),
|
|
462
|
-
failed: Array.from(failed.entries()).map(([name, error]) => ({name, error})),
|
|
459
|
+
failed: Array.from(failed.entries()).map(([name, error]) => ({ name, error })),
|
|
463
460
|
duration,
|
|
464
461
|
events: capture.events,
|
|
465
462
|
summary,
|
|
466
463
|
plan_errors: plan.errors,
|
|
467
|
-
plan_warnings: plan.warnings
|
|
464
|
+
plan_warnings: plan.warnings
|
|
468
465
|
};
|
|
469
466
|
};
|
|
470
467
|
|
|
@@ -483,9 +480,9 @@ const publish_single_repo = async (
|
|
|
483
480
|
repo: LocalRepo,
|
|
484
481
|
options: PublishingOptions,
|
|
485
482
|
ops: GitopsOperations,
|
|
486
|
-
planned: VersionChange
|
|
483
|
+
planned: VersionChange
|
|
487
484
|
): Promise<PublishedVersion> => {
|
|
488
|
-
const {wetrun} = options;
|
|
485
|
+
const { wetrun } = options;
|
|
489
486
|
|
|
490
487
|
if (!wetrun) {
|
|
491
488
|
// Dry run reports the precomputed plan — the single source of truth for the
|
|
@@ -497,7 +494,7 @@ const publish_single_repo = async (
|
|
|
497
494
|
bump_type: planned.bump_type,
|
|
498
495
|
breaking: planned.breaking,
|
|
499
496
|
commit: 'simulated',
|
|
500
|
-
tag: `v${planned.to}
|
|
497
|
+
tag: `v${planned.to}`
|
|
501
498
|
};
|
|
502
499
|
}
|
|
503
500
|
|
|
@@ -505,7 +502,7 @@ const publish_single_repo = async (
|
|
|
505
502
|
const publish_result = await ops.process.spawn({
|
|
506
503
|
cmd: 'gro',
|
|
507
504
|
args: ['publish', '--no-build'],
|
|
508
|
-
cwd: repo.repo_dir
|
|
505
|
+
cwd: repo.repo_dir
|
|
509
506
|
});
|
|
510
507
|
|
|
511
508
|
if (!publish_result.ok) {
|
|
@@ -514,7 +511,7 @@ const publish_single_repo = async (
|
|
|
514
511
|
|
|
515
512
|
// Read the new version from package.json after gro publish
|
|
516
513
|
const package_json_path = join(repo.repo_dir, 'package.json');
|
|
517
|
-
const content_result = await ops.fs.readFile({path: package_json_path, encoding: 'utf8'});
|
|
514
|
+
const content_result = await ops.fs.readFile({ path: package_json_path, encoding: 'utf8' });
|
|
518
515
|
|
|
519
516
|
if (!content_result.ok) {
|
|
520
517
|
throw new Error(`Failed to read package.json: ${content_result.message}`);
|
|
@@ -524,7 +521,7 @@ const publish_single_repo = async (
|
|
|
524
521
|
const new_version = package_json.version;
|
|
525
522
|
|
|
526
523
|
// Get actual commit hash
|
|
527
|
-
const commit_result = await ops.git.current_commit_hash({cwd: repo.repo_dir});
|
|
524
|
+
const commit_result = await ops.git.current_commit_hash({ cwd: repo.repo_dir });
|
|
528
525
|
|
|
529
526
|
if (!commit_result.ok) {
|
|
530
527
|
throw new Error(`Failed to get commit hash: ${commit_result.message}`);
|
|
@@ -541,7 +538,7 @@ const publish_single_repo = async (
|
|
|
541
538
|
bump_type: planned.bump_type,
|
|
542
539
|
breaking: planned.breaking,
|
|
543
540
|
commit,
|
|
544
|
-
tag: `v${new_version}
|
|
541
|
+
tag: `v${new_version}`
|
|
545
542
|
};
|
|
546
543
|
};
|
|
547
544
|
|
|
@@ -554,7 +551,7 @@ const publish_single_repo = async (
|
|
|
554
551
|
export const group_dependency_updates = (
|
|
555
552
|
updates: Array<DependencyUpdate>,
|
|
556
553
|
published: Map<string, PublishedVersion>,
|
|
557
|
-
predicate: (update: DependencyUpdate) => boolean
|
|
554
|
+
predicate: (update: DependencyUpdate) => boolean
|
|
558
555
|
): Map<string, Map<string, string>> => {
|
|
559
556
|
const by_repo: Map<string, Map<string, string>> = new Map();
|
|
560
557
|
for (const update of updates) {
|
|
@@ -577,13 +574,13 @@ export const group_dependency_updates = (
|
|
|
577
574
|
const dependency_update_type = (
|
|
578
575
|
plan: PublishingPlan,
|
|
579
576
|
dependent: string,
|
|
580
|
-
dependency: string
|
|
577
|
+
dependency: string
|
|
581
578
|
): 'prod' | 'peer' =>
|
|
582
579
|
plan.dependency_updates.some(
|
|
583
580
|
(u) =>
|
|
584
581
|
u.dependent_package === dependent &&
|
|
585
582
|
u.updated_dependency === dependency &&
|
|
586
|
-
u.type === 'peerDependencies'
|
|
583
|
+
u.type === 'peerDependencies'
|
|
587
584
|
)
|
|
588
585
|
? 'peer'
|
|
589
586
|
: 'prod';
|
package/src/lib/npm_registry.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {Logger} from '@fuzdev/fuz_util/log.ts';
|
|
2
|
-
import {spawn_out} from '@fuzdev/fuz_util/process.ts';
|
|
3
|
-
import {wait} from '@fuzdev/fuz_util/async.ts';
|
|
4
|
-
import {styleText as st} from 'node:util';
|
|
1
|
+
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
2
|
+
import { spawn_out } from '@fuzdev/fuz_util/process.ts';
|
|
3
|
+
import { wait } from '@fuzdev/fuz_util/async.ts';
|
|
4
|
+
import { styleText as st } from 'node:util';
|
|
5
5
|
|
|
6
6
|
export interface WaitOptions {
|
|
7
7
|
log?: Logger;
|
|
@@ -19,9 +19,9 @@ export interface PackageInfo {
|
|
|
19
19
|
export const check_package_available = async (
|
|
20
20
|
pkg: string,
|
|
21
21
|
version: string,
|
|
22
|
-
options: {log?: Logger} = {}
|
|
22
|
+
options: { log?: Logger } = {}
|
|
23
23
|
): Promise<boolean> => {
|
|
24
|
-
const {log} = options;
|
|
24
|
+
const { log } = options;
|
|
25
25
|
try {
|
|
26
26
|
// Use npm view to check if the specific version exists
|
|
27
27
|
const result = await spawn_out('npm', ['view', `${pkg}@${version}`, 'version']);
|
|
@@ -57,14 +57,14 @@ export const check_package_available = async (
|
|
|
57
57
|
export const wait_for_package = async (
|
|
58
58
|
pkg: string,
|
|
59
59
|
version: string,
|
|
60
|
-
options: WaitOptions = {}
|
|
60
|
+
options: WaitOptions = {}
|
|
61
61
|
): Promise<void> => {
|
|
62
62
|
const {
|
|
63
63
|
log,
|
|
64
64
|
max_attempts = 30,
|
|
65
65
|
initial_delay = 1000,
|
|
66
66
|
max_delay = 60000,
|
|
67
|
-
timeout = 300000
|
|
67
|
+
timeout = 300000 // 5 minutes default
|
|
68
68
|
} = options;
|
|
69
69
|
|
|
70
70
|
const start_time = Date.now();
|
|
@@ -81,7 +81,7 @@ export const wait_for_package = async (
|
|
|
81
81
|
|
|
82
82
|
// Check if package is available
|
|
83
83
|
|
|
84
|
-
if (await check_package_available(pkg, version, {log})) {
|
|
84
|
+
if (await check_package_available(pkg, version, { log })) {
|
|
85
85
|
log?.info(st('green', ` ✓ ${pkg}@${version} is now available on NPM`));
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
@@ -113,9 +113,9 @@ export const wait_for_package = async (
|
|
|
113
113
|
*/
|
|
114
114
|
export const get_package_info = async (
|
|
115
115
|
pkg: string,
|
|
116
|
-
options: {log?: Logger} = {}
|
|
116
|
+
options: { log?: Logger } = {}
|
|
117
117
|
): Promise<PackageInfo | null> => {
|
|
118
|
-
const {log} = options;
|
|
118
|
+
const { log } = options;
|
|
119
119
|
try {
|
|
120
120
|
const result = await spawn_out('npm', ['view', pkg, '--json']);
|
|
121
121
|
|
|
@@ -123,7 +123,7 @@ export const get_package_info = async (
|
|
|
123
123
|
const data = JSON.parse(result.stdout);
|
|
124
124
|
return {
|
|
125
125
|
name: data.name,
|
|
126
|
-
version: data.version
|
|
126
|
+
version: data.version
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -136,7 +136,7 @@ export const get_package_info = async (
|
|
|
136
136
|
|
|
137
137
|
export const package_exists = async (
|
|
138
138
|
pkg: string,
|
|
139
|
-
options: {log?: Logger} = {}
|
|
139
|
+
options: { log?: Logger } = {}
|
|
140
140
|
): Promise<boolean> => {
|
|
141
141
|
const info = await get_package_info(pkg, options);
|
|
142
142
|
return info !== null;
|