@wipcomputer/wip-release 1.9.73 → 1.9.74
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/cli.js +4 -0
- package/core.mjs +122 -2
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -24,6 +24,7 @@ const skipWorktreeCheck = args.includes('--skip-worktree-check');
|
|
|
24
24
|
const skipTechDocsCheck = args.includes('--skip-tech-docs-check');
|
|
25
25
|
const skipCoverageCheck = args.includes('--skip-coverage-check');
|
|
26
26
|
const allowSubToolDrift = args.includes('--allow-sub-tool-drift');
|
|
27
|
+
const noDeployPublic = args.includes('--no-deploy-public');
|
|
27
28
|
const wantReleaseNotes = args.includes('--release-notes');
|
|
28
29
|
const noReleaseNotes = args.includes('--no-release-notes');
|
|
29
30
|
const notesFilePath = flag('notes-file');
|
|
@@ -174,6 +175,7 @@ Flags:
|
|
|
174
175
|
--skip-stale-check Skip stale remote branch check
|
|
175
176
|
--skip-worktree-check Skip main-branch + worktree guard (break-glass only)
|
|
176
177
|
--allow-sub-tool-drift Allow release even if a sub-tool's files changed since the last tag without a version bump (error by default)
|
|
178
|
+
--no-deploy-public Skip the deploy-public.sh step at the end of stable and prerelease flows (runs by default for -private repos)
|
|
177
179
|
|
|
178
180
|
Release notes (REQUIRED for stable, optional for other tracks):
|
|
179
181
|
1. --notes-file=path Explicit file path
|
|
@@ -224,6 +226,7 @@ if (level === 'alpha' || level === 'beta') {
|
|
|
224
226
|
publishReleaseNotes: level === 'alpha' ? wantReleaseNotes : !noReleaseNotes,
|
|
225
227
|
skipWorktreeCheck,
|
|
226
228
|
allowSubToolDrift,
|
|
229
|
+
noDeployPublic,
|
|
227
230
|
}).catch(err => {
|
|
228
231
|
console.error(` \u2717 ${err.message}`);
|
|
229
232
|
process.exit(1);
|
|
@@ -258,6 +261,7 @@ if (level === 'alpha' || level === 'beta') {
|
|
|
258
261
|
skipTechDocsCheck,
|
|
259
262
|
skipCoverageCheck,
|
|
260
263
|
allowSubToolDrift,
|
|
264
|
+
noDeployPublic,
|
|
261
265
|
}).catch(err => {
|
|
262
266
|
console.error(` \u2717 ${err.message}`);
|
|
263
267
|
process.exit(1);
|
package/core.mjs
CHANGED
|
@@ -1626,6 +1626,79 @@ function logPushFailure(result, tag) {
|
|
|
1626
1626
|
}
|
|
1627
1627
|
}
|
|
1628
1628
|
|
|
1629
|
+
/**
|
|
1630
|
+
* Resolve the public GitHub repo name for a private-to-public mirror setup.
|
|
1631
|
+
*
|
|
1632
|
+
* Strategy:
|
|
1633
|
+
* 1. Read `origin` remote URL (e.g. git@github.com:owner/repo-private.git)
|
|
1634
|
+
* 2. Strip `-private` suffix to get the public repo name
|
|
1635
|
+
* 3. Return `owner/repo` format suitable for gh CLI
|
|
1636
|
+
*
|
|
1637
|
+
* Returns null if the remote URL cannot be parsed or the repo name does not
|
|
1638
|
+
* end in `-private` (in which case the caller should skip deploy-public as a
|
|
1639
|
+
* no-op rather than error).
|
|
1640
|
+
*/
|
|
1641
|
+
function resolvePublicRepoName(repoPath) {
|
|
1642
|
+
try {
|
|
1643
|
+
const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], {
|
|
1644
|
+
cwd: repoPath, encoding: 'utf8'
|
|
1645
|
+
}).trim();
|
|
1646
|
+
// Match owner/repo from either SSH (git@github.com:owner/repo.git) or HTTPS
|
|
1647
|
+
const match = remoteUrl.match(/github\.com[:/]([^/]+)\/(.+?)(\.git)?$/);
|
|
1648
|
+
if (!match) return null;
|
|
1649
|
+
const [, owner, repoName] = match;
|
|
1650
|
+
if (!repoName.endsWith('-private')) {
|
|
1651
|
+
return null;
|
|
1652
|
+
}
|
|
1653
|
+
return `${owner}/${repoName.replace(/-private$/, '')}`;
|
|
1654
|
+
} catch {
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
/**
|
|
1660
|
+
* Run deploy-public.sh as the final step of the release pipeline.
|
|
1661
|
+
*
|
|
1662
|
+
* Previously deploy-public was a separate manual step. Every release that
|
|
1663
|
+
* forgot it left the public mirror stale, so `ldm install` pulled old code
|
|
1664
|
+
* from the public repo. Now wip-release invokes it automatically for stable
|
|
1665
|
+
* and prerelease tracks (hotfix still skips, per prior convention).
|
|
1666
|
+
*
|
|
1667
|
+
* Callable with `--no-deploy-public` to opt out.
|
|
1668
|
+
*
|
|
1669
|
+
* Skips silently if:
|
|
1670
|
+
* - The repo has no tools/deploy-public/deploy-public.sh (not a toolbox-
|
|
1671
|
+
* style repo, or deploy-public is provided by a parent install)
|
|
1672
|
+
* - The origin remote is not a -private repo (no public mirror to sync)
|
|
1673
|
+
*
|
|
1674
|
+
* Related: `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` Phase 6.
|
|
1675
|
+
*/
|
|
1676
|
+
function runDeployPublic(repoPath, { skip } = {}) {
|
|
1677
|
+
if (skip) {
|
|
1678
|
+
return { ok: true, skipped: true, reason: 'flag' };
|
|
1679
|
+
}
|
|
1680
|
+
const scriptPath = join(repoPath, 'tools', 'deploy-public', 'deploy-public.sh');
|
|
1681
|
+
if (!existsSync(scriptPath)) {
|
|
1682
|
+
return { ok: true, skipped: true, reason: 'no-script' };
|
|
1683
|
+
}
|
|
1684
|
+
const publicRepo = resolvePublicRepoName(repoPath);
|
|
1685
|
+
if (!publicRepo) {
|
|
1686
|
+
return { ok: true, skipped: true, reason: 'not-private-repo' };
|
|
1687
|
+
}
|
|
1688
|
+
try {
|
|
1689
|
+
execFileSync('bash', [scriptPath, repoPath, publicRepo], {
|
|
1690
|
+
cwd: repoPath, stdio: 'inherit',
|
|
1691
|
+
});
|
|
1692
|
+
return { ok: true, publicRepo };
|
|
1693
|
+
} catch (err) {
|
|
1694
|
+
return {
|
|
1695
|
+
ok: false,
|
|
1696
|
+
detail: String(err?.stderr ?? err?.message ?? err),
|
|
1697
|
+
publicRepo,
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1629
1702
|
function logMainBranchGuardFailure(result) {
|
|
1630
1703
|
if (result.reason === 'linked-worktree') {
|
|
1631
1704
|
console.log(` \u2717 wip-release must run from the main working tree, not a worktree.`);
|
|
@@ -1645,7 +1718,7 @@ function logMainBranchGuardFailure(result) {
|
|
|
1645
1718
|
/**
|
|
1646
1719
|
* Run the full release pipeline.
|
|
1647
1720
|
*/
|
|
1648
|
-
export async function release({ repoPath, level, notes, notesSource, dryRun, noPublish, skipProductCheck, skipStaleCheck, skipWorktreeCheck, skipTechDocsCheck, skipCoverageCheck, allowSubToolDrift }) {
|
|
1721
|
+
export async function release({ repoPath, level, notes, notesSource, dryRun, noPublish, skipProductCheck, skipStaleCheck, skipWorktreeCheck, skipTechDocsCheck, skipCoverageCheck, allowSubToolDrift, noDeployPublic }) {
|
|
1649
1722
|
repoPath = repoPath || process.cwd();
|
|
1650
1723
|
const currentVersion = detectCurrentVersion(repoPath);
|
|
1651
1724
|
const newVersion = bumpSemver(currentVersion, level);
|
|
@@ -2288,6 +2361,29 @@ export async function release({ repoPath, level, notes, notesSource, dryRun, noP
|
|
|
2288
2361
|
}) + '\n');
|
|
2289
2362
|
} catch {}
|
|
2290
2363
|
|
|
2364
|
+
// 12. deploy-public: sync private -> public mirror (Phase 6)
|
|
2365
|
+
// Runs at the end of every stable release unless --no-deploy-public is set
|
|
2366
|
+
// or the repo has no deploy-public.sh script. Skips silently for non-
|
|
2367
|
+
// -private repos (no public mirror to sync).
|
|
2368
|
+
{
|
|
2369
|
+
const dp = runDeployPublic(repoPath, { skip: noDeployPublic });
|
|
2370
|
+
if (dp.skipped) {
|
|
2371
|
+
if (dp.reason === 'flag') {
|
|
2372
|
+
console.log(` - deploy-public: skipped (--no-deploy-public)`);
|
|
2373
|
+
} else if (dp.reason === 'no-script') {
|
|
2374
|
+
console.log(` - deploy-public: skipped (no tools/deploy-public/deploy-public.sh)`);
|
|
2375
|
+
} else if (dp.reason === 'not-private-repo') {
|
|
2376
|
+
console.log(` - deploy-public: skipped (origin is not a -private repo)`);
|
|
2377
|
+
}
|
|
2378
|
+
} else if (dp.ok) {
|
|
2379
|
+
console.log(` \u2713 deploy-public: synced to ${dp.publicRepo}`);
|
|
2380
|
+
} else {
|
|
2381
|
+
console.log(` \u2717 deploy-public failed for ${dp.publicRepo}`);
|
|
2382
|
+
if (dp.detail) console.log(` ${dp.detail.split('\n')[0]}`);
|
|
2383
|
+
console.log(` Manual recovery: bash tools/deploy-public/deploy-public.sh ${repoPath} ${dp.publicRepo}`);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2291
2387
|
console.log('');
|
|
2292
2388
|
console.log(` Done. ${repoName} v${newVersion} released.`);
|
|
2293
2389
|
console.log('');
|
|
@@ -2306,7 +2402,7 @@ export async function release({ repoPath, level, notes, notesSource, dryRun, noP
|
|
|
2306
2402
|
* No deploy-public. No code sync. No CHANGELOG gate. No product docs gate.
|
|
2307
2403
|
* Lightweight: bump version, npm publish with tag, optional GitHub prerelease.
|
|
2308
2404
|
*/
|
|
2309
|
-
export async function releasePrerelease({ repoPath, track, notes, dryRun, noPublish, publishReleaseNotes, skipWorktreeCheck, allowSubToolDrift }) {
|
|
2405
|
+
export async function releasePrerelease({ repoPath, track, notes, dryRun, noPublish, publishReleaseNotes, skipWorktreeCheck, allowSubToolDrift, noDeployPublic }) {
|
|
2310
2406
|
repoPath = repoPath || process.cwd();
|
|
2311
2407
|
const currentVersion = detectCurrentVersion(repoPath);
|
|
2312
2408
|
const newVersion = bumpPrerelease(currentVersion, track);
|
|
@@ -2430,6 +2526,30 @@ export async function releasePrerelease({ repoPath, track, notes, dryRun, noPubl
|
|
|
2430
2526
|
}
|
|
2431
2527
|
}
|
|
2432
2528
|
|
|
2529
|
+
// deploy-public: sync private -> public mirror (Phase 6)
|
|
2530
|
+
// Prerelease tracks (alpha/beta) also run deploy-public so the public
|
|
2531
|
+
// mirror stays current. Flagged in the bridge master plan and the
|
|
2532
|
+
// release-pipeline master plan: forgetting deploy-public left the public
|
|
2533
|
+
// repo stale across multiple days of alpha releases.
|
|
2534
|
+
{
|
|
2535
|
+
const dp = runDeployPublic(repoPath, { skip: noDeployPublic });
|
|
2536
|
+
if (dp.skipped) {
|
|
2537
|
+
if (dp.reason === 'flag') {
|
|
2538
|
+
console.log(` - deploy-public: skipped (--no-deploy-public)`);
|
|
2539
|
+
} else if (dp.reason === 'no-script') {
|
|
2540
|
+
console.log(` - deploy-public: skipped (no deploy-public.sh)`);
|
|
2541
|
+
} else if (dp.reason === 'not-private-repo') {
|
|
2542
|
+
console.log(` - deploy-public: skipped (origin is not a -private repo)`);
|
|
2543
|
+
}
|
|
2544
|
+
} else if (dp.ok) {
|
|
2545
|
+
console.log(` \u2713 deploy-public: synced to ${dp.publicRepo}`);
|
|
2546
|
+
} else {
|
|
2547
|
+
console.log(` \u2717 deploy-public failed for ${dp.publicRepo}`);
|
|
2548
|
+
if (dp.detail) console.log(` ${dp.detail.split('\n')[0]}`);
|
|
2549
|
+
console.log(` Manual recovery: bash tools/deploy-public/deploy-public.sh ${repoPath} ${dp.publicRepo}`);
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2433
2553
|
console.log('');
|
|
2434
2554
|
console.log(` Done. ${repoName} v${newVersion} (${track}) released.`);
|
|
2435
2555
|
console.log('');
|
package/package.json
CHANGED