@fuzdev/fuz_gitops 0.71.0 → 0.73.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 +13 -6
- 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/dependency_graph.js +1 -1
- 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 +3 -2
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +90 -26
- 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 +22 -10
- package/dist/local_repo.d.ts.map +1 -1
- package/dist/local_repo.js +92 -75
- 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 +29 -2
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +307 -233
- 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 +1 -19
- 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 +123 -0
- package/dist/publishing_event.d.ts.map +1 -0
- package/dist/publishing_event.js +140 -0
- package/dist/publishing_event_handler.d.ts +42 -0
- package/dist/publishing_event_handler.d.ts.map +1 -0
- package/dist/publishing_event_handler.js +75 -0
- package/dist/publishing_plan.d.ts +1 -2
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +18 -1
- 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_ops.d.ts +1 -1
- package/dist/repo_ops.js +1 -1
- 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 +6 -7
- package/src/lib/changeset_generator.ts +10 -19
- package/src/lib/changeset_reader.ts +1 -2
- package/src/lib/dependency_graph.ts +1 -1
- 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 +100 -25
- 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 +114 -83
- package/src/lib/log_helpers.ts +8 -26
- package/src/lib/multi_repo_publisher.ts +387 -269
- package/src/lib/operations.ts +6 -22
- package/src/lib/operations_defaults.ts +1 -19
- 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 +151 -0
- package/src/lib/publishing_event_handler.ts +98 -0
- package/src/lib/publishing_plan.ts +23 -3
- package/src/lib/publishing_plan_helpers.ts +5 -18
- package/src/lib/publishing_plan_logging.ts +19 -39
- package/src/lib/repo_ops.ts +1 -1
- 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/README.md
CHANGED
|
@@ -96,12 +96,19 @@ gro gitops_sync --download # clone missing repos first
|
|
|
96
96
|
### Diagnostic commands (read-only)
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
gro gitops_validate
|
|
100
|
-
gro gitops_analyze
|
|
101
|
-
gro gitops_plan
|
|
102
|
-
gro gitops_publish
|
|
99
|
+
gro gitops_validate # run all validation checks (analyze + plan + dry run)
|
|
100
|
+
gro gitops_analyze # analyze dependency graph and detect cycles
|
|
101
|
+
gro gitops_plan # generate publishing plan showing version changes and cascades
|
|
102
|
+
gro gitops_publish # simulate publishing without side effects (dry run default)
|
|
103
|
+
gro gitops_publish --preview # show the ordered side-effects a --wetrun would perform
|
|
103
104
|
```
|
|
104
105
|
|
|
106
|
+
These read each repo's working tree exactly as it sits on disk — no branch
|
|
107
|
+
switching, pulling, or installing — so they're safe to run with feature
|
|
108
|
+
branches checked out and uncommitted changes. Pass `--sync` to refresh repos
|
|
109
|
+
(switch to the configured branch, pull, install) before running, or run
|
|
110
|
+
`gro gitops_sync` first.
|
|
111
|
+
|
|
105
112
|
### Publishing packages
|
|
106
113
|
|
|
107
114
|
```bash
|
|
@@ -119,8 +126,8 @@ gro gitops_publish --wetrun --no-plan # skip plan confirmation
|
|
|
119
126
|
- ./docs/troubleshooting.md - Common errors and
|
|
120
127
|
debugging tips
|
|
121
128
|
|
|
122
|
-
Getting started as a dev? Start with [Gro](https://github.com/
|
|
123
|
-
and the [Fuz template](https://github.com/
|
|
129
|
+
Getting started as a dev? Start with [Gro](https://github.com/fuzdev/gro)
|
|
130
|
+
and the [Fuz template](https://github.com/fuzdev/fuz_template).
|
|
124
131
|
|
|
125
132
|
TODO
|
|
126
133
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changeset_generator.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/changeset_generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"changeset_generator.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/changeset_generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAMhE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAGlD,MAAM,WAAW,uBAAuB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,SAAS,KAAK,CAAC,uBAAuB,CAAC,EACvC,UAAS;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAM,KACjD,OAAO,CAAC,MAAM,CAiChB,CAAC;AAWF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GACtC,cAAc,MAAM,EACpB,SAAS,KAAK,CAAC,uBAAuB,CAAC,EACvC,WAAW,OAAO,GAAG,OAAO,GAAG,OAAO,KACpC,MAsCF,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACrC,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,oBAAoB,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAC/C,KAAK,CAAC,uBAAuB,CAoB/B,CAAC"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
import { join } from 'node:path';
|
|
10
|
-
import { strip_version_prefix } from './version_utils.js';
|
|
10
|
+
import { strip_version_prefix, required_bump_for_dependency_update, } from './version_utils.js';
|
|
11
11
|
import { default_fs_operations } from './operations_defaults.js';
|
|
12
12
|
/**
|
|
13
13
|
* Creates a changeset file for dependency updates.
|
|
@@ -40,21 +40,7 @@ export const create_changeset_for_dependency_updates = async (repo, updates, opt
|
|
|
40
40
|
log?.info(` Created changeset: ${filename}`);
|
|
41
41
|
return filepath;
|
|
42
42
|
};
|
|
43
|
-
const calculate_required_bump = (repo, updates) =>
|
|
44
|
-
const current_version = repo.library.package_json.version || '0.0.0';
|
|
45
|
-
const [major] = current_version.split('.').map(Number);
|
|
46
|
-
const is_pre_1_0 = major === 0;
|
|
47
|
-
// Check if any dependency had breaking changes
|
|
48
|
-
const has_breaking = updates.some((u) => u.breaking);
|
|
49
|
-
if (has_breaking) {
|
|
50
|
-
// Breaking changes propagate
|
|
51
|
-
// Pre-1.0: use minor for breaking changes
|
|
52
|
-
// 1.0+: use major for breaking changes
|
|
53
|
-
return is_pre_1_0 ? 'minor' : 'major';
|
|
54
|
-
}
|
|
55
|
-
// For non-breaking dependency updates, always use patch
|
|
56
|
-
return 'patch';
|
|
57
|
-
};
|
|
43
|
+
const calculate_required_bump = (repo, updates) => required_bump_for_dependency_update(repo.library.package_json.version || '0.0.0', updates.some((u) => u.breaking));
|
|
58
44
|
/**
|
|
59
45
|
* Generates markdown changeset content for dependency updates.
|
|
60
46
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
10
10
|
import type { LocalRepo } from './local_repo.js';
|
|
11
|
-
import type
|
|
11
|
+
import { type BumpType } from './version_utils.js';
|
|
12
12
|
export interface ChangesetInfo {
|
|
13
13
|
filename: string;
|
|
14
14
|
packages: Array<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changeset_reader.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/changeset_reader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"changeset_reader.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/changeset_reader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAA6C,KAAK,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAE7F,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAA;KAAC,CAAC,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,uBAAuB,GACnC,SAAS,MAAM,EACf,iBAAyB,KACvB,aAAa,GAAG,IAmClB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,UAAU,MAAM,EAChB,MAAM,MAAM,KACV,OAAO,CAAC,aAAa,GAAG,IAAI,CAgB9B,CAAC;AAEF,eAAO,MAAM,eAAe,GAC3B,MAAM,SAAS,EACf,MAAM,MAAM,KACV,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAsB9B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,GAC1C,YAAY,KAAK,CAAC,aAAa,CAAC,EAChC,cAAc,MAAM,KAClB,QAAQ,GAAG,IAcb,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAU,MAAM,SAAS,KAAG,OAAO,CAAC,OAAO,CAarE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,SAAS,EACf,MAAM,MAAM,KACV,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,QAAQ,CAAA;CAAC,GAAG,IAAI,CAsBvD,CAAC"}
|
package/dist/dependency_graph.js
CHANGED
|
@@ -31,7 +31,7 @@ export class DependencyGraph {
|
|
|
31
31
|
repo,
|
|
32
32
|
dependencies: new Map(),
|
|
33
33
|
dependents: new Set(),
|
|
34
|
-
publishable:
|
|
34
|
+
publishable: !library.package_json.private,
|
|
35
35
|
};
|
|
36
36
|
// Extract dependencies
|
|
37
37
|
const deps = library.package_json.dependencies || EMPTY_OBJECT;
|
package/dist/git_operations.d.ts
CHANGED
|
@@ -20,6 +20,11 @@ export declare const git_tag: (tag_name: string, message?: string, options?: Spa
|
|
|
20
20
|
* Pushes a tag to origin and throws if anything goes wrong.
|
|
21
21
|
*/
|
|
22
22
|
export declare const git_push_tag: (tag_name: string, origin?: GitOrigin, options?: SpawnOptions) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Returns `true` if the working tree has any changes — staged, unstaged, or
|
|
25
|
+
* untracked (`git status --porcelain`). Broader than `git_list_uncommitted_files`,
|
|
26
|
+
* which reports only tracked working-tree changes relative to HEAD.
|
|
27
|
+
*/
|
|
23
28
|
export declare const git_has_changes: (options?: SpawnOptions) => Promise<boolean>;
|
|
24
29
|
/**
|
|
25
30
|
* Lists uncommitted files in the working tree (`git diff --name-only HEAD`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git_operations.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/git_operations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAMN,KAAK,SAAS,EACd,KAAK,SAAS,EACd,MAAM,yBAAyB,CAAC;AAEjC;;GAEG;AACH,eAAO,MAAM,OAAO,GACnB,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAC7B,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAU,SAAS,MAAM,EAAE,UAAU,YAAY,KAAG,OAAO,CAAC,IAAI,CAOtF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC9B,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAC7B,SAAS,MAAM,EACf,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAGd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,GACnB,UAAU,MAAM,EAChB,UAAU,MAAM,EAChB,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CASd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GACxB,UAAU,MAAM,EAChB,SAAQ,SAAiC,EACzC,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,UAAU,YAAY,KAAG,OAAO,CAAC,OAAO,CAG7E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,UAAU,YAAY,KACpB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAQvB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,aAAa,MAAM,EACnB,WAAW,MAAM,EACjB,WAAW,MAAM,EACjB,UAAU,YAAY,KACpB,OAAO,CAAC,OAAO,CAOjB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAU,UAAU,MAAM,EAAE,UAAU,YAAY,KAAG,OAAO,CAAC,IAAI,CAStF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAU,UAAU,YAAY,KAAG,OAAO,CAAC,IAAI,CAOxE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC7B,QAAQ,SAAS,EACjB,OAAM,OAAc,EACpB,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAoBd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gCAAgC,GAAU,UAAU,YAAY,KAAG,OAAO,CAAC,MAAM,CAM7F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gCAAgC,GAC5C,SAAS,MAAM,EACf,UAAU,YAAY,KACpB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oCAAoC,GAChD,UAAU,YAAY,KACpB,OAAO,CAAC,OAAO,CAGjB,CAAC;AAEF,eAAO,MAAM,cAAc,GAC1B,SAAQ,MAAiB,EACzB,UAAU,YAAY,KACpB,OAAO,CAAC,OAAO,CAQjB,CAAC"}
|
|
1
|
+
{"version":3,"file":"git_operations.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/git_operations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAMN,KAAK,SAAS,EACd,KAAK,SAAS,EACd,MAAM,yBAAyB,CAAC;AAEjC;;GAEG;AACH,eAAO,MAAM,OAAO,GACnB,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAC7B,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAU,SAAS,MAAM,EAAE,UAAU,YAAY,KAAG,OAAO,CAAC,IAAI,CAOtF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC9B,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAC7B,SAAS,MAAM,EACf,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAGd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,GACnB,UAAU,MAAM,EAChB,UAAU,MAAM,EAChB,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CASd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GACxB,UAAU,MAAM,EAChB,SAAQ,SAAiC,EACzC,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAU,UAAU,YAAY,KAAG,OAAO,CAAC,OAAO,CAG7E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,UAAU,YAAY,KACpB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAQvB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,aAAa,MAAM,EACnB,WAAW,MAAM,EACjB,WAAW,MAAM,EACjB,UAAU,YAAY,KACpB,OAAO,CAAC,OAAO,CAOjB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAU,UAAU,MAAM,EAAE,UAAU,YAAY,KAAG,OAAO,CAAC,IAAI,CAStF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAU,UAAU,YAAY,KAAG,OAAO,CAAC,IAAI,CAOxE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC7B,QAAQ,SAAS,EACjB,OAAM,OAAc,EACpB,UAAU,YAAY,KACpB,OAAO,CAAC,IAAI,CAoBd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gCAAgC,GAAU,UAAU,YAAY,KAAG,OAAO,CAAC,MAAM,CAM7F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gCAAgC,GAC5C,SAAS,MAAM,EACf,UAAU,YAAY,KACpB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oCAAoC,GAChD,UAAU,YAAY,KACpB,OAAO,CAAC,OAAO,CAGjB,CAAC;AAEF,eAAO,MAAM,cAAc,GAC1B,SAAQ,MAAiB,EACzB,UAAU,YAAY,KACpB,OAAO,CAAC,OAAO,CAQjB,CAAC"}
|
package/dist/git_operations.js
CHANGED
|
@@ -45,6 +45,11 @@ export const git_push_tag = async (tag_name, origin = 'origin', options) => {
|
|
|
45
45
|
throw Error(`git_push_tag failed for tag '${tag_name}' with ${spawn_result_to_message(result)}${stderr ? ': ' + stderr.trim() : ''}`);
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Returns `true` if the working tree has any changes — staged, unstaged, or
|
|
50
|
+
* untracked (`git status --porcelain`). Broader than `git_list_uncommitted_files`,
|
|
51
|
+
* which reports only tracked working-tree changes relative to HEAD.
|
|
52
|
+
*/
|
|
48
53
|
export const git_has_changes = async (options) => {
|
|
49
54
|
const { stdout } = await spawn_out('git', ['status', '--porcelain'], options);
|
|
50
55
|
return stdout ? stdout.trim().length > 0 : false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_analyze.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_analyze.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAgBtB,cAAc;AACd,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"gitops_analyze.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_analyze.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAgBtB,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;;;;;kBAqBf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,cAAc;AACd,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CAsB3B,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
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 { validate_dependency_graph } from './graph_validation.js';
|
|
4
|
+
import { analyze_repos } from './graph_validation.js';
|
|
6
5
|
import { format_wildcard_dependencies, format_dev_cycles, format_production_cycles, } from './log_helpers.js';
|
|
7
6
|
import { format_and_output } from './output_helpers.js';
|
|
8
7
|
import { GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.js';
|
|
@@ -21,27 +20,23 @@ export const Args = z.strictObject({
|
|
|
21
20
|
.meta({ description: 'output format' })
|
|
22
21
|
.default('stdout'),
|
|
23
22
|
outfile: z.string().meta({ description: 'write output to file instead of logging' }).optional(),
|
|
23
|
+
sync: z
|
|
24
|
+
.boolean()
|
|
25
|
+
.meta({
|
|
26
|
+
description: 'sync repos (switch branch, pull, install) before analyzing instead of reading the working tree as-is',
|
|
27
|
+
})
|
|
28
|
+
.default(false),
|
|
24
29
|
});
|
|
25
30
|
/** @nodocs */
|
|
26
31
|
export const task = {
|
|
27
32
|
Args,
|
|
28
33
|
summary: 'analyze dependency structure and relationships across repos',
|
|
29
34
|
run: async ({ args, log }) => {
|
|
30
|
-
const { config, dir, format, outfile } = args;
|
|
31
|
-
// Get repos ready (without downloading)
|
|
32
|
-
const { local_repos } = await get_gitops_ready({ config, dir, download: false, log });
|
|
33
|
-
// Build dependency graph and
|
|
34
|
-
const { graph, publishing_order
|
|
35
|
-
log,
|
|
36
|
-
throw_on_prod_cycles: false, // Analyze should report, not throw
|
|
37
|
-
log_cycles: false, // We'll show cycles in our formatted output
|
|
38
|
-
log_order: false, // We'll show order in our formatted output
|
|
39
|
-
});
|
|
40
|
-
// Perform additional analysis
|
|
41
|
-
const builder = new DependencyGraphBuilder();
|
|
42
|
-
const analysis = builder.analyze(graph);
|
|
43
|
-
// Publishing order (may be null if prod cycles exist)
|
|
44
|
-
const publishing_order = order.length > 0 ? order : null;
|
|
35
|
+
const { config, dir, format, outfile, sync } = args;
|
|
36
|
+
// Get repos ready (without downloading); read the working tree as-is unless `--sync`
|
|
37
|
+
const { local_repos } = await get_gitops_ready({ config, dir, download: false, sync, log });
|
|
38
|
+
// Build the dependency graph and analyze cycles/wildcards (tolerating cycles)
|
|
39
|
+
const { graph, analysis, publishing_order } = analyze_repos(local_repos);
|
|
45
40
|
// Format and output using output_helpers
|
|
46
41
|
const data = {
|
|
47
42
|
repos: local_repos,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_plan.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_plan.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAatB,cAAc;AACd,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"gitops_plan.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_plan.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAatB,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;;;;;;kBAsBf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CAmC3B,CAAC"}
|
package/dist/gitops_plan.task.js
CHANGED
|
@@ -20,6 +20,12 @@ export const Args = z.strictObject({
|
|
|
20
20
|
.default('stdout'),
|
|
21
21
|
outfile: z.string().meta({ description: 'write output to file instead of logging' }).optional(),
|
|
22
22
|
verbose: z.boolean().meta({ description: 'show additional details' }).default(false),
|
|
23
|
+
sync: z
|
|
24
|
+
.boolean()
|
|
25
|
+
.meta({
|
|
26
|
+
description: 'sync repos (switch branch, pull, install) before planning instead of reading the working tree as-is',
|
|
27
|
+
})
|
|
28
|
+
.default(false),
|
|
23
29
|
});
|
|
24
30
|
/**
|
|
25
31
|
* Generate a publishing plan showing what would happen during multi-repo publishing.
|
|
@@ -36,13 +42,14 @@ export const task = {
|
|
|
36
42
|
summary: 'generate a publishing plan based on changesets',
|
|
37
43
|
Args,
|
|
38
44
|
run: async ({ args, log }) => {
|
|
39
|
-
const { dir, config, format, outfile, verbose } = args;
|
|
45
|
+
const { dir, config, format, outfile, verbose, sync } = args;
|
|
40
46
|
log.info(st('cyan', 'Generating multi-repo publishing plan...'));
|
|
41
|
-
// Load local repos
|
|
47
|
+
// Load local repos; read the working tree as-is unless `--sync`
|
|
42
48
|
const { local_repos } = await get_gitops_ready({
|
|
43
49
|
config,
|
|
44
50
|
dir,
|
|
45
51
|
download: false, // Don't download if missing
|
|
52
|
+
sync,
|
|
46
53
|
log,
|
|
47
54
|
});
|
|
48
55
|
if (local_repos.length === 0) {
|
|
@@ -17,11 +17,12 @@ export declare const Args: z.ZodObject<{
|
|
|
17
17
|
}>>;
|
|
18
18
|
deploy: z.ZodDefault<z.ZodBoolean>;
|
|
19
19
|
plan: z.ZodDefault<z.ZodBoolean>;
|
|
20
|
-
'no-plan': z.ZodDefault<z.ZodBoolean>;
|
|
21
20
|
max_wait: z.ZodDefault<z.ZodNumber>;
|
|
22
|
-
|
|
21
|
+
emit_json: z.ZodDefault<z.ZodBoolean>;
|
|
23
22
|
outfile: z.ZodOptional<z.ZodString>;
|
|
24
23
|
verbose: z.ZodDefault<z.ZodBoolean>;
|
|
24
|
+
sync: z.ZodDefault<z.ZodBoolean>;
|
|
25
|
+
preview: z.ZodDefault<z.ZodBoolean>;
|
|
25
26
|
}, z.core.$strict>;
|
|
26
27
|
export type Args = z.infer<typeof Args>;
|
|
27
28
|
/** @nodocs */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_publish.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_publish.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"gitops_publish.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_publish.task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAiBtB,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;kBA4Cf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,cAAc;AACd,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CAiH3B,CAAC"}
|
|
@@ -2,8 +2,11 @@ import { z } from 'zod';
|
|
|
2
2
|
import { createInterface } from 'node:readline/promises';
|
|
3
3
|
import { styleText as st } from 'node:util';
|
|
4
4
|
import { get_gitops_ready } from './gitops_task_helpers.js';
|
|
5
|
-
import {
|
|
5
|
+
import { execute_publishing_plan, } from './multi_repo_publisher.js';
|
|
6
|
+
import { stdout_handler } from './publishing_event_handler.js';
|
|
6
7
|
import { generate_publishing_plan, log_publishing_plan } from './publishing_plan.js';
|
|
8
|
+
import { derive_publish_steps, format_publish_steps } from './publish_steps.js';
|
|
9
|
+
import { decide_publish_gate, publish_run_failed } from './publish_gate.js';
|
|
7
10
|
import { format_and_output } from './output_helpers.js';
|
|
8
11
|
import { GITOPS_CONFIG_PATH_DEFAULT, GITOPS_NPM_WAIT_TIMEOUT_DEFAULT } from './gitops_constants.js';
|
|
9
12
|
/** @nodocs */
|
|
@@ -26,43 +29,64 @@ export const Args = z.strictObject({
|
|
|
26
29
|
.meta({ description: 'output format' })
|
|
27
30
|
.default('stdout'),
|
|
28
31
|
deploy: z.boolean().meta({ description: 'deploy all repos after publishing' }).default(false),
|
|
29
|
-
plan: z
|
|
30
|
-
'no-plan': z
|
|
32
|
+
plan: z
|
|
31
33
|
.boolean()
|
|
32
|
-
.meta({ description: '
|
|
33
|
-
.default(
|
|
34
|
+
.meta({ description: 'show the plan and confirm before publishing; --no-plan to skip' })
|
|
35
|
+
.default(true),
|
|
34
36
|
max_wait: z
|
|
35
37
|
.number()
|
|
36
38
|
.meta({ description: 'max time to wait for npm propagation in ms' })
|
|
37
39
|
.default(GITOPS_NPM_WAIT_TIMEOUT_DEFAULT),
|
|
38
|
-
|
|
40
|
+
emit_json: z
|
|
39
41
|
.boolean()
|
|
40
|
-
.meta({ description: '
|
|
42
|
+
.meta({ description: 'stream structured publishing events as JSON-lines to stdout' })
|
|
41
43
|
.default(false),
|
|
42
44
|
outfile: z.string().meta({ description: 'write output to file instead of logging' }).optional(),
|
|
43
45
|
verbose: z.boolean().meta({ description: 'show additional details in plan output' }).default(false),
|
|
46
|
+
sync: z
|
|
47
|
+
.boolean()
|
|
48
|
+
.meta({
|
|
49
|
+
description: 'sync repos (switch branch, pull, install) before the dry run instead of reading the working tree as-is; always on for --wetrun',
|
|
50
|
+
})
|
|
51
|
+
.default(false),
|
|
52
|
+
preview: z
|
|
53
|
+
.boolean()
|
|
54
|
+
.meta({ description: 'show the ordered side-effects a --wetrun would perform' })
|
|
55
|
+
.default(false),
|
|
44
56
|
});
|
|
45
57
|
/** @nodocs */
|
|
46
58
|
export const task = {
|
|
47
59
|
summary: 'publish all repos in dependency order',
|
|
48
60
|
Args,
|
|
49
61
|
run: async ({ args, log }) => {
|
|
50
|
-
const { config, dir, peer_strategy, wetrun, format, deploy, plan, max_wait,
|
|
51
|
-
// Load repos
|
|
62
|
+
const { config, dir, peer_strategy, wetrun, format, deploy, plan, max_wait, emit_json, outfile, verbose, sync, preview, } = args;
|
|
63
|
+
// Load repos. A dry run reads the working tree as-is unless `--sync`;
|
|
64
|
+
// a real publish (`--wetrun`) always syncs so preflight sees the canonical branches.
|
|
52
65
|
const { local_repos: repos } = await get_gitops_ready({
|
|
53
66
|
config,
|
|
54
67
|
dir,
|
|
55
68
|
download: false, // Don't download if missing
|
|
69
|
+
sync: sync || wetrun,
|
|
56
70
|
log,
|
|
57
71
|
});
|
|
58
|
-
//
|
|
59
|
-
|
|
72
|
+
// Generate the plan once; the executor consumes this exact plan (no second pass).
|
|
73
|
+
const publishing_plan = await generate_publishing_plan(repos, { verbose });
|
|
74
|
+
const preview_steps = preview ? derive_publish_steps(publishing_plan, { deploy }) : null;
|
|
75
|
+
// Decide whether to show the plan + confirm, block, or proceed (the decision table lives
|
|
76
|
+
// in `decide_publish_gate`; readline + exit stay here at the edge).
|
|
77
|
+
const gate = decide_publish_gate({ wetrun, show_plan: plan, plan: publishing_plan });
|
|
78
|
+
// A real publish that shows its plan prints it first — including before a `blocked` throw,
|
|
79
|
+
// so the operator sees the errors that blocked it.
|
|
80
|
+
if (gate.action !== 'proceed') {
|
|
60
81
|
log.info(st('cyan', 'Publishing Plan'));
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
log_publishing_plan(publishing_plan, log, { verbose });
|
|
83
|
+
}
|
|
84
|
+
if (gate.action === 'blocked') {
|
|
85
|
+
throw new Error(gate.message);
|
|
86
|
+
}
|
|
87
|
+
else if (gate.action === 'confirm') {
|
|
88
|
+
if (preview_steps)
|
|
89
|
+
log_preview(preview_steps, log);
|
|
66
90
|
// Ask for confirmation
|
|
67
91
|
log.info(st('yellow', '⚠️ This will publish the packages shown above.'));
|
|
68
92
|
process.stdout.write('Continue with publishing? (y/n): ');
|
|
@@ -72,21 +96,27 @@ export const task = {
|
|
|
72
96
|
process.exit(0);
|
|
73
97
|
}
|
|
74
98
|
}
|
|
99
|
+
else if (preview_steps && format === 'stdout') {
|
|
100
|
+
// proceed (dry run or --no-plan): only render to stdout for the human format;
|
|
101
|
+
// json/markdown carry the preview in their structured output, so logging here too
|
|
102
|
+
// would corrupt that stream.
|
|
103
|
+
log_preview(preview_steps, log);
|
|
104
|
+
}
|
|
75
105
|
// Publishing options
|
|
76
106
|
const options = {
|
|
77
107
|
wetrun,
|
|
78
|
-
update_deps: true, // Always update dependencies
|
|
79
108
|
version_strategy: peer_strategy,
|
|
80
109
|
deploy,
|
|
81
110
|
max_wait,
|
|
82
|
-
skip_install,
|
|
83
111
|
log,
|
|
112
|
+
// Live JSON-lines stream when requested; events also surface on the result.
|
|
113
|
+
events: emit_json ? stdout_handler() : undefined,
|
|
84
114
|
};
|
|
85
115
|
// Execute publishing (may throw on fatal errors like circular dependencies)
|
|
86
116
|
let result;
|
|
87
117
|
let fatal_error = null;
|
|
88
118
|
try {
|
|
89
|
-
result = await
|
|
119
|
+
result = await execute_publishing_plan(repos, publishing_plan, options);
|
|
90
120
|
}
|
|
91
121
|
catch (error) {
|
|
92
122
|
// Construct a failure result for fatal errors so output can still be generated
|
|
@@ -97,33 +127,44 @@ export const task = {
|
|
|
97
127
|
// Note: FATAL_ERROR is a placeholder - only fatal_error.message is displayed in output
|
|
98
128
|
failed: [{ name: 'FATAL_ERROR', error: fatal_error }],
|
|
99
129
|
duration: 0,
|
|
130
|
+
events: [],
|
|
131
|
+
summary: { total: 0, published: 0, failed: 1, skipped: 0, duration: 0 },
|
|
132
|
+
plan_errors: publishing_plan.errors,
|
|
133
|
+
plan_warnings: publishing_plan.warnings,
|
|
100
134
|
};
|
|
101
135
|
}
|
|
102
136
|
// Format and output result (always runs, even on fatal errors)
|
|
103
|
-
// Note: stdout format is handled by
|
|
137
|
+
// Note: stdout format is handled by the executor's logging
|
|
104
138
|
if (format !== 'stdout') {
|
|
105
|
-
await format_and_output({ result, fatal_error }, create_publish_formatters(), {
|
|
139
|
+
await format_and_output({ result, fatal_error, preview_steps }, create_publish_formatters(), {
|
|
106
140
|
format,
|
|
107
141
|
outfile,
|
|
108
142
|
log,
|
|
109
143
|
});
|
|
110
144
|
}
|
|
111
145
|
// Exit with error if failed
|
|
112
|
-
if (
|
|
146
|
+
if (publish_run_failed(result, fatal_error)) {
|
|
113
147
|
process.exit(1);
|
|
114
148
|
}
|
|
115
149
|
},
|
|
116
150
|
};
|
|
117
151
|
const create_publish_formatters = () => ({
|
|
118
|
-
json: (data) => JSON.stringify(data.result, null, 2),
|
|
119
|
-
markdown: (data) => format_result_markdown(data.result, data.fatal_error),
|
|
152
|
+
json: (data) => JSON.stringify(data.preview_steps ? { ...data.result, preview: data.preview_steps } : data.result, null, 2),
|
|
153
|
+
markdown: (data) => format_result_markdown(data.result, data.fatal_error, data.preview_steps),
|
|
120
154
|
stdout: () => {
|
|
121
|
-
// stdout format is handled by
|
|
155
|
+
// stdout format is handled by the executor's logging
|
|
122
156
|
// This should never be called due to early return in task
|
|
123
157
|
},
|
|
124
158
|
});
|
|
159
|
+
/** Logs the ordered side-effect preview to stdout. */
|
|
160
|
+
const log_preview = (steps, log) => {
|
|
161
|
+
log.info(st('cyan', '\nSide-effect preview (what a real publish would perform):'));
|
|
162
|
+
for (const line of format_publish_steps(steps)) {
|
|
163
|
+
log.info(st('dim', ` ${line}`));
|
|
164
|
+
}
|
|
165
|
+
};
|
|
125
166
|
// Format the publishing result as markdown
|
|
126
|
-
const format_result_markdown = (result, fatal_error) => {
|
|
167
|
+
const format_result_markdown = (result, fatal_error, preview_steps) => {
|
|
127
168
|
const lines = [];
|
|
128
169
|
lines.push('# Publishing Result');
|
|
129
170
|
lines.push('');
|
|
@@ -159,6 +200,29 @@ const format_result_markdown = (result, fatal_error) => {
|
|
|
159
200
|
lines.push(`- \`${name}\`: ${error.message}`);
|
|
160
201
|
}
|
|
161
202
|
}
|
|
203
|
+
if (result.plan_warnings.length > 0) {
|
|
204
|
+
lines.push('');
|
|
205
|
+
lines.push('## Plan Warnings');
|
|
206
|
+
lines.push('');
|
|
207
|
+
for (const warning of result.plan_warnings)
|
|
208
|
+
lines.push(`- ${warning}`);
|
|
209
|
+
}
|
|
210
|
+
if (result.plan_errors.length > 0) {
|
|
211
|
+
lines.push('');
|
|
212
|
+
lines.push('## Plan Errors');
|
|
213
|
+
lines.push('');
|
|
214
|
+
for (const plan_error of result.plan_errors)
|
|
215
|
+
lines.push(`- ${plan_error}`);
|
|
216
|
+
}
|
|
217
|
+
if (preview_steps) {
|
|
218
|
+
lines.push('');
|
|
219
|
+
lines.push('## Side-Effect Preview');
|
|
220
|
+
lines.push('');
|
|
221
|
+
lines.push('```');
|
|
222
|
+
for (const line of format_publish_steps(preview_steps))
|
|
223
|
+
lines.push(line);
|
|
224
|
+
lines.push('```');
|
|
225
|
+
}
|
|
162
226
|
return lines;
|
|
163
227
|
};
|
|
164
228
|
/**
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { type Task } from '@fuzdev/gro';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const Args: z.ZodObject<{
|
|
4
|
-
|
|
4
|
+
_: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
5
5
|
config: z.ZodDefault<z.ZodString>;
|
|
6
6
|
concurrency: z.ZodDefault<z.ZodNumber>;
|
|
7
7
|
format: z.ZodDefault<z.ZodEnum<{
|
|
8
8
|
text: "text";
|
|
9
9
|
json: "json";
|
|
10
10
|
}>>;
|
|
11
|
+
outfile: z.ZodOptional<z.ZodString>;
|
|
11
12
|
}, z.core.$strict>;
|
|
12
13
|
export type Args = z.infer<typeof Args>;
|
|
13
14
|
export declare const task: Task<Args>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitops_run.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_run.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,IAAI,EAAC,MAAM,aAAa,CAAC;AACjD,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"gitops_run.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gitops_run.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,IAAI,EAAC,MAAM,aAAa,CAAC;AACjD,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAUtB,eAAO,MAAM,IAAI;;;;;;;;;kBAmBf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAaxC,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CAyM3B,CAAC"}
|
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
|