@adobe/aem-cli 16.19.0 → 16.19.2
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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [16.19.2](https://github.com/adobe/helix-cli/compare/v16.19.1...v16.19.2) (2026-05-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **content:** correctness fixes for push, merge, and delete ([#2721](https://github.com/adobe/helix-cli/issues/2721)) ([efc6f11](https://github.com/adobe/helix-cli/commit/efc6f1138d55493dd546da300114df83ad006c5e))
|
|
7
|
+
|
|
8
|
+
## [16.19.1](https://github.com/adobe/helix-cli/compare/v16.19.0...v16.19.1) (2026-04-28)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **deps:** update adobe fixes ([#2718](https://github.com/adobe/helix-cli/issues/2718)) ([487bd65](https://github.com/adobe/helix-cli/commit/487bd65e26a38707050f4605f45f515bf59bf9e3))
|
|
14
|
+
|
|
1
15
|
# [16.19.0](https://github.com/adobe/helix-cli/compare/v16.18.7...v16.19.0) (2026-04-27)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/aem-cli",
|
|
3
|
-
"version": "16.19.
|
|
3
|
+
"version": "16.19.2",
|
|
4
4
|
"description": "AEM CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@adobe/fetch": "4.3.0",
|
|
47
47
|
"@adobe/helix-log": "7.0.0",
|
|
48
|
-
"@adobe/helix-shared-config": "11.1.
|
|
48
|
+
"@adobe/helix-shared-config": "11.1.22",
|
|
49
49
|
"@adobe/helix-shared-git": "3.0.23",
|
|
50
50
|
"@adobe/helix-shared-indexer": "2.2.7",
|
|
51
|
-
"@adobe/helix-shared-process-queue": "3.1.
|
|
51
|
+
"@adobe/helix-shared-process-queue": "3.1.9",
|
|
52
52
|
"camelcase": "9.0.0",
|
|
53
53
|
"chalk-template": "1.1.2",
|
|
54
54
|
"chokidar": "5.0.0",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"yargs": "18.0.0"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@adobe/eslint-config-helix": "3.0.
|
|
90
|
+
"@adobe/eslint-config-helix": "3.0.26",
|
|
91
91
|
"@eslint/config-helpers": "0.5.5",
|
|
92
92
|
"@semantic-release/changelog": "6.0.3",
|
|
93
93
|
"@semantic-release/git": "10.0.1",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"eslint": "9.4.0",
|
|
96
96
|
"esmock": "2.7.3",
|
|
97
97
|
"husky": "9.1.7",
|
|
98
|
-
"junit-report-builder": "5.1.
|
|
98
|
+
"junit-report-builder": "5.1.2",
|
|
99
99
|
"lint-staged": "16.4.0",
|
|
100
100
|
"mocha": "11.7.5",
|
|
101
101
|
"mocha-multi-reporters": "1.5.1",
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"node_modules/@adobe/eslint-config-helix": {
|
|
25
|
-
"version": "3.0.
|
|
26
|
-
"resolved": "https://registry.npmjs.org/@adobe/eslint-config-helix/-/eslint-config-helix-3.0.
|
|
27
|
-
"integrity": "sha512-
|
|
25
|
+
"version": "3.0.26",
|
|
26
|
+
"resolved": "https://registry.npmjs.org/@adobe/eslint-config-helix/-/eslint-config-helix-3.0.26.tgz",
|
|
27
|
+
"integrity": "sha512-fF+yS57VSRd7ydKSgY170Q412dqwAB9euugEHDNBv3+qNvKByqiLvgfcAtodY6cwN9aUa6K8z1Yuezi3Q2+RyQ==",
|
|
28
28
|
"dev": true,
|
|
29
29
|
"license": "Apache-2.0",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@eslint/config-helpers": "0.5.
|
|
31
|
+
"@eslint/config-helpers": "0.5.5",
|
|
32
32
|
"eslint-plugin-import": "2.32.0",
|
|
33
|
-
"globals": "17.
|
|
33
|
+
"globals": "17.5.0"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">= 12"
|
|
@@ -39,32 +39,6 @@
|
|
|
39
39
|
"eslint": "^9.0.0"
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
|
-
"node_modules/@adobe/eslint-config-helix/node_modules/@eslint/config-helpers": {
|
|
43
|
-
"version": "0.5.4",
|
|
44
|
-
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz",
|
|
45
|
-
"integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==",
|
|
46
|
-
"dev": true,
|
|
47
|
-
"license": "Apache-2.0",
|
|
48
|
-
"dependencies": {
|
|
49
|
-
"@eslint/core": "^1.2.0"
|
|
50
|
-
},
|
|
51
|
-
"engines": {
|
|
52
|
-
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
"node_modules/@adobe/eslint-config-helix/node_modules/@eslint/core": {
|
|
56
|
-
"version": "1.2.1",
|
|
57
|
-
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
|
|
58
|
-
"integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
|
|
59
|
-
"dev": true,
|
|
60
|
-
"license": "Apache-2.0",
|
|
61
|
-
"dependencies": {
|
|
62
|
-
"@types/json-schema": "^7.0.15"
|
|
63
|
-
},
|
|
64
|
-
"engines": {
|
|
65
|
-
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
42
|
"node_modules/@babel/code-frame": {
|
|
69
43
|
"version": "7.27.1",
|
|
70
44
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
|
@@ -3595,9 +3569,9 @@
|
|
|
3595
3569
|
}
|
|
3596
3570
|
},
|
|
3597
3571
|
"node_modules/globals": {
|
|
3598
|
-
"version": "17.
|
|
3599
|
-
"resolved": "https://registry.npmjs.org/globals/-/globals-17.
|
|
3600
|
-
"integrity": "sha512-
|
|
3572
|
+
"version": "17.5.0",
|
|
3573
|
+
"resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz",
|
|
3574
|
+
"integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==",
|
|
3601
3575
|
"dev": true,
|
|
3602
3576
|
"license": "MIT",
|
|
3603
3577
|
"engines": {
|
package/src/content/da-api.js
CHANGED
|
@@ -162,7 +162,8 @@ export class DaClient {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
/**
|
|
165
|
-
* Deletes a file or folder. Idempotent.
|
|
165
|
+
* Deletes a file or folder. Idempotent: 404 is treated as success.
|
|
166
|
+
* Throws on transport or server errors so callers don't silently treat them as success.
|
|
166
167
|
*/
|
|
167
168
|
async deleteSource(org, repo, daPath) {
|
|
168
169
|
const url = `${DA_ADMIN}/source/${org}/${repo}${daPath}`;
|
|
@@ -173,7 +174,10 @@ export class DaClient {
|
|
|
173
174
|
if (res.status === 401) {
|
|
174
175
|
throw new Error('Unauthorized: invalid or missing token');
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
+
if (res.ok || res.status === 204 || res.status === 404) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
throw new Error(`DELETE failed for ${daPath}: ${res.status} ${res.statusText}`);
|
|
177
181
|
}
|
|
178
182
|
|
|
179
183
|
/**
|
package/src/content/merge.cmd.js
CHANGED
|
@@ -96,7 +96,7 @@ export default class MergeCommand {
|
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const token = await getValidToken(log, this._token,
|
|
99
|
+
const token = await getValidToken(log, this._token, this._dir);
|
|
100
100
|
const client = new DaClient(token);
|
|
101
101
|
|
|
102
102
|
// Get the HEAD commit to read base blobs
|
package/src/content/push.cmd.js
CHANGED
|
@@ -108,16 +108,16 @@ export default class PushCommand {
|
|
|
108
108
|
* @param {string} repo
|
|
109
109
|
* @param {string} contentDir
|
|
110
110
|
* @param {string[]} targets
|
|
111
|
-
* @returns {Promise<{ pushed: number, errors: number
|
|
111
|
+
* @returns {Promise<{ pushed: number, errors: number }>}
|
|
112
112
|
*/
|
|
113
113
|
async _uploadFiles(client, org, repo, contentDir, targets) {
|
|
114
114
|
const { log } = this;
|
|
115
115
|
let pushed = 0;
|
|
116
116
|
let errors = 0;
|
|
117
|
-
const successfullyPushed = new Set();
|
|
118
117
|
|
|
118
|
+
// processQueue consumes its input array via shift(); copy so the caller's list survives.
|
|
119
119
|
const results = await processQueue(
|
|
120
|
-
targets,
|
|
120
|
+
[...targets],
|
|
121
121
|
async (daPath) => {
|
|
122
122
|
const localPath = path.join(contentDir, ...daPath.split('/').filter(Boolean));
|
|
123
123
|
const ext = daPath.split('.').pop();
|
|
@@ -125,7 +125,7 @@ export default class PushCommand {
|
|
|
125
125
|
const buffer = await fse.readFile(localPath);
|
|
126
126
|
await client.putSource(org, repo, daPath, buffer, getContentType(ext));
|
|
127
127
|
log.info(` ✓ ${daPath}`);
|
|
128
|
-
return { ok: true
|
|
128
|
+
return { ok: true };
|
|
129
129
|
} catch (err) {
|
|
130
130
|
log.warn(` ✗ ${daPath}: ${err.message}`);
|
|
131
131
|
return { ok: false };
|
|
@@ -136,13 +136,12 @@ export default class PushCommand {
|
|
|
136
136
|
for (const r of results) {
|
|
137
137
|
if (r.ok) {
|
|
138
138
|
pushed += 1;
|
|
139
|
-
successfullyPushed.add(r.daPath);
|
|
140
139
|
} else {
|
|
141
140
|
errors += 1;
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
return { pushed, errors
|
|
144
|
+
return { pushed, errors };
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
/**
|
|
@@ -151,21 +150,21 @@ export default class PushCommand {
|
|
|
151
150
|
* @param {string} org
|
|
152
151
|
* @param {string} repo
|
|
153
152
|
* @param {string[]} deleted
|
|
154
|
-
* @returns {Promise<{ pushed: number, errors: number
|
|
153
|
+
* @returns {Promise<{ pushed: number, errors: number }>}
|
|
155
154
|
*/
|
|
156
155
|
async _deleteFiles(client, org, repo, deleted) {
|
|
157
156
|
const { log } = this;
|
|
158
157
|
let pushed = 0;
|
|
159
158
|
let errors = 0;
|
|
160
|
-
const successfullyDeleted = new Set();
|
|
161
159
|
|
|
160
|
+
// processQueue consumes its input array via shift(); copy so the caller's list survives.
|
|
162
161
|
const results = await processQueue(
|
|
163
|
-
deleted,
|
|
162
|
+
[...deleted],
|
|
164
163
|
async (daPath) => {
|
|
165
164
|
try {
|
|
166
165
|
await client.deleteSource(org, repo, daPath);
|
|
167
166
|
log.info(` ✓ deleted ${daPath}`);
|
|
168
|
-
return { ok: true
|
|
167
|
+
return { ok: true };
|
|
169
168
|
} catch (err) {
|
|
170
169
|
log.warn(` ✗ ${daPath}: ${err.message}`);
|
|
171
170
|
return { ok: false };
|
|
@@ -176,13 +175,12 @@ export default class PushCommand {
|
|
|
176
175
|
for (const r of results) {
|
|
177
176
|
if (r.ok) {
|
|
178
177
|
pushed += 1;
|
|
179
|
-
successfullyDeleted.add(r.daPath);
|
|
180
178
|
} else {
|
|
181
179
|
errors += 1;
|
|
182
180
|
}
|
|
183
181
|
}
|
|
184
182
|
|
|
185
|
-
return { pushed, errors
|
|
183
|
+
return { pushed, errors };
|
|
186
184
|
}
|
|
187
185
|
|
|
188
186
|
async run() {
|
|
@@ -207,12 +205,21 @@ export default class PushCommand {
|
|
|
207
205
|
const syncedOid = await resolveSyncedOid(fs, contentDir);
|
|
208
206
|
const lastSyncTime = await getCommitCommitterTimeMs(fs, contentDir, syncedOid);
|
|
209
207
|
|
|
210
|
-
|
|
208
|
+
const fullChanges = await diffCommitTrees(fs, contentDir, syncedOid, headOid);
|
|
209
|
+
|
|
210
|
+
const scope = this._pushPath ? this._pushPath.replace(/\/+$/, '') : null;
|
|
211
|
+
const inScope = (daPath) => scope === null
|
|
212
|
+
|| daPath === scope
|
|
213
|
+
|| daPath.startsWith(`${scope}/`);
|
|
214
|
+
const added = fullChanges.added.filter(inScope);
|
|
215
|
+
const modified = fullChanges.modified.filter(inScope);
|
|
216
|
+
const deleted = fullChanges.deleted.filter(inScope);
|
|
211
217
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
218
|
+
const fullCount = fullChanges.added.length
|
|
219
|
+
+ fullChanges.modified.length
|
|
220
|
+
+ fullChanges.deleted.length;
|
|
221
|
+
const scopeCount = added.length + modified.length + deleted.length;
|
|
222
|
+
const scopeIsComplete = fullCount === scopeCount;
|
|
216
223
|
|
|
217
224
|
if (added.length === 0 && modified.length === 0 && deleted.length === 0) {
|
|
218
225
|
log.info('Nothing to push. No commits ahead of the last da.live sync.');
|
|
@@ -261,27 +268,27 @@ export default class PushCommand {
|
|
|
261
268
|
return;
|
|
262
269
|
}
|
|
263
270
|
|
|
264
|
-
const putTargets = [...added, ...modified];
|
|
265
271
|
const {
|
|
266
272
|
pushed: putPushed,
|
|
267
273
|
errors: putErrors,
|
|
268
|
-
|
|
269
|
-
} = await this._uploadFiles(client, org, repo, contentDir, putTargets);
|
|
274
|
+
} = await this._uploadFiles(client, org, repo, contentDir, [...added, ...modified]);
|
|
270
275
|
|
|
271
276
|
const {
|
|
272
277
|
pushed: deletePushed,
|
|
273
278
|
errors: deleteErrors,
|
|
274
|
-
successfullyDeleted,
|
|
275
279
|
} = await this._deleteFiles(client, org, repo, deleted);
|
|
276
280
|
|
|
277
281
|
const pushed = putPushed + deletePushed;
|
|
278
282
|
const pushErrors = putErrors + deleteErrors;
|
|
283
|
+
const allOk = pushErrors === 0;
|
|
279
284
|
|
|
280
|
-
|
|
281
|
-
const allDeletesOk = deleted.every((p) => successfullyDeleted.has(p));
|
|
282
|
-
|
|
283
|
-
if (allPutsOk && allDeletesOk) {
|
|
285
|
+
if (allOk && scopeIsComplete) {
|
|
284
286
|
await writeSyncedRef(fs, contentDir, headOid);
|
|
287
|
+
} else if (allOk) {
|
|
288
|
+
log.info(
|
|
289
|
+
'\n--path filter held back other changes; sync ref not advanced. '
|
|
290
|
+
+ 'Run \'aem content push\' (without --path) to fully sync.',
|
|
291
|
+
);
|
|
285
292
|
} else {
|
|
286
293
|
log.warn('\nSync ref not updated: fix errors and push again to finish syncing this commit.');
|
|
287
294
|
}
|