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 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 a saved state file (`.cicd/hash.json` by default).
17
- 3. **Propagate** — Any package whose hash changed is marked `CHANGED`. All transitive dependents (read from `dependencies.json`) are also marked `CHANGED` via a breadth-first traversal.
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 | 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 manifest (`package.json`, `version.json`, 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/hash.json` if a `.github/` directory exists at the root, otherwise `.cicd/hash.json`. |
40
- | `--dependencies <path>` | `dependencies.json` | Path to the NX-style dependency graph used for transitive change propagation. |
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). |
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 | Format | Version field |
56
- |---|---|---|
57
- | `package.json` | JSON | `"version": "1.2.3"` |
58
- | `version.json` | JSON (same shape as `package.json`) | `"version": "1.2.3"` |
59
- | `pyproject.toml` | TOML | `version = "1.2.3"` under `[project]` or `[tool.poetry]` |
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 | 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` |
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 | Value |
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` | JSON array of changed package folder names. |
113
- | `<folderName>` | `true` for each top-level folder containing at least one changed package. |
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
- ## `dependencies.json` format
117
+ ## Dependency Source
118
118
 
119
- 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:
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
- { "source": "@scope/pkg-a", "target": "@scope/shared-lib", "type": "static" }
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 `package.json`:
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 | Command |
189
- |---|---|
190
- | `release:try` | dry-run of the full release flow |
191
- | `release:changed` | list changed packages |
192
- | `release:version` | bump and save versions |
193
- | `release:finalize` | write hashes |
194
- | `release:retag` | migrate tags to package-name format |
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.4",
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": "^29.0.0"
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
- if (options.dependencies) {
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
- // load previous hashes
56
- const data = existsSync(changeConfig) ? readFileSync(changeConfig, "utf8") : "{}";
57
- previous = JSON.parse(data);
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
- let results = await compare(packageFolder, previous, current, dependencies, options);
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 hasGitHub = existsSync(path.join(options.prefixPath, '.github/hash.json'));
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
- options.hashFile = hasGitHub ? '.github/hash.json' : '.cicd/hash.json';
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 = hasGitHub ? 'github' : 'ado';
464
+ options.platform = configDir === '.github' ? 'github' : 'ado';
299
465
  }
300
466
 
301
467
  async function initPackage(options) {