@codluv/versionguard 0.9.0 → 1.0.0
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 +34 -12
- package/dist/chunks/{src-BPMDUQfR.js → src-Bofo3tVH.js} +541 -232
- package/dist/chunks/src-Bofo3tVH.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +38 -36
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/guard.d.ts +2 -33
- package/dist/guard.d.ts.map +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/publish.d.ts +61 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/types.d.ts +185 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/src-BPMDUQfR.js.map +0 -1
|
@@ -1101,9 +1101,16 @@ function areHooksInstalled(cwd = process.cwd()) {
|
|
|
1101
1101
|
* @param hookName - Name of the Git hook to generate.
|
|
1102
1102
|
* @returns The VG block with start/end markers.
|
|
1103
1103
|
*/
|
|
1104
|
+
/** Mode description per hook for generated comments. */
|
|
1105
|
+
var HOOK_MODE_COMMENTS = {
|
|
1106
|
+
"pre-commit": "# Mode: lightweight (version + sync only — fast)",
|
|
1107
|
+
"pre-push": "# Mode: full (version, sync, changelog, scan, guard, publish)",
|
|
1108
|
+
"post-tag": "# Mode: full with post-tag actions"
|
|
1109
|
+
};
|
|
1104
1110
|
function generateHookBlock(hookName) {
|
|
1105
1111
|
return `${VG_BLOCK_START}
|
|
1106
1112
|
# VersionGuard ${hookName} hook
|
|
1113
|
+
${HOOK_MODE_COMMENTS[hookName] ?? "# Mode: full"}
|
|
1107
1114
|
# --no-install prevents accidentally downloading an unscoped package
|
|
1108
1115
|
# if @codluv/versionguard is not installed locally
|
|
1109
1116
|
npx --no-install versionguard validate --hook=${hookName}
|
|
@@ -1160,6 +1167,212 @@ function removeVgBlock(content) {
|
|
|
1160
1167
|
return content.slice(0, startIdx).replace(/\n\n$/, "\n") + content.slice(endIdx + 22).replace(/^\n\n/, "\n");
|
|
1161
1168
|
}
|
|
1162
1169
|
//#endregion
|
|
1170
|
+
//#region src/guard.ts
|
|
1171
|
+
var HOOK_NAMES = [
|
|
1172
|
+
"pre-commit",
|
|
1173
|
+
"pre-push",
|
|
1174
|
+
"post-tag"
|
|
1175
|
+
];
|
|
1176
|
+
/**
|
|
1177
|
+
* Checks whether git hooks have been redirected away from the repository.
|
|
1178
|
+
*
|
|
1179
|
+
* @remarks
|
|
1180
|
+
* When `core.hooksPath` is set to a non-default location, git hooks installed
|
|
1181
|
+
* in `.git/hooks/` are silently ignored. This is a common bypass vector.
|
|
1182
|
+
*
|
|
1183
|
+
* @param cwd - Repository directory to inspect.
|
|
1184
|
+
* @returns A guard warning when a hooksPath override is detected.
|
|
1185
|
+
*
|
|
1186
|
+
* @example
|
|
1187
|
+
* ```ts
|
|
1188
|
+
* import { checkHooksPathOverride } from './guard';
|
|
1189
|
+
*
|
|
1190
|
+
* const warning = checkHooksPathOverride(process.cwd());
|
|
1191
|
+
* if (warning) console.warn(warning.message);
|
|
1192
|
+
* ```
|
|
1193
|
+
*
|
|
1194
|
+
* @public
|
|
1195
|
+
* @since 0.2.0
|
|
1196
|
+
*/
|
|
1197
|
+
function checkHooksPathOverride(cwd) {
|
|
1198
|
+
try {
|
|
1199
|
+
const hooksPath = execSync("git config core.hooksPath", {
|
|
1200
|
+
cwd,
|
|
1201
|
+
encoding: "utf-8"
|
|
1202
|
+
}).trim();
|
|
1203
|
+
if (hooksPath) {
|
|
1204
|
+
const resolved = path.resolve(cwd, hooksPath);
|
|
1205
|
+
const huskyDir = path.resolve(cwd, ".husky");
|
|
1206
|
+
if (resolved === huskyDir || resolved.startsWith(`${huskyDir}${path.sep}`)) return {
|
|
1207
|
+
code: "HOOKS_PATH_HUSKY",
|
|
1208
|
+
severity: "warning",
|
|
1209
|
+
message: `Husky detected — core.hooksPath is set to "${hooksPath}". Hooks in .git/hooks/ are bypassed. Add versionguard validate to your .husky/pre-commit manually or use a tool like forge-ts that manages .husky/ hooks cooperatively.`
|
|
1210
|
+
};
|
|
1211
|
+
return {
|
|
1212
|
+
code: "HOOKS_PATH_OVERRIDE",
|
|
1213
|
+
severity: "error",
|
|
1214
|
+
message: `git core.hooksPath is set to "${hooksPath}" — hooks in .git/hooks/ are bypassed`,
|
|
1215
|
+
fix: "git config --unset core.hooksPath"
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
} catch {}
|
|
1219
|
+
return null;
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Checks whether the HUSKY environment variable is disabling hooks.
|
|
1223
|
+
*
|
|
1224
|
+
* @remarks
|
|
1225
|
+
* Setting `HUSKY=0` is a documented way to disable Husky hooks. Since
|
|
1226
|
+
* VersionGuard hooks may run alongside or through Husky, this bypass
|
|
1227
|
+
* can silently disable enforcement.
|
|
1228
|
+
*
|
|
1229
|
+
* @returns A guard warning when the HUSKY bypass is detected.
|
|
1230
|
+
*
|
|
1231
|
+
* @example
|
|
1232
|
+
* ```ts
|
|
1233
|
+
* import { checkHuskyBypass } from './guard';
|
|
1234
|
+
*
|
|
1235
|
+
* const warning = checkHuskyBypass();
|
|
1236
|
+
* if (warning) console.warn(warning.message);
|
|
1237
|
+
* ```
|
|
1238
|
+
*
|
|
1239
|
+
* @public
|
|
1240
|
+
* @since 0.2.0
|
|
1241
|
+
*/
|
|
1242
|
+
function checkHuskyBypass() {
|
|
1243
|
+
if (process.env.HUSKY === "0") return {
|
|
1244
|
+
code: "HUSKY_BYPASS",
|
|
1245
|
+
severity: "error",
|
|
1246
|
+
message: "HUSKY=0 is set — git hooks are disabled via environment variable",
|
|
1247
|
+
fix: "unset HUSKY"
|
|
1248
|
+
};
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Verifies that installed hook scripts match the expected content.
|
|
1253
|
+
*
|
|
1254
|
+
* @remarks
|
|
1255
|
+
* This compares each hook file against what `generateHookScript` would produce.
|
|
1256
|
+
* Tampered hooks that still contain "versionguard" pass `areHooksInstalled` but
|
|
1257
|
+
* may have had critical lines removed or modified.
|
|
1258
|
+
*
|
|
1259
|
+
* @param config - VersionGuard configuration that defines which hooks should exist.
|
|
1260
|
+
* @param cwd - Repository directory to inspect.
|
|
1261
|
+
* @returns Guard warnings for each hook that has been tampered with.
|
|
1262
|
+
*
|
|
1263
|
+
* @example
|
|
1264
|
+
* ```ts
|
|
1265
|
+
* import { checkHookIntegrity } from './guard';
|
|
1266
|
+
*
|
|
1267
|
+
* const warnings = checkHookIntegrity(config, process.cwd());
|
|
1268
|
+
* for (const w of warnings) console.warn(w.code, w.message);
|
|
1269
|
+
* ```
|
|
1270
|
+
*
|
|
1271
|
+
* @public
|
|
1272
|
+
* @since 0.2.0
|
|
1273
|
+
*/
|
|
1274
|
+
function checkHookIntegrity(config, cwd) {
|
|
1275
|
+
const warnings = [];
|
|
1276
|
+
const gitDir = findGitDir(cwd);
|
|
1277
|
+
if (!gitDir) return warnings;
|
|
1278
|
+
const hooksDir = path.join(gitDir, "hooks");
|
|
1279
|
+
for (const hookName of HOOK_NAMES) {
|
|
1280
|
+
if (!config.git.hooks[hookName]) continue;
|
|
1281
|
+
const hookPath = path.join(hooksDir, hookName);
|
|
1282
|
+
if (!fs.existsSync(hookPath)) {
|
|
1283
|
+
warnings.push({
|
|
1284
|
+
code: "HOOK_MISSING",
|
|
1285
|
+
severity: "error",
|
|
1286
|
+
message: `Required hook "${hookName}" is not installed`,
|
|
1287
|
+
fix: "npx versionguard hooks install"
|
|
1288
|
+
});
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
const actual = fs.readFileSync(hookPath, "utf-8");
|
|
1292
|
+
if (actual !== generateHookScript(hookName)) if (!actual.includes("versionguard")) warnings.push({
|
|
1293
|
+
code: "HOOK_REPLACED",
|
|
1294
|
+
severity: "error",
|
|
1295
|
+
message: `Hook "${hookName}" has been replaced — versionguard invocation is missing`,
|
|
1296
|
+
fix: "npx versionguard hooks install"
|
|
1297
|
+
});
|
|
1298
|
+
else warnings.push({
|
|
1299
|
+
code: "HOOK_TAMPERED",
|
|
1300
|
+
severity: "warning",
|
|
1301
|
+
message: `Hook "${hookName}" has been modified from the expected template`,
|
|
1302
|
+
fix: "npx versionguard hooks install"
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
return warnings;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Checks whether hooks are configured as required but not enforced.
|
|
1309
|
+
*
|
|
1310
|
+
* @remarks
|
|
1311
|
+
* When hooks are enabled in the config but `enforceHooks` is false, validation
|
|
1312
|
+
* will not fail for missing hooks. In strict mode this is a policy gap.
|
|
1313
|
+
*
|
|
1314
|
+
* @param config - VersionGuard configuration to inspect.
|
|
1315
|
+
* @returns A guard warning when hooks are enabled but not enforced.
|
|
1316
|
+
*
|
|
1317
|
+
* @example
|
|
1318
|
+
* ```ts
|
|
1319
|
+
* import { checkEnforceHooksPolicy } from './guard';
|
|
1320
|
+
*
|
|
1321
|
+
* const warning = checkEnforceHooksPolicy(config);
|
|
1322
|
+
* if (warning) console.warn(warning.message);
|
|
1323
|
+
* ```
|
|
1324
|
+
*
|
|
1325
|
+
* @public
|
|
1326
|
+
* @since 0.2.0
|
|
1327
|
+
*/
|
|
1328
|
+
function checkEnforceHooksPolicy(config) {
|
|
1329
|
+
if (HOOK_NAMES.some((name) => config.git.hooks[name]) && !config.git.enforceHooks) return {
|
|
1330
|
+
code: "HOOKS_NOT_ENFORCED",
|
|
1331
|
+
severity: "warning",
|
|
1332
|
+
message: "Hooks are enabled but enforceHooks is false — missing hooks will not fail validation",
|
|
1333
|
+
fix: "Set git.enforceHooks: true in .versionguard.yml"
|
|
1334
|
+
};
|
|
1335
|
+
return null;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Runs all guard checks and returns a consolidated report.
|
|
1339
|
+
*
|
|
1340
|
+
* @remarks
|
|
1341
|
+
* This is the primary entry point for strict mode. It runs every detection
|
|
1342
|
+
* check and returns a report indicating whether the repository is safe from
|
|
1343
|
+
* known bypass patterns.
|
|
1344
|
+
*
|
|
1345
|
+
* @param config - VersionGuard configuration.
|
|
1346
|
+
* @param cwd - Repository directory to inspect.
|
|
1347
|
+
* @returns A guard report with all findings.
|
|
1348
|
+
*
|
|
1349
|
+
* @example
|
|
1350
|
+
* ```ts
|
|
1351
|
+
* import { runGuardChecks } from './guard';
|
|
1352
|
+
*
|
|
1353
|
+
* const report = runGuardChecks(config, process.cwd());
|
|
1354
|
+
* if (!report.safe) console.error('Guard check failed:', report.warnings);
|
|
1355
|
+
* ```
|
|
1356
|
+
*
|
|
1357
|
+
* @public
|
|
1358
|
+
* @since 0.2.0
|
|
1359
|
+
*/
|
|
1360
|
+
function runGuardChecks(config, cwd) {
|
|
1361
|
+
const warnings = [];
|
|
1362
|
+
const hooksPathWarning = checkHooksPathOverride(cwd);
|
|
1363
|
+
if (hooksPathWarning) warnings.push(hooksPathWarning);
|
|
1364
|
+
const huskyWarning = checkHuskyBypass();
|
|
1365
|
+
if (huskyWarning) warnings.push(huskyWarning);
|
|
1366
|
+
const integrityWarnings = checkHookIntegrity(config, cwd);
|
|
1367
|
+
warnings.push(...integrityWarnings);
|
|
1368
|
+
const enforceWarning = checkEnforceHooksPolicy(config);
|
|
1369
|
+
if (enforceWarning) warnings.push(enforceWarning);
|
|
1370
|
+
return {
|
|
1371
|
+
safe: !warnings.some((w) => w.severity === "error"),
|
|
1372
|
+
warnings
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
//#endregion
|
|
1163
1376
|
//#region src/sources/git-tag.ts
|
|
1164
1377
|
/**
|
|
1165
1378
|
* Git tag-based version source for Go, Swift, and similar ecosystems.
|
|
@@ -2119,23 +2332,261 @@ function setPackageVersion(version, cwd = process.cwd(), manifest) {
|
|
|
2119
2332
|
* for the configured manifest type. Use this when you need direct access
|
|
2120
2333
|
* to the provider's `exists`, `getVersion`, and `setVersion` methods.
|
|
2121
2334
|
*
|
|
2122
|
-
* @param manifest - Manifest configuration.
|
|
2335
|
+
* @param manifest - Manifest configuration.
|
|
2336
|
+
* @param cwd - Project directory.
|
|
2337
|
+
* @returns The resolved provider instance.
|
|
2338
|
+
*
|
|
2339
|
+
* @example
|
|
2340
|
+
* ```ts
|
|
2341
|
+
* import { getVersionSource } from 'versionguard';
|
|
2342
|
+
*
|
|
2343
|
+
* const source = getVersionSource({ source: 'package.json' }, process.cwd());
|
|
2344
|
+
* const version = source.getVersion(process.cwd());
|
|
2345
|
+
* ```
|
|
2346
|
+
*
|
|
2347
|
+
* @public
|
|
2348
|
+
* @since 0.3.0
|
|
2349
|
+
*/
|
|
2350
|
+
function getVersionSource(manifest, cwd = process.cwd()) {
|
|
2351
|
+
return resolveVersionSource(manifest, cwd);
|
|
2352
|
+
}
|
|
2353
|
+
//#endregion
|
|
2354
|
+
//#region src/publish.ts
|
|
2355
|
+
/**
|
|
2356
|
+
* Registry publish status verification.
|
|
2357
|
+
*
|
|
2358
|
+
* Checks whether a package version has been published to its ecosystem registry.
|
|
2359
|
+
* Supports npm (via execFileSync), crates.io, PyPI, Packagist, pub.dev, and Maven Central (via fetch).
|
|
2360
|
+
*
|
|
2361
|
+
* @packageDocumentation
|
|
2362
|
+
*/
|
|
2363
|
+
/**
|
|
2364
|
+
* Maps manifest source types to their registry check implementations.
|
|
2365
|
+
*
|
|
2366
|
+
* @remarks
|
|
2367
|
+
* Each entry provides the registry name and a check function that returns
|
|
2368
|
+
* whether the given version is published. The check function receives the
|
|
2369
|
+
* package name, version, and publish config.
|
|
2370
|
+
*
|
|
2371
|
+
* @public
|
|
2372
|
+
* @since 1.0.0
|
|
2373
|
+
*/
|
|
2374
|
+
var REGISTRY_TABLE = {
|
|
2375
|
+
"package.json": {
|
|
2376
|
+
registry: "npm",
|
|
2377
|
+
check: checkNpmPublished
|
|
2378
|
+
},
|
|
2379
|
+
"Cargo.toml": {
|
|
2380
|
+
registry: "crates.io",
|
|
2381
|
+
check: checkHttpRegistry("crates.io", (name, version) => `https://crates.io/api/v1/crates/${encodeURIComponent(name)}/${encodeURIComponent(version)}`)
|
|
2382
|
+
},
|
|
2383
|
+
"pyproject.toml": {
|
|
2384
|
+
registry: "pypi",
|
|
2385
|
+
check: checkHttpRegistry("pypi", (name, version) => `https://pypi.org/pypi/${encodeURIComponent(name)}/${encodeURIComponent(version)}/json`)
|
|
2386
|
+
},
|
|
2387
|
+
"composer.json": {
|
|
2388
|
+
registry: "packagist",
|
|
2389
|
+
check: checkHttpRegistry("packagist", (name) => `https://repo.packagist.org/p2/${encodeURIComponent(name)}.json`, (body, version) => {
|
|
2390
|
+
try {
|
|
2391
|
+
const packages = JSON.parse(body).packages;
|
|
2392
|
+
if (!packages) return false;
|
|
2393
|
+
return Object.values(packages).flat().some((v) => v.version === version);
|
|
2394
|
+
} catch {
|
|
2395
|
+
return false;
|
|
2396
|
+
}
|
|
2397
|
+
})
|
|
2398
|
+
},
|
|
2399
|
+
"pubspec.yaml": {
|
|
2400
|
+
registry: "pub.dev",
|
|
2401
|
+
check: checkHttpRegistry("pub.dev", (name, version) => `https://pub.dev/api/packages/${encodeURIComponent(name)}/versions/${encodeURIComponent(version)}`)
|
|
2402
|
+
},
|
|
2403
|
+
"pom.xml": {
|
|
2404
|
+
registry: "maven-central",
|
|
2405
|
+
check: checkHttpRegistry("maven-central", (name, version) => `https://search.maven.org/solrsearch/select?q=a:"${encodeURIComponent(name)}"+AND+v:"${encodeURIComponent(version)}"&rows=1&wt=json`, (body) => {
|
|
2406
|
+
try {
|
|
2407
|
+
return (JSON.parse(body).response?.numFound ?? 0) > 0;
|
|
2408
|
+
} catch {
|
|
2409
|
+
return false;
|
|
2410
|
+
}
|
|
2411
|
+
})
|
|
2412
|
+
}
|
|
2413
|
+
};
|
|
2414
|
+
/** Source types that have no registry to check. */
|
|
2415
|
+
var SKIP_SOURCES = new Set([
|
|
2416
|
+
"VERSION",
|
|
2417
|
+
"git-tag",
|
|
2418
|
+
"auto",
|
|
2419
|
+
"custom"
|
|
2420
|
+
]);
|
|
2421
|
+
/**
|
|
2422
|
+
* Checks whether a package version has been published to its ecosystem registry.
|
|
2423
|
+
*
|
|
2424
|
+
* @remarks
|
|
2425
|
+
* Uses the REGISTRY_TABLE to dispatch to the correct check implementation
|
|
2426
|
+
* based on the detected manifest source type. Fail-open on network errors:
|
|
2427
|
+
* returns `published: false` with an error message when the check cannot complete.
|
|
2428
|
+
*
|
|
2429
|
+
* @param manifestSource - The detected manifest source type.
|
|
2430
|
+
* @param packageName - Package name as read from the manifest.
|
|
2431
|
+
* @param version - Version string to check.
|
|
2432
|
+
* @param config - Publish configuration with timeout and optional registry URL.
|
|
2433
|
+
* @returns The publish check result.
|
|
2434
|
+
*
|
|
2435
|
+
* @example
|
|
2436
|
+
* ```ts
|
|
2437
|
+
* import { checkPublishStatus } from './publish';
|
|
2438
|
+
*
|
|
2439
|
+
* const result = await checkPublishStatus('package.json', '@codluv/vg', '1.0.0', { enabled: true, timeout: 5000 });
|
|
2440
|
+
* ```
|
|
2441
|
+
*
|
|
2442
|
+
* @public
|
|
2443
|
+
* @since 1.0.0
|
|
2444
|
+
*/
|
|
2445
|
+
async function checkPublishStatus(manifestSource, packageName, version, config) {
|
|
2446
|
+
if (SKIP_SOURCES.has(manifestSource)) return {
|
|
2447
|
+
published: false,
|
|
2448
|
+
registry: "none",
|
|
2449
|
+
packageName
|
|
2450
|
+
};
|
|
2451
|
+
if (config.registryUrl && !/^https?:\/\//i.test(config.registryUrl)) return {
|
|
2452
|
+
published: false,
|
|
2453
|
+
registry: "unknown",
|
|
2454
|
+
packageName,
|
|
2455
|
+
error: `Invalid registry URL scheme — only http:// and https:// are allowed: ${config.registryUrl}`
|
|
2456
|
+
};
|
|
2457
|
+
const entry = REGISTRY_TABLE[manifestSource];
|
|
2458
|
+
if (!entry) return {
|
|
2459
|
+
published: false,
|
|
2460
|
+
registry: "unknown",
|
|
2461
|
+
packageName
|
|
2462
|
+
};
|
|
2463
|
+
try {
|
|
2464
|
+
return await entry.check(packageName, version, config);
|
|
2465
|
+
} catch (err) {
|
|
2466
|
+
return {
|
|
2467
|
+
published: false,
|
|
2468
|
+
registry: entry.registry,
|
|
2469
|
+
packageName,
|
|
2470
|
+
error: `Publish check failed: ${err.message}`
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
/**
|
|
2475
|
+
* Checks npm registry using execFileSync (shell-injection safe, inherits .npmrc auth).
|
|
2476
|
+
*/
|
|
2477
|
+
function checkNpmPublished(packageName, version, config) {
|
|
2478
|
+
try {
|
|
2479
|
+
const args = [
|
|
2480
|
+
"view",
|
|
2481
|
+
`${packageName}@${version}`,
|
|
2482
|
+
"version"
|
|
2483
|
+
];
|
|
2484
|
+
if (config.registryUrl) args.push(`--registry=${config.registryUrl}`);
|
|
2485
|
+
return {
|
|
2486
|
+
published: execFileSync("npm", args, {
|
|
2487
|
+
encoding: "utf-8",
|
|
2488
|
+
timeout: config.timeout,
|
|
2489
|
+
stdio: [
|
|
2490
|
+
"pipe",
|
|
2491
|
+
"pipe",
|
|
2492
|
+
"pipe"
|
|
2493
|
+
]
|
|
2494
|
+
}).trim() === version,
|
|
2495
|
+
registry: "npm",
|
|
2496
|
+
packageName
|
|
2497
|
+
};
|
|
2498
|
+
} catch (err) {
|
|
2499
|
+
const message = err.message || "";
|
|
2500
|
+
if (message.includes("E404") || message.includes("is not in this registry")) return {
|
|
2501
|
+
published: false,
|
|
2502
|
+
registry: "npm",
|
|
2503
|
+
packageName
|
|
2504
|
+
};
|
|
2505
|
+
return {
|
|
2506
|
+
published: false,
|
|
2507
|
+
registry: "npm",
|
|
2508
|
+
packageName,
|
|
2509
|
+
error: `npm check failed: ${message.split("\n")[0].slice(0, 100)}`
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
/**
|
|
2514
|
+
* Creates an HTTP registry check function using fetch with AbortController timeout.
|
|
2515
|
+
*/
|
|
2516
|
+
function checkHttpRegistry(registry, urlBuilder, bodyChecker) {
|
|
2517
|
+
return async (packageName, version, config) => {
|
|
2518
|
+
const url = config.registryUrl ? `${config.registryUrl.replace(/\/$/, "")}/${packageName}/${version}` : urlBuilder(packageName, version);
|
|
2519
|
+
const controller = new AbortController();
|
|
2520
|
+
const timeout = setTimeout(() => controller.abort(), config.timeout);
|
|
2521
|
+
try {
|
|
2522
|
+
const response = await fetch(url, {
|
|
2523
|
+
signal: controller.signal,
|
|
2524
|
+
headers: { Accept: "application/json" }
|
|
2525
|
+
});
|
|
2526
|
+
if (response.status === 404) return {
|
|
2527
|
+
published: false,
|
|
2528
|
+
registry,
|
|
2529
|
+
packageName
|
|
2530
|
+
};
|
|
2531
|
+
if (!response.ok) return {
|
|
2532
|
+
published: false,
|
|
2533
|
+
registry,
|
|
2534
|
+
packageName,
|
|
2535
|
+
error: `Registry returned HTTP ${response.status}`
|
|
2536
|
+
};
|
|
2537
|
+
if (bodyChecker) return {
|
|
2538
|
+
published: bodyChecker(await response.text(), version),
|
|
2539
|
+
registry,
|
|
2540
|
+
packageName
|
|
2541
|
+
};
|
|
2542
|
+
return {
|
|
2543
|
+
published: true,
|
|
2544
|
+
registry,
|
|
2545
|
+
packageName
|
|
2546
|
+
};
|
|
2547
|
+
} catch (err) {
|
|
2548
|
+
const message = err.message || "";
|
|
2549
|
+
if (message.includes("abort")) return {
|
|
2550
|
+
published: false,
|
|
2551
|
+
registry,
|
|
2552
|
+
packageName,
|
|
2553
|
+
error: `Registry check timed out after ${config.timeout}ms`
|
|
2554
|
+
};
|
|
2555
|
+
return {
|
|
2556
|
+
published: false,
|
|
2557
|
+
registry,
|
|
2558
|
+
packageName,
|
|
2559
|
+
error: `Registry check failed: ${message.slice(0, 200)}`
|
|
2560
|
+
};
|
|
2561
|
+
} finally {
|
|
2562
|
+
clearTimeout(timeout);
|
|
2563
|
+
}
|
|
2564
|
+
};
|
|
2565
|
+
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Reads the package name from a manifest file for registry lookups.
|
|
2568
|
+
*
|
|
2569
|
+
* @param manifestSource - Detected manifest type.
|
|
2123
2570
|
* @param cwd - Project directory.
|
|
2124
|
-
* @returns The
|
|
2125
|
-
*
|
|
2126
|
-
* @example
|
|
2127
|
-
* ```ts
|
|
2128
|
-
* import { getVersionSource } from 'versionguard';
|
|
2129
|
-
*
|
|
2130
|
-
* const source = getVersionSource({ source: 'package.json' }, process.cwd());
|
|
2131
|
-
* const version = source.getVersion(process.cwd());
|
|
2132
|
-
* ```
|
|
2571
|
+
* @returns The package name, or null if it cannot be determined.
|
|
2133
2572
|
*
|
|
2134
2573
|
* @public
|
|
2135
|
-
* @since 0.
|
|
2574
|
+
* @since 1.0.0
|
|
2136
2575
|
*/
|
|
2137
|
-
function
|
|
2138
|
-
|
|
2576
|
+
function readPackageName(manifestSource, cwd) {
|
|
2577
|
+
try {
|
|
2578
|
+
switch (manifestSource) {
|
|
2579
|
+
case "package.json": return JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf-8")).name || null;
|
|
2580
|
+
case "Cargo.toml": return fs.readFileSync(path.join(cwd, "Cargo.toml"), "utf-8").match(/^\s*name\s*=\s*"([^"]+)"/m)?.[1] || null;
|
|
2581
|
+
case "pyproject.toml": return fs.readFileSync(path.join(cwd, "pyproject.toml"), "utf-8").match(/^\s*name\s*=\s*"([^"]+)"/m)?.[1] || null;
|
|
2582
|
+
case "composer.json": return JSON.parse(fs.readFileSync(path.join(cwd, "composer.json"), "utf-8")).name || null;
|
|
2583
|
+
case "pubspec.yaml": return fs.readFileSync(path.join(cwd, "pubspec.yaml"), "utf-8").match(/^name:\s*(.+)$/m)?.[1]?.trim() || null;
|
|
2584
|
+
case "pom.xml": return fs.readFileSync(path.join(cwd, "pom.xml"), "utf-8").match(/<artifactId>([^<]+)<\/artifactId>/)?.[1] || null;
|
|
2585
|
+
default: return null;
|
|
2586
|
+
}
|
|
2587
|
+
} catch {
|
|
2588
|
+
return null;
|
|
2589
|
+
}
|
|
2139
2590
|
}
|
|
2140
2591
|
//#endregion
|
|
2141
2592
|
//#region src/semver.ts
|
|
@@ -3029,7 +3480,7 @@ var DEFAULT_CONFIG = {
|
|
|
3029
3480
|
},
|
|
3030
3481
|
github: { dependabot: true },
|
|
3031
3482
|
scan: {
|
|
3032
|
-
enabled:
|
|
3483
|
+
enabled: true,
|
|
3033
3484
|
patterns: [
|
|
3034
3485
|
"(?:version\\s*[:=]\\s*[\"'])([\\d]+\\.[\\d]+\\.[\\d]+(?:-[\\w.]+)?)[\"']",
|
|
3035
3486
|
"(?:FROM\\s+\\S+:)(\\d+\\.\\d+\\.\\d+(?:-[\\w.]+)?)",
|
|
@@ -3045,6 +3496,11 @@ var DEFAULT_CONFIG = {
|
|
|
3045
3496
|
},
|
|
3046
3497
|
enforceHooks: true
|
|
3047
3498
|
},
|
|
3499
|
+
guard: { enabled: true },
|
|
3500
|
+
publish: {
|
|
3501
|
+
enabled: true,
|
|
3502
|
+
timeout: 5e3
|
|
3503
|
+
},
|
|
3048
3504
|
ignore: [
|
|
3049
3505
|
"node_modules/**",
|
|
3050
3506
|
"dist/**",
|
|
@@ -3204,6 +3660,16 @@ changelog:
|
|
|
3204
3660
|
github:
|
|
3205
3661
|
dependabot: true
|
|
3206
3662
|
|
|
3663
|
+
scan:
|
|
3664
|
+
enabled: true
|
|
3665
|
+
|
|
3666
|
+
guard:
|
|
3667
|
+
enabled: true
|
|
3668
|
+
|
|
3669
|
+
publish:
|
|
3670
|
+
enabled: true
|
|
3671
|
+
timeout: 5000
|
|
3672
|
+
|
|
3207
3673
|
git:
|
|
3208
3674
|
hooks:
|
|
3209
3675
|
pre-commit: true
|
|
@@ -3816,212 +4282,6 @@ function suggestNextVersion(currentVersion, config, changeType) {
|
|
|
3816
4282
|
return suggestions;
|
|
3817
4283
|
}
|
|
3818
4284
|
//#endregion
|
|
3819
|
-
//#region src/guard.ts
|
|
3820
|
-
var HOOK_NAMES = [
|
|
3821
|
-
"pre-commit",
|
|
3822
|
-
"pre-push",
|
|
3823
|
-
"post-tag"
|
|
3824
|
-
];
|
|
3825
|
-
/**
|
|
3826
|
-
* Checks whether git hooks have been redirected away from the repository.
|
|
3827
|
-
*
|
|
3828
|
-
* @remarks
|
|
3829
|
-
* When `core.hooksPath` is set to a non-default location, git hooks installed
|
|
3830
|
-
* in `.git/hooks/` are silently ignored. This is a common bypass vector.
|
|
3831
|
-
*
|
|
3832
|
-
* @param cwd - Repository directory to inspect.
|
|
3833
|
-
* @returns A guard warning when a hooksPath override is detected.
|
|
3834
|
-
*
|
|
3835
|
-
* @example
|
|
3836
|
-
* ```ts
|
|
3837
|
-
* import { checkHooksPathOverride } from './guard';
|
|
3838
|
-
*
|
|
3839
|
-
* const warning = checkHooksPathOverride(process.cwd());
|
|
3840
|
-
* if (warning) console.warn(warning.message);
|
|
3841
|
-
* ```
|
|
3842
|
-
*
|
|
3843
|
-
* @public
|
|
3844
|
-
* @since 0.2.0
|
|
3845
|
-
*/
|
|
3846
|
-
function checkHooksPathOverride(cwd) {
|
|
3847
|
-
try {
|
|
3848
|
-
const hooksPath = execSync("git config core.hooksPath", {
|
|
3849
|
-
cwd,
|
|
3850
|
-
encoding: "utf-8"
|
|
3851
|
-
}).trim();
|
|
3852
|
-
if (hooksPath) {
|
|
3853
|
-
const resolved = path.resolve(cwd, hooksPath);
|
|
3854
|
-
const huskyDir = path.resolve(cwd, ".husky");
|
|
3855
|
-
if (resolved === huskyDir || resolved.startsWith(`${huskyDir}${path.sep}`)) return {
|
|
3856
|
-
code: "HOOKS_PATH_HUSKY",
|
|
3857
|
-
severity: "warning",
|
|
3858
|
-
message: `Husky detected — core.hooksPath is set to "${hooksPath}". Hooks in .git/hooks/ are bypassed. Add versionguard validate to your .husky/pre-commit manually or use a tool like forge-ts that manages .husky/ hooks cooperatively.`
|
|
3859
|
-
};
|
|
3860
|
-
return {
|
|
3861
|
-
code: "HOOKS_PATH_OVERRIDE",
|
|
3862
|
-
severity: "error",
|
|
3863
|
-
message: `git core.hooksPath is set to "${hooksPath}" — hooks in .git/hooks/ are bypassed`,
|
|
3864
|
-
fix: "git config --unset core.hooksPath"
|
|
3865
|
-
};
|
|
3866
|
-
}
|
|
3867
|
-
} catch {}
|
|
3868
|
-
return null;
|
|
3869
|
-
}
|
|
3870
|
-
/**
|
|
3871
|
-
* Checks whether the HUSKY environment variable is disabling hooks.
|
|
3872
|
-
*
|
|
3873
|
-
* @remarks
|
|
3874
|
-
* Setting `HUSKY=0` is a documented way to disable Husky hooks. Since
|
|
3875
|
-
* VersionGuard hooks may run alongside or through Husky, this bypass
|
|
3876
|
-
* can silently disable enforcement.
|
|
3877
|
-
*
|
|
3878
|
-
* @returns A guard warning when the HUSKY bypass is detected.
|
|
3879
|
-
*
|
|
3880
|
-
* @example
|
|
3881
|
-
* ```ts
|
|
3882
|
-
* import { checkHuskyBypass } from './guard';
|
|
3883
|
-
*
|
|
3884
|
-
* const warning = checkHuskyBypass();
|
|
3885
|
-
* if (warning) console.warn(warning.message);
|
|
3886
|
-
* ```
|
|
3887
|
-
*
|
|
3888
|
-
* @public
|
|
3889
|
-
* @since 0.2.0
|
|
3890
|
-
*/
|
|
3891
|
-
function checkHuskyBypass() {
|
|
3892
|
-
if (process.env.HUSKY === "0") return {
|
|
3893
|
-
code: "HUSKY_BYPASS",
|
|
3894
|
-
severity: "error",
|
|
3895
|
-
message: "HUSKY=0 is set — git hooks are disabled via environment variable",
|
|
3896
|
-
fix: "unset HUSKY"
|
|
3897
|
-
};
|
|
3898
|
-
return null;
|
|
3899
|
-
}
|
|
3900
|
-
/**
|
|
3901
|
-
* Verifies that installed hook scripts match the expected content.
|
|
3902
|
-
*
|
|
3903
|
-
* @remarks
|
|
3904
|
-
* This compares each hook file against what `generateHookScript` would produce.
|
|
3905
|
-
* Tampered hooks that still contain "versionguard" pass `areHooksInstalled` but
|
|
3906
|
-
* may have had critical lines removed or modified.
|
|
3907
|
-
*
|
|
3908
|
-
* @param config - VersionGuard configuration that defines which hooks should exist.
|
|
3909
|
-
* @param cwd - Repository directory to inspect.
|
|
3910
|
-
* @returns Guard warnings for each hook that has been tampered with.
|
|
3911
|
-
*
|
|
3912
|
-
* @example
|
|
3913
|
-
* ```ts
|
|
3914
|
-
* import { checkHookIntegrity } from './guard';
|
|
3915
|
-
*
|
|
3916
|
-
* const warnings = checkHookIntegrity(config, process.cwd());
|
|
3917
|
-
* for (const w of warnings) console.warn(w.code, w.message);
|
|
3918
|
-
* ```
|
|
3919
|
-
*
|
|
3920
|
-
* @public
|
|
3921
|
-
* @since 0.2.0
|
|
3922
|
-
*/
|
|
3923
|
-
function checkHookIntegrity(config, cwd) {
|
|
3924
|
-
const warnings = [];
|
|
3925
|
-
const gitDir = findGitDir(cwd);
|
|
3926
|
-
if (!gitDir) return warnings;
|
|
3927
|
-
const hooksDir = path.join(gitDir, "hooks");
|
|
3928
|
-
for (const hookName of HOOK_NAMES) {
|
|
3929
|
-
if (!config.git.hooks[hookName]) continue;
|
|
3930
|
-
const hookPath = path.join(hooksDir, hookName);
|
|
3931
|
-
if (!fs.existsSync(hookPath)) {
|
|
3932
|
-
warnings.push({
|
|
3933
|
-
code: "HOOK_MISSING",
|
|
3934
|
-
severity: "error",
|
|
3935
|
-
message: `Required hook "${hookName}" is not installed`,
|
|
3936
|
-
fix: "npx versionguard hooks install"
|
|
3937
|
-
});
|
|
3938
|
-
continue;
|
|
3939
|
-
}
|
|
3940
|
-
const actual = fs.readFileSync(hookPath, "utf-8");
|
|
3941
|
-
if (actual !== generateHookScript(hookName)) if (!actual.includes("versionguard")) warnings.push({
|
|
3942
|
-
code: "HOOK_REPLACED",
|
|
3943
|
-
severity: "error",
|
|
3944
|
-
message: `Hook "${hookName}" has been replaced — versionguard invocation is missing`,
|
|
3945
|
-
fix: "npx versionguard hooks install"
|
|
3946
|
-
});
|
|
3947
|
-
else warnings.push({
|
|
3948
|
-
code: "HOOK_TAMPERED",
|
|
3949
|
-
severity: "warning",
|
|
3950
|
-
message: `Hook "${hookName}" has been modified from the expected template`,
|
|
3951
|
-
fix: "npx versionguard hooks install"
|
|
3952
|
-
});
|
|
3953
|
-
}
|
|
3954
|
-
return warnings;
|
|
3955
|
-
}
|
|
3956
|
-
/**
|
|
3957
|
-
* Checks whether hooks are configured as required but not enforced.
|
|
3958
|
-
*
|
|
3959
|
-
* @remarks
|
|
3960
|
-
* When hooks are enabled in the config but `enforceHooks` is false, validation
|
|
3961
|
-
* will not fail for missing hooks. In strict mode this is a policy gap.
|
|
3962
|
-
*
|
|
3963
|
-
* @param config - VersionGuard configuration to inspect.
|
|
3964
|
-
* @returns A guard warning when hooks are enabled but not enforced.
|
|
3965
|
-
*
|
|
3966
|
-
* @example
|
|
3967
|
-
* ```ts
|
|
3968
|
-
* import { checkEnforceHooksPolicy } from './guard';
|
|
3969
|
-
*
|
|
3970
|
-
* const warning = checkEnforceHooksPolicy(config);
|
|
3971
|
-
* if (warning) console.warn(warning.message);
|
|
3972
|
-
* ```
|
|
3973
|
-
*
|
|
3974
|
-
* @public
|
|
3975
|
-
* @since 0.2.0
|
|
3976
|
-
*/
|
|
3977
|
-
function checkEnforceHooksPolicy(config) {
|
|
3978
|
-
if (HOOK_NAMES.some((name) => config.git.hooks[name]) && !config.git.enforceHooks) return {
|
|
3979
|
-
code: "HOOKS_NOT_ENFORCED",
|
|
3980
|
-
severity: "warning",
|
|
3981
|
-
message: "Hooks are enabled but enforceHooks is false — missing hooks will not fail validation",
|
|
3982
|
-
fix: "Set git.enforceHooks: true in .versionguard.yml"
|
|
3983
|
-
};
|
|
3984
|
-
return null;
|
|
3985
|
-
}
|
|
3986
|
-
/**
|
|
3987
|
-
* Runs all guard checks and returns a consolidated report.
|
|
3988
|
-
*
|
|
3989
|
-
* @remarks
|
|
3990
|
-
* This is the primary entry point for strict mode. It runs every detection
|
|
3991
|
-
* check and returns a report indicating whether the repository is safe from
|
|
3992
|
-
* known bypass patterns.
|
|
3993
|
-
*
|
|
3994
|
-
* @param config - VersionGuard configuration.
|
|
3995
|
-
* @param cwd - Repository directory to inspect.
|
|
3996
|
-
* @returns A guard report with all findings.
|
|
3997
|
-
*
|
|
3998
|
-
* @example
|
|
3999
|
-
* ```ts
|
|
4000
|
-
* import { runGuardChecks } from './guard';
|
|
4001
|
-
*
|
|
4002
|
-
* const report = runGuardChecks(config, process.cwd());
|
|
4003
|
-
* if (!report.safe) console.error('Guard check failed:', report.warnings);
|
|
4004
|
-
* ```
|
|
4005
|
-
*
|
|
4006
|
-
* @public
|
|
4007
|
-
* @since 0.2.0
|
|
4008
|
-
*/
|
|
4009
|
-
function runGuardChecks(config, cwd) {
|
|
4010
|
-
const warnings = [];
|
|
4011
|
-
const hooksPathWarning = checkHooksPathOverride(cwd);
|
|
4012
|
-
if (hooksPathWarning) warnings.push(hooksPathWarning);
|
|
4013
|
-
const huskyWarning = checkHuskyBypass();
|
|
4014
|
-
if (huskyWarning) warnings.push(huskyWarning);
|
|
4015
|
-
const integrityWarnings = checkHookIntegrity(config, cwd);
|
|
4016
|
-
warnings.push(...integrityWarnings);
|
|
4017
|
-
const enforceWarning = checkEnforceHooksPolicy(config);
|
|
4018
|
-
if (enforceWarning) warnings.push(enforceWarning);
|
|
4019
|
-
return {
|
|
4020
|
-
safe: !warnings.some((w) => w.severity === "error"),
|
|
4021
|
-
warnings
|
|
4022
|
-
};
|
|
4023
|
-
}
|
|
4024
|
-
//#endregion
|
|
4025
4285
|
//#region src/project-root.ts
|
|
4026
4286
|
/**
|
|
4027
4287
|
* Project root detection and boundary validation.
|
|
@@ -4556,20 +4816,22 @@ function validateVersion(version, config) {
|
|
|
4556
4816
|
* @public
|
|
4557
4817
|
* @since 0.1.0
|
|
4558
4818
|
* @remarks
|
|
4559
|
-
*
|
|
4560
|
-
*
|
|
4819
|
+
* Runs version, sync, changelog, scan, guard, and publish checks based on
|
|
4820
|
+
* the validation mode. Full mode (default) runs all checks. Lightweight
|
|
4821
|
+
* mode (for pre-commit hooks) runs only version + sync.
|
|
4561
4822
|
*
|
|
4562
4823
|
* @param config - VersionGuard configuration to apply.
|
|
4563
4824
|
* @param cwd - Project directory to inspect.
|
|
4825
|
+
* @param mode - Validation mode: 'full' (default) or 'lightweight'.
|
|
4564
4826
|
* @returns A full validation report for the project rooted at `cwd`.
|
|
4565
4827
|
* @example
|
|
4566
4828
|
* ```ts
|
|
4567
4829
|
* import { getDefaultConfig, validate } from 'versionguard';
|
|
4568
4830
|
*
|
|
4569
|
-
* const result = validate(getDefaultConfig(), process.cwd());
|
|
4831
|
+
* const result = await validate(getDefaultConfig(), process.cwd());
|
|
4570
4832
|
* ```
|
|
4571
4833
|
*/
|
|
4572
|
-
function validate(config, cwd = process.cwd()) {
|
|
4834
|
+
async function validate(config, cwd = process.cwd(), mode = "full") {
|
|
4573
4835
|
const errors = [];
|
|
4574
4836
|
let version;
|
|
4575
4837
|
try {
|
|
@@ -4581,6 +4843,9 @@ function validate(config, cwd = process.cwd()) {
|
|
|
4581
4843
|
versionValid: false,
|
|
4582
4844
|
syncValid: false,
|
|
4583
4845
|
changelogValid: false,
|
|
4846
|
+
scanValid: true,
|
|
4847
|
+
guardValid: true,
|
|
4848
|
+
publishValid: true,
|
|
4584
4849
|
errors: [err.message]
|
|
4585
4850
|
};
|
|
4586
4851
|
}
|
|
@@ -4588,10 +4853,17 @@ function validate(config, cwd = process.cwd()) {
|
|
|
4588
4853
|
if (!versionResult.valid) errors.push(...versionResult.errors.map((error) => error.message));
|
|
4589
4854
|
const hardcoded = checkHardcodedVersions(version, config.sync, config.ignore, cwd);
|
|
4590
4855
|
if (hardcoded.length > 0) for (const mismatch of hardcoded) errors.push(`Version mismatch in ${mismatch.file}:${mismatch.line} - found "${mismatch.found}" but expected "${version}"`);
|
|
4591
|
-
if (
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4856
|
+
if (mode === "lightweight") return {
|
|
4857
|
+
valid: errors.length === 0,
|
|
4858
|
+
version,
|
|
4859
|
+
versionValid: versionResult.valid,
|
|
4860
|
+
syncValid: hardcoded.length === 0,
|
|
4861
|
+
changelogValid: true,
|
|
4862
|
+
scanValid: true,
|
|
4863
|
+
guardValid: true,
|
|
4864
|
+
publishValid: true,
|
|
4865
|
+
errors
|
|
4866
|
+
};
|
|
4595
4867
|
let changelogValid = true;
|
|
4596
4868
|
if (config.changelog.enabled) {
|
|
4597
4869
|
const changelogResult = validateChangelog(path.join(cwd, config.changelog.file), version, config.changelog.strict, config.changelog.requireEntry, {
|
|
@@ -4603,12 +4875,46 @@ function validate(config, cwd = process.cwd()) {
|
|
|
4603
4875
|
errors.push(...changelogResult.errors);
|
|
4604
4876
|
}
|
|
4605
4877
|
}
|
|
4878
|
+
let scanValid = true;
|
|
4879
|
+
if (config.scan?.enabled) {
|
|
4880
|
+
const scanFindings = scanRepoForVersions(version, config.scan, config.ignore, cwd);
|
|
4881
|
+
if (scanFindings.length > 0) {
|
|
4882
|
+
scanValid = false;
|
|
4883
|
+
for (const finding of scanFindings) errors.push(`Stale version in ${finding.file}:${finding.line} - found "${finding.found}" but expected "${version}"`);
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
let guardValid = true;
|
|
4887
|
+
let guardReport;
|
|
4888
|
+
if (config.guard?.enabled) {
|
|
4889
|
+
guardReport = runGuardChecks(config, cwd);
|
|
4890
|
+
if (!guardReport.safe) {
|
|
4891
|
+
guardValid = false;
|
|
4892
|
+
for (const warning of guardReport.warnings) if (warning.severity === "error") errors.push(`[${warning.code}] ${warning.message}`);
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
const publishValid = true;
|
|
4896
|
+
let publishCheck;
|
|
4897
|
+
if (config.publish?.enabled) {
|
|
4898
|
+
const manifestSource = config.manifest.source !== "auto" ? config.manifest.source : detectManifests(cwd)[0] ?? null;
|
|
4899
|
+
if (manifestSource) {
|
|
4900
|
+
const packageName = readPackageName(manifestSource, cwd);
|
|
4901
|
+
if (packageName) {
|
|
4902
|
+
publishCheck = await checkPublishStatus(manifestSource, packageName, version, config.publish);
|
|
4903
|
+
if (publishCheck.error) errors.push(`Publish check warning: ${publishCheck.error}`);
|
|
4904
|
+
}
|
|
4905
|
+
}
|
|
4906
|
+
}
|
|
4606
4907
|
return {
|
|
4607
4908
|
valid: errors.length === 0,
|
|
4608
4909
|
version,
|
|
4609
4910
|
versionValid: versionResult.valid,
|
|
4610
4911
|
syncValid: hardcoded.length === 0,
|
|
4611
4912
|
changelogValid,
|
|
4913
|
+
scanValid,
|
|
4914
|
+
guardValid,
|
|
4915
|
+
publishValid,
|
|
4916
|
+
publishCheck,
|
|
4917
|
+
guardReport,
|
|
4612
4918
|
errors
|
|
4613
4919
|
};
|
|
4614
4920
|
}
|
|
@@ -4631,8 +4937,8 @@ function validate(config, cwd = process.cwd()) {
|
|
|
4631
4937
|
* const report = doctor(getDefaultConfig(), process.cwd());
|
|
4632
4938
|
* ```
|
|
4633
4939
|
*/
|
|
4634
|
-
function doctor(config, cwd = process.cwd()) {
|
|
4635
|
-
const validation = validate(config, cwd);
|
|
4940
|
+
async function doctor(config, cwd = process.cwd()) {
|
|
4941
|
+
const validation = await validate(config, cwd);
|
|
4636
4942
|
const gitRepository = findGitDir(cwd) !== null;
|
|
4637
4943
|
const hooksInstalled = gitRepository ? areHooksInstalled(cwd) : false;
|
|
4638
4944
|
const worktreeClean = gitRepository ? isWorktreeClean(cwd) : true;
|
|
@@ -4646,6 +4952,9 @@ function doctor(config, cwd = process.cwd()) {
|
|
|
4646
4952
|
versionValid: validation.versionValid,
|
|
4647
4953
|
syncValid: validation.syncValid,
|
|
4648
4954
|
changelogValid: validation.changelogValid,
|
|
4955
|
+
scanValid: validation.scanValid,
|
|
4956
|
+
guardValid: validation.guardValid,
|
|
4957
|
+
publishValid: validation.publishValid,
|
|
4649
4958
|
gitRepository,
|
|
4650
4959
|
hooksInstalled,
|
|
4651
4960
|
worktreeClean,
|
|
@@ -4736,6 +5045,6 @@ function isWorktreeClean(cwd) {
|
|
|
4736
5045
|
}
|
|
4737
5046
|
}
|
|
4738
5047
|
//#endregion
|
|
4739
|
-
export {
|
|
5048
|
+
export { uninstallHooks as $, syncVersion as A, YamlVersionSource as B, getConfig as C, getSemVerConfig as D, getCalVerConfig as E, getPackageVersion as F, GitTagSource as G, TomlVersionSource as H, getVersionSource as I, checkHooksPathOverride as J, checkEnforceHooksPolicy as K, setPackageVersion as L, REGISTRY_TABLE as M, checkPublishStatus as N, checkHardcodedVersions as O, readPackageName as P, installHooks as Q, detectManifests as R, getVersionFeedback as S, createCkmEngine as T, RegexVersionSource as U, VersionFileSource as V, JsonVersionSource as W, runGuardChecks as X, checkHuskyBypass as Y, areHooksInstalled as Z, fixSyncIssues as _, validateVersion as a, isChangesetMangled as at, getSyncFeedback as b, getLatestTag as c, isValidCalVerFormat as ct, validateTagForPush as d, MANIFEST_TO_ECOSYSTEM as et, findProjectRoot as f, fixPackageVersion as g, fixChangelog as h, validate as i, fixChangesetMangling as it, semver_exports as j, scanRepoForVersions as k, handlePostTag as l, fixAll as m, doctor as n, generateDependabotConfig as nt, createTag as o, validateChangelog as ot, formatNotProjectError as p, checkHookIntegrity as q, sync as r, writeDependabotConfig as rt, getAllTags as s, calver_exports as st, canBump as t, dependabotConfigExists as tt, suggestTagMessage as u, suggestNextVersion as v, initConfig as w, getTagFeedback as x, getChangelogFeedback as y, resolveVersionSource as z };
|
|
4740
5049
|
|
|
4741
|
-
//# sourceMappingURL=src-
|
|
5050
|
+
//# sourceMappingURL=src-Bofo3tVH.js.map
|