@kb-labs/release-manager-core 2.118.2 → 2.119.0-canary.0c078654e
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/dist/index.d.ts +32 -3
- package/dist/index.js +32 -24
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -357,6 +357,14 @@ interface ChangelogGenerator {
|
|
|
357
357
|
repoRoot: string;
|
|
358
358
|
gitCwd: string;
|
|
359
359
|
config: ReleaseConfig;
|
|
360
|
+
/** Named flow whose release tag pattern bounds the changelog. */
|
|
361
|
+
flow?: string;
|
|
362
|
+
/** Explicit git boundaries; these take precedence over the flow baseline. */
|
|
363
|
+
range?: {
|
|
364
|
+
from?: string;
|
|
365
|
+
to?: string;
|
|
366
|
+
sinceTag?: string;
|
|
367
|
+
};
|
|
360
368
|
}): Promise<string>;
|
|
361
369
|
}
|
|
362
370
|
interface PipelineOptions {
|
|
@@ -744,12 +752,26 @@ declare function runReleaseChecks(checks: CustomCheckConfig[], options: CheckRun
|
|
|
744
752
|
declare function verifyPackages(packages: PackageVersion[], options?: {
|
|
745
753
|
logger?: Pick<PluginLogger, 'info'>;
|
|
746
754
|
onProgress?: (pkg: string, result: VerifyResult) => void;
|
|
755
|
+
packageManager?: 'pnpm' | 'npm' | 'yarn';
|
|
747
756
|
}): Promise<VerifyResult[]>;
|
|
748
757
|
/**
|
|
749
758
|
* Verify a single package is publishable.
|
|
750
|
-
*
|
|
751
|
-
|
|
752
|
-
|
|
759
|
+
* pack → extract → check exports, directory imports, test leaks, syntax.
|
|
760
|
+
*
|
|
761
|
+
* Packing tool must match what the real publish step will actually use:
|
|
762
|
+
* `pnpm pack` resolves `workspace:`/`link:` protocol refs to real version
|
|
763
|
+
* ranges natively (confirmed: `pnpm pack` on a package with
|
|
764
|
+
* `peerDependencies: { "@kb-labs/sdk": "workspace:^" }` produces a tarball
|
|
765
|
+
* with `"@kb-labs/sdk": "^2.115.4"`). `npm pack` does not — it packs the
|
|
766
|
+
* manifest byte-for-byte, so an unrewritten `workspace:*`/`link:` ref
|
|
767
|
+
* survives into the tarball and gets correctly flagged by
|
|
768
|
+
* findForbiddenDependencyProtocols() below. Defaulting to 'npm' here when
|
|
769
|
+
* the caller doesn't say otherwise is deliberately the strict reading (catch
|
|
770
|
+
* it even if we don't know yet what will actually publish); passing 'pnpm'
|
|
771
|
+
* for a pipeline that really does pack with pnpm avoids false positives on
|
|
772
|
+
* refs pnpm already resolves for free.
|
|
773
|
+
*/
|
|
774
|
+
declare function verifyPackage(packagePath: string, packageName?: string, packageManager?: 'pnpm' | 'npm' | 'yarn'): VerifyResult;
|
|
753
775
|
/**
|
|
754
776
|
* Run the static artifact checks (test-file leaks, exports existence,
|
|
755
777
|
* directory-import detection, syntax validation) against an already
|
|
@@ -798,6 +820,13 @@ interface VerifyAgainstRegistryOptions {
|
|
|
798
820
|
* Default: 0 (single attempt, matches pre-existing Verdaccio behavior).
|
|
799
821
|
*/
|
|
800
822
|
retries?: number;
|
|
823
|
+
/**
|
|
824
|
+
* Total time to wait for npm metadata and tarballs to propagate after a
|
|
825
|
+
* publish. When provided this supersedes the legacy fixed retry count, so
|
|
826
|
+
* an idempotent re-run resumes verification of already-published tarballs
|
|
827
|
+
* instead of requiring a new publish or a workflow-owned sleep.
|
|
828
|
+
*/
|
|
829
|
+
visibilityDeadlineMs?: number;
|
|
801
830
|
retryDelaysMs?: readonly number[];
|
|
802
831
|
logger?: Pick<PluginLogger, 'info' | 'warn'>;
|
|
803
832
|
}
|
package/dist/index.js
CHANGED
|
@@ -1287,13 +1287,13 @@ function evaluateParser(check, stdout, stderr, exitCode) {
|
|
|
1287
1287
|
async function verifyPackages(packages, options) {
|
|
1288
1288
|
const results = [];
|
|
1289
1289
|
for (const pkg of packages) {
|
|
1290
|
-
const result = verifyPackage(pkg.path, pkg.name);
|
|
1290
|
+
const result = verifyPackage(pkg.path, pkg.name, options?.packageManager);
|
|
1291
1291
|
results.push(result);
|
|
1292
1292
|
options?.onProgress?.(pkg.name, result);
|
|
1293
1293
|
}
|
|
1294
1294
|
return results;
|
|
1295
1295
|
}
|
|
1296
|
-
function verifyPackage(packagePath, packageName) {
|
|
1296
|
+
function verifyPackage(packagePath, packageName, packageManager = "npm") {
|
|
1297
1297
|
const pkgJsonPath = join(packagePath, "package.json");
|
|
1298
1298
|
if (!existsSync(pkgJsonPath)) {
|
|
1299
1299
|
return { name: packageName ?? packagePath, success: true, issues: [] };
|
|
@@ -1310,23 +1310,26 @@ function verifyPackage(packagePath, packageName) {
|
|
|
1310
1310
|
const tmpDir = join(tmpdir(), `kb-verify-${randomBytes(6).toString("hex")}`);
|
|
1311
1311
|
try {
|
|
1312
1312
|
mkdirSync(tmpDir, { recursive: true });
|
|
1313
|
+
const isPnpm = packageManager === "pnpm";
|
|
1313
1314
|
const origPkg = readFileSync(pkgJsonPath, "utf-8");
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
const
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1315
|
+
if (!isPnpm) {
|
|
1316
|
+
const modPkg = JSON.parse(origPkg);
|
|
1317
|
+
for (const section of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
1318
|
+
const deps = modPkg[section];
|
|
1319
|
+
if (!deps) {
|
|
1320
|
+
continue;
|
|
1321
|
+
}
|
|
1322
|
+
for (const [k, v] of Object.entries(deps)) {
|
|
1323
|
+
if (typeof v === "string" && v.startsWith("link:")) {
|
|
1324
|
+
deps[k] = "*";
|
|
1325
|
+
}
|
|
1323
1326
|
}
|
|
1324
1327
|
}
|
|
1328
|
+
writeFileSync(pkgJsonPath, JSON.stringify(modPkg, null, 2) + "\n");
|
|
1325
1329
|
}
|
|
1326
|
-
writeFileSync(pkgJsonPath, JSON.stringify(modPkg, null, 2) + "\n");
|
|
1327
1330
|
let tgzFile;
|
|
1328
1331
|
try {
|
|
1329
|
-
spawnSync("npm", ["pack", "--pack-destination", tmpDir], { cwd: packagePath, stdio: "pipe", timeout: 3e4 });
|
|
1332
|
+
spawnSync(isPnpm ? "pnpm" : "npm", ["pack", "--pack-destination", tmpDir], { cwd: packagePath, stdio: "pipe", timeout: 3e4 });
|
|
1330
1333
|
const files = readdirSync(tmpDir).filter((f) => f.endsWith(".tgz"));
|
|
1331
1334
|
tgzFile = files[0] ? join(tmpDir, files[0]) : void 0;
|
|
1332
1335
|
} finally {
|
|
@@ -1483,31 +1486,35 @@ async function verifyAgainstRegistry(packages, options) {
|
|
|
1483
1486
|
const { registry, timeout = DEFAULT_TIMEOUT_MS, retries = 0, retryDelaysMs = DEFAULT_POLL_RETRY_DELAYS_MS, logger } = options;
|
|
1484
1487
|
const results = [];
|
|
1485
1488
|
for (const pkg of packages) {
|
|
1486
|
-
results.push(await verifyOneAgainstRegistry(pkg, registry, timeout, retries, retryDelaysMs, logger));
|
|
1489
|
+
results.push(await verifyOneAgainstRegistry(pkg, registry, timeout, retries, retryDelaysMs, options.visibilityDeadlineMs, logger));
|
|
1487
1490
|
}
|
|
1488
1491
|
return results;
|
|
1489
1492
|
}
|
|
1490
|
-
async function waitUntilPublished(pkg, registry, retries, retryDelaysMs, logger) {
|
|
1491
|
-
|
|
1493
|
+
async function waitUntilPublished(pkg, registry, retries, retryDelaysMs, visibilityDeadlineMs, logger) {
|
|
1494
|
+
const deadline = visibilityDeadlineMs === void 0 ? void 0 : Date.now() + visibilityDeadlineMs;
|
|
1495
|
+
for (let attempt = 0; deadline === void 0 ? attempt <= retries : Date.now() <= deadline; attempt++) {
|
|
1492
1496
|
if (await isVersionPublished(pkg.name, pkg.version, registry)) {
|
|
1493
1497
|
return true;
|
|
1494
1498
|
}
|
|
1495
|
-
if (attempt < retries) {
|
|
1499
|
+
if (deadline === void 0 ? attempt < retries : Date.now() < deadline) {
|
|
1496
1500
|
const delay = retryDelaysMs[Math.min(attempt, retryDelaysMs.length - 1)];
|
|
1501
|
+
const remaining = deadline === void 0 ? void 0 : deadline - Date.now();
|
|
1502
|
+
const waitMs = remaining === void 0 ? delay : Math.min(delay, Math.max(0, remaining));
|
|
1497
1503
|
logger?.warn?.(
|
|
1498
|
-
`${pkg.name}@${pkg.version} not yet visible on ${registry} (attempt ${attempt + 1}
|
|
1504
|
+
`${pkg.name}@${pkg.version} not yet visible on ${registry} (attempt ${attempt + 1}${deadline === void 0 ? `/${retries + 1}` : ""}), retrying in ${(waitMs / 1e3).toFixed(0)}s${remaining === void 0 ? "" : `; ${(Math.max(0, remaining) / 1e3).toFixed(0)}s remain`} \u2014 likely registry propagation lag`
|
|
1499
1505
|
);
|
|
1500
1506
|
await new Promise((r) => {
|
|
1501
|
-
setTimeout(r,
|
|
1507
|
+
setTimeout(r, waitMs);
|
|
1502
1508
|
});
|
|
1503
1509
|
}
|
|
1504
1510
|
}
|
|
1505
1511
|
return false;
|
|
1506
1512
|
}
|
|
1507
|
-
async function verifyOneAgainstRegistry(pkg, registry, timeout, retries, retryDelaysMs, logger) {
|
|
1508
|
-
const published = await waitUntilPublished(pkg, registry, retries, retryDelaysMs, logger);
|
|
1513
|
+
async function verifyOneAgainstRegistry(pkg, registry, timeout, retries, retryDelaysMs, visibilityDeadlineMs, logger) {
|
|
1514
|
+
const published = await waitUntilPublished(pkg, registry, retries, retryDelaysMs, visibilityDeadlineMs, logger);
|
|
1509
1515
|
if (!published) {
|
|
1510
|
-
|
|
1516
|
+
const waited = visibilityDeadlineMs === void 0 ? `waited through ${retries} retr${retries === 1 ? "y" : "ies"}` : `visibility deadline of ${(visibilityDeadlineMs / 1e3).toFixed(0)}s elapsed`;
|
|
1517
|
+
return { name: pkg.name, success: false, issues: [`${pkg.name}@${pkg.version} was not found on ${registry} after publish (${waited})`] };
|
|
1511
1518
|
}
|
|
1512
1519
|
logger?.info?.(`${pkg.name}@${pkg.version} confirmed on ${registry}`);
|
|
1513
1520
|
const tmpDir = join(tmpdir(), `kb-verdaccio-verify-${randomBytes(6).toString("hex")}`);
|
|
@@ -1809,7 +1816,8 @@ async function _runPipeline(ctx) {
|
|
|
1809
1816
|
}
|
|
1810
1817
|
if (!skipVerify && !dryRun) {
|
|
1811
1818
|
progress("verifying", "Verifying package artifacts...");
|
|
1812
|
-
const
|
|
1819
|
+
const packageManager = config.workspace?.type ?? config.publish?.packageManager ?? "pnpm";
|
|
1820
|
+
const verifyResults = await verifyPackages(plan.packages, { logger, packageManager });
|
|
1813
1821
|
const verifyFailed = verifyResults.filter((r) => !r.success);
|
|
1814
1822
|
if (verifyFailed.length > 0) {
|
|
1815
1823
|
await restoreSnapshot(repoRoot);
|
|
@@ -1851,7 +1859,7 @@ async function _runPipeline(ctx) {
|
|
|
1851
1859
|
if (changelogGen && channel === "stable") {
|
|
1852
1860
|
progress("versioning", "Generating changelog...");
|
|
1853
1861
|
try {
|
|
1854
|
-
changelogMd = await changelogGen.generate(plan, { repoRoot, gitCwd: scopeCwd, config });
|
|
1862
|
+
changelogMd = await changelogGen.generate(plan, { repoRoot, gitCwd: scopeCwd, config, flow });
|
|
1855
1863
|
} catch (err) {
|
|
1856
1864
|
logger?.warn?.(`Changelog generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1857
1865
|
}
|