@@ -3,7 +3,15 @@ import { readFile } from 'node:fs/promises';
33import path from 'node:path' ;
44import test from 'node:test' ;
55import { fileURLToPath } from 'node:url' ;
6- import { inferDryRunWouldRelease } from '../release-local.mjs' ;
6+ import {
7+ buildSemanticReleaseArgs ,
8+ buildSemanticReleaseEnv ,
9+ detectPreviewTargetFromBranchName ,
10+ getRepositoryUrlCandidates ,
11+ inferPreviewTargetBranch ,
12+ inferDryRunWouldRelease ,
13+ splitPreviewArgs ,
14+ } from '../release-local.mjs' ;
715
816const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
917const REPO_ROOT = path . resolve ( __dirname , '../../' ) ;
@@ -31,6 +39,93 @@ test('inferDryRunWouldRelease detects pending release previews', () => {
3139 ) ;
3240} ) ;
3341
42+ test ( 'release-local helper does not inject semantic-release branch overrides' , ( ) => {
43+ assert . deepEqual (
44+ buildSemanticReleaseArgs ( {
45+ packageCwd : 'packages/superdoc' ,
46+ extraArgs : [ '--dry-run' ] ,
47+ } ) ,
48+ [
49+ '--prefix' ,
50+ 'packages/superdoc' ,
51+ 'exec' ,
52+ 'semantic-release' ,
53+ '--no-ci' ,
54+ '--dry-run' ,
55+ ] ,
56+ ) ;
57+ } ) ;
58+
59+ test ( 'release-local helper strips custom preview-branch flags before forwarding args' , ( ) => {
60+ assert . deepEqual (
61+ splitPreviewArgs ( [ '--dry-run' , '--preview-branch' , 'stable' , '--debug' ] ) ,
62+ {
63+ semanticReleaseArgs : [ '--dry-run' , '--debug' ] ,
64+ previewBranchOverride : 'stable' ,
65+ } ,
66+ ) ;
67+ } ) ;
68+
69+ test ( 'release-local helper supports equals-style preview branch overrides' , ( ) => {
70+ assert . deepEqual (
71+ splitPreviewArgs ( [ '--dry-run' , '--preview-branch=main' ] ) ,
72+ {
73+ semanticReleaseArgs : [ '--dry-run' ] ,
74+ previewBranchOverride : 'main' ,
75+ } ,
76+ ) ;
77+ } ) ;
78+
79+ test ( 'release-local helper marks dry runs as local preview mode' , ( ) => {
80+ const env = buildSemanticReleaseEnv ( {
81+ branch : 'stable' ,
82+ extraArgs : [ '--dry-run' ] ,
83+ baseEnv : { } ,
84+ } ) ;
85+
86+ assert . equal ( env . GITHUB_REF_NAME , 'stable' ) ;
87+ assert . equal ( env . SUPERDOC_RELEASE_PREVIEW , '1' ) ;
88+ assert . equal ( env . LEFTHOOK , '0' ) ;
89+ } ) ;
90+
91+ test ( 'release-local helper infers preview target from merge-branch names' , ( ) => {
92+ assert . equal (
93+ detectPreviewTargetFromBranchName ( 'merge/main-into-stable-2026-04-24' , [ 'stable' , 'main' ] ) ,
94+ 'stable' ,
95+ ) ;
96+ assert . equal (
97+ detectPreviewTargetFromBranchName ( 'hotfix/to-0.29.x-urgent' , [ 'stable' , 'main' , '0.29.x' ] ) ,
98+ '0.29.x' ,
99+ ) ;
100+ } ) ;
101+
102+ test ( 'release-local helper honors explicit preview-branch overrides' , ( ) => {
103+ assert . equal (
104+ inferPreviewTargetBranch ( {
105+ currentBranch : 'merge/main-into-stable-2026-04-24' ,
106+ releaseBranches : [ 'stable' , 'main' ] ,
107+ previewBranchOverride : 'main' ,
108+ } ) ,
109+ 'main' ,
110+ ) ;
111+ } ) ;
112+
113+ test ( 'release-local helper rewrites both ssh and https repository urls for previews' , ( ) => {
114+ const candidates = getRepositoryUrlCandidates ( 'packages/superdoc' ) ;
115+ assert . ok (
116+ candidates . includes ( 'git+https://github.com/superdoc-dev/superdoc.git' ) ,
117+ 'packages/superdoc/package.json repository url must be included' ,
118+ ) ;
119+ assert . ok (
120+ candidates . includes ( 'https://github.com/superdoc-dev/superdoc.git' ) ,
121+ 'git+https package repository urls must normalize to https for git rewrites' ,
122+ ) ;
123+ assert . ok (
124+ candidates . includes ( 'git@github.com:superdoc-dev/superdoc.git' ) ,
125+ 'origin ssh urls must also be rewritten for preview remotes' ,
126+ ) ;
127+ } ) ;
128+
34129test ( 'release-local helper prunes local-only tags across all release namespaces' , async ( ) => {
35130 const content = await readRepoFile ( 'scripts/release-local.mjs' ) ;
36131 assert . ok (
@@ -46,6 +141,34 @@ test('release-local helper prunes local-only tags across all release namespaces'
46141 content . includes ( "'v[0-9]*'" ) ,
47142 'scripts/release-local.mjs: superdoc tag matching must not also match vscode release tags' ,
48143 ) ;
144+ assert . ok (
145+ content . includes ( 'pruneLocalOnlyReleaseTags({ allowRemoteFailure: isDryRunEnabled(semanticReleaseArgs) })' ) ,
146+ 'scripts/release-local.mjs: dry-run previews must treat remote tag pruning as best-effort' ,
147+ ) ;
148+ } ) ;
149+
150+ test ( 'root release:dry-run script uses the local preview helper' , async ( ) => {
151+ const content = await readRepoFile ( 'package.json' ) ;
152+ assert . ok (
153+ content . includes ( '"release:dry-run": "pnpm run build:superdoc && pnpm run type-check && node scripts/release-local-superdoc.mjs --dry-run"' ) ,
154+ 'package.json: release:dry-run must delegate to the local preview helper' ,
155+ ) ;
156+ } ) ;
157+
158+ test ( 'superdoc releaserc uses preview mode to avoid AI notes and side-effect plugins' , async ( ) => {
159+ const content = await readRepoFile ( 'packages/superdoc/.releaserc.cjs' ) ;
160+ assert . ok (
161+ content . includes ( "const isLocalPreview = process.env.SUPERDOC_RELEASE_PREVIEW === '1'" ) ,
162+ 'packages/superdoc/.releaserc.cjs: must detect local preview mode' ,
163+ ) ;
164+ assert . ok (
165+ content . includes ( "const notesPlugin = isLocalPreview || isPrerelease" ) ,
166+ 'packages/superdoc/.releaserc.cjs: preview mode must fall back to conventional release notes' ,
167+ ) ;
168+ assert . ok (
169+ content . includes ( 'if (!isLocalPreview) {' ) ,
170+ 'packages/superdoc/.releaserc.cjs: preview mode must gate side-effect plugins' ,
171+ ) ;
49172} ) ;
50173
51174test ( 'stable orchestrator prunes before snapshot and reports would-release previews' , async ( ) => {
0 commit comments