infra-kit 0.1.97 → 0.1.98
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/.turbo/turbo-eslint-check.log +4 -5
- package/.turbo/turbo-prettier-check.log +4 -5
- package/.turbo/turbo-test.log +191 -18
- package/.turbo/turbo-ts-check.log +9 -5
- package/dist/cli.js +57 -37
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +29 -28
- package/dist/mcp.js.map +4 -4
- package/package.json +1 -1
- package/src/commands/config/config.ts +125 -0
- package/src/commands/config/index.ts +1 -0
- package/src/commands/doctor/doctor.ts +27 -18
- package/src/commands/init/init.ts +54 -1
- package/src/commands/release-create/release-create.ts +123 -72
- package/src/commands/release-create-batch/release-create-batch.ts +45 -21
- package/src/entry/cli.ts +26 -5
- package/src/lib/__tests__/infra-kit-config.test.ts +3 -1
- package/src/lib/infra-kit-config/index.ts +2 -2
- package/src/lib/infra-kit-config/infra-kit-config.ts +183 -37
- package/src/lib/version-utils/__tests__/next-version.test.ts +112 -0
- package/src/lib/version-utils/index.ts +11 -0
- package/src/lib/version-utils/load-existing-versions.ts +67 -0
- package/src/lib/version-utils/next-version.ts +148 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { ReleaseType } from 'src/lib/release-utils'
|
|
2
|
+
|
|
3
|
+
import { parseVersion, sortVersions } from './version-utils'
|
|
4
|
+
|
|
5
|
+
export const NEXT_TOKEN = 'next'
|
|
6
|
+
|
|
7
|
+
export type SemVer = readonly [number, number, number]
|
|
8
|
+
|
|
9
|
+
export interface ExistingVersionsSources {
|
|
10
|
+
remoteBranches?: string[]
|
|
11
|
+
jiraVersions?: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const VERSION_RE = /^v?(\d+)\.(\d+)\.(\d+)$/
|
|
15
|
+
|
|
16
|
+
const stripBranchPrefix = (raw: string): string => {
|
|
17
|
+
return raw.replace(/^.*release\//, '')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const tryParse = (raw: string): SemVer | null => {
|
|
21
|
+
const cleaned = stripBranchPrefix(raw.trim())
|
|
22
|
+
const match = VERSION_RE.exec(cleaned)
|
|
23
|
+
|
|
24
|
+
if (!match) return null
|
|
25
|
+
|
|
26
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const semverKey = (v: SemVer): string => {
|
|
30
|
+
return `${v[0]}.${v[1]}.${v[2]}`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const collectKnownVersions = (sources: ExistingVersionsSources): SemVer[] => {
|
|
34
|
+
const all = [...(sources.remoteBranches ?? []), ...(sources.jiraVersions ?? [])]
|
|
35
|
+
const parsed: SemVer[] = []
|
|
36
|
+
const seen = new Set<string>()
|
|
37
|
+
|
|
38
|
+
for (const raw of all) {
|
|
39
|
+
const v = tryParse(raw)
|
|
40
|
+
|
|
41
|
+
if (!v) continue
|
|
42
|
+
|
|
43
|
+
const key = semverKey(v)
|
|
44
|
+
|
|
45
|
+
if (seen.has(key)) continue
|
|
46
|
+
|
|
47
|
+
seen.add(key)
|
|
48
|
+
parsed.push(v)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return sortVersions(
|
|
52
|
+
parsed.map((v) => {
|
|
53
|
+
return semverKey(v)
|
|
54
|
+
}),
|
|
55
|
+
).map((s) => {
|
|
56
|
+
return parseVersion(`v${s}`)
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class NoPriorVersionsError extends Error {
|
|
61
|
+
constructor() {
|
|
62
|
+
super('No prior release versions found from git or Jira. Specify the version explicitly.')
|
|
63
|
+
this.name = 'NoPriorVersionsError'
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Compute the next semantic version based on release type.
|
|
69
|
+
* - regular: bump minor, reset patch to 0
|
|
70
|
+
* - hotfix: bump patch on the highest minor (any patch)
|
|
71
|
+
*
|
|
72
|
+
* Returns the version without the leading "v" (e.g. "1.64.0").
|
|
73
|
+
*/
|
|
74
|
+
export const computeNextVersion = (known: SemVer[], type: ReleaseType): string => {
|
|
75
|
+
if (known.length === 0) throw new NoPriorVersionsError()
|
|
76
|
+
|
|
77
|
+
const max = known[known.length - 1] as SemVer
|
|
78
|
+
|
|
79
|
+
if (type === 'hotfix') {
|
|
80
|
+
const [major, minor] = max
|
|
81
|
+
|
|
82
|
+
const highestPatchOnMinor = known.reduce((acc, v) => {
|
|
83
|
+
if (v[0] === major && v[1] === minor) return Math.max(acc, v[2])
|
|
84
|
+
|
|
85
|
+
return acc
|
|
86
|
+
}, 0)
|
|
87
|
+
|
|
88
|
+
return `${major}.${minor}.${highestPatchOnMinor + 1}`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const [major, minor] = max
|
|
92
|
+
|
|
93
|
+
return `${major}.${minor + 1}.0`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const isNextToken = (token: string): boolean => {
|
|
97
|
+
return token.trim().toLowerCase() === NEXT_TOKEN
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Resolve a list of input tokens (mix of "next" and explicit semver strings)
|
|
102
|
+
* into concrete version strings. Each "next" advances based on the running
|
|
103
|
+
* max so "next,next" produces sequential versions.
|
|
104
|
+
*/
|
|
105
|
+
export const resolveVersionTokens = (tokens: string[], type: ReleaseType, known: SemVer[]): string[] => {
|
|
106
|
+
const running: SemVer[] = [...known]
|
|
107
|
+
const resolved: string[] = []
|
|
108
|
+
|
|
109
|
+
for (const token of tokens) {
|
|
110
|
+
const trimmed = token.trim()
|
|
111
|
+
|
|
112
|
+
if (trimmed === '') continue
|
|
113
|
+
|
|
114
|
+
if (isNextToken(trimmed)) {
|
|
115
|
+
const next = computeNextVersion(running, type)
|
|
116
|
+
|
|
117
|
+
resolved.push(next)
|
|
118
|
+
running.push(parseVersion(`v${next}`))
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const parsed = tryParse(trimmed)
|
|
123
|
+
|
|
124
|
+
if (!parsed) {
|
|
125
|
+
throw new Error(`Invalid version "${trimmed}". Expected semver like "1.2.5" or the token "next".`)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const explicit = `${parsed[0]}.${parsed[1]}.${parsed[2]}`
|
|
129
|
+
|
|
130
|
+
resolved.push(explicit)
|
|
131
|
+
running.push(parsed)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return resolved
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Split a raw user input into tokens, trimming and removing empties.
|
|
139
|
+
* Accepts both whitespace-separated and comma-separated lists.
|
|
140
|
+
*/
|
|
141
|
+
export const splitVersionInput = (input: string): string[] => {
|
|
142
|
+
return input
|
|
143
|
+
.split(',')
|
|
144
|
+
.map((t) => {
|
|
145
|
+
return t.trim()
|
|
146
|
+
})
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
}
|