@bushizhanghan/dsh-publish-gate 0.1.4 → 0.1.5
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 -2
- package/lib/engine.js +27 -0
- package/lib/index.js +20 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ dsh plugin --profile desktop add @bushizhanghan/dsh-publish-gate
|
|
|
29
29
|
| `publish_gate` | 全量门禁:静态检查 + 网络检查,返回 `safeToPublish` |
|
|
30
30
|
| `publish_gate_patch` | 只查 `cordis.patch.yml`——「插件装了但工具没出现」的第一个怀疑对象 |
|
|
31
31
|
| `publish_gate_market` | 校验市场条目 YAML(url/name/category/description 双语) |
|
|
32
|
-
| `publish_gate_next_version` | 当前版本、是否已被 registry 占用、建议 bump
|
|
32
|
+
| `publish_gate_next_version` | 当前版本、是否已被 registry 占用、建议 bump 到多少(本地比 npm 旧时从 npm 的 latest 往上加,不会推荐一个已被占用的版本) |
|
|
33
33
|
| `publish_gate_doctor` | 扫整个目录,按 blocker 数排序,看哪个插件还不能发 |
|
|
34
34
|
| `publish_gate_commands` | 按顺序列出发布命令,并标出这台机器已经走到哪一步 |
|
|
35
35
|
|
|
@@ -90,7 +90,7 @@ dsh plugin --profile desktop add @bushizhanghan/dsh-publish-gate
|
|
|
90
90
|
## 开发
|
|
91
91
|
|
|
92
92
|
```sh
|
|
93
|
-
node --test #
|
|
93
|
+
node --test # 26 个测试(含 4 个真实插件作 fixture)
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
## License
|
package/lib/engine.js
CHANGED
|
@@ -433,6 +433,33 @@ export function bumpPatch(v) {
|
|
|
433
433
|
return m ? `${m[1]}.${m[2]}.${Number(m[3]) + 1}` : v
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
/** -1 / 0 / 1 by semver-ish comparison of the numeric part. */
|
|
437
|
+
export function compareVersions(a, b) {
|
|
438
|
+
const pa = /^(\d+)\.(\d+)\.(\d+)/.exec(String(a))?.slice(1).map(Number) ?? [0, 0, 0]
|
|
439
|
+
const pb = /^(\d+)\.(\d+)\.(\d+)/.exec(String(b))?.slice(1).map(Number) ?? [0, 0, 0]
|
|
440
|
+
for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return pa[i] > pb[i] ? 1 : -1
|
|
441
|
+
return 0
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* The registry's `dist-tags.latest`, or null when it could not be read.
|
|
446
|
+
* next_version needs this: a local checkout that is BEHIND npm would otherwise
|
|
447
|
+
* be told to publish a version that is already taken.
|
|
448
|
+
*/
|
|
449
|
+
export async function latestPublished(name, { registry = 'https://registry.npmjs.org', timeoutMs = 8000 } = {}) {
|
|
450
|
+
try {
|
|
451
|
+
const res = await fetch(`${registry.replace(/\/$/, '')}/${name.replace('/', '%2f')}`, {
|
|
452
|
+
headers: { accept: 'application/vnd.npm.install-v1+json' },
|
|
453
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
454
|
+
})
|
|
455
|
+
if (!res.ok) return null
|
|
456
|
+
const json = await res.json()
|
|
457
|
+
return json?.['dist-tags']?.latest ?? null
|
|
458
|
+
} catch {
|
|
459
|
+
return null
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
436
463
|
export function checkGitState(dir) {
|
|
437
464
|
const out = []
|
|
438
465
|
const gitDir = join(dir, '.git')
|
package/lib/index.js
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
checkPatchYml,
|
|
19
19
|
checkTests,
|
|
20
20
|
checkVersionTaken,
|
|
21
|
+
compareVersions,
|
|
22
|
+
latestPublished,
|
|
21
23
|
renderReport,
|
|
22
24
|
runStaticChecks,
|
|
23
25
|
} from './engine.js'
|
|
@@ -168,23 +170,36 @@ export function apply(ctx, config = {}) {
|
|
|
168
170
|
if (!dir) return { ok: false, error: 'no plugin directory given' }
|
|
169
171
|
const json = readJson(join(dir, 'package.json'))
|
|
170
172
|
if (!json?.version) return { ok: false, error: 'no version in package.json' }
|
|
171
|
-
const taken = (await checkVersionTaken(json.name, json.version, { registry: cfg.registry })).map((f) => f.title)
|
|
172
|
-
const
|
|
173
|
+
const taken = (await checkVersionTaken(json.name, json.version, { registry: cfg.registry, timeoutMs: cfg.networkTimeoutMs })).map((f) => f.title)
|
|
174
|
+
const latest = await latestPublished(json.name, { registry: cfg.registry, timeoutMs: cfg.networkTimeoutMs })
|
|
175
|
+
// A checkout that is behind npm must bump from npm's latest, or the
|
|
176
|
+
// "suggested" version is one that is already published.
|
|
177
|
+
const behind = latest && compareVersions(latest, json.version) > 0 ? latest : null
|
|
178
|
+
const base = behind ?? json.version
|
|
179
|
+
const [a, b, c] = /^(\d+)\.(\d+)\.(\d+)/.exec(base)?.slice(1).map(Number) ?? [0, 0, 0]
|
|
173
180
|
const bump = args.bump || 'patch'
|
|
174
181
|
const suggested =
|
|
175
182
|
bump === 'major' ? `${a + 1}.0.0` : bump === 'minor' ? `${a}.${b + 1}.0` : `${a}.${b}.${c + 1}`
|
|
176
|
-
return {
|
|
183
|
+
return {
|
|
184
|
+
ok: true,
|
|
185
|
+
current: json.version,
|
|
186
|
+
latest,
|
|
187
|
+
behind,
|
|
188
|
+
taken,
|
|
189
|
+
suggested,
|
|
190
|
+
suggestedFor: bump,
|
|
191
|
+
note: behind ? `package.json is behind the registry (${behind} is live); the suggestion bumps from there.` : undefined,
|
|
192
|
+
}
|
|
177
193
|
},
|
|
178
194
|
},
|
|
179
195
|
{
|
|
180
196
|
name: 'publish_gate_doctor',
|
|
181
197
|
description:
|
|
182
|
-
'Run the gate over every plugin in a directory tree (e.g. a workspace holding several plugin checkouts) and rank them by blocker count, so you can see which one is not ready to ship before you start a publish session. Returns {ok, plugins:[{dir,blockers,warns,notes,top}], totals}.',
|
|
198
|
+
'Run the gate over every plugin in a directory tree (e.g. a workspace holding several plugin checkouts) and rank them by blocker count, so you can see which one is not ready to ship before you start a publish session. Static checks only — no registry or GitHub calls, so it is fast and works offline. Returns {ok, plugins:[{dir,blockers,warns,notes,top}], totals}.',
|
|
183
199
|
parameters: {
|
|
184
200
|
type: 'object',
|
|
185
201
|
properties: {
|
|
186
202
|
root: { type: 'string', description: 'Directory containing plugin checkouts.' },
|
|
187
|
-
skipNetwork: { type: 'boolean', description: 'Skip registry/GitHub checks (default true for a multi-plugin sweep).' },
|
|
188
203
|
},
|
|
189
204
|
},
|
|
190
205
|
async execute(args) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bushizhanghan/dsh-publish-gate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Helps DSH plugin AUTHORS publish their plugins: a one-command gate that turns every silent failure in the publish path into a deterministic check — package.json completeness, BOM, YAML/JSON parseability, junction and patch insert correctness, npm scope permissions, GitHub repo and token state, market entry format, LICENSE/README, test suite. 帮助插件作者一键发布:写完插件后跑一遍门禁,把发布链路上的每个静默坑变成确定性检查,然后 GitHub + npm + 市场一键三连。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|