@fuzdev/fuz_gitops 0.72.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.
Files changed (110) hide show
  1. package/README.md +13 -6
  2. package/dist/changeset_generator.d.ts.map +1 -1
  3. package/dist/changeset_generator.js +2 -16
  4. package/dist/changeset_reader.d.ts +1 -1
  5. package/dist/changeset_reader.d.ts.map +1 -1
  6. package/dist/dependency_graph.js +1 -1
  7. package/dist/git_operations.d.ts +5 -0
  8. package/dist/git_operations.d.ts.map +1 -1
  9. package/dist/git_operations.js +5 -0
  10. package/dist/gitops_analyze.task.d.ts +1 -0
  11. package/dist/gitops_analyze.task.d.ts.map +1 -1
  12. package/dist/gitops_analyze.task.js +12 -17
  13. package/dist/gitops_plan.task.d.ts +1 -0
  14. package/dist/gitops_plan.task.d.ts.map +1 -1
  15. package/dist/gitops_plan.task.js +9 -2
  16. package/dist/gitops_publish.task.d.ts +2 -2
  17. package/dist/gitops_publish.task.d.ts.map +1 -1
  18. package/dist/gitops_publish.task.js +83 -28
  19. package/dist/gitops_run.task.d.ts +2 -1
  20. package/dist/gitops_run.task.d.ts.map +1 -1
  21. package/dist/gitops_run.task.js +40 -7
  22. package/dist/gitops_sync.task.d.ts +1 -0
  23. package/dist/gitops_sync.task.d.ts.map +1 -1
  24. package/dist/gitops_sync.task.js +16 -2
  25. package/dist/gitops_task_helpers.d.ts +16 -2
  26. package/dist/gitops_task_helpers.d.ts.map +1 -1
  27. package/dist/gitops_task_helpers.js +11 -3
  28. package/dist/gitops_validate.task.d.ts +1 -0
  29. package/dist/gitops_validate.task.d.ts.map +1 -1
  30. package/dist/gitops_validate.task.js +20 -20
  31. package/dist/graph_validation.d.ts +16 -1
  32. package/dist/graph_validation.d.ts.map +1 -1
  33. package/dist/graph_validation.js +15 -0
  34. package/dist/local_repo.d.ts +22 -10
  35. package/dist/local_repo.d.ts.map +1 -1
  36. package/dist/local_repo.js +92 -75
  37. package/dist/log_helpers.d.ts +0 -5
  38. package/dist/log_helpers.d.ts.map +1 -1
  39. package/dist/log_helpers.js +8 -19
  40. package/dist/multi_repo_publisher.d.ts +21 -2
  41. package/dist/multi_repo_publisher.d.ts.map +1 -1
  42. package/dist/multi_repo_publisher.js +279 -287
  43. package/dist/operations.d.ts +6 -26
  44. package/dist/operations.d.ts.map +1 -1
  45. package/dist/operations_defaults.d.ts.map +1 -1
  46. package/dist/operations_defaults.js +1 -19
  47. package/dist/output_helpers.d.ts.map +1 -1
  48. package/dist/output_helpers.js +7 -6
  49. package/dist/paths.d.ts +0 -4
  50. package/dist/paths.d.ts.map +1 -1
  51. package/dist/paths.js +0 -4
  52. package/dist/publish_gate.d.ts +44 -0
  53. package/dist/publish_gate.d.ts.map +1 -0
  54. package/dist/publish_gate.js +32 -0
  55. package/dist/publish_steps.d.ts +60 -0
  56. package/dist/publish_steps.d.ts.map +1 -0
  57. package/dist/publish_steps.js +113 -0
  58. package/dist/publishing_event.d.ts +12 -19
  59. package/dist/publishing_event.d.ts.map +1 -1
  60. package/dist/publishing_event.js +16 -25
  61. package/dist/publishing_plan.d.ts +1 -2
  62. package/dist/publishing_plan.d.ts.map +1 -1
  63. package/dist/publishing_plan.js +18 -1
  64. package/dist/publishing_plan_helpers.d.ts +1 -1
  65. package/dist/publishing_plan_helpers.d.ts.map +1 -1
  66. package/dist/publishing_plan_helpers.js +2 -15
  67. package/dist/publishing_plan_logging.d.ts.map +1 -1
  68. package/dist/publishing_plan_logging.js +15 -23
  69. package/dist/version_utils.d.ts +17 -3
  70. package/dist/version_utils.d.ts.map +1 -1
  71. package/dist/version_utils.js +22 -0
  72. package/package.json +5 -6
  73. package/src/lib/changeset_generator.ts +10 -19
  74. package/src/lib/changeset_reader.ts +1 -2
  75. package/src/lib/dependency_graph.ts +1 -1
  76. package/src/lib/git_operations.ts +5 -0
  77. package/src/lib/gitops_analyze.task.ts +18 -23
  78. package/src/lib/gitops_plan.task.ts +10 -2
  79. package/src/lib/gitops_publish.task.ts +92 -27
  80. package/src/lib/gitops_run.task.ts +39 -7
  81. package/src/lib/gitops_sync.task.ts +18 -3
  82. package/src/lib/gitops_task_helpers.ts +20 -3
  83. package/src/lib/gitops_validate.task.ts +30 -22
  84. package/src/lib/graph_validation.ts +26 -0
  85. package/src/lib/local_repo.ts +114 -83
  86. package/src/lib/log_helpers.ts +8 -26
  87. package/src/lib/multi_repo_publisher.ts +336 -353
  88. package/src/lib/operations.ts +6 -22
  89. package/src/lib/operations_defaults.ts +1 -19
  90. package/src/lib/output_helpers.ts +7 -6
  91. package/src/lib/paths.ts +0 -5
  92. package/src/lib/publish_gate.ts +53 -0
  93. package/src/lib/publish_steps.ts +149 -0
  94. package/src/lib/publishing_event.ts +16 -25
  95. package/src/lib/publishing_plan.ts +23 -3
  96. package/src/lib/publishing_plan_helpers.ts +5 -18
  97. package/src/lib/publishing_plan_logging.ts +19 -39
  98. package/src/lib/version_utils.ts +30 -9
  99. package/dist/npm_install_helpers.d.ts +0 -23
  100. package/dist/npm_install_helpers.d.ts.map +0 -1
  101. package/dist/npm_install_helpers.js +0 -60
  102. package/dist/semver.d.ts +0 -26
  103. package/dist/semver.d.ts.map +0 -1
  104. package/dist/semver.js +0 -137
  105. package/dist/serialization_types.d.ts +0 -59
  106. package/dist/serialization_types.d.ts.map +0 -1
  107. package/dist/serialization_types.js +0 -42
  108. package/src/lib/npm_install_helpers.ts +0 -85
  109. package/src/lib/semver.ts +0 -170
  110. package/src/lib/serialization_types.ts +0 -92
@@ -1,6 +1,6 @@
1
1
  import { styleText as st } from 'node:util';
2
2
  import { validate_dependency_graph } from './graph_validation.js';
3
- import { is_breaking_change, compare_bump_types, calculate_next_version } from './version_utils.js';
3
+ import { is_breaking_change, compare_bump_types, calculate_next_version, } from './version_utils.js';
4
4
  import { default_changeset_operations } from './operations_defaults.js';
5
5
  import { GITOPS_MAX_ITERATIONS_DEFAULT } from './gitops_constants.js';
6
6
  import { calculate_dependency_updates, get_required_bump_for_dependencies, } from './publishing_plan_helpers.js';
@@ -70,6 +70,17 @@ export const generate_publishing_plan = async (repos, options = {}) => {
70
70
  const repo = repos.find((r) => r.library.name === pkg_name);
71
71
  if (!repo)
72
72
  continue;
73
+ // Private packages never publish — exclude them from version changes entirely (no
74
+ // publish step, npm-wait, bump escalation, or auto-changeset). They keep their slot in
75
+ // the topological order. Flag a private package that carries a changeset, since that
76
+ // changeset can't be published.
77
+ if (repo.library.package_json.private) {
78
+ const private_has_changesets = await ops.has_changesets({ repo });
79
+ if (private_has_changesets.ok && private_has_changesets.value) {
80
+ warnings.push(`${pkg_name} is private — its changeset(s) will not be published`);
81
+ }
82
+ continue;
83
+ }
73
84
  // Check for changesets
74
85
  const has_result = await ops.has_changesets({ repo });
75
86
  if (!has_result.ok) {
@@ -140,6 +151,10 @@ export const generate_publishing_plan = async (repos, options = {}) => {
140
151
  // Process packages to check for bump escalation and auto-generated changesets
141
152
  for (const repo of repos) {
142
153
  const pkg_name = repo.library.name;
154
+ // Private packages are excluded from version changes (they never publish), so they
155
+ // never escalate or auto-generate a changeset.
156
+ if (repo.library.package_json.private)
157
+ continue;
143
158
  // Get required bump from dependencies
144
159
  const required_bump = get_required_bump_for_dependencies(repo, dependency_updates, breaking_packages);
145
160
  // Find triggering dependency for verbose output
@@ -248,6 +263,8 @@ export const generate_publishing_plan = async (repos, options = {}) => {
248
263
  const { dependency_updates: pending_updates } = calculate_dependency_updates(repos, predicted_versions, breaking_packages);
249
264
  for (const repo of repos) {
250
265
  const pkg_name = repo.library.name;
266
+ if (repo.library.package_json.private)
267
+ continue; // private packages never publish
251
268
  const required_bump = get_required_bump_for_dependencies(repo, pending_updates, breaking_packages);
252
269
  // Check if this package would need processing
253
270
  const existing_entry = version_changes.find((vc) => vc.package_name === pkg_name);
@@ -6,7 +6,7 @@
6
6
  * @module
7
7
  */
8
8
  import type { LocalRepo } from './local_repo.js';
9
- import type { BumpType } from './semver.js';
9
+ import { type BumpType } from './version_utils.js';
10
10
  import type { DependencyUpdate } from './publishing_plan.js';
11
11
  /**
12
12
  * Calculates all dependency updates between packages based on predicted versions.
@@ -1 +1 @@
1
- {"version":3,"file":"publishing_plan_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,oBAAoB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,mBAAmB,GAAG,CAAC,MAAM,CAAC,KAC5B;IACF,kBAAkB,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC5C,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;CA2E9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,oBAAoB,KAAK,CAAC,gBAAgB,CAAC,EAC3C,mBAAmB,GAAG,CAAC,MAAM,CAAC,KAC5B,QAAQ,GAAG,IA8Bb,CAAC"}
1
+ {"version":3,"file":"publishing_plan_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAoD,KAAK,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,oBAAoB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,mBAAmB,GAAG,CAAC,MAAM,CAAC,KAC5B;IACF,kBAAkB,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC5C,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;CAwE9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,oBAAoB,KAAK,CAAC,gBAAgB,CAAC,EAC3C,mBAAmB,GAAG,CAAC,MAAM,CAAC,KAC5B,QAAQ,GAAG,IAqBb,CAAC"}
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @module
7
7
  */
8
- import { needs_update } from './version_utils.js';
8
+ import { needs_update, required_bump_for_dependency_update } from './version_utils.js';
9
9
  /**
10
10
  * Calculates all dependency updates between packages based on predicted versions.
11
11
  *
@@ -29,7 +29,6 @@ export const calculate_dependency_updates = (repos, predicted_versions, breaking
29
29
  current_version,
30
30
  new_version,
31
31
  type: 'dependencies',
32
- causes_republish: true,
33
32
  });
34
33
  if (breaking_packages.has(dep_name)) {
35
34
  const cascades = breaking_cascades.get(dep_name) || [];
@@ -52,7 +51,6 @@ export const calculate_dependency_updates = (repos, predicted_versions, breaking
52
51
  current_version,
53
52
  new_version,
54
53
  type: 'peerDependencies',
55
- causes_republish: true,
56
54
  });
57
55
  if (breaking_packages.has(dep_name)) {
58
56
  const cascades = breaking_cascades.get(dep_name) || [];
@@ -75,7 +73,6 @@ export const calculate_dependency_updates = (repos, predicted_versions, breaking
75
73
  current_version,
76
74
  new_version,
77
75
  type: 'devDependencies',
78
- causes_republish: false,
79
76
  });
80
77
  }
81
78
  }
@@ -100,15 +97,5 @@ export const get_required_bump_for_dependencies = (repo, dependency_updates, bre
100
97
  }
101
98
  // Check if any of these dependencies have breaking changes
102
99
  const has_breaking_deps = relevant_updates.some((update) => breaking_packages.has(update.updated_dependency));
103
- const current_version = repo.library.package_json.version || '0.0.0';
104
- const [major] = current_version.split('.').map(Number);
105
- const is_pre_1_0 = major === 0;
106
- if (has_breaking_deps) {
107
- // Breaking changes propagate
108
- // Pre-1.0: use minor for breaking changes
109
- // 1.0+: use major for breaking changes
110
- return is_pre_1_0 ? 'minor' : 'major';
111
- }
112
- // For non-breaking dependency updates, use patch
113
- return 'patch';
100
+ return required_bump_for_dependency_update(repo.library.package_json.version || '0.0.0', has_breaking_deps);
114
101
  };
@@ -1 +1 @@
1
- {"version":3,"file":"publishing_plan_logging.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan_logging.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,EACX,cAAc,EAQd,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AA2GD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,cAAc,EACpB,KAAK,MAAM,EACX,UAAS,cAAmB,KAC1B,IAiKF,CAAC"}
1
+ {"version":3,"file":"publishing_plan_logging.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan_logging.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,EACX,cAAc,EAQd,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AA2GD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,cAAc,EACpB,KAAK,MAAM,EACX,UAAS,cAAmB,KAC1B,IA6IF,CAAC"}
@@ -120,31 +120,23 @@ export const log_publishing_plan = (plan, log, options = {}) => {
120
120
  const with_changesets = ordered_changes.filter((vc) => vc.has_changesets && !vc.needs_bump_escalation);
121
121
  const with_escalation = ordered_changes.filter((vc) => vc.needs_bump_escalation);
122
122
  const with_auto_changesets = ordered_changes.filter((vc) => vc.will_generate_changeset);
123
- // Log each group with diff-style output
124
- if (with_changesets.length > 0) {
125
- log.info(st('cyan', 'Version Changes (from changesets):'));
126
- for (const change of with_changesets) {
127
- const idx = ordered_changes.indexOf(change);
128
- log_version_change_with_diffs(change, idx, ordered_changes.length, dependency_updates, breaking_cascades, log);
123
+ // A single running counter across all groups so positions read 1..N with no
124
+ // gaps. (Numbering per-group index would make the first group skip the numbers
125
+ // that land in a later group, e.g. jump from `[9/12]` to `[11/12]`.)
126
+ const total = with_changesets.length + with_escalation.length + with_auto_changesets.length;
127
+ let position = 0;
128
+ const log_change_group = (title, color, changes) => {
129
+ if (changes.length === 0)
130
+ return;
131
+ log.info(st(color, title));
132
+ for (const change of changes) {
133
+ log_version_change_with_diffs(change, position++, total, dependency_updates, breaking_cascades, log);
129
134
  }
130
135
  log.info('');
131
- }
132
- if (with_escalation.length > 0) {
133
- log.info(st('yellow', 'Version Changes (bump escalation):'));
134
- for (const change of with_escalation) {
135
- const idx = ordered_changes.indexOf(change);
136
- log_version_change_with_diffs(change, idx, ordered_changes.length, dependency_updates, breaking_cascades, log);
137
- }
138
- log.info('');
139
- }
140
- if (with_auto_changesets.length > 0) {
141
- log.info(st('cyan', 'Version Changes (auto-generated):'));
142
- for (const change of with_auto_changesets) {
143
- const idx = ordered_changes.indexOf(change);
144
- log_version_change_with_diffs(change, idx, ordered_changes.length, dependency_updates, breaking_cascades, log);
145
- }
146
- log.info('');
147
- }
136
+ };
137
+ log_change_group('Version Changes (from changesets):', 'cyan', with_changesets);
138
+ log_change_group('Version Changes (bump escalation):', 'yellow', with_escalation);
139
+ log_change_group('Version Changes (auto-generated):', 'cyan', with_auto_changesets);
148
140
  }
149
141
  else {
150
142
  log.info(st('dim', 'No packages to publish'));
@@ -1,4 +1,5 @@
1
- import type { BumpType } from './semver.js';
1
+ /** A semver bump kind: `major`, `minor`, or `patch`. */
2
+ export type BumpType = 'major' | 'minor' | 'patch';
2
3
  export declare const is_wildcard: (version: string) => boolean;
3
4
  /**
4
5
  * Strips version prefix (^, ~, >=, <=, etc) from a version string.
@@ -47,8 +48,21 @@ export declare const get_update_prefix: (current_version: string, default_strate
47
48
  * Pre-1.0: minor bumps are breaking
48
49
  * 1.0+: major bumps are breaking
49
50
  */
50
- export declare const is_breaking_change: (old_version: string, bump_type: "major" | "minor" | "patch") => boolean;
51
- export declare const detect_bump_type: (old_version: string, new_version: string) => "major" | "minor" | "patch";
51
+ export declare const is_breaking_change: (old_version: string, bump_type: BumpType) => boolean;
52
+ /**
53
+ * The bump a package must take when one of its prod/peer dependencies updates.
54
+ * Pre-1.0: `minor` for a breaking dependency, otherwise `patch`.
55
+ * 1.0+: `major` for a breaking dependency, otherwise `patch`.
56
+ *
57
+ * Single source of truth for the dependency-driven bump rule, shared by the plan
58
+ * (`get_required_bump_for_dependencies`) and the auto-changeset generator
59
+ * (`calculate_required_bump`) so the two never drift.
60
+ *
61
+ * @param current_version - the package's current version, used to detect the pre-1.0 regime
62
+ * @param has_breaking_deps - whether any updated dependency is a breaking change
63
+ */
64
+ export declare const required_bump_for_dependency_update: (current_version: string, has_breaking_deps: boolean) => BumpType;
65
+ export declare const detect_bump_type: (old_version: string, new_version: string) => BumpType;
52
66
  /**
53
67
  * Compares bump types. Returns positive if a > b, negative if a < b, 0 if equal.
54
68
  */
@@ -1 +1 @@
1
- {"version":3,"file":"version_utils.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/version_utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAE1C,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,OAE7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,MAEtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MAGpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,MAAM,KAAG,MAWlE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,EAAE,aAAa,MAAM,KAAG,OASnE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAC7B,iBAAiB,MAAM,EACvB,mBAAkB,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,IAAU,KAC3C,MAcF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC9B,aAAa,MAAM,EACnB,WAAW,OAAO,GAAG,OAAO,GAAG,OAAO,KACpC,OAWF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC5B,aAAa,MAAM,EACnB,aAAa,MAAM,KACjB,OAAO,GAAG,OAAO,GAAG,OAOtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,GAAG,QAAQ,EAAE,GAAG,QAAQ,KAAG,MAO7D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,iBAAiB,MAAM,EAAE,WAAW,QAAQ,KAAG,MAkBrF,CAAC"}
1
+ {"version":3,"file":"version_utils.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/version_utils.ts"],"names":[],"mappings":"AAEA,wDAAwD;AACxD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEnD,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,OAE7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,MAEtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MAGpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,MAAM,KAAG,MAWlE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,EAAE,aAAa,MAAM,KAAG,OASnE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAC7B,iBAAiB,MAAM,EACvB,mBAAkB,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,IAAU,KAC3C,MAcF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,aAAa,MAAM,EAAE,WAAW,QAAQ,KAAG,OAW7E,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mCAAmC,GAC/C,iBAAiB,MAAM,EACvB,mBAAmB,OAAO,KACxB,QASF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,EAAE,aAAa,MAAM,KAAG,QAO3E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,GAAG,QAAQ,EAAE,GAAG,QAAQ,KAAG,MAO7D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,iBAAiB,MAAM,EAAE,WAAW,QAAQ,KAAG,MAkBrF,CAAC"}
@@ -96,6 +96,28 @@ export const is_breaking_change = (old_version, bump_type) => {
96
96
  return bump_type === 'major';
97
97
  }
98
98
  };
99
+ /**
100
+ * The bump a package must take when one of its prod/peer dependencies updates.
101
+ * Pre-1.0: `minor` for a breaking dependency, otherwise `patch`.
102
+ * 1.0+: `major` for a breaking dependency, otherwise `patch`.
103
+ *
104
+ * Single source of truth for the dependency-driven bump rule, shared by the plan
105
+ * (`get_required_bump_for_dependencies`) and the auto-changeset generator
106
+ * (`calculate_required_bump`) so the two never drift.
107
+ *
108
+ * @param current_version - the package's current version, used to detect the pre-1.0 regime
109
+ * @param has_breaking_deps - whether any updated dependency is a breaking change
110
+ */
111
+ export const required_bump_for_dependency_update = (current_version, has_breaking_deps) => {
112
+ const [major] = current_version.split('.').map(Number);
113
+ const is_pre_1_0 = major === 0;
114
+ if (has_breaking_deps) {
115
+ // Breaking changes propagate: pre-1.0 uses minor, 1.0+ uses major
116
+ return is_pre_1_0 ? 'minor' : 'major';
117
+ }
118
+ // Non-breaking dependency updates only need a patch
119
+ return 'patch';
120
+ };
99
121
  export const detect_bump_type = (old_version, new_version) => {
100
122
  const old_parts = old_version.split('.').map(Number);
101
123
  const new_parts = new_version.split('.').map(Number);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_gitops",
3
- "version": "0.72.0",
3
+ "version": "0.73.0",
4
4
  "description": "a tool for managing many repos",
5
5
  "glyph": "🪄",
6
6
  "logo": "logo.svg",
@@ -42,10 +42,9 @@
42
42
  "@fuzdev/blake3_wasm": "^0.1.1",
43
43
  "@fuzdev/fuz_code": "^0.45.1",
44
44
  "@fuzdev/fuz_css": "^0.61.1",
45
- "@fuzdev/fuz_ui": "^0.198.0",
46
- "@fuzdev/fuz_util": "^0.63.1",
47
- "@fuzdev/gro": "^0.200.0",
48
- "@jridgewell/trace-mapping": "^0.3.31",
45
+ "@fuzdev/fuz_ui": "^0.198.1",
46
+ "@fuzdev/fuz_util": "^0.63.2",
47
+ "@fuzdev/gro": "^0.202.0",
49
48
  "@ryanatkn/eslint-config": "^0.12.1",
50
49
  "@sveltejs/acorn-typescript": "^1.0.9",
51
50
  "@sveltejs/adapter-static": "^3.0.10",
@@ -63,7 +62,7 @@
63
62
  "prettier-plugin-svelte": "^3.5.1",
64
63
  "svelte": "^5.56.0",
65
64
  "svelte-check": "^4.4.6",
66
- "svelte-docinfo": "^0.2.1",
65
+ "svelte-docinfo": "^0.4.0",
67
66
  "svelte2tsx": "^0.7.52",
68
67
  "tslib": "^2.8.1",
69
68
  "typescript": "^5.9.3",
@@ -11,7 +11,11 @@ import {join} from 'node:path';
11
11
  import type {Logger} from '@fuzdev/fuz_util/log.js';
12
12
  import type {LocalRepo} from './local_repo.js';
13
13
  import type {PublishedVersion} from './multi_repo_publisher.js';
14
- import {strip_version_prefix} from './version_utils.js';
14
+ import {
15
+ strip_version_prefix,
16
+ required_bump_for_dependency_update,
17
+ type BumpType,
18
+ } from './version_utils.js';
15
19
  import type {FsOperations} from './operations.js';
16
20
  import {default_fs_operations} from './operations_defaults.js';
17
21
 
@@ -69,24 +73,11 @@ export const create_changeset_for_dependency_updates = async (
69
73
  const calculate_required_bump = (
70
74
  repo: LocalRepo,
71
75
  updates: Array<DependencyVersionChange>,
72
- ): 'major' | 'minor' | 'patch' => {
73
- const current_version = repo.library.package_json.version || '0.0.0';
74
- const [major] = current_version.split('.').map(Number);
75
- const is_pre_1_0 = major === 0;
76
-
77
- // Check if any dependency had breaking changes
78
- const has_breaking = updates.some((u) => u.breaking);
79
-
80
- if (has_breaking) {
81
- // Breaking changes propagate
82
- // Pre-1.0: use minor for breaking changes
83
- // 1.0+: use major for breaking changes
84
- return is_pre_1_0 ? 'minor' : 'major';
85
- }
86
-
87
- // For non-breaking dependency updates, always use patch
88
- return 'patch';
89
- };
76
+ ): BumpType =>
77
+ required_bump_for_dependency_update(
78
+ repo.library.package_json.version || '0.0.0',
79
+ updates.some((u) => u.breaking),
80
+ );
90
81
 
91
82
  /**
92
83
  * Generates markdown changeset content for dependency updates.
@@ -13,8 +13,7 @@ import {readdir, readFile} from 'node:fs/promises';
13
13
  import {join} from 'node:path';
14
14
 
15
15
  import type {LocalRepo} from './local_repo.js';
16
- import type {BumpType} from './semver.js';
17
- import {compare_bump_types, calculate_next_version} from './version_utils.js';
16
+ import {compare_bump_types, calculate_next_version, type BumpType} from './version_utils.js';
18
17
 
19
18
  export interface ChangesetInfo {
20
19
  filename: string;
@@ -66,7 +66,7 @@ export class DependencyGraph {
66
66
  repo,
67
67
  dependencies: new Map(),
68
68
  dependents: new Set(),
69
- publishable: !!library.package_json.private === false, // eslint-disable-line @typescript-eslint/no-unnecessary-boolean-literal-compare
69
+ publishable: !library.package_json.private,
70
70
  };
71
71
 
72
72
  // Extract dependencies
@@ -84,6 +84,11 @@ export const git_push_tag = async (
84
84
  }
85
85
  };
86
86
 
87
+ /**
88
+ * Returns `true` if the working tree has any changes — staged, unstaged, or
89
+ * untracked (`git status --porcelain`). Broader than `git_list_uncommitted_files`,
90
+ * which reports only tracked working-tree changes relative to HEAD.
91
+ */
87
92
  export const git_has_changes = async (options?: SpawnOptions): Promise<boolean> => {
88
93
  const {stdout} = await spawn_out('git', ['status', '--porcelain'], options);
89
94
  return stdout ? stdout.trim().length > 0 : false;
@@ -4,9 +4,9 @@ import {styleText as st} from 'node:util';
4
4
  import type {Logger} from '@fuzdev/fuz_util/log.js';
5
5
 
6
6
  import {get_gitops_ready} from './gitops_task_helpers.js';
7
- import {type DependencyGraph, DependencyGraphBuilder} from './dependency_graph.js';
7
+ import type {DependencyGraph} from './dependency_graph.js';
8
8
  import type {LocalRepo} from './local_repo.js';
9
- import {validate_dependency_graph} from './graph_validation.js';
9
+ import {analyze_repos, type DependencyAnalysis} from './graph_validation.js';
10
10
  import {
11
11
  format_wildcard_dependencies,
12
12
  format_dev_cycles,
@@ -30,6 +30,13 @@ export const Args = z.strictObject({
30
30
  .meta({description: 'output format'})
31
31
  .default('stdout'),
32
32
  outfile: z.string().meta({description: 'write output to file instead of logging'}).optional(),
33
+ sync: z
34
+ .boolean()
35
+ .meta({
36
+ description:
37
+ 'sync repos (switch branch, pull, install) before analyzing instead of reading the working tree as-is',
38
+ })
39
+ .default(false),
33
40
  });
34
41
  export type Args = z.infer<typeof Args>;
35
42
 
@@ -38,25 +45,13 @@ export const task: Task<Args> = {
38
45
  Args,
39
46
  summary: 'analyze dependency structure and relationships across repos',
40
47
  run: async ({args, log}) => {
41
- const {config, dir, format, outfile} = args;
48
+ const {config, dir, format, outfile, sync} = args;
42
49
 
43
- // Get repos ready (without downloading)
44
- const {local_repos} = await get_gitops_ready({config, dir, download: false, log});
50
+ // Get repos ready (without downloading); read the working tree as-is unless `--sync`
51
+ const {local_repos} = await get_gitops_ready({config, dir, download: false, sync, log});
45
52
 
46
- // Build dependency graph and validate (but don't throw on cycles for analyze)
47
- const {graph, publishing_order: order} = validate_dependency_graph(local_repos, {
48
- log,
49
- throw_on_prod_cycles: false, // Analyze should report, not throw
50
- log_cycles: false, // We'll show cycles in our formatted output
51
- log_order: false, // We'll show order in our formatted output
52
- });
53
-
54
- // Perform additional analysis
55
- const builder = new DependencyGraphBuilder();
56
- const analysis = builder.analyze(graph);
57
-
58
- // Publishing order (may be null if prod cycles exist)
59
- const publishing_order = order.length > 0 ? order : null;
53
+ // Build the dependency graph and analyze cycles/wildcards (tolerating cycles)
54
+ const {graph, analysis, publishing_order} = analyze_repos(local_repos);
60
55
 
61
56
  // Format and output using output_helpers
62
57
  const data = {
@@ -74,7 +69,7 @@ export const task: Task<Args> = {
74
69
  interface AnalysisData {
75
70
  repos: Array<LocalRepo>;
76
71
  graph: DependencyGraph;
77
- analysis: ReturnType<DependencyGraphBuilder['analyze']>;
72
+ analysis: DependencyAnalysis;
78
73
  publishing_order: Array<string> | null;
79
74
  }
80
75
 
@@ -102,7 +97,7 @@ const calculate_stats = (graph: DependencyGraph) => {
102
97
 
103
98
  const format_json = (
104
99
  graph: DependencyGraph,
105
- analysis: ReturnType<DependencyGraphBuilder['analyze']>,
100
+ analysis: DependencyAnalysis,
106
101
  publishing_order: Array<string> | null,
107
102
  ): string => {
108
103
  const output = {
@@ -116,7 +111,7 @@ const format_json = (
116
111
  const format_markdown = (
117
112
  repos: Array<LocalRepo>,
118
113
  graph: DependencyGraph,
119
- analysis: ReturnType<DependencyGraphBuilder['analyze']>,
114
+ analysis: DependencyAnalysis,
120
115
  publishing_order: Array<string> | null,
121
116
  ): Array<string> => {
122
117
  const lines: Array<string> = ['# Dependency Analysis'];
@@ -192,7 +187,7 @@ const format_markdown = (
192
187
  const format_stdout = (
193
188
  repos: Array<LocalRepo>,
194
189
  graph: DependencyGraph,
195
- analysis: ReturnType<DependencyGraphBuilder['analyze']>,
190
+ analysis: DependencyAnalysis,
196
191
  publishing_order: Array<string> | null,
197
192
  log: Logger,
198
193
  ): void => {
@@ -28,6 +28,13 @@ export const Args = z.strictObject({
28
28
  .default('stdout'),
29
29
  outfile: z.string().meta({description: 'write output to file instead of logging'}).optional(),
30
30
  verbose: z.boolean().meta({description: 'show additional details'}).default(false),
31
+ sync: z
32
+ .boolean()
33
+ .meta({
34
+ description:
35
+ 'sync repos (switch branch, pull, install) before planning instead of reading the working tree as-is',
36
+ })
37
+ .default(false),
31
38
  });
32
39
  export type Args = z.infer<typeof Args>;
33
40
 
@@ -46,15 +53,16 @@ export const task: Task<Args> = {
46
53
  summary: 'generate a publishing plan based on changesets',
47
54
  Args,
48
55
  run: async ({args, log}): Promise<void> => {
49
- const {dir, config, format, outfile, verbose} = args;
56
+ const {dir, config, format, outfile, verbose, sync} = args;
50
57
 
51
58
  log.info(st('cyan', 'Generating multi-repo publishing plan...'));
52
59
 
53
- // Load local repos
60
+ // Load local repos; read the working tree as-is unless `--sync`
54
61
  const {local_repos} = await get_gitops_ready({
55
62
  config,
56
63
  dir,
57
64
  download: false, // Don't download if missing
65
+ sync,
58
66
  log,
59
67
  });
60
68