infra-kit 0.1.108 → 0.1.110
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/.eslintcache +1 -1
- package/.omc/state/sessions/3a844fbd-ace8-4af1-8516-33d611839886/pre-tool-advisory-throttle.json +18 -0
- package/.turbo/turbo-build.log +6 -7
- package/.turbo/turbo-eslint-check.log +1 -2
- package/.turbo/turbo-prettier-check.log +1 -2
- package/.turbo/turbo-test.log +70 -72
- package/.turbo/turbo-ts-check.log +1 -2
- package/dist/cli.js +50 -50
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +37 -37
- package/dist/mcp.js.map +4 -4
- package/package.json +1 -1
- package/src/commands/gh-merge-dev/gh-merge-dev.ts +3 -0
- package/src/commands/gh-release-deliver/gh-release-deliver.ts +5 -0
- package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +2 -2
- package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +1 -1
- package/src/commands/release-create/__tests__/release-create.test.ts +38 -1
- package/src/commands/release-create/release-create.ts +36 -4
- package/src/commands/release-desc-edit/release-desc-edit.ts +2 -2
- package/src/commands/worktrees-add/worktrees-add.ts +3 -0
- package/src/commands/worktrees-open/__tests__/open-cmux.test.ts +2 -2
- package/src/commands/worktrees-remove/worktrees-remove.ts +3 -0
- package/src/commands/worktrees-sync/worktrees-sync.ts +3 -0
- package/src/integrations/cmux/__tests__/canonicalize-cmux-title.test.ts +1 -1
- package/src/integrations/cmux/workspace-title.ts +1 -1
- package/src/integrations/gh/gh-release-prs/__tests__/gh-release-prs.test.ts +10 -10
- package/src/integrations/gh/gh-release-prs/gh-release-prs.ts +1 -1
- package/src/lib/git-guard/__tests__/git-guard.test.ts +92 -0
- package/src/lib/git-guard/git-guard.ts +55 -0
- package/src/lib/git-guard/index.ts +2 -0
- package/src/lib/git-utils/__tests__/git-primitives.test.ts +96 -0
- package/src/lib/git-utils/__tests__/git-utils.test.ts +4 -4
- package/src/lib/git-utils/git-utils.ts +41 -0
- package/src/lib/git-utils/index.ts +8 -1
- package/src/lib/release-id/__tests__/release-id.test.ts +27 -19
- package/src/lib/release-id/release-id.ts +19 -18
- package/src/lib/release-utils/__tests__/release-utils.test.ts +8 -8
- package/src/lib/release-utils/release-utils.ts +1 -1
- package/src/lib/version-utils/__tests__/load-existing-versions.test.ts +4 -4
- package/src/lib/version-utils/__tests__/next-version.test.ts +1 -1
- package/src/lib/version-utils/load-existing-versions.ts +1 -1
- package/src/lib/version-utils/version-utils.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -23,8 +23,8 @@ describe('getCurrentWorktrees', () => {
|
|
|
23
23
|
worktreeList.stdout = [
|
|
24
24
|
asWorktreeLine('main'),
|
|
25
25
|
asWorktreeLine('release/v1.18.22'),
|
|
26
|
-
asWorktreeLine('release/
|
|
27
|
-
asWorktreeLine('release/
|
|
26
|
+
asWorktreeLine('release/checkout-redesign'),
|
|
27
|
+
asWorktreeLine('release/Bad_Name'),
|
|
28
28
|
asWorktreeLine('feature/login-page'),
|
|
29
29
|
'/repos/project abc1234 (bare)',
|
|
30
30
|
'',
|
|
@@ -32,13 +32,13 @@ describe('getCurrentWorktrees', () => {
|
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
it('returns versioned AND named release worktrees for type release', async () => {
|
|
35
|
-
await expect(getCurrentWorktrees('release')).resolves.toEqual(['release/v1.18.22', 'release/
|
|
35
|
+
await expect(getCurrentWorktrees('release')).resolves.toEqual(['release/v1.18.22', 'release/checkout-redesign'])
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
it('excludes junk release branches and non-release branches', async () => {
|
|
39
39
|
const branches = await getCurrentWorktrees('release')
|
|
40
40
|
|
|
41
|
-
expect(branches).not.toContain('release/
|
|
41
|
+
expect(branches).not.toContain('release/Bad_Name')
|
|
42
42
|
expect(branches).not.toContain('feature/login-page')
|
|
43
43
|
expect(branches).not.toContain('main')
|
|
44
44
|
})
|
|
@@ -93,6 +93,47 @@ export const getProjectRoot = async (): Promise<string> => {
|
|
|
93
93
|
return result.stdout.trim()
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Get the current git branch name (e.g. `dev`, `main`, `release/v1.2.3`).
|
|
98
|
+
*/
|
|
99
|
+
export const getCurrentBranch = async (): Promise<string> => {
|
|
100
|
+
const result = await $`git rev-parse --abbrev-ref HEAD`
|
|
101
|
+
|
|
102
|
+
return result.stdout.trim()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Whether the working tree has no staged, unstaged, or untracked changes.
|
|
107
|
+
*/
|
|
108
|
+
export const isWorkingTreeClean = async (): Promise<boolean> => {
|
|
109
|
+
const result = await $`git status --porcelain`
|
|
110
|
+
|
|
111
|
+
return result.stdout.trim().length === 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether the current checkout is a linked git worktree rather than the main
|
|
116
|
+
* repository checkout.
|
|
117
|
+
*
|
|
118
|
+
* A linked worktree's git dir lives under `<main>/.git/worktrees/<name>`, so it
|
|
119
|
+
* differs from the shared common dir; in the main checkout the two resolve to
|
|
120
|
+
* the same path. Both are anchored to the toplevel so `--git-common-dir` (which
|
|
121
|
+
* git may report relative to cwd) resolves consistently.
|
|
122
|
+
*/
|
|
123
|
+
export const isInsideLinkedWorktree = async (): Promise<boolean> => {
|
|
124
|
+
const cwd = await getProjectRoot()
|
|
125
|
+
|
|
126
|
+
const [gitDirResult, commonDirResult] = await Promise.all([
|
|
127
|
+
$({ cwd })`git rev-parse --absolute-git-dir`,
|
|
128
|
+
$({ cwd })`git rev-parse --git-common-dir`,
|
|
129
|
+
])
|
|
130
|
+
|
|
131
|
+
const gitDir = gitDirResult.stdout.trim()
|
|
132
|
+
const commonDir = path.resolve(cwd, commonDirResult.stdout.trim())
|
|
133
|
+
|
|
134
|
+
return gitDir !== commonDir
|
|
135
|
+
}
|
|
136
|
+
|
|
96
137
|
/**
|
|
97
138
|
* Get the current repository name (basename of the project root)
|
|
98
139
|
*/
|
|
@@ -29,13 +29,13 @@ describe('parseBranchName', () => {
|
|
|
29
29
|
expect(parseBranchName('release/v1.2.3')).toEqual(version(1, 2, 3))
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
it('parses release
|
|
33
|
-
expect(parseBranchName('release/
|
|
32
|
+
it('parses release/<name> as a name', () => {
|
|
33
|
+
expect(parseBranchName('release/checkout-redesign')).toEqual(name('checkout-redesign'))
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
it('strips a leading refs/heads/ prefix for versions and names', () => {
|
|
37
37
|
expect(parseBranchName('refs/heads/release/v2.0.1')).toEqual(version(2, 0, 1))
|
|
38
|
-
expect(parseBranchName('refs/heads/release/
|
|
38
|
+
expect(parseBranchName('refs/heads/release/my-feature')).toEqual(name('my-feature'))
|
|
39
39
|
})
|
|
40
40
|
|
|
41
41
|
it('trims surrounding whitespace', () => {
|
|
@@ -48,23 +48,31 @@ describe('parseBranchName', () => {
|
|
|
48
48
|
expect(parseBranchName('dev')).toBeNull()
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
it('
|
|
52
|
-
expect(parseBranchName('release/foo')).
|
|
53
|
-
expect(parseBranchName('release/garbage')).
|
|
51
|
+
it('parses bare release/<kebab> as a name', () => {
|
|
52
|
+
expect(parseBranchName('release/foo')).toEqual(name('foo'))
|
|
53
|
+
expect(parseBranchName('release/garbage')).toEqual(name('garbage'))
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
it('returns null for
|
|
56
|
+
it('returns null for malformed version branches that are also not valid names', () => {
|
|
57
57
|
expect(parseBranchName('release/v1.2')).toBeNull()
|
|
58
|
-
expect(parseBranchName('release/v1')).toBeNull()
|
|
59
58
|
expect(parseBranchName('release/v1.2.3.4')).toBeNull()
|
|
60
|
-
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('falls through to a name when the release/v segment is not valid semver', () => {
|
|
62
|
+
expect(parseBranchName('release/v1.2.3')).toEqual(version(1, 2, 3))
|
|
63
|
+
expect(parseBranchName('release/v1')).toEqual(name('v1'))
|
|
64
|
+
expect(parseBranchName('release/vfoo')).toEqual(name('vfoo'))
|
|
65
|
+
expect(parseBranchName('release/vnext')).toEqual(name('vnext'))
|
|
61
66
|
})
|
|
62
67
|
|
|
63
68
|
it('returns null for invalid names', () => {
|
|
64
|
-
expect(parseBranchName('release/
|
|
65
|
-
expect(parseBranchName('release/
|
|
66
|
-
expect(parseBranchName('release/
|
|
67
|
-
expect(parseBranchName('release/
|
|
69
|
+
expect(parseBranchName('release/Bad_Name')).toBeNull()
|
|
70
|
+
expect(parseBranchName('release/UPPER')).toBeNull()
|
|
71
|
+
expect(parseBranchName('release/main')).toBeNull()
|
|
72
|
+
expect(parseBranchName('release/')).toBeNull()
|
|
73
|
+
// The retired release/n/<name> form is no longer valid: 'n/checkout-redesign'
|
|
74
|
+
// contains a slash and fails the kebab-case rule.
|
|
75
|
+
expect(parseBranchName('release/n/checkout-redesign')).toBeNull()
|
|
68
76
|
})
|
|
69
77
|
|
|
70
78
|
it('never throws on arbitrary input', () => {
|
|
@@ -81,19 +89,19 @@ describe('parseBranchName', () => {
|
|
|
81
89
|
describe('parseReleaseRef', () => {
|
|
82
90
|
it('delegates a release branch ref to parseBranchName', () => {
|
|
83
91
|
expect(parseReleaseRef('release/v1.2.3')).toEqual(version(1, 2, 3))
|
|
84
|
-
expect(parseReleaseRef('release/
|
|
92
|
+
expect(parseReleaseRef('release/checkout-redesign')).toEqual(name('checkout-redesign'))
|
|
85
93
|
expect(parseReleaseRef('refs/heads/release/v3.4.5')).toEqual(version(3, 4, 5))
|
|
86
94
|
})
|
|
87
95
|
|
|
88
96
|
it('throws when a release branch ref is invalid', () => {
|
|
89
97
|
expect(() => {
|
|
90
|
-
return parseReleaseRef('release/
|
|
98
|
+
return parseReleaseRef('release/Bad_Name')
|
|
91
99
|
}).toThrow(InvalidReleaseRefError)
|
|
92
100
|
expect(() => {
|
|
93
101
|
return parseReleaseRef('release/v1.2')
|
|
94
102
|
}).toThrow(InvalidReleaseRefError)
|
|
95
103
|
expect(() => {
|
|
96
|
-
return parseReleaseRef('release/
|
|
104
|
+
return parseReleaseRef('release/main')
|
|
97
105
|
}).toThrow(InvalidReleaseRefError)
|
|
98
106
|
})
|
|
99
107
|
|
|
@@ -204,7 +212,7 @@ describe('validateName', () => {
|
|
|
204
212
|
describe('formatBranchName', () => {
|
|
205
213
|
it('formats versions and names', () => {
|
|
206
214
|
expect(formatBranchName(version(1, 2, 3))).toBe('release/v1.2.3')
|
|
207
|
-
expect(formatBranchName(name('checkout-redesign'))).toBe('release/
|
|
215
|
+
expect(formatBranchName(name('checkout-redesign'))).toBe('release/checkout-redesign')
|
|
208
216
|
})
|
|
209
217
|
})
|
|
210
218
|
|
|
@@ -244,13 +252,13 @@ describe('displayLabel', () => {
|
|
|
244
252
|
describe('isReleaseBranch', () => {
|
|
245
253
|
it('returns true for both branch schemes', () => {
|
|
246
254
|
expect(isReleaseBranch('release/v1.2.3')).toBe(true)
|
|
247
|
-
expect(isReleaseBranch('release/
|
|
255
|
+
expect(isReleaseBranch('release/checkout-redesign')).toBe(true)
|
|
248
256
|
expect(isReleaseBranch('refs/heads/release/v1.2.3')).toBe(true)
|
|
249
257
|
})
|
|
250
258
|
|
|
251
259
|
it('returns false for junk', () => {
|
|
252
260
|
expect(isReleaseBranch('feature/x')).toBe(false)
|
|
253
|
-
expect(isReleaseBranch('release/
|
|
261
|
+
expect(isReleaseBranch('release/Bad_Name')).toBe(false)
|
|
254
262
|
expect(isReleaseBranch('main')).toBe(false)
|
|
255
263
|
})
|
|
256
264
|
|
|
@@ -18,7 +18,6 @@ const KEBAB_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
|
|
|
18
18
|
|
|
19
19
|
const RELEASE_BRANCH_PREFIX = 'release/'
|
|
20
20
|
const VERSION_BRANCH_PREFIX = 'release/v'
|
|
21
|
-
const NAME_BRANCH_PREFIX = 'release/n/'
|
|
22
21
|
const REFS_HEADS_PREFIX = 'refs/heads/'
|
|
23
22
|
|
|
24
23
|
const NEXT_TOKEN = 'next'
|
|
@@ -91,33 +90,35 @@ export const validateName = (name: string): void => {
|
|
|
91
90
|
/**
|
|
92
91
|
* Lenient parse of a git branch name into a {@link ReleaseId}. Tolerates a
|
|
93
92
|
* leading `refs/heads/`. Returns `null` for anything that is not a valid
|
|
94
|
-
* `release/v<semver>` or `release
|
|
93
|
+
* `release/v<semver>` or `release/<name>` branch. Never throws.
|
|
94
|
+
*
|
|
95
|
+
* Precedence is version-first: `release/v<semver>` is a version, but if the
|
|
96
|
+
* segment after `release/v` is not a valid semver (e.g. `release/vnext`), the
|
|
97
|
+
* whole token after `release/` is treated as a candidate name instead.
|
|
95
98
|
*/
|
|
96
99
|
export const parseBranchName = (branch: string): ReleaseId | null => {
|
|
97
100
|
const stripped = stripRefsHeads(branch.trim())
|
|
98
101
|
|
|
102
|
+
if (!stripped.startsWith(RELEASE_BRANCH_PREFIX)) return null
|
|
103
|
+
|
|
99
104
|
if (stripped.startsWith(VERSION_BRANCH_PREFIX)) {
|
|
100
105
|
const semverPart = stripped.slice(VERSION_BRANCH_PREFIX.length)
|
|
101
106
|
const match = BRANCH_SEMVER_RE.exec(semverPart)
|
|
102
107
|
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
108
|
+
if (match) {
|
|
109
|
+
return makeVersion(Number(match[1]), Number(match[2]), Number(match[3]))
|
|
110
|
+
}
|
|
106
111
|
}
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
const namePart = stripped.slice(NAME_BRANCH_PREFIX.length)
|
|
113
|
+
const namePart = stripped.slice(RELEASE_BRANCH_PREFIX.length)
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return { kind: 'name', name: namePart, raw: namePart }
|
|
115
|
+
try {
|
|
116
|
+
validateName(namePart)
|
|
117
|
+
} catch {
|
|
118
|
+
return null
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
return
|
|
121
|
+
return { kind: 'name', name: namePart, raw: namePart }
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
/**
|
|
@@ -138,7 +139,7 @@ export const parseReleaseRef = (input: string): ReleaseId => {
|
|
|
138
139
|
|
|
139
140
|
if (!parsed) {
|
|
140
141
|
throw new InvalidReleaseRefError(
|
|
141
|
-
`"${input}" looks like a release branch but is not a valid release/v<semver> or release
|
|
142
|
+
`"${input}" looks like a release branch but is not a valid release/v<semver> or release/<name> ref.`,
|
|
142
143
|
)
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -168,11 +169,11 @@ export const parseReleaseRef = (input: string): ReleaseId => {
|
|
|
168
169
|
return { kind: 'name', name: trimmed, raw: trimmed }
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
/** Render the branch name for a release id: `release/v1.2.3` | `release
|
|
172
|
+
/** Render the branch name for a release id: `release/v1.2.3` | `release/<name>`. */
|
|
172
173
|
export const formatBranchName = (id: ReleaseId): string => {
|
|
173
174
|
if (id.kind === 'version') return `${VERSION_BRANCH_PREFIX}${id.raw}`
|
|
174
175
|
|
|
175
|
-
return `${
|
|
176
|
+
return `${RELEASE_BRANCH_PREFIX}${id.name}`
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
/**
|
|
@@ -14,7 +14,7 @@ describe('parseBranchChoices', () => {
|
|
|
14
14
|
it('parses version and name branches and drops junk', () => {
|
|
15
15
|
const result = parseBranchChoices([
|
|
16
16
|
'release/v1.2.3',
|
|
17
|
-
'release/
|
|
17
|
+
'release/checkout-redesign',
|
|
18
18
|
'feature/not-a-release',
|
|
19
19
|
'release/v9.9', // malformed semver
|
|
20
20
|
])
|
|
@@ -31,7 +31,7 @@ describe('parseBranchChoices', () => {
|
|
|
31
31
|
|
|
32
32
|
expect(labels).toEqual(['1.2.3', 'checkout-redesign'])
|
|
33
33
|
expect(kinds).toEqual(['version', 'name'])
|
|
34
|
-
expect(branches).toEqual(['release/v1.2.3', 'release/
|
|
34
|
+
expect(branches).toEqual(['release/v1.2.3', 'release/checkout-redesign'])
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
it('returns an empty array when nothing parses', () => {
|
|
@@ -42,7 +42,7 @@ describe('parseBranchChoices', () => {
|
|
|
42
42
|
describe('formatBranchChoices', () => {
|
|
43
43
|
it('labels versions and names, keying Jira descriptions by the Jira version name', () => {
|
|
44
44
|
const choices = formatBranchChoices({
|
|
45
|
-
branches: ['release/v1.2.3', 'release/
|
|
45
|
+
branches: ['release/v1.2.3', 'release/checkout-redesign'],
|
|
46
46
|
// Jira descriptions are keyed by the Jira version NAME: `v1.2.3` | `<name>`.
|
|
47
47
|
descriptions: new Map([
|
|
48
48
|
['v1.2.3', 'version desc'],
|
|
@@ -54,16 +54,16 @@ describe('formatBranchChoices', () => {
|
|
|
54
54
|
expect(choices[0]?.value).toBe('release/v1.2.3')
|
|
55
55
|
expect(choices[0]?.name).toContain('1.2.3')
|
|
56
56
|
expect(choices[0]?.name).toContain('version desc')
|
|
57
|
-
expect(choices[1]?.value).toBe('release/
|
|
57
|
+
expect(choices[1]?.value).toBe('release/checkout-redesign')
|
|
58
58
|
expect(choices[1]?.name).toContain('checkout-redesign')
|
|
59
59
|
expect(choices[1]?.name).toContain('name desc')
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
it('includes the type tag when types are provided', () => {
|
|
63
63
|
const choices = formatBranchChoices({
|
|
64
|
-
branches: ['release/
|
|
64
|
+
branches: ['release/checkout-redesign'],
|
|
65
65
|
descriptions: new Map(),
|
|
66
|
-
types: new Map([['release/
|
|
66
|
+
types: new Map([['release/checkout-redesign', 'hotfix']]),
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
expect(choices[0]?.name).toContain('[hotfix]')
|
|
@@ -90,7 +90,7 @@ describe('resolveReleaseBranch', () => {
|
|
|
90
90
|
})
|
|
91
91
|
|
|
92
92
|
it('builds a name branch from a release name', () => {
|
|
93
|
-
expect(resolveReleaseBranch('checkout-redesign')).toBe('release/
|
|
93
|
+
expect(resolveReleaseBranch('checkout-redesign')).toBe('release/checkout-redesign')
|
|
94
94
|
})
|
|
95
95
|
|
|
96
96
|
it('throws an OperationError for junk input', () => {
|
|
@@ -113,7 +113,7 @@ describe('releaseLabelFromBranch', () => {
|
|
|
113
113
|
|
|
114
114
|
it('labels version and name branches', () => {
|
|
115
115
|
expect(releaseLabelFromBranch('release/v1.2.3')).toBe('1.2.3')
|
|
116
|
-
expect(releaseLabelFromBranch('release/
|
|
116
|
+
expect(releaseLabelFromBranch('release/checkout-redesign')).toBe('checkout-redesign')
|
|
117
117
|
})
|
|
118
118
|
|
|
119
119
|
it('falls back to the raw branch when it does not parse', () => {
|
|
@@ -160,7 +160,7 @@ export const parseBranchChoices = (branches: string[]): ParsedBranchChoice[] =>
|
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
162
|
* Resolve an operator-supplied release ref (version `1.2.3` / `v1.2.3` or name
|
|
163
|
-
* `checkout-redesign`) to its branch name (`release/v1.2.3` | `release
|
|
163
|
+
* `checkout-redesign`) to its branch name (`release/v1.2.3` | `release/<name>`).
|
|
164
164
|
* Strict: surfaces a parse failure as an OperationError with remediation text.
|
|
165
165
|
*/
|
|
166
166
|
export const resolveReleaseBranch = (versionArg: string): string => {
|
|
@@ -13,11 +13,11 @@ describe('extractVersionBranches', () => {
|
|
|
13
13
|
expect(extractVersionBranches(stdout)).toEqual(['1.62.0', '1.64.5'])
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
it('ignores named release
|
|
16
|
+
it('ignores named release/<name> branches (irrelevant to next-bump math)', () => {
|
|
17
17
|
const stdout = [
|
|
18
18
|
lsRemoteLine('release/v1.0.0'),
|
|
19
|
-
lsRemoteLine('release/
|
|
20
|
-
lsRemoteLine('release/
|
|
19
|
+
lsRemoteLine('release/checkout-redesign'),
|
|
20
|
+
lsRemoteLine('release/zeta-feature'),
|
|
21
21
|
].join('\n')
|
|
22
22
|
|
|
23
23
|
expect(extractVersionBranches(stdout)).toEqual(['1.0.0'])
|
|
@@ -25,7 +25,7 @@ describe('extractVersionBranches', () => {
|
|
|
25
25
|
|
|
26
26
|
it('ignores junk and non-release lines without throwing', () => {
|
|
27
27
|
const stdout = [
|
|
28
|
-
lsRemoteLine('release/
|
|
28
|
+
lsRemoteLine('release/Bad_Name'),
|
|
29
29
|
lsRemoteLine('release/v2.3.4'),
|
|
30
30
|
'malformed-line-without-tab',
|
|
31
31
|
lsRemoteLine('feature/login'),
|
|
@@ -295,7 +295,7 @@ describe('resolveReleaseEntries', () => {
|
|
|
295
295
|
it('named entry produces the named branch/PR/Jira output', () => {
|
|
296
296
|
const { id } = resolve({ name: 'checkout-redesign', type: 'regular' })
|
|
297
297
|
|
|
298
|
-
expect(formatBranchName(id)).toBe('release/
|
|
298
|
+
expect(formatBranchName(id)).toBe('release/checkout-redesign')
|
|
299
299
|
expect(formatPrTitle(id, 'regular')).toBe('Release checkout-redesign')
|
|
300
300
|
expect(formatJiraName(id)).toBe('checkout-redesign')
|
|
301
301
|
})
|
|
@@ -11,7 +11,7 @@ import type { SemVer } from './next-version'
|
|
|
11
11
|
* Extract version-branch tokens from raw `git ls-remote` stdout. Each line is
|
|
12
12
|
* `<sha>\t<ref>`; refs are routed through release-id's lenient
|
|
13
13
|
* {@link parseBranchName} and only `kind: 'version'` ids are kept (named
|
|
14
|
-
* `release
|
|
14
|
+
* `release/<name>` branches are irrelevant to `next`-bump math and are dropped).
|
|
15
15
|
* Returns the no-`v` semver tokens (e.g. `1.2.3`) that
|
|
16
16
|
* {@link collectKnownVersions} parses as versions. Pure — no I/O — so it is
|
|
17
17
|
* unit-testable without the network.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* SemVer-ONLY: this assumes a `v<semver>` token and will produce `NaN`s for
|
|
5
5
|
* anything else. Callers that may see branch names or named releases
|
|
6
|
-
* (`release
|
|
6
|
+
* (`release/<name>`) MUST use the `release-id` module (`parseBranchName` /
|
|
7
7
|
* `parseReleaseRef` + `compareReleaseIds`) instead. Only provably names-free
|
|
8
8
|
* callers (the `collectKnownVersions` / `next`-bump math path) may use this.
|
|
9
9
|
*/
|