enablement-build-monorepo-version 2.0.4 → 2.0.6
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 +54 -46
- package/package.json +2 -2
- package/src/index.mjs +182 -16
- package/src/lib.mjs +288 -145
- package/tests/lib.test.mjs +453 -253
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ npx enablement-build-monorepo-version@latest [flags]
|
|
|
13
13
|
## How it works
|
|
14
14
|
|
|
15
15
|
1. **Hash** — Each subfolder under the configured `children` directories is hashed (source files only; `node_modules`, `dist`, etc. are excluded).
|
|
16
|
-
2. **Compare** — Hashes are diffed against
|
|
17
|
-
3. **Propagate** — Any package whose hash changed is marked `CHANGED`. All transitive dependents (read from `
|
|
16
|
+
2. **Compare** — Hashes are diffed against saved state from `{configDir}/manifest.json` when present (`cicd[packageName].hash`), falling back to `{configDir}/hash.json` for legacy repos.
|
|
17
|
+
3. **Propagate** — Any package whose hash changed is marked `CHANGED`. All transitive dependents (read from `{configDir}/manifest.json` `dependencies` when available, or from `--dependencies` when explicitly provided) are also marked `CHANGED` via a breadth-first traversal.
|
|
18
18
|
4. **Version** — The next semver is determined from the current version found in each package's version manifest (`package.json`, `version.json`, or `pyproject.toml`) using conventional-commit rules.
|
|
19
19
|
5. **Output** — Azure DevOps `##vso[task.setvariable]` lines are written to stdout for consumption by downstream pipeline steps.
|
|
20
20
|
|
|
@@ -22,25 +22,25 @@ npx enablement-build-monorepo-version@latest [flags]
|
|
|
22
22
|
|
|
23
23
|
## CLI flags
|
|
24
24
|
|
|
25
|
-
| Flag
|
|
26
|
-
|
|
27
|
-
| `--hash`
|
|
28
|
-
| `--changed`
|
|
29
|
-
| `--version`
|
|
30
|
-
| `--save`
|
|
31
|
-
| `--tag`
|
|
32
|
-
| `--retag`
|
|
33
|
-
| `--init`
|
|
34
|
-
| `--try`
|
|
35
|
-
| `--debug`
|
|
36
|
-
| `--children <dirs>`
|
|
37
|
-
| `--platform <name>`
|
|
38
|
-
| `--prefixPath <path>`
|
|
39
|
-
| `--hashFile <path>`
|
|
40
|
-
| `--dependencies <path>`
|
|
41
|
-
| `--hashExcludeFolders <list>` | see below
|
|
42
|
-
| `--hashExcludeFiles <list>`
|
|
43
|
-
| `--hashFiles <list>`
|
|
25
|
+
| Flag | Default | Description |
|
|
26
|
+
| ----------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
27
|
+
| `--hash` | off | Compute and **save** current hashes to the hash state file. Must be run before `--changed` / `--version` to establish a baseline. |
|
|
28
|
+
| `--changed` | off | Print the list of changed packages and emit a `changed` pipeline variable. |
|
|
29
|
+
| `--version` | off | Emit a pipeline variable per changed package containing its next version. |
|
|
30
|
+
| `--save` | off | Write the bumped version back into each changed package's version manifests (`project.json`, `version.json`, and/or `pyproject.toml`). Requires `--version`. |
|
|
31
|
+
| `--tag` | off | Create a git tag (`<short-name>/<version>`) for each changed package, where `short-name` is the npm package name with its scope prefix removed (e.g. `@scope/lib-foo` → `lib-foo/1.2.3`). |
|
|
32
|
+
| `--retag` | off | Convert existing tags that use the old folder-name format to the new short-package-name format. Non-destructive: old tags are left in place. |
|
|
33
|
+
| `--init` | off | Inject `release:*` scripts into the root `package.json` of the target project. Adds scripts that are missing; strips `--children` from any that already exist. Combine with `--try` to preview changes. |
|
|
34
|
+
| `--try` | off | Dry-run mode. Prints what each operation **would** do without writing any files, creating tags, or modifying any manifests. Combine with any other flags to preview their effect. |
|
|
35
|
+
| `--debug` | off | Verbose logging of hashes, comparisons, and version resolution. |
|
|
36
|
+
| `--children <dirs>` | auto-detect | Comma- or space-separated list of top-level directories to scan (e.g. `components,saas`). When omitted, directories are read from `pnpm-workspace.yaml` or `package.json` workspaces automatically. Falls back to `packages` if neither file is found. |
|
|
37
|
+
| `--platform <name>` | auto-detect | Force the CI output format: `ado` (Azure DevOps) or `github` (GitHub Actions). Auto-detected from the presence of a `.github/` directory. |
|
|
38
|
+
| `--prefixPath <path>` | `./` | Root path prepended to all file lookups. Useful when running from a different working directory. |
|
|
39
|
+
| `--hashFile <path>` | auto-detect | Path (relative to `prefixPath`) where hash state is stored between runs. Defaults to `.github/manifest.json` or `.cicd/manifest.json` when those files exist (hashes stored inside `cicd[packageName].hash`); falls back to `.github/hash.json` or `.cicd/hash.json` for legacy standalone hash files. |
|
|
40
|
+
| `--dependencies <path>` | `dependencies.json` | Path to the NX-style dependency graph used for transitive change propagation. By default, manifest dependencies are used when `{configDir}/manifest.json` exists; passing this flag explicitly overrides that and forces file-based dependency input. |
|
|
41
|
+
| `--hashExcludeFolders <list>` | see below | Comma-separated folder names to skip when hashing. |
|
|
42
|
+
| `--hashExcludeFiles <list>` | see below | Comma-separated file names to skip when hashing. |
|
|
43
|
+
| `--hashFiles <list>` | — | Comma-separated individual file paths to include in the hash state (outside of `children` folders). |
|
|
44
44
|
|
|
45
45
|
**Default excluded folders:** `node_modules`, `coverage`, `dist`, `bin`, `obj`, `__pycache__`, `.vs`, `.nx`, `.vscode`, `.idea`, `.git`, `.github`, `.azuredevops`, `.release`
|
|
46
46
|
|
|
@@ -52,13 +52,13 @@ npx enablement-build-monorepo-version@latest [flags]
|
|
|
52
52
|
|
|
53
53
|
Each package directory is scanned for a version manifest in this priority order:
|
|
54
54
|
|
|
55
|
-
| File
|
|
56
|
-
|
|
57
|
-
| `
|
|
58
|
-
| `version.json`
|
|
59
|
-
| `pyproject.toml` | TOML
|
|
55
|
+
| File | Format | Version field |
|
|
56
|
+
| ---------------- | ----------------------------------- | -------------------------------------------------------- |
|
|
57
|
+
| `project.json` | JSON | `"version": "1.2.3"` |
|
|
58
|
+
| `version.json` | JSON (same shape as `project.json`) | `"version": "1.2.3"` |
|
|
59
|
+
| `pyproject.toml` | TOML | `version = "1.2.3"` under `[project]` or `[tool.poetry]` |
|
|
60
60
|
|
|
61
|
-
The first file found is used. If none exists the package is treated as version `0.0.0`.
|
|
61
|
+
The first file found is used to determine the current version. When `--save` is enabled, all existing manifests in this set are updated. If none exists the package is treated as version `0.0.0`.
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
@@ -66,10 +66,10 @@ The first file found is used. If none exists the package is treated as version `
|
|
|
66
66
|
|
|
67
67
|
Versions follow semver and are bumped based on the **current version** in the package's version manifest:
|
|
68
68
|
|
|
69
|
-
| Trigger
|
|
70
|
-
|
|
71
|
-
| `fix:` prefix in any recent commit message
|
|
72
|
-
| `feat:` prefix in any recent commit message
|
|
69
|
+
| Trigger | Bump | Example |
|
|
70
|
+
| ------------------------------------------------ | --------------- | ----------------- |
|
|
71
|
+
| `fix:` prefix in any recent commit message | Patch (`0.0.x`) | `1.2.3` → `1.2.4` |
|
|
72
|
+
| `feat:` prefix in any recent commit message | Minor (`0.x.0`) | `1.2.3` → `1.3.0` |
|
|
73
73
|
| `BREAKING` anywhere in any recent commit message | Major (`x.0.0`) | `1.2.3` → `2.0.0` |
|
|
74
74
|
|
|
75
75
|
> Currently the version bump always applies a patch increment — conventional-commit scanning via `git log` is stubbed. The bump logic is in `src/version.mjs`.
|
|
@@ -106,24 +106,30 @@ Consume them in a subsequent step with `${{ steps.<step-id>.outputs.<name> }}`.
|
|
|
106
106
|
|
|
107
107
|
### Variable reference
|
|
108
108
|
|
|
109
|
-
| Variable
|
|
110
|
-
|
|
109
|
+
| Variable | Value |
|
|
110
|
+
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
111
111
|
| `<safeName>` (per changed package) | Next version for changed packages; previous version for unchanged ones. `safeName` is the folder name with `-`, `_`, and `.` removed. |
|
|
112
|
-
| `changed`
|
|
113
|
-
| `<folderName>`
|
|
112
|
+
| `changed` | JSON array of changed package folder names. |
|
|
113
|
+
| `<folderName>` | `true` for each top-level folder containing at least one changed package. |
|
|
114
114
|
|
|
115
115
|
---
|
|
116
116
|
|
|
117
|
-
##
|
|
117
|
+
## Dependency Source
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
By default, transitive dependency propagation uses `dependencies` from `{configDir}/manifest.json` when that manifest exists.
|
|
120
|
+
|
|
121
|
+
To force file-based dependency input, pass `--dependencies <path>`. The file must be an NX project graph export. The relevant section is `graph.dependencies`, where each key is a package name and its value is an array of `{ source, target }` edges:
|
|
120
122
|
|
|
121
123
|
```json
|
|
122
124
|
{
|
|
123
125
|
"graph": {
|
|
124
126
|
"dependencies": {
|
|
125
127
|
"@scope/pkg-a": [
|
|
126
|
-
{
|
|
128
|
+
{
|
|
129
|
+
"source": "@scope/pkg-a",
|
|
130
|
+
"target": "@scope/shared-lib",
|
|
131
|
+
"type": "static"
|
|
132
|
+
}
|
|
127
133
|
]
|
|
128
134
|
}
|
|
129
135
|
}
|
|
@@ -155,12 +161,14 @@ If the file is missing or the `--dependencies` path doesn't exist, change propag
|
|
|
155
161
|
- script: echo "$(versions.mypackagename)"
|
|
156
162
|
```
|
|
157
163
|
|
|
158
|
-
To bump and persist the new versions back to `
|
|
164
|
+
To bump and persist the new versions back to the package version manifests (`project.json`, `version.json`, and `pyproject.toml` when present):
|
|
159
165
|
|
|
160
166
|
```bash
|
|
161
167
|
npx enablement-build-monorepo-version --changed --version --save
|
|
162
168
|
```
|
|
163
169
|
|
|
170
|
+
When `--changed --version --save` detects any changed package, the root `package.json` version is also bumped by a patch increment.
|
|
171
|
+
|
|
164
172
|
To override the auto-detected directories, pass `--children` explicitly:
|
|
165
173
|
|
|
166
174
|
```bash
|
|
@@ -185,13 +193,13 @@ npx enablement-build-monorepo-version --init --try
|
|
|
185
193
|
|
|
186
194
|
The following scripts are injected (skipped if already present; `--children` stripped if already there):
|
|
187
195
|
|
|
188
|
-
| Script
|
|
189
|
-
|
|
190
|
-
| `release:try`
|
|
191
|
-
| `release:changed`
|
|
192
|
-
| `release:version`
|
|
193
|
-
| `release:finalize` | write hashes
|
|
194
|
-
| `release:retag`
|
|
196
|
+
| Script | Command |
|
|
197
|
+
| ------------------ | ----------------------------------- |
|
|
198
|
+
| `release:try` | dry-run of the full release flow |
|
|
199
|
+
| `release:changed` | list changed packages |
|
|
200
|
+
| `release:version` | bump and save versions |
|
|
201
|
+
| `release:finalize` | write hashes |
|
|
202
|
+
| `release:retag` | migrate tags to package-name format |
|
|
195
203
|
|
|
196
204
|
---
|
|
197
205
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "enablement-build-monorepo-version",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "This detects changes in the children packages of a monorepo.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./src/index.mjs",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"minimatch": "~10.1.1"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"jest": "^
|
|
20
|
+
"jest": "^30.4.2"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"start": "node src/index.mjs",
|
package/src/index.mjs
CHANGED
|
@@ -7,6 +7,100 @@ import { hashElement } from "./folder-hash.mjs";
|
|
|
7
7
|
import { dependencyMap, compare, getCurrentVersion, updateVersion, retagToPackageNames, detectOldFormatTags, resolveWorkspaceChildren, applyInitScripts, RELEASE_SCRIPTS, emitVariable } from "./lib.mjs";
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
// ─── Hash Format Conversion Helpers ──────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
// Convert old hash.json format (keyed by shortName) to new nested structure (keyed by fullName)
|
|
13
|
+
function convertOldHashFormat(oldHashData) {
|
|
14
|
+
const result = {};
|
|
15
|
+
Object.keys(oldHashData).forEach(shortName => {
|
|
16
|
+
const entry = oldHashData[shortName];
|
|
17
|
+
if (entry.fullName) {
|
|
18
|
+
result[entry.fullName] = {
|
|
19
|
+
hash: entry.hash,
|
|
20
|
+
version: entry.version
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Convert current hashes to structure for cicd property
|
|
28
|
+
function buildHashesForCicd(current) {
|
|
29
|
+
const hashData = {};
|
|
30
|
+
const versions = {};
|
|
31
|
+
|
|
32
|
+
Object.keys(current).forEach(shortName => {
|
|
33
|
+
const entry = current[shortName];
|
|
34
|
+
if (entry.fullName) {
|
|
35
|
+
hashData[entry.fullName] = {
|
|
36
|
+
hash: entry.hash,
|
|
37
|
+
version: entry.version,
|
|
38
|
+
folderName: shortName,
|
|
39
|
+
packageFolder: entry.packageFolder
|
|
40
|
+
};
|
|
41
|
+
versions[entry.fullName] = entry.version;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return { hashData, versions };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Extract hashes from manifest.json (from cicd property) keyed by fullName
|
|
49
|
+
function extractHashesFromManifestByFullName(manifest) {
|
|
50
|
+
const result = {};
|
|
51
|
+
|
|
52
|
+
if (manifest.cicd) {
|
|
53
|
+
Object.keys(manifest.cicd).forEach(fullname => {
|
|
54
|
+
if (manifest.cicd[fullname].hash) {
|
|
55
|
+
result[fullname] = {
|
|
56
|
+
hash: manifest.cicd[fullname].hash,
|
|
57
|
+
version: manifest.versions ? manifest.versions[fullname] : manifest.cicd[fullname].version
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function bumpPatchVersion(version) {
|
|
67
|
+
const value = (version || '0.0.0').trim();
|
|
68
|
+
const parts = value.split('-');
|
|
69
|
+
const base = parts[0] || '0.0.0';
|
|
70
|
+
const suffix = parts.length > 1 ? parts.slice(1).join('-') : '';
|
|
71
|
+
|
|
72
|
+
const nums = base.split('.');
|
|
73
|
+
const major = Number.parseInt(nums[0] || '0', 10) || 0;
|
|
74
|
+
const minor = Number.parseInt(nums[1] || '0', 10) || 0;
|
|
75
|
+
const patch = (Number.parseInt(nums[2] || '0', 10) || 0) + 1;
|
|
76
|
+
|
|
77
|
+
const next = `${major}.${minor}.${patch}`;
|
|
78
|
+
return suffix ? `${next}-${suffix}` : next;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function updateRootVersionIfNeeded(options, changeList) {
|
|
82
|
+
if (!options.saveVersion || !options.version || changeList.length === 0) return;
|
|
83
|
+
|
|
84
|
+
const rootPackageFile = path.join(options.prefixPath, 'package.json');
|
|
85
|
+
if (!existsSync(rootPackageFile)) return;
|
|
86
|
+
|
|
87
|
+
const pkg = JSON.parse(readFileSync(rootPackageFile, 'utf8'));
|
|
88
|
+
const previous = pkg.version || '0.0.0';
|
|
89
|
+
const next = bumpPatchVersion(previous);
|
|
90
|
+
|
|
91
|
+
if (options.try) {
|
|
92
|
+
console.log('\x1b[36m%s\x1b[0m', `[try] Would update ${rootPackageFile} version ${previous} -> ${next}`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (previous !== next) {
|
|
97
|
+
pkg.version = next;
|
|
98
|
+
writeFileSync(rootPackageFile, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
|
99
|
+
console.log(`root package.json version updated: ${previous} -> ${next}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
10
104
|
async function main(options) {
|
|
11
105
|
return new Promise((mainResolve, mainreject) => {
|
|
12
106
|
const hashOptions = { encoding: 'hex', folders: { exclude: options.hashExcludeFolders }, files: { exclude: options.hashExcludeFiles } };
|
|
@@ -33,8 +127,8 @@ async function main(options) {
|
|
|
33
127
|
const changeConfig = path.join(options.prefixPath, options.hashFile);
|
|
34
128
|
let previous = {};
|
|
35
129
|
|
|
36
|
-
// make sure hash config file exists
|
|
37
|
-
if (!existsSync(changeConfig)) {
|
|
130
|
+
// make sure hash config file exists only when using a dedicated hash.json file
|
|
131
|
+
if (!usesManifestHashFile && !existsSync(changeConfig)) {
|
|
38
132
|
if (options.try) {
|
|
39
133
|
console.log('\x1b[36m%s\x1b[0m', `[try] Hash file ${changeConfig} not found — treating previous state as empty`);
|
|
40
134
|
} else {
|
|
@@ -43,7 +137,16 @@ async function main(options) {
|
|
|
43
137
|
}
|
|
44
138
|
|
|
45
139
|
let dependencies = {};
|
|
46
|
-
|
|
140
|
+
|
|
141
|
+
const manifestDependencyPath = path.join(options.prefixPath, `${configDir}/manifest.json`);
|
|
142
|
+
const shouldPreferManifestDependencies = !options.dependenciesProvided && existsSync(manifestDependencyPath);
|
|
143
|
+
|
|
144
|
+
if (shouldPreferManifestDependencies) {
|
|
145
|
+
const manifestText = readFileSync(manifestDependencyPath, 'utf8');
|
|
146
|
+
const manifest = JSON.parse(manifestText || '{}');
|
|
147
|
+
dependencies = manifest.dependencies || {};
|
|
148
|
+
if (options.debug) console.log(`Loaded dependencies from ${manifestDependencyPath}\n`, JSON.stringify(dependencies));
|
|
149
|
+
} else if (options.dependencies) {
|
|
47
150
|
if (existsSync(options.dependencies)) {
|
|
48
151
|
dependencies = dependencyMap(options.dependencies);
|
|
49
152
|
if (options.debug) console.log('Loaded dependencies\n', JSON.stringify(dependencies));
|
|
@@ -52,9 +155,16 @@ async function main(options) {
|
|
|
52
155
|
}
|
|
53
156
|
}
|
|
54
157
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
158
|
+
// Load manifest for later use (will extract hashes after building current)
|
|
159
|
+
let manifestData = {};
|
|
160
|
+
if (usesManifestHashFile) {
|
|
161
|
+
const data = existsSync(changeConfig) ? readFileSync(changeConfig, "utf8") : "{}";
|
|
162
|
+
manifestData = JSON.parse(data || "{}");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// For now, set previous to empty - will populate after building current
|
|
166
|
+
// (because we need the fullName mapping from current)
|
|
167
|
+
previous = {};
|
|
58
168
|
if (options.debug) console.log("PREVIOUS", JSON.stringify(previous));
|
|
59
169
|
|
|
60
170
|
options.hashFiles.forEach(file => {
|
|
@@ -95,7 +205,21 @@ async function main(options) {
|
|
|
95
205
|
}
|
|
96
206
|
|
|
97
207
|
if (options.changed || options.version || options.tag) {
|
|
98
|
-
|
|
208
|
+
// Build previous hashes keyed by short name using fullName mapping
|
|
209
|
+
let previousHashes = {};
|
|
210
|
+
if (usesManifestHashFile) {
|
|
211
|
+
const hashesByFullName = extractHashesFromManifestByFullName(manifestData);
|
|
212
|
+
Object.keys(current).forEach(shortName => {
|
|
213
|
+
const entry = current[shortName];
|
|
214
|
+
if (entry.fullName && hashesByFullName[entry.fullName]) {
|
|
215
|
+
previousHashes[shortName] = hashesByFullName[entry.fullName];
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
previousHashes = previous;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let results = await compare(packageFolder, previousHashes, current, dependencies, options);
|
|
99
223
|
if (options.debug) console.log("COMPARE", JSON.stringify(results));
|
|
100
224
|
|
|
101
225
|
for (let i = 0; i < results.length; i++) {
|
|
@@ -164,7 +288,9 @@ async function main(options) {
|
|
|
164
288
|
}));
|
|
165
289
|
});
|
|
166
290
|
|
|
167
|
-
Promise.all(scanlist).then(() => {
|
|
291
|
+
Promise.all(scanlist).then(async () => {
|
|
292
|
+
await updateRootVersionIfNeeded(options, changeList);
|
|
293
|
+
|
|
168
294
|
if (options.changed) {
|
|
169
295
|
console.log(`CHANGED - ${JSON.stringify(changeList)}`);
|
|
170
296
|
emitVariable('changed', JSON.stringify(changeList), options.platform);
|
|
@@ -180,13 +306,39 @@ async function main(options) {
|
|
|
180
306
|
|
|
181
307
|
// write current hashes
|
|
182
308
|
if (options.hash) {
|
|
183
|
-
let result = Object.keys(current).sort().reduce(
|
|
184
|
-
(obj, key) => { obj[key] = current[key]; return obj; },
|
|
185
|
-
{}
|
|
186
|
-
);
|
|
187
309
|
if (options.try) {
|
|
188
310
|
console.log('\x1b[36m%s\x1b[0m', `[try] Would write updated hashes to ${changeConfig}`);
|
|
311
|
+
} else if (usesManifestHashFile) {
|
|
312
|
+
const manifestData = existsSync(changeConfig) ? readFileSync(changeConfig, "utf8") : "{}";
|
|
313
|
+
const manifest = JSON.parse(manifestData || "{}");
|
|
314
|
+
|
|
315
|
+
const { hashData, versions } = buildHashesForCicd(current);
|
|
316
|
+
|
|
317
|
+
// Update cicd properties with hash and metadata
|
|
318
|
+
Object.keys(hashData).forEach(fullname => {
|
|
319
|
+
if (!manifest.cicd) manifest.cicd = {};
|
|
320
|
+
if (!manifest.cicd[fullname]) manifest.cicd[fullname] = {};
|
|
321
|
+
manifest.cicd[fullname].hash = hashData[fullname].hash;
|
|
322
|
+
manifest.cicd[fullname].folderName = hashData[fullname].folderName;
|
|
323
|
+
manifest.cicd[fullname].packageFolder = hashData[fullname].packageFolder;
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Update versions section
|
|
327
|
+
if (!manifest.versions) manifest.versions = {};
|
|
328
|
+
Object.keys(versions).forEach(fullname => {
|
|
329
|
+
manifest.versions[fullname] = versions[fullname];
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Remove old hash property if it exists
|
|
333
|
+
delete manifest.hash;
|
|
334
|
+
|
|
335
|
+
writeFileSync(changeConfig, JSON.stringify(manifest, null, 2), "utf8");
|
|
336
|
+
console.log('manifest hashes written successfully');
|
|
189
337
|
} else {
|
|
338
|
+
let result = Object.keys(current).sort().reduce(
|
|
339
|
+
(obj, key) => { obj[key] = current[key]; return obj; },
|
|
340
|
+
{}
|
|
341
|
+
);
|
|
190
342
|
writeFileSync(changeConfig, JSON.stringify(result, null, 2), "utf8");
|
|
191
343
|
console.log('folder hashes written successfully');
|
|
192
344
|
}
|
|
@@ -250,7 +402,8 @@ let options = {
|
|
|
250
402
|
hashFile: null,
|
|
251
403
|
hashExcludeFolders: ['node_modules', 'coverage', 'dist', 'bin', 'obj', '__pycache__', '.vs', '.nx', '.vscode', '.idea', '.git', '.github', '.azuredevops', '.release'],
|
|
252
404
|
hashExcludeFiles: ['.npmrc', 'CHANGELOG.md', 'README.md'],
|
|
253
|
-
dependencies: "dependencies.json"
|
|
405
|
+
dependencies: "dependencies.json",
|
|
406
|
+
dependenciesProvided: false
|
|
254
407
|
};
|
|
255
408
|
|
|
256
409
|
if (process.argv.length === 2) {
|
|
@@ -281,6 +434,7 @@ if (process.argv.length === 2) {
|
|
|
281
434
|
let name = argv[i].substring(2);
|
|
282
435
|
if (options[name] !== undefined) {
|
|
283
436
|
options[name] = argv[i + 1];
|
|
437
|
+
if (name === 'dependencies') options.dependenciesProvided = true;
|
|
284
438
|
i++;
|
|
285
439
|
} else {
|
|
286
440
|
console.error(`Expected a known option, got ${argv[i]}`);
|
|
@@ -290,12 +444,24 @@ if (process.argv.length === 2) {
|
|
|
290
444
|
}
|
|
291
445
|
}
|
|
292
446
|
|
|
293
|
-
const
|
|
447
|
+
const hasGitHubManifest = existsSync(path.join(options.prefixPath, '.github/manifest.json'));
|
|
448
|
+
const hasAdoManifest = existsSync(path.join(options.prefixPath, '.cicd/manifest.json'));
|
|
449
|
+
const hasGitHubHash = existsSync(path.join(options.prefixPath, '.github/hash.json'));
|
|
450
|
+
|
|
451
|
+
const configDir = (hasGitHubManifest || hasGitHubHash) ? '.github' : '.cicd';
|
|
294
452
|
if (!options.hashFile) {
|
|
295
|
-
|
|
453
|
+
if (configDir === '.github' && hasGitHubManifest) {
|
|
454
|
+
options.hashFile = '.github/manifest.json';
|
|
455
|
+
} else if (configDir === '.cicd' && hasAdoManifest) {
|
|
456
|
+
options.hashFile = '.cicd/manifest.json';
|
|
457
|
+
} else {
|
|
458
|
+
options.hashFile = configDir + '/hash.json';
|
|
459
|
+
}
|
|
296
460
|
}
|
|
461
|
+
const usesManifestHashFile = options.hashFile.replace(/\\/g, '/').endsWith('/manifest.json');
|
|
462
|
+
|
|
297
463
|
if (!options.platform) {
|
|
298
|
-
options.platform =
|
|
464
|
+
options.platform = configDir === '.github' ? 'github' : 'ado';
|
|
299
465
|
}
|
|
300
466
|
|
|
301
467
|
async function initPackage(options) {
|