@dsh-workbench/module-tools 1.1.6 → 1.1.8
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 +2 -0
- package/bin/dsh-wb-module.mjs +1 -0
- package/package.json +2 -2
- package/src/market-index.mjs +100 -92
- package/src/release-util.mjs +8 -0
- package/src/release.mjs +27 -2
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ pnpm design check # 设计底稿有没有空格、README 有没有落后
|
|
|
32
32
|
`package.json` 缺 `files` 里的 `CHANGELOG.md` 一样拦下;`author` 没写时从本机 `git config` 补进 manifest,索引与产物都带上。
|
|
33
33
|
模块的 `package.json` 可用 `dsh.workbench.market` 声明 `category` 与 `labels`(字符串数组);
|
|
34
34
|
不写就不带分类和标签,索引里只留 `metadata.workbench: true` 这条身份标记。
|
|
35
|
+
发布时带 `--label <短词>`(可重复,最多两个):它写回 `dsh.workbench.market.labels`;不传就用模块里已有的。
|
|
36
|
+
每次发布都会把模块里的标签并进索引条目的 `metadata.labels` —— 标题 / 署名 / 说明仍保持索引里现有的那份不动。
|
|
35
37
|
要换署名时带 `--author "姓名 <邮箱>"`(或只给姓名):它写回 `package.json`,索引、产物与提交都用它,
|
|
36
38
|
`--refresh` 时也一样。**发布本身不改市集里的标题 / 署名 / 说明**:这些元数据只由 `--refresh`(或显式 `--author`)写,
|
|
37
39
|
避免一台还没更新的机器发新版时把别人刚改的元数据盖回去。一个包名归第一次发布的人(条目文件里的 `owner`):换署名发同名会被拒,
|
package/bin/dsh-wb-module.mjs
CHANGED
|
@@ -61,6 +61,7 @@ const RELEASE_HELP = `
|
|
|
61
61
|
--registry <url> --access restricted|public --npmrc <文件>
|
|
62
62
|
--license <id> --out <目录> --git <remote>
|
|
63
63
|
--author <署名> 换署名(姓名,或 姓名 <邮箱>);写回 package.json
|
|
64
|
+
--label <短词> 给市集条目打标签(1–2 个,可重复);写回 package.json
|
|
64
65
|
--changelog-note <文字> --changelog-type added|changed|fixed|removed|security|deprecated
|
|
65
66
|
这一版还没有更新日志时写进 CHANGELOG.md(文件不在先建)
|
|
66
67
|
--index auto|none|<目录|git 地址> 发布后要更新的索引源
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/module-tools",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "模块包的构建与门禁工具:build(单文件 ESM 宿主侧 + 套 loader 壳的浏览器侧)、check(契约/产物边界/源码边界/卡片渲染)。模块包不再各带一份构建脚本。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"semver": "^7.8.5",
|
|
34
34
|
"typescript": "5.9.3",
|
|
35
35
|
"typescript-eslint": "^8.71.0",
|
|
36
|
-
"@dsh-workbench/shared": "1.1.
|
|
36
|
+
"@dsh-workbench/shared": "1.1.8"
|
|
37
37
|
},
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
package/src/market-index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cpSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { cpSync, copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
2
|
import { dirname, join, resolve } from 'node:path';
|
|
4
3
|
import { isDeepStrictEqual } from 'node:util';
|
|
5
4
|
|
|
@@ -11,15 +10,12 @@ import {
|
|
|
11
10
|
collectMarketEntryFiles,
|
|
12
11
|
gitUrlOk,
|
|
13
12
|
marketArtifactPath,
|
|
14
|
-
marketArtifactPathFor,
|
|
15
13
|
marketArtifactRoot,
|
|
14
|
+
marketEntryFileOf,
|
|
16
15
|
marketEntryFilesOfLegacy,
|
|
17
|
-
marketEntryPath,
|
|
18
|
-
marketMetaDocOf,
|
|
19
|
-
marketMetaPath,
|
|
20
16
|
marketSourceKey,
|
|
21
|
-
marketVersionDocOf,
|
|
22
17
|
parseMarketIndexJson,
|
|
18
|
+
sortMarketVersions,
|
|
23
19
|
} from '@dsh-workbench/shared/host';
|
|
24
20
|
|
|
25
21
|
const MARKET_DIR = 'market';
|
|
@@ -182,48 +178,12 @@ function ensureVersionFree(workdir, dir, input) {
|
|
|
182
178
|
}
|
|
183
179
|
}
|
|
184
180
|
|
|
185
|
-
function writeEntryFile(workdir, dir, entry
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (isDeepStrictEqual(current, doc)) return rel;
|
|
192
|
-
throw new MarketIndexError(
|
|
193
|
-
`索引里已经有 ${entry.name}@${version.version}(${rel})—— 换个版本号再发`,
|
|
194
|
-
'market-owner',
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
198
|
-
writeFileSync(file, `${JSON.stringify(doc, null, 2)}\n`);
|
|
199
|
-
return rel;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function metaEpochOf(workdir, dir, name) {
|
|
203
|
-
const root = join(workdir, dir, name);
|
|
204
|
-
if (!existsSync(root)) return 0;
|
|
205
|
-
let epoch = 0;
|
|
206
|
-
for (const item of readdirSync(root)) {
|
|
207
|
-
if (!item.startsWith('meta-') || !item.endsWith('.json')) continue;
|
|
208
|
-
try {
|
|
209
|
-
const doc = JSON.parse(readFileSync(join(root, item), 'utf8'));
|
|
210
|
-
if (typeof doc.epoch === 'number' && doc.epoch > epoch) epoch = doc.epoch;
|
|
211
|
-
} catch {
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
return epoch;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function writeMetaFile(workdir, dir, entry, at) {
|
|
219
|
-
const epoch = metaEpochOf(workdir, dir, entry.name) + 1;
|
|
220
|
-
const suffix = randomBytes(3).toString('hex');
|
|
221
|
-
const doc = marketMetaDocOf(entry, epoch, Math.floor(at / 1000));
|
|
222
|
-
const rel = marketMetaPath(dir, entry.name, epoch, suffix);
|
|
223
|
-
const file = join(workdir, ...rel.split('/'));
|
|
224
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
225
|
-
writeFileSync(file, `${JSON.stringify(doc, null, 2)}\n`);
|
|
226
|
-
return rel;
|
|
181
|
+
function writeEntryFile(workdir, dir, entry) {
|
|
182
|
+
const file = marketEntryFileOf(entry, dir);
|
|
183
|
+
const target = join(workdir, ...file.path.split('/'));
|
|
184
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
185
|
+
writeFileSync(target, file.text);
|
|
186
|
+
return file.path;
|
|
227
187
|
}
|
|
228
188
|
|
|
229
189
|
function migrateLegacyIndex(workdir, dir) {
|
|
@@ -344,14 +304,44 @@ function textListOf(value) {
|
|
|
344
304
|
: [];
|
|
345
305
|
}
|
|
346
306
|
|
|
307
|
+
function recordOf(value) {
|
|
308
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function recordFieldOf(container, key) {
|
|
312
|
+
const value = container[key];
|
|
313
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) return value;
|
|
314
|
+
const next = {};
|
|
315
|
+
container[key] = next;
|
|
316
|
+
return next;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export function labelsOfManifest(manifest) {
|
|
320
|
+
const dsh = recordOf(recordOf(manifest).dsh);
|
|
321
|
+
const workbench = recordOf(dsh.workbench);
|
|
322
|
+
return textListOf(recordOf(workbench.market).labels);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function setManifestLabels(manifest, labels) {
|
|
326
|
+
if (labels.length === 0) return;
|
|
327
|
+
const market = recordFieldOf(recordFieldOf(recordFieldOf(manifest, 'dsh'), 'workbench'), 'market');
|
|
328
|
+
market.labels = [...labels];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function mergeEntryLabels(entry, labels) {
|
|
332
|
+
if (!Array.isArray(labels) || labels.length === 0) return entry;
|
|
333
|
+
const wanted = [...labels];
|
|
334
|
+
if (isDeepStrictEqual(entry.metadata?.labels ?? [], wanted)) return entry;
|
|
335
|
+
return { ...entry, metadata: { ...(entry.metadata ?? {}), labels: wanted } };
|
|
336
|
+
}
|
|
337
|
+
|
|
347
338
|
export function entryMetaOf(manifest) {
|
|
348
339
|
const author = authorOf(manifest);
|
|
349
340
|
const homepage = typeof manifest.homepage === 'string' ? manifest.homepage.trim() : '';
|
|
350
341
|
const keywords = textListOf(manifest.keywords);
|
|
351
|
-
const
|
|
352
|
-
const marketRecord = market !== null && typeof market === 'object' && !Array.isArray(market) ? market : {};
|
|
342
|
+
const marketRecord = recordOf(manifest.dsh?.workbench?.market);
|
|
353
343
|
const category = typeof marketRecord.category === 'string' ? marketRecord.category.trim() : '';
|
|
354
|
-
const labels =
|
|
344
|
+
const labels = labelsOfManifest(manifest);
|
|
355
345
|
const order = manifest.dsh?.workbench?.card?.order;
|
|
356
346
|
const unit = unitOf(manifest);
|
|
357
347
|
const title = titleOf(manifest);
|
|
@@ -373,21 +363,22 @@ export function entryMetaOf(manifest) {
|
|
|
373
363
|
}
|
|
374
364
|
|
|
375
365
|
export function indexEntryOf(input) {
|
|
376
|
-
const
|
|
377
|
-
const dsh = manifest.engines?.dsh;
|
|
378
|
-
const owner = authorTextOf(manifest);
|
|
366
|
+
const owner = authorTextOf(input.manifest);
|
|
379
367
|
return {
|
|
380
|
-
name: manifest.name,
|
|
368
|
+
name: input.manifest.name,
|
|
381
369
|
...(owner === '' ? {} : { owner }),
|
|
382
|
-
...entryMetaOf(manifest),
|
|
383
|
-
versions: [
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
370
|
+
...entryMetaOf(input.manifest),
|
|
371
|
+
versions: [versionRecordOf(input)],
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function versionRecordOf(input) {
|
|
376
|
+
const dsh = input.manifest.engines?.dsh;
|
|
377
|
+
return {
|
|
378
|
+
version: input.version,
|
|
379
|
+
publishTimestamp: Math.floor(input.at / 1000),
|
|
380
|
+
source: input.source,
|
|
381
|
+
...(typeof dsh === 'string' && dsh.trim() !== '' ? { engines: { dsh: dsh.trim() } } : {}),
|
|
391
382
|
};
|
|
392
383
|
}
|
|
393
384
|
|
|
@@ -590,11 +581,11 @@ function remoteHeadOf(exec, workdir, branch) {
|
|
|
590
581
|
return line.split(/\s+/)[0] ?? '';
|
|
591
582
|
}
|
|
592
583
|
|
|
593
|
-
function copyArtifacts(root, workdir, name,
|
|
584
|
+
function copyArtifacts(root, workdir, name, manifest) {
|
|
594
585
|
if (!SAFE_PACKAGE_NAME.test(name)) {
|
|
595
586
|
throw new MarketIndexError(`包名不是合法 npm 名,没法当产物目录:${JSON.stringify(name)}`, 'index-write');
|
|
596
587
|
}
|
|
597
|
-
const path =
|
|
588
|
+
const path = marketArtifactRoot(name);
|
|
598
589
|
const dest = join(workdir, path);
|
|
599
590
|
rmSync(dest, { recursive: true, force: true });
|
|
600
591
|
mkdirSync(dest, { recursive: true });
|
|
@@ -637,22 +628,6 @@ export function marketClaim({ plan, exec, home, name, unit, publisher }) {
|
|
|
637
628
|
});
|
|
638
629
|
}
|
|
639
630
|
|
|
640
|
-
const META_KEYS = ['title', 'description', 'author', 'owner', 'homepage', 'icon', 'metadata'];
|
|
641
|
-
|
|
642
|
-
function withCurrentMeta(entry, current, update) {
|
|
643
|
-
if (current === undefined) return entry;
|
|
644
|
-
const next = { ...entry };
|
|
645
|
-
if (!update) {
|
|
646
|
-
for (const key of META_KEYS) {
|
|
647
|
-
if (key === 'owner') continue;
|
|
648
|
-
if (current[key] === undefined) delete next[key];
|
|
649
|
-
else next[key] = current[key];
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
if (current.owner !== undefined) next.owner = current.owner;
|
|
653
|
-
return next;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
631
|
export function updateMarketIndex(options) {
|
|
657
632
|
const { plan, exec, home, root, manifest, version, publish, now, resume, onStep } = options;
|
|
658
633
|
const unit = options.unit ?? unitOf(manifest);
|
|
@@ -677,11 +652,19 @@ export function updateMarketIndex(options) {
|
|
|
677
652
|
if (plan.source.localPath === undefined) {
|
|
678
653
|
const fetched = runGit(exec, workdir, ['fetch', 'origin', branch], { allowFailure: true });
|
|
679
654
|
if (fetched.status === 0) runGit(exec, workdir, ['reset', '--hard', `origin/${branch}`], { allowFailure: true });
|
|
680
|
-
runGit(exec, workdir, ['clean', '-fd', '--',
|
|
655
|
+
runGit(exec, workdir, ['clean', '-fd', '--', marketArtifactRoot(manifest.name), dir], {
|
|
681
656
|
allowFailure: true,
|
|
682
657
|
});
|
|
683
658
|
}
|
|
684
|
-
|
|
659
|
+
const file = join(workdir, dir, `${manifest.name}.json`);
|
|
660
|
+
if (existsSync(file)) {
|
|
661
|
+
const kept = JSON.parse(readFileSync(file, 'utf8'));
|
|
662
|
+
const versions = (Array.isArray(kept.versions) ? kept.versions : []).filter(
|
|
663
|
+
(one) => one?.version !== version,
|
|
664
|
+
);
|
|
665
|
+
if (versions.length === 0) rmSync(file, { force: true });
|
|
666
|
+
else writeFileSync(file, `${JSON.stringify({ ...kept, versions }, null, 2)}\n`);
|
|
667
|
+
}
|
|
685
668
|
} else {
|
|
686
669
|
assertClean(exec, workdir);
|
|
687
670
|
}
|
|
@@ -719,7 +702,7 @@ export function updateMarketIndex(options) {
|
|
|
719
702
|
const done = replicatePush(exec, workdir, branch, baseSha, () => {
|
|
720
703
|
ensureClaimFree(workdir, dir, claimInput);
|
|
721
704
|
migrateLegacyIndex(workdir, dir);
|
|
722
|
-
artifactPath = copyArtifacts(root, workdir, manifest.name,
|
|
705
|
+
artifactPath = copyArtifacts(root, workdir, manifest.name, manifest);
|
|
723
706
|
report({ phase: 'artifacts-copied' });
|
|
724
707
|
artifactSha = commitOf(exec, workdir, `chore(release): ${entryName}`, identityOf(manifest));
|
|
725
708
|
report({ phase: 'artifacts-committed', artifactCommit: artifactSha });
|
|
@@ -740,15 +723,32 @@ export function updateMarketIndex(options) {
|
|
|
740
723
|
if (source === undefined) throw new MarketIndexError('这个出口没有可写进索引的 source(tarball 不进索引)', 'index-write');
|
|
741
724
|
if (source.type === 'npm' && source.registry === 'https://registry.npmjs.org/') delete source.registry;
|
|
742
725
|
}
|
|
743
|
-
const
|
|
726
|
+
const versionRecord = versionRecordOf({ manifest, version, source, at: now() });
|
|
744
727
|
report({ phase: 'index' });
|
|
745
728
|
const indexed = replicatePush(exec, workdir, branch, baseSha, () => {
|
|
746
729
|
if (plan.policy !== 'artifacts-in-repo') migrateLegacyIndex(workdir, dir);
|
|
747
730
|
ensureClaimFree(workdir, dir, claimInput);
|
|
731
|
+
ensureVersionFree(workdir, dir, claimInput);
|
|
748
732
|
const current = readWorktreeIndex(workdir, dir).plugins.find((one) => one.name === manifest.name);
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
733
|
+
const owner = authorTextOf(manifest);
|
|
734
|
+
let next;
|
|
735
|
+
if (current === undefined) {
|
|
736
|
+
next = {
|
|
737
|
+
name: manifest.name,
|
|
738
|
+
...(owner === '' ? {} : { owner }),
|
|
739
|
+
...entryMetaOf(manifest),
|
|
740
|
+
versions: [versionRecord],
|
|
741
|
+
};
|
|
742
|
+
} else {
|
|
743
|
+
next = { ...current, versions: sortMarketVersions([versionRecord, ...current.versions]) };
|
|
744
|
+
if (options.metadata === true) {
|
|
745
|
+
const merged = { ...next, ...entryMetaOf(manifest) };
|
|
746
|
+
if (current.owner !== undefined) merged.owner = current.owner;
|
|
747
|
+
next = merged;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
next = mergeEntryLabels(next, options.labels);
|
|
751
|
+
writeEntryFile(workdir, dir, next);
|
|
752
752
|
indexSha = commitOf(exec, workdir, `chore(market): ${entryName}`, identityOf(manifest));
|
|
753
753
|
report({ phase: 'index-committed', indexCommit: indexSha });
|
|
754
754
|
return indexSha;
|
|
@@ -830,10 +830,18 @@ export function refreshMarketEntry(options) {
|
|
|
830
830
|
if (isDeepStrictEqual(next, existing)) {
|
|
831
831
|
return { ...base, updated: false, unchanged: true, version: latest, phase: 'done' };
|
|
832
832
|
}
|
|
833
|
-
const at = Date.now();
|
|
834
833
|
const baseSha = revOf(exec, workdir, 'HEAD');
|
|
835
834
|
const done = replicatePush(exec, workdir, branch, baseSha, () => {
|
|
836
|
-
|
|
835
|
+
const fresh = readWorktreeIndex(workdir, dir).plugins.find((one) => one.name === manifest.name);
|
|
836
|
+
if (fresh === undefined) {
|
|
837
|
+
throw new MarketIndexError(`${manifest.name} 还不在索引里 —— 先正常发一版`, 'index-write');
|
|
838
|
+
}
|
|
839
|
+
const updated = { ...fresh };
|
|
840
|
+
for (const key of ['title', 'description', 'author', 'homepage', 'metadata']) {
|
|
841
|
+
if (Object.hasOwn(meta, key)) updated[key] = meta[key];
|
|
842
|
+
else delete updated[key];
|
|
843
|
+
}
|
|
844
|
+
writeEntryFile(workdir, dir, updated);
|
|
837
845
|
return commitOf(exec, workdir, `chore(market): refresh ${manifest.name}`, identityOf(manifest));
|
|
838
846
|
});
|
|
839
847
|
if (!done.ok) throw new MarketIndexError(done.reason, done.code);
|
package/src/release-util.mjs
CHANGED
|
@@ -58,6 +58,14 @@ export function argValue(args, flag) {
|
|
|
58
58
|
return at === -1 ? undefined : args[at + 1];
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
export function argValues(args, flag) {
|
|
62
|
+
const values = [];
|
|
63
|
+
for (let at = 0; at < args.length; at += 1) {
|
|
64
|
+
if (args[at] === flag) values.push(args[at + 1] ?? '');
|
|
65
|
+
}
|
|
66
|
+
return values;
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
export function hasFlag(args, flag) {
|
|
62
70
|
return args.includes(flag);
|
|
63
71
|
}
|
package/src/release.mjs
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
ReleaseError,
|
|
26
26
|
ResumableError,
|
|
27
27
|
argValue,
|
|
28
|
+
argValues,
|
|
28
29
|
defaultExec,
|
|
29
30
|
dshHomeOf,
|
|
30
31
|
hasFlag,
|
|
@@ -52,11 +53,13 @@ import {
|
|
|
52
53
|
authorTextOf,
|
|
53
54
|
claimProblemText,
|
|
54
55
|
identityOf,
|
|
56
|
+
labelsOfManifest,
|
|
55
57
|
marketClaim,
|
|
56
58
|
marketVersionExists,
|
|
57
59
|
missingPublisherText,
|
|
58
60
|
refreshMarketEntry,
|
|
59
61
|
resolveIndexPlan,
|
|
62
|
+
setManifestLabels,
|
|
60
63
|
updateMarketIndex,
|
|
61
64
|
verifyMarketArtifact,
|
|
62
65
|
} from './market-index.mjs';
|
|
@@ -262,6 +265,11 @@ export async function runRelease({
|
|
|
262
265
|
if (!CHANGELOG_KINDS.includes(changelogKind)) {
|
|
263
266
|
throw new ReleaseError(`--changelog-type 只认 ${CHANGELOG_KINDS.join(' / ')}(收到「${changelogKind}」)`);
|
|
264
267
|
}
|
|
268
|
+
const askedLabels = [...new Set(argValues(args, '--label').map((one) => String(one).trim()))];
|
|
269
|
+
if (askedLabels.some((one) => one === '' || /[\r\n]/u.test(one))) {
|
|
270
|
+
throw new ReleaseError('--label 只认一行短词:不能是空的');
|
|
271
|
+
}
|
|
272
|
+
if (askedLabels.length > 2) throw new ReleaseError('--label 最多两个 —— 一个模块的标签是 1–2 个短词');
|
|
265
273
|
const manifest = readManifest(root);
|
|
266
274
|
const unit = manifest?.dsh?.workbench?.unit;
|
|
267
275
|
if (typeof unit !== 'string' || unit === '') throw new ReleaseError('这不是一个 wb 模块包(没有 dsh.workbench.unit)');
|
|
@@ -313,6 +321,14 @@ export async function runRelease({
|
|
|
313
321
|
emit(out, json, summary);
|
|
314
322
|
return summary;
|
|
315
323
|
}
|
|
324
|
+
const labels = askedLabels;
|
|
325
|
+
const labelsKept = labels.length === 0 || isDeepStrictEqual(labelsOfManifest(manifest), labels);
|
|
326
|
+
const labelsChange = verify || labelsKept ? undefined : `标签 ← ${labels.join(' · ')}`;
|
|
327
|
+
if (!labelsKept && !verify && !dryRun) {
|
|
328
|
+
setManifestLabels(manifest, labels);
|
|
329
|
+
writeManifest(root, manifest);
|
|
330
|
+
}
|
|
331
|
+
const labelsForIndex = labels.length > 0 ? labels : labelsOfManifest(manifest);
|
|
316
332
|
const explicitApplied = explicitAuthor !== undefined && !verify && !dryRun;
|
|
317
333
|
if (explicitApplied) {
|
|
318
334
|
manifest.author = explicitAuthor;
|
|
@@ -343,7 +359,7 @@ export async function runRelease({
|
|
|
343
359
|
}
|
|
344
360
|
const authored = authorChangeOf(root, manifest, exec);
|
|
345
361
|
if (hasFlag(args, '--refresh')) {
|
|
346
|
-
if (dryRun) throw new ReleaseError('--refresh 没有预览:它只改索引里的标题 / 作者 / 说明');
|
|
362
|
+
if (dryRun) throw new ReleaseError('--refresh 没有预览:它只改索引里的标题 / 作者 / 说明 / 标签');
|
|
347
363
|
if (target !== 'market') throw new ReleaseError('--refresh 只对市场索引有意义(--target market)');
|
|
348
364
|
if (indexPlan === undefined) {
|
|
349
365
|
throw new ReleaseError('没有可写的 git 索引源 —— 用 --index <仓库> 指定,或先在「模块市场 → 发现」里初始化索引');
|
|
@@ -369,8 +385,13 @@ export async function runRelease({
|
|
|
369
385
|
},
|
|
370
386
|
changes:
|
|
371
387
|
result.updated === true
|
|
372
|
-
? [
|
|
388
|
+
? [
|
|
389
|
+
'市集元数据已刷新',
|
|
390
|
+
...(explicitAuthor === undefined ? [] : ['author ← --author']),
|
|
391
|
+
...(labelsChange === undefined ? [] : [labelsChange]),
|
|
392
|
+
]
|
|
373
393
|
: [],
|
|
394
|
+
...(labels.length === 0 ? {} : { labels }),
|
|
374
395
|
install: '',
|
|
375
396
|
text:
|
|
376
397
|
result.updated === true
|
|
@@ -481,6 +502,7 @@ export async function runRelease({
|
|
|
481
502
|
publish,
|
|
482
503
|
publisher: authorTextOf(manifestNow),
|
|
483
504
|
metadata: authorChange !== undefined,
|
|
505
|
+
...(labelsForIndex.length === 0 ? {} : { labels: labelsForIndex }),
|
|
484
506
|
exec,
|
|
485
507
|
home,
|
|
486
508
|
now: () => Date.now(),
|
|
@@ -489,6 +511,7 @@ export async function runRelease({
|
|
|
489
511
|
let changelogChange;
|
|
490
512
|
const changesOf = (version) => [
|
|
491
513
|
...(authorChange === undefined ? [] : [authorChange]),
|
|
514
|
+
...(labelsChange === undefined ? [] : [labelsChange]),
|
|
492
515
|
...(version === manifest.version ? [] : [`version → ${version}`]),
|
|
493
516
|
...(changelogChange === undefined ? [] : [changelogChange]),
|
|
494
517
|
];
|
|
@@ -708,6 +731,7 @@ export async function runRelease({
|
|
|
708
731
|
version,
|
|
709
732
|
files,
|
|
710
733
|
changes: changesOf(version),
|
|
734
|
+
...(labels.length === 0 ? {} : { labels }),
|
|
711
735
|
...(changelogReport === undefined ? {} : { changelog: changelogReport }),
|
|
712
736
|
install: '',
|
|
713
737
|
market: indexPreviewOf(manifest.name, version),
|
|
@@ -730,6 +754,7 @@ export async function runRelease({
|
|
|
730
754
|
publish: {},
|
|
731
755
|
publisher,
|
|
732
756
|
metadata: authorChange !== undefined,
|
|
757
|
+
...(labelsForIndex.length === 0 ? {} : { labels: labelsForIndex }),
|
|
733
758
|
exec,
|
|
734
759
|
home,
|
|
735
760
|
now: () => Date.now(),
|