@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.
- 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 +2 -2
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +83 -28
- package/dist/gitops_run.task.d.ts +2 -1
- package/dist/gitops_run.task.d.ts.map +1 -1
- package/dist/gitops_run.task.js +40 -7
- package/dist/gitops_sync.task.d.ts +1 -0
- package/dist/gitops_sync.task.d.ts.map +1 -1
- package/dist/gitops_sync.task.js +16 -2
- package/dist/gitops_task_helpers.d.ts +16 -2
- package/dist/gitops_task_helpers.d.ts.map +1 -1
- package/dist/gitops_task_helpers.js +11 -3
- package/dist/gitops_validate.task.d.ts +1 -0
- package/dist/gitops_validate.task.d.ts.map +1 -1
- package/dist/gitops_validate.task.js +20 -20
- package/dist/graph_validation.d.ts +16 -1
- package/dist/graph_validation.d.ts.map +1 -1
- package/dist/graph_validation.js +15 -0
- package/dist/local_repo.d.ts +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 +21 -2
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +279 -287
- package/dist/operations.d.ts +6 -26
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations_defaults.d.ts.map +1 -1
- package/dist/operations_defaults.js +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 +12 -19
- package/dist/publishing_event.d.ts.map +1 -1
- package/dist/publishing_event.js +16 -25
- package/dist/publishing_plan.d.ts +1 -2
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +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/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 +5 -6
- 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 +92 -27
- package/src/lib/gitops_run.task.ts +39 -7
- package/src/lib/gitops_sync.task.ts +18 -3
- package/src/lib/gitops_task_helpers.ts +20 -3
- package/src/lib/gitops_validate.task.ts +30 -22
- package/src/lib/graph_validation.ts +26 -0
- package/src/lib/local_repo.ts +114 -83
- package/src/lib/log_helpers.ts +8 -26
- package/src/lib/multi_repo_publisher.ts +336 -353
- package/src/lib/operations.ts +6 -22
- package/src/lib/operations_defaults.ts +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 +16 -25
- 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/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
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
2
|
-
import type { LocalRepo } from './local_repo.js';
|
|
3
|
-
import type { GitopsOperations } from './operations.js';
|
|
4
|
-
/**
|
|
5
|
-
* Installs npm dependencies with cache healing on ETARGET errors.
|
|
6
|
-
*
|
|
7
|
-
* **Strategy:**
|
|
8
|
-
* 1. First attempt: regular `npm install`
|
|
9
|
-
* 2. On ETARGET error (stale cache): `npm cache clean --force` then retry
|
|
10
|
-
* 3. On other errors: fail immediately
|
|
11
|
-
*
|
|
12
|
-
* **Why ETARGET errors occur:**
|
|
13
|
-
* After publishing a package and waiting for NPM registry propagation,
|
|
14
|
-
* npm's local cache may still have stale "404" metadata. This healing
|
|
15
|
-
* strategy clears the cache to force fresh metadata fetch.
|
|
16
|
-
*
|
|
17
|
-
* @param repo - the repository to install dependencies for
|
|
18
|
-
* @param ops - gitops operations (for dependency injection)
|
|
19
|
-
* @param log - optional logger
|
|
20
|
-
* @throws Error if install fails (with details about cache healing attempts)
|
|
21
|
-
*/
|
|
22
|
-
export declare const install_with_cache_healing: (repo: LocalRepo, ops: GitopsOperations, log?: Logger) => Promise<void>;
|
|
23
|
-
//# sourceMappingURL=npm_install_helpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"npm_install_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/npm_install_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAmBtD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,GACtC,MAAM,SAAS,EACf,KAAK,gBAAgB,EACrB,MAAM,MAAM,KACV,OAAO,CAAC,IAAI,CAuCd,CAAC"}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { styleText as st } from 'node:util';
|
|
2
|
-
/**
|
|
3
|
-
* Checks if an npm install error is caused by stale cache (ETARGET).
|
|
4
|
-
* Detects various error message formats:
|
|
5
|
-
* - "code ETARGET"
|
|
6
|
-
* - "ETARGET"
|
|
7
|
-
* - "notarget"
|
|
8
|
-
* - "No matching version found"
|
|
9
|
-
*/
|
|
10
|
-
const is_etarget_error = (message, stderr) => {
|
|
11
|
-
const combined = `${message} ${stderr}`.toLowerCase();
|
|
12
|
-
return (combined.includes('etarget') ||
|
|
13
|
-
combined.includes('notarget') ||
|
|
14
|
-
combined.includes('no matching version found'));
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Installs npm dependencies with cache healing on ETARGET errors.
|
|
18
|
-
*
|
|
19
|
-
* **Strategy:**
|
|
20
|
-
* 1. First attempt: regular `npm install`
|
|
21
|
-
* 2. On ETARGET error (stale cache): `npm cache clean --force` then retry
|
|
22
|
-
* 3. On other errors: fail immediately
|
|
23
|
-
*
|
|
24
|
-
* **Why ETARGET errors occur:**
|
|
25
|
-
* After publishing a package and waiting for NPM registry propagation,
|
|
26
|
-
* npm's local cache may still have stale "404" metadata. This healing
|
|
27
|
-
* strategy clears the cache to force fresh metadata fetch.
|
|
28
|
-
*
|
|
29
|
-
* @param repo - the repository to install dependencies for
|
|
30
|
-
* @param ops - gitops operations (for dependency injection)
|
|
31
|
-
* @param log - optional logger
|
|
32
|
-
* @throws Error if install fails (with details about cache healing attempts)
|
|
33
|
-
*/
|
|
34
|
-
export const install_with_cache_healing = async (repo, ops, log) => {
|
|
35
|
-
// First attempt
|
|
36
|
-
const install_result = await ops.npm.install({ cwd: repo.repo_dir });
|
|
37
|
-
if (install_result.ok) {
|
|
38
|
-
return; // Success
|
|
39
|
-
}
|
|
40
|
-
// Check if error is ETARGET (package not found due to stale cache)
|
|
41
|
-
const stderr = install_result.stderr || '';
|
|
42
|
-
const message = install_result.message || '';
|
|
43
|
-
if (!is_etarget_error(message, stderr)) {
|
|
44
|
-
// Different error - fail immediately without cache healing
|
|
45
|
-
throw new Error(`Failed to install dependencies in ${repo.library.name}: ${install_result.message}${stderr ? `\n${stderr}` : ''}`);
|
|
46
|
-
}
|
|
47
|
-
// ETARGET error - try cache healing
|
|
48
|
-
log?.warn(st('yellow', ` ⚠️ ETARGET error detected - cleaning npm cache...`));
|
|
49
|
-
const cache_result = await ops.npm.cache_clean();
|
|
50
|
-
if (!cache_result.ok) {
|
|
51
|
-
throw new Error(`Failed to clean npm cache: ${cache_result.message}`);
|
|
52
|
-
}
|
|
53
|
-
log?.info(' ✓ Cache cleaned, retrying install...');
|
|
54
|
-
// Retry install after cache clean
|
|
55
|
-
const retry_result = await ops.npm.install({ cwd: repo.repo_dir });
|
|
56
|
-
if (!retry_result.ok) {
|
|
57
|
-
throw new Error(`Failed to install dependencies after cache clean in ${repo.library.name}: ${retry_result.message}${retry_result.stderr ? `\n${retry_result.stderr}` : ''}`);
|
|
58
|
-
}
|
|
59
|
-
log?.info(st('green', ` ✓ Dependencies installed successfully after cache heal`));
|
|
60
|
-
};
|
package/dist/semver.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Semantic Versioning 2.0.0 utilities
|
|
3
|
-
* @see https://semver.org/
|
|
4
|
-
*
|
|
5
|
-
* @module
|
|
6
|
-
*/
|
|
7
|
-
export type BumpType = 'major' | 'minor' | 'patch';
|
|
8
|
-
export interface Semver {
|
|
9
|
-
major: number;
|
|
10
|
-
minor: number;
|
|
11
|
-
patch: number;
|
|
12
|
-
prerelease?: string;
|
|
13
|
-
build?: string;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Compares two semver versions according to SemVer 2.0.0 spec.
|
|
17
|
-
* Returns -1 if a < b, 0 if a === b, 1 if a > b.
|
|
18
|
-
* Build metadata is ignored in precedence comparison.
|
|
19
|
-
*/
|
|
20
|
-
export declare const semver_compare_versions: (a: string, b: string) => number;
|
|
21
|
-
/**
|
|
22
|
-
* Bumps a version according to the specified type.
|
|
23
|
-
* Resets lower version numbers per SemVer spec.
|
|
24
|
-
*/
|
|
25
|
-
export declare const semver_bump_version: (version: string, type: BumpType) => string;
|
|
26
|
-
//# sourceMappingURL=semver.d.ts.map
|
package/dist/semver.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"semver.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/semver.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEnD,MAAM,WAAW,MAAM;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAiGD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAqB9D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,EAAE,MAAM,QAAQ,KAAG,MAuBrE,CAAC"}
|
package/dist/semver.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// TODO: candidate for extraction to `@fuzdev/fuz_util`
|
|
2
|
-
/**
|
|
3
|
-
* SemVer 2.0.0 validation regex.
|
|
4
|
-
* @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
|
5
|
-
*/
|
|
6
|
-
const SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
7
|
-
/**
|
|
8
|
-
* Parses a semver version string.
|
|
9
|
-
* Accepts optional 'v' prefix for convenience.
|
|
10
|
-
*/
|
|
11
|
-
const semver_parse = (version) => {
|
|
12
|
-
// Remove leading 'v' if present (common in git tags)
|
|
13
|
-
const clean = version.replace(/^v/, '');
|
|
14
|
-
// Validate the cleaned version
|
|
15
|
-
if (!SEMVER_REGEX.test(clean)) {
|
|
16
|
-
throw new Error(`Invalid semver: ${version}`);
|
|
17
|
-
}
|
|
18
|
-
const match = SEMVER_REGEX.exec(clean);
|
|
19
|
-
return {
|
|
20
|
-
major: parseInt(match[1], 10),
|
|
21
|
-
minor: parseInt(match[2], 10),
|
|
22
|
-
patch: parseInt(match[3], 10),
|
|
23
|
-
prerelease: match[4],
|
|
24
|
-
build: match[5],
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
const semver_to_string = (semver) => {
|
|
28
|
-
let version = `${semver.major}.${semver.minor}.${semver.patch}`;
|
|
29
|
-
if (semver.prerelease) {
|
|
30
|
-
version += `-${semver.prerelease}`;
|
|
31
|
-
}
|
|
32
|
-
if (semver.build) {
|
|
33
|
-
version += `+${semver.build}`;
|
|
34
|
-
}
|
|
35
|
-
return version;
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Compares two prerelease versions according to SemVer 2.0.0 spec.
|
|
39
|
-
* Returns -1 if a < b, 0 if a === b, 1 if a > b.
|
|
40
|
-
*/
|
|
41
|
-
const semver_compare_prerelease = (a, b) => {
|
|
42
|
-
// Handle missing prereleases
|
|
43
|
-
if (!a && !b)
|
|
44
|
-
return 0;
|
|
45
|
-
if (!a)
|
|
46
|
-
return 1; // normal version > prerelease
|
|
47
|
-
if (!b)
|
|
48
|
-
return -1; // prerelease < normal version
|
|
49
|
-
// Split into identifiers
|
|
50
|
-
const a_parts = a.split('.');
|
|
51
|
-
const b_parts = b.split('.');
|
|
52
|
-
// Compare each identifier
|
|
53
|
-
const min_length = Math.min(a_parts.length, b_parts.length);
|
|
54
|
-
for (let i = 0; i < min_length; i++) {
|
|
55
|
-
const a_part = a_parts[i];
|
|
56
|
-
const b_part = b_parts[i];
|
|
57
|
-
// Check if numeric
|
|
58
|
-
const a_is_numeric = /^\d+$/.test(a_part);
|
|
59
|
-
const b_is_numeric = /^\d+$/.test(b_part);
|
|
60
|
-
if (a_is_numeric && b_is_numeric) {
|
|
61
|
-
// Both numeric - compare numerically
|
|
62
|
-
const a_num = parseInt(a_part, 10);
|
|
63
|
-
const b_num = parseInt(b_part, 10);
|
|
64
|
-
if (a_num !== b_num) {
|
|
65
|
-
return a_num < b_num ? -1 : 1;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else if (a_is_numeric && !b_is_numeric) {
|
|
69
|
-
// Numeric identifiers always have lower precedence
|
|
70
|
-
return -1;
|
|
71
|
-
}
|
|
72
|
-
else if (!a_is_numeric && b_is_numeric) {
|
|
73
|
-
// Numeric identifiers always have lower precedence
|
|
74
|
-
return 1;
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
// Both alphanumeric - compare lexically
|
|
78
|
-
const cmp = a_part.localeCompare(b_part);
|
|
79
|
-
if (cmp !== 0) {
|
|
80
|
-
return cmp < 0 ? -1 : 1;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
// All identifiers equal - larger set has higher precedence
|
|
85
|
-
if (a_parts.length !== b_parts.length) {
|
|
86
|
-
return a_parts.length < b_parts.length ? -1 : 1;
|
|
87
|
-
}
|
|
88
|
-
return 0;
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* Compares two semver versions according to SemVer 2.0.0 spec.
|
|
92
|
-
* Returns -1 if a < b, 0 if a === b, 1 if a > b.
|
|
93
|
-
* Build metadata is ignored in precedence comparison.
|
|
94
|
-
*/
|
|
95
|
-
export const semver_compare_versions = (a, b) => {
|
|
96
|
-
const v1 = semver_parse(a);
|
|
97
|
-
const v2 = semver_parse(b);
|
|
98
|
-
// Compare major
|
|
99
|
-
if (v1.major !== v2.major) {
|
|
100
|
-
return v1.major < v2.major ? -1 : 1;
|
|
101
|
-
}
|
|
102
|
-
// Compare minor
|
|
103
|
-
if (v1.minor !== v2.minor) {
|
|
104
|
-
return v1.minor < v2.minor ? -1 : 1;
|
|
105
|
-
}
|
|
106
|
-
// Compare patch
|
|
107
|
-
if (v1.patch !== v2.patch) {
|
|
108
|
-
return v1.patch < v2.patch ? -1 : 1;
|
|
109
|
-
}
|
|
110
|
-
// Compare prerelease (build metadata is ignored)
|
|
111
|
-
return semver_compare_prerelease(v1.prerelease, v2.prerelease);
|
|
112
|
-
};
|
|
113
|
-
/**
|
|
114
|
-
* Bumps a version according to the specified type.
|
|
115
|
-
* Resets lower version numbers per SemVer spec.
|
|
116
|
-
*/
|
|
117
|
-
export const semver_bump_version = (version, type) => {
|
|
118
|
-
const semver = semver_parse(version);
|
|
119
|
-
switch (type) {
|
|
120
|
-
case 'major':
|
|
121
|
-
semver.major++;
|
|
122
|
-
semver.minor = 0;
|
|
123
|
-
semver.patch = 0;
|
|
124
|
-
break;
|
|
125
|
-
case 'minor':
|
|
126
|
-
semver.minor++;
|
|
127
|
-
semver.patch = 0;
|
|
128
|
-
break;
|
|
129
|
-
case 'patch':
|
|
130
|
-
semver.patch++;
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
// Remove prerelease and build when bumping
|
|
134
|
-
semver.prerelease = undefined;
|
|
135
|
-
semver.build = undefined;
|
|
136
|
-
return semver_to_string(semver);
|
|
137
|
-
};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON-serializable types for command output formats.
|
|
3
|
-
*
|
|
4
|
-
* Gitops commands support `--format json` and `--format markdown` output modes
|
|
5
|
-
* in addition to styled terminal output. These types define the JSON schema for:
|
|
6
|
-
* - Dependency graph structures (`SerializedGraph`)
|
|
7
|
-
* - Publishing plan predictions (`SerializedPublishingPlan`)
|
|
8
|
-
*
|
|
9
|
-
* Used by `gitops_analyze`, `gitops_plan`, and `gitops_publish` (dry run) when
|
|
10
|
-
* `--format json` or `--outfile` is specified.
|
|
11
|
-
*
|
|
12
|
-
* @module
|
|
13
|
-
*/
|
|
14
|
-
import type { DependencyGraph } from './dependency_graph.js';
|
|
15
|
-
export interface SerializedNode {
|
|
16
|
-
name: string;
|
|
17
|
-
version: string;
|
|
18
|
-
dependencies: Array<{
|
|
19
|
-
name: string;
|
|
20
|
-
type: string;
|
|
21
|
-
version: string;
|
|
22
|
-
}>;
|
|
23
|
-
dependents: Array<string>;
|
|
24
|
-
publishable: boolean;
|
|
25
|
-
}
|
|
26
|
-
export interface SerializedGraph {
|
|
27
|
-
nodes: Array<SerializedNode>;
|
|
28
|
-
edges: Array<[string, string]>;
|
|
29
|
-
}
|
|
30
|
-
export interface SerializedPublishingPlan {
|
|
31
|
-
publishing_order: Array<string>;
|
|
32
|
-
version_changes: Array<{
|
|
33
|
-
package_name: string;
|
|
34
|
-
from: string;
|
|
35
|
-
to: string;
|
|
36
|
-
bump_type: string;
|
|
37
|
-
breaking: boolean;
|
|
38
|
-
has_changesets: boolean;
|
|
39
|
-
will_generate_changeset?: boolean;
|
|
40
|
-
needs_bump_escalation?: boolean;
|
|
41
|
-
existing_bump?: string;
|
|
42
|
-
required_bump?: string;
|
|
43
|
-
}>;
|
|
44
|
-
dependency_updates: Array<{
|
|
45
|
-
dependent_package: string;
|
|
46
|
-
updated_dependency: string;
|
|
47
|
-
new_version: string;
|
|
48
|
-
type: string;
|
|
49
|
-
causes_republish: boolean;
|
|
50
|
-
}>;
|
|
51
|
-
breaking_cascades: Record<string, Array<string>>;
|
|
52
|
-
warnings: Array<string>;
|
|
53
|
-
errors: Array<string>;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Serializes a dependency graph to a JSON-safe format.
|
|
57
|
-
*/
|
|
58
|
-
export declare const serialize_graph: (graph: DependencyGraph) => SerializedGraph;
|
|
59
|
-
//# sourceMappingURL=serialization_types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serialization_types.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/serialization_types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACxC,gBAAgB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChC,eAAe,EAAE,KAAK,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;QAClB,cAAc,EAAE,OAAO,CAAC;QACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;QAChC,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;IACH,kBAAkB,EAAE,KAAK,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,gBAAgB,EAAE,OAAO,CAAC;KAC1B,CAAC,CAAC;IACH,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,eAAe,KAAG,eA6BxD,CAAC"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON-serializable types for command output formats.
|
|
3
|
-
*
|
|
4
|
-
* Gitops commands support `--format json` and `--format markdown` output modes
|
|
5
|
-
* in addition to styled terminal output. These types define the JSON schema for:
|
|
6
|
-
* - Dependency graph structures (`SerializedGraph`)
|
|
7
|
-
* - Publishing plan predictions (`SerializedPublishingPlan`)
|
|
8
|
-
*
|
|
9
|
-
* Used by `gitops_analyze`, `gitops_plan`, and `gitops_publish` (dry run) when
|
|
10
|
-
* `--format json` or `--outfile` is specified.
|
|
11
|
-
*
|
|
12
|
-
* @module
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Serializes a dependency graph to a JSON-safe format.
|
|
16
|
-
*/
|
|
17
|
-
export const serialize_graph = (graph) => {
|
|
18
|
-
const nodes = [];
|
|
19
|
-
const edges = [];
|
|
20
|
-
// Serialize nodes
|
|
21
|
-
for (const node of graph.nodes.values()) {
|
|
22
|
-
const dependencies = Array.from(node.dependencies, ([dep_name, spec]) => ({
|
|
23
|
-
name: dep_name,
|
|
24
|
-
type: spec.type,
|
|
25
|
-
version: spec.version,
|
|
26
|
-
}));
|
|
27
|
-
nodes.push({
|
|
28
|
-
name: node.name,
|
|
29
|
-
version: node.version,
|
|
30
|
-
dependencies,
|
|
31
|
-
dependents: Array.from(node.dependents),
|
|
32
|
-
publishable: node.publishable,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
// Serialize edges
|
|
36
|
-
for (const [from, tos] of graph.edges) {
|
|
37
|
-
for (const to of tos) {
|
|
38
|
-
edges.push([from, to]);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return { nodes, edges };
|
|
42
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
2
|
-
import {styleText as st} from 'node:util';
|
|
3
|
-
|
|
4
|
-
import type {LocalRepo} from './local_repo.js';
|
|
5
|
-
import type {GitopsOperations} from './operations.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Checks if an npm install error is caused by stale cache (ETARGET).
|
|
9
|
-
* Detects various error message formats:
|
|
10
|
-
* - "code ETARGET"
|
|
11
|
-
* - "ETARGET"
|
|
12
|
-
* - "notarget"
|
|
13
|
-
* - "No matching version found"
|
|
14
|
-
*/
|
|
15
|
-
const is_etarget_error = (message: string, stderr: string): boolean => {
|
|
16
|
-
const combined = `${message} ${stderr}`.toLowerCase();
|
|
17
|
-
return (
|
|
18
|
-
combined.includes('etarget') ||
|
|
19
|
-
combined.includes('notarget') ||
|
|
20
|
-
combined.includes('no matching version found')
|
|
21
|
-
);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Installs npm dependencies with cache healing on ETARGET errors.
|
|
26
|
-
*
|
|
27
|
-
* **Strategy:**
|
|
28
|
-
* 1. First attempt: regular `npm install`
|
|
29
|
-
* 2. On ETARGET error (stale cache): `npm cache clean --force` then retry
|
|
30
|
-
* 3. On other errors: fail immediately
|
|
31
|
-
*
|
|
32
|
-
* **Why ETARGET errors occur:**
|
|
33
|
-
* After publishing a package and waiting for NPM registry propagation,
|
|
34
|
-
* npm's local cache may still have stale "404" metadata. This healing
|
|
35
|
-
* strategy clears the cache to force fresh metadata fetch.
|
|
36
|
-
*
|
|
37
|
-
* @param repo - the repository to install dependencies for
|
|
38
|
-
* @param ops - gitops operations (for dependency injection)
|
|
39
|
-
* @param log - optional logger
|
|
40
|
-
* @throws Error if install fails (with details about cache healing attempts)
|
|
41
|
-
*/
|
|
42
|
-
export const install_with_cache_healing = async (
|
|
43
|
-
repo: LocalRepo,
|
|
44
|
-
ops: GitopsOperations,
|
|
45
|
-
log?: Logger,
|
|
46
|
-
): Promise<void> => {
|
|
47
|
-
// First attempt
|
|
48
|
-
const install_result = await ops.npm.install({cwd: repo.repo_dir});
|
|
49
|
-
|
|
50
|
-
if (install_result.ok) {
|
|
51
|
-
return; // Success
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Check if error is ETARGET (package not found due to stale cache)
|
|
55
|
-
const stderr = install_result.stderr || '';
|
|
56
|
-
const message = install_result.message || '';
|
|
57
|
-
|
|
58
|
-
if (!is_etarget_error(message, stderr)) {
|
|
59
|
-
// Different error - fail immediately without cache healing
|
|
60
|
-
throw new Error(
|
|
61
|
-
`Failed to install dependencies in ${repo.library.name}: ${install_result.message}${stderr ? `\n${stderr}` : ''}`,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ETARGET error - try cache healing
|
|
66
|
-
log?.warn(st('yellow', ` ⚠️ ETARGET error detected - cleaning npm cache...`));
|
|
67
|
-
|
|
68
|
-
const cache_result = await ops.npm.cache_clean();
|
|
69
|
-
if (!cache_result.ok) {
|
|
70
|
-
throw new Error(`Failed to clean npm cache: ${cache_result.message}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
log?.info(' ✓ Cache cleaned, retrying install...');
|
|
74
|
-
|
|
75
|
-
// Retry install after cache clean
|
|
76
|
-
const retry_result = await ops.npm.install({cwd: repo.repo_dir});
|
|
77
|
-
|
|
78
|
-
if (!retry_result.ok) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
`Failed to install dependencies after cache clean in ${repo.library.name}: ${retry_result.message}${retry_result.stderr ? `\n${retry_result.stderr}` : ''}`,
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
log?.info(st('green', ` ✓ Dependencies installed successfully after cache heal`));
|
|
85
|
-
};
|
package/src/lib/semver.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
// TODO: candidate for extraction to `@fuzdev/fuz_util`
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Semantic Versioning 2.0.0 utilities
|
|
5
|
-
* @see https://semver.org/
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export type BumpType = 'major' | 'minor' | 'patch';
|
|
11
|
-
|
|
12
|
-
export interface Semver {
|
|
13
|
-
major: number;
|
|
14
|
-
minor: number;
|
|
15
|
-
patch: number;
|
|
16
|
-
prerelease?: string;
|
|
17
|
-
build?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* SemVer 2.0.0 validation regex.
|
|
22
|
-
* @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
|
23
|
-
*/
|
|
24
|
-
const SEMVER_REGEX =
|
|
25
|
-
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Parses a semver version string.
|
|
29
|
-
* Accepts optional 'v' prefix for convenience.
|
|
30
|
-
*/
|
|
31
|
-
const semver_parse = (version: string): Semver => {
|
|
32
|
-
// Remove leading 'v' if present (common in git tags)
|
|
33
|
-
const clean = version.replace(/^v/, '');
|
|
34
|
-
|
|
35
|
-
// Validate the cleaned version
|
|
36
|
-
if (!SEMVER_REGEX.test(clean)) {
|
|
37
|
-
throw new Error(`Invalid semver: ${version}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const match = SEMVER_REGEX.exec(clean)!;
|
|
41
|
-
return {
|
|
42
|
-
major: parseInt(match[1]!, 10),
|
|
43
|
-
minor: parseInt(match[2]!, 10),
|
|
44
|
-
patch: parseInt(match[3]!, 10),
|
|
45
|
-
prerelease: match[4],
|
|
46
|
-
build: match[5],
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const semver_to_string = (semver: Semver): string => {
|
|
51
|
-
let version = `${semver.major}.${semver.minor}.${semver.patch}`;
|
|
52
|
-
if (semver.prerelease) {
|
|
53
|
-
version += `-${semver.prerelease}`;
|
|
54
|
-
}
|
|
55
|
-
if (semver.build) {
|
|
56
|
-
version += `+${semver.build}`;
|
|
57
|
-
}
|
|
58
|
-
return version;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Compares two prerelease versions according to SemVer 2.0.0 spec.
|
|
63
|
-
* Returns -1 if a < b, 0 if a === b, 1 if a > b.
|
|
64
|
-
*/
|
|
65
|
-
const semver_compare_prerelease = (a: string | undefined, b: string | undefined): number => {
|
|
66
|
-
// Handle missing prereleases
|
|
67
|
-
if (!a && !b) return 0;
|
|
68
|
-
if (!a) return 1; // normal version > prerelease
|
|
69
|
-
if (!b) return -1; // prerelease < normal version
|
|
70
|
-
|
|
71
|
-
// Split into identifiers
|
|
72
|
-
const a_parts = a.split('.');
|
|
73
|
-
const b_parts = b.split('.');
|
|
74
|
-
|
|
75
|
-
// Compare each identifier
|
|
76
|
-
const min_length = Math.min(a_parts.length, b_parts.length);
|
|
77
|
-
for (let i = 0; i < min_length; i++) {
|
|
78
|
-
const a_part = a_parts[i]!;
|
|
79
|
-
const b_part = b_parts[i]!;
|
|
80
|
-
|
|
81
|
-
// Check if numeric
|
|
82
|
-
const a_is_numeric = /^\d+$/.test(a_part);
|
|
83
|
-
const b_is_numeric = /^\d+$/.test(b_part);
|
|
84
|
-
|
|
85
|
-
if (a_is_numeric && b_is_numeric) {
|
|
86
|
-
// Both numeric - compare numerically
|
|
87
|
-
const a_num = parseInt(a_part, 10);
|
|
88
|
-
const b_num = parseInt(b_part, 10);
|
|
89
|
-
if (a_num !== b_num) {
|
|
90
|
-
return a_num < b_num ? -1 : 1;
|
|
91
|
-
}
|
|
92
|
-
} else if (a_is_numeric && !b_is_numeric) {
|
|
93
|
-
// Numeric identifiers always have lower precedence
|
|
94
|
-
return -1;
|
|
95
|
-
} else if (!a_is_numeric && b_is_numeric) {
|
|
96
|
-
// Numeric identifiers always have lower precedence
|
|
97
|
-
return 1;
|
|
98
|
-
} else {
|
|
99
|
-
// Both alphanumeric - compare lexically
|
|
100
|
-
const cmp = a_part.localeCompare(b_part);
|
|
101
|
-
if (cmp !== 0) {
|
|
102
|
-
return cmp < 0 ? -1 : 1;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// All identifiers equal - larger set has higher precedence
|
|
108
|
-
if (a_parts.length !== b_parts.length) {
|
|
109
|
-
return a_parts.length < b_parts.length ? -1 : 1;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return 0;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Compares two semver versions according to SemVer 2.0.0 spec.
|
|
117
|
-
* Returns -1 if a < b, 0 if a === b, 1 if a > b.
|
|
118
|
-
* Build metadata is ignored in precedence comparison.
|
|
119
|
-
*/
|
|
120
|
-
export const semver_compare_versions = (a: string, b: string): number => {
|
|
121
|
-
const v1 = semver_parse(a);
|
|
122
|
-
const v2 = semver_parse(b);
|
|
123
|
-
|
|
124
|
-
// Compare major
|
|
125
|
-
if (v1.major !== v2.major) {
|
|
126
|
-
return v1.major < v2.major ? -1 : 1;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Compare minor
|
|
130
|
-
if (v1.minor !== v2.minor) {
|
|
131
|
-
return v1.minor < v2.minor ? -1 : 1;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Compare patch
|
|
135
|
-
if (v1.patch !== v2.patch) {
|
|
136
|
-
return v1.patch < v2.patch ? -1 : 1;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Compare prerelease (build metadata is ignored)
|
|
140
|
-
return semver_compare_prerelease(v1.prerelease, v2.prerelease);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Bumps a version according to the specified type.
|
|
145
|
-
* Resets lower version numbers per SemVer spec.
|
|
146
|
-
*/
|
|
147
|
-
export const semver_bump_version = (version: string, type: BumpType): string => {
|
|
148
|
-
const semver = semver_parse(version);
|
|
149
|
-
|
|
150
|
-
switch (type) {
|
|
151
|
-
case 'major':
|
|
152
|
-
semver.major++;
|
|
153
|
-
semver.minor = 0;
|
|
154
|
-
semver.patch = 0;
|
|
155
|
-
break;
|
|
156
|
-
case 'minor':
|
|
157
|
-
semver.minor++;
|
|
158
|
-
semver.patch = 0;
|
|
159
|
-
break;
|
|
160
|
-
case 'patch':
|
|
161
|
-
semver.patch++;
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Remove prerelease and build when bumping
|
|
166
|
-
semver.prerelease = undefined;
|
|
167
|
-
semver.build = undefined;
|
|
168
|
-
|
|
169
|
-
return semver_to_string(semver);
|
|
170
|
-
};
|