infra-kit 0.1.80 → 0.1.82
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/cli.js +35 -33
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +25 -24
- package/dist/mcp.js.map +3 -3
- package/package.json +3 -2
- package/src/commands/env-list/env-list.ts +2 -2
- package/src/commands/gh-merge-dev/gh-merge-dev.ts +5 -7
- package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +12 -22
- package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +12 -20
- package/src/commands/gh-release-deploy-service/gh-release-deploy-service.ts +12 -22
- package/src/commands/init/index.ts +1 -0
- package/src/commands/{env-init/env-init.ts → init/init.ts} +40 -7
- package/src/commands/release-create-batch/release-create-batch.ts +6 -3
- package/src/commands/worktrees-add/worktrees-add.ts +35 -35
- package/src/commands/worktrees-list/worktrees-list.ts +53 -278
- package/src/commands/worktrees-remove/worktrees-remove.ts +7 -2
- package/src/entry/cli.ts +68 -5
- package/src/lib/command-echo/command-echo.ts +1 -2
- package/src/lib/constants.ts +1 -1
- package/src/lib/release-utils/release-utils.ts +1 -0
- package/src/commands/env-init/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infra-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.82",
|
|
5
5
|
"description": "infra-kit",
|
|
6
6
|
"main": "dist/cli.js",
|
|
7
7
|
"module": "dist/cli.js",
|
|
8
8
|
"bin": {
|
|
9
|
-
"infra-kit": "dist/cli.js"
|
|
9
|
+
"infra-kit": "dist/cli.js",
|
|
10
|
+
"ik": "dist/cli.js"
|
|
10
11
|
},
|
|
11
12
|
"engines": {
|
|
12
13
|
"node": ">=20.x"
|
|
@@ -14,8 +14,8 @@ export const envList = async (): Promise<ToolsExecutionResult> => {
|
|
|
14
14
|
|
|
15
15
|
const project = await getDopplerProject()
|
|
16
16
|
|
|
17
|
-
logger.info(`Doppler
|
|
18
|
-
logger.info('Available
|
|
17
|
+
logger.info(`Doppler project: ${project}\n`)
|
|
18
|
+
logger.info('Available configs:')
|
|
19
19
|
|
|
20
20
|
for (const env of ENVs) {
|
|
21
21
|
logger.info(` - ${env}`)
|
|
@@ -101,7 +101,7 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// Track --yes flag if confirmation was interactive (user confirmed)
|
|
104
|
-
if (
|
|
104
|
+
if (!confirmedCommand) {
|
|
105
105
|
commandEcho.addOption('--yes', true)
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -126,13 +126,11 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
|
|
|
126
126
|
|
|
127
127
|
if (failedBranches.length > 0) {
|
|
128
128
|
logger.info(`\n⚠️ ${failedBranches.length} branch(es) failed to merge automatically.\n`)
|
|
129
|
-
logger.info('📋 Manual merge script for failed branches
|
|
130
|
-
logger.info('```bash')
|
|
129
|
+
logger.info('📋 Manual merge script for failed branches:')
|
|
131
130
|
for (const branch of failedBranches) {
|
|
132
|
-
logger.info(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
logger.info(`git push origin ${branch} && git switch dev`)
|
|
131
|
+
logger.info(
|
|
132
|
+
`# Merge dev into ${branch} and resolve conflicts if any \ngit switch ${branch} && git pull origin ${branch} && git merge origin/dev\ngit push origin ${branch} && git switch dev\n`,
|
|
133
|
+
)
|
|
136
134
|
}
|
|
137
135
|
logger.info(
|
|
138
136
|
`✅ ${selectedReleaseBranches.length - failedBranches.length}/${selectedReleaseBranches.length} merges completed successfully.`,
|
|
@@ -25,22 +25,6 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
|
|
|
25
25
|
|
|
26
26
|
commandEcho.start('release-deploy-all')
|
|
27
27
|
|
|
28
|
-
// TODO: add validation for semver version for version variable
|
|
29
|
-
|
|
30
|
-
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
31
|
-
|
|
32
|
-
const branches = releasePRsInfo.map((pr) => {
|
|
33
|
-
return pr.branch
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
const releaseTypes = new Map<string, ReleaseType>(
|
|
37
|
-
releasePRsInfo.map((pr) => {
|
|
38
|
-
return [pr.branch, detectReleaseType(pr.title)]
|
|
39
|
-
}),
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
const releasePRsList: string[] = ['dev', ...branches]
|
|
43
|
-
|
|
44
28
|
let selectedReleaseBranch = '' // "release/v1.8.0"
|
|
45
29
|
|
|
46
30
|
if (version) {
|
|
@@ -48,6 +32,18 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
|
|
|
48
32
|
} else {
|
|
49
33
|
commandEcho.setInteractive()
|
|
50
34
|
|
|
35
|
+
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
36
|
+
|
|
37
|
+
const branches = releasePRsInfo.map((pr) => {
|
|
38
|
+
return pr.branch
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const releaseTypes = new Map<string, ReleaseType>(
|
|
42
|
+
releasePRsInfo.map((pr) => {
|
|
43
|
+
return [pr.branch, detectReleaseType(pr.title)]
|
|
44
|
+
}),
|
|
45
|
+
)
|
|
46
|
+
|
|
51
47
|
const descriptions = await getJiraDescriptions()
|
|
52
48
|
|
|
53
49
|
selectedReleaseBranch = await select({
|
|
@@ -60,12 +56,6 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
|
|
|
60
56
|
|
|
61
57
|
commandEcho.addOption('--version', selectedVersion)
|
|
62
58
|
|
|
63
|
-
// Check if release branch exists in the list
|
|
64
|
-
if (!releasePRsList.includes(selectedReleaseBranch)) {
|
|
65
|
-
logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
|
|
66
|
-
process.exit(1)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
59
|
let selectedEnv = ''
|
|
70
60
|
|
|
71
61
|
if (env) {
|
|
@@ -32,20 +32,6 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
|
|
|
32
32
|
|
|
33
33
|
commandEcho.start('release-deploy-selected')
|
|
34
34
|
|
|
35
|
-
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
36
|
-
|
|
37
|
-
const branches = releasePRsInfo.map((pr) => {
|
|
38
|
-
return pr.branch
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const releaseTypes = new Map<string, ReleaseType>(
|
|
42
|
-
releasePRsInfo.map((pr) => {
|
|
43
|
-
return [pr.branch, detectReleaseType(pr.title)]
|
|
44
|
-
}),
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
const releasePRsList: string[] = ['dev', ...branches]
|
|
48
|
-
|
|
49
35
|
let selectedReleaseBranch = ''
|
|
50
36
|
|
|
51
37
|
if (version) {
|
|
@@ -53,6 +39,18 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
|
|
|
53
39
|
} else {
|
|
54
40
|
commandEcho.setInteractive()
|
|
55
41
|
|
|
42
|
+
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
43
|
+
|
|
44
|
+
const branches = releasePRsInfo.map((pr) => {
|
|
45
|
+
return pr.branch
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const releaseTypes = new Map<string, ReleaseType>(
|
|
49
|
+
releasePRsInfo.map((pr) => {
|
|
50
|
+
return [pr.branch, detectReleaseType(pr.title)]
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
|
|
56
54
|
const descriptions = await getJiraDescriptions()
|
|
57
55
|
|
|
58
56
|
selectedReleaseBranch = await select({
|
|
@@ -65,12 +63,6 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
|
|
|
65
63
|
|
|
66
64
|
commandEcho.addOption('--version', selectedVersion)
|
|
67
65
|
|
|
68
|
-
// Check if release branch exists in the list
|
|
69
|
-
if (!releasePRsList.includes(selectedReleaseBranch)) {
|
|
70
|
-
logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
|
|
71
|
-
process.exit(1)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
66
|
let selectedEnv = ''
|
|
75
67
|
|
|
76
68
|
if (env) {
|
|
@@ -30,22 +30,6 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
|
|
|
30
30
|
|
|
31
31
|
commandEcho.start('release-deploy-service')
|
|
32
32
|
|
|
33
|
-
// TODO: add validation for semver version for version variable
|
|
34
|
-
|
|
35
|
-
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
36
|
-
|
|
37
|
-
const branches = releasePRsInfo.map((pr) => {
|
|
38
|
-
return pr.branch
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const releaseTypes = new Map<string, ReleaseType>(
|
|
42
|
-
releasePRsInfo.map((pr) => {
|
|
43
|
-
return [pr.branch, detectReleaseType(pr.title)]
|
|
44
|
-
}),
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
const releasePRsList: string[] = ['dev', ...branches]
|
|
48
|
-
|
|
49
33
|
let selectedReleaseBranch = '' // "release/v1.8.0"
|
|
50
34
|
|
|
51
35
|
if (version) {
|
|
@@ -53,6 +37,18 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
|
|
|
53
37
|
} else {
|
|
54
38
|
commandEcho.setInteractive()
|
|
55
39
|
|
|
40
|
+
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
41
|
+
|
|
42
|
+
const branches = releasePRsInfo.map((pr) => {
|
|
43
|
+
return pr.branch
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const releaseTypes = new Map<string, ReleaseType>(
|
|
47
|
+
releasePRsInfo.map((pr) => {
|
|
48
|
+
return [pr.branch, detectReleaseType(pr.title)]
|
|
49
|
+
}),
|
|
50
|
+
)
|
|
51
|
+
|
|
56
52
|
const descriptions = await getJiraDescriptions()
|
|
57
53
|
|
|
58
54
|
selectedReleaseBranch = await select({
|
|
@@ -65,12 +61,6 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
|
|
|
65
61
|
|
|
66
62
|
commandEcho.addOption('--version', selectedVersion)
|
|
67
63
|
|
|
68
|
-
// Check if release branch exists in the list
|
|
69
|
-
if (!releasePRsList.includes(selectedReleaseBranch)) {
|
|
70
|
-
logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
|
|
71
|
-
process.exit(1)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
64
|
let selectedEnv = ''
|
|
75
65
|
|
|
76
66
|
if (env) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { init } from './init'
|
|
@@ -4,12 +4,16 @@ import path from 'node:path'
|
|
|
4
4
|
|
|
5
5
|
import { logger } from 'src/lib/logger'
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const MARKER_START = '# -- infra-kit:begin --'
|
|
8
|
+
const MARKER_END = '# -- infra-kit:end --'
|
|
9
|
+
|
|
10
|
+
const LEGACY_PAIRED: [start: string, end: string][] = [['# region infra-kit', '# endregion infra-kit']]
|
|
11
|
+
const LEGACY_SINGLE = '# infra-kit shell functions'
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
14
|
* Append infra-kit shell functions directly to .zshrc.
|
|
11
15
|
*/
|
|
12
|
-
export const
|
|
16
|
+
export const init = async (): Promise<void> => {
|
|
13
17
|
const zshrcPath = path.join(os.homedir(), '.zshrc')
|
|
14
18
|
const shellBlock = buildShellBlock()
|
|
15
19
|
|
|
@@ -28,6 +32,7 @@ export const envInit = async (): Promise<void> => {
|
|
|
28
32
|
const isBlockLine = (line: string): boolean => {
|
|
29
33
|
return (
|
|
30
34
|
line.startsWith('#') ||
|
|
35
|
+
line.startsWith('alias ') ||
|
|
31
36
|
line.startsWith('env-load') ||
|
|
32
37
|
line.startsWith('env-clear') ||
|
|
33
38
|
line.startsWith('env-status') ||
|
|
@@ -37,14 +42,40 @@ const isBlockLine = (line: string): boolean => {
|
|
|
37
42
|
)
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
const removeBetween = (content: string, start: string, end: string): string | null => {
|
|
46
|
+
const startIdx = content.indexOf(start)
|
|
47
|
+
const endIdx = content.indexOf(end)
|
|
48
|
+
|
|
49
|
+
if (startIdx === -1 || endIdx === -1) return null
|
|
50
|
+
|
|
51
|
+
// eslint-disable-next-line sonarjs/slow-regex
|
|
52
|
+
const before = content.slice(0, startIdx).replace(/\n+$/, '')
|
|
53
|
+
const after = content.slice(endIdx + end.length).replace(/^\n+/, '')
|
|
54
|
+
|
|
55
|
+
return before + (after ? `\n${after}` : '')
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
const removeExistingBlock = (content: string): string => {
|
|
41
|
-
|
|
59
|
+
// 1. Current markers
|
|
60
|
+
const result = removeBetween(content, MARKER_START, MARKER_END)
|
|
61
|
+
|
|
62
|
+
if (result !== null) return result
|
|
63
|
+
|
|
64
|
+
// 2. Legacy paired markers (# region / # endregion)
|
|
65
|
+
for (const [start, end] of LEGACY_PAIRED) {
|
|
66
|
+
const legacyResult = removeBetween(content, start, end)
|
|
67
|
+
|
|
68
|
+
if (legacyResult !== null) return legacyResult
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 3. Oldest format: single marker + heuristic scan
|
|
72
|
+
const legacyIdx = content.indexOf(LEGACY_SINGLE)
|
|
42
73
|
|
|
43
|
-
if (
|
|
74
|
+
if (legacyIdx === -1) return content
|
|
44
75
|
|
|
45
76
|
// eslint-disable-next-line sonarjs/slow-regex
|
|
46
|
-
const before = content.slice(0,
|
|
47
|
-
const afterLines = content.slice(
|
|
77
|
+
const before = content.slice(0, legacyIdx).replace(/\n+$/, '')
|
|
78
|
+
const afterLines = content.slice(legacyIdx).split('\n')
|
|
48
79
|
|
|
49
80
|
let i = 0
|
|
50
81
|
|
|
@@ -61,7 +92,7 @@ const buildShellBlock = (): string => {
|
|
|
61
92
|
const runCmd = 'pnpm exec infra-kit'
|
|
62
93
|
|
|
63
94
|
return [
|
|
64
|
-
|
|
95
|
+
MARKER_START,
|
|
65
96
|
// eslint-disable-next-line no-template-curly-in-string
|
|
66
97
|
'if [[ -z "${INFRA_KIT_SESSION}" ]]; then',
|
|
67
98
|
' export INFRA_KIT_SESSION=$(head -c 4 /dev/urandom | xxd -p)',
|
|
@@ -69,5 +100,7 @@ const buildShellBlock = (): string => {
|
|
|
69
100
|
`env-load() { local f; f=$(${runCmd} env-load "$@") && source "$f" && ${runCmd} env-status; }`,
|
|
70
101
|
`env-clear() { local f; f=$(${runCmd} env-clear) && source "$f" && ${runCmd} env-status; }`,
|
|
71
102
|
`env-status() { ${runCmd} env-status; }`,
|
|
103
|
+
`alias ik='${runCmd}'`,
|
|
104
|
+
MARKER_END,
|
|
72
105
|
].join('\n')
|
|
73
106
|
}
|
|
@@ -30,9 +30,12 @@ const resolveInputs = async (args: ReleaseCreateBatchArgs): Promise<{ versionsLi
|
|
|
30
30
|
versionInput = await question('Enter versions by comma (e.g. 1.2.5, 1.2.6): ')
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const versionsList = versionInput
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const versionsList = versionInput
|
|
34
|
+
.split(',')
|
|
35
|
+
.map((version) => {
|
|
36
|
+
return version.trim()
|
|
37
|
+
})
|
|
38
|
+
.filter(Boolean)
|
|
36
39
|
|
|
37
40
|
commandEcho.addOption('--versions', versionsList.join(', '))
|
|
38
41
|
|
|
@@ -44,53 +44,53 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
|
|
|
44
44
|
await ensureWorktreeDirectory(`${worktreeDir}/${RELEASE_DIR}`)
|
|
45
45
|
await ensureWorktreeDirectory(`${worktreeDir}/${FEATURE_DIR}`)
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
let selectedReleaseBranches: string[] = []
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (versions) {
|
|
50
|
+
selectedReleaseBranches = versions.split(',').map((v) => {
|
|
51
|
+
return `release/v${v.trim()}`
|
|
52
|
+
})
|
|
53
|
+
} else {
|
|
54
|
+
const releasePRsInfo = await getReleasePRsWithInfo()
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}),
|
|
57
|
-
)
|
|
56
|
+
const releasePRsList = releasePRsInfo.map((pr) => {
|
|
57
|
+
return pr.branch
|
|
58
|
+
})
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if (releasePRsList.length === 0) {
|
|
61
|
+
logger.info('ℹ️ No open release branches found')
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
commandEcho.print()
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: JSON.stringify({ createdWorktrees: [], count: 0 }, null, 2) }],
|
|
67
|
+
structuredContent: { createdWorktrees: [], count: 0 },
|
|
68
|
+
}
|
|
67
69
|
}
|
|
68
|
-
}
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
if (all) {
|
|
72
|
+
selectedReleaseBranches = releasePRsList
|
|
73
|
+
} else {
|
|
74
|
+
commandEcho.setInteractive()
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})
|
|
78
|
-
} else {
|
|
79
|
-
commandEcho.setInteractive()
|
|
76
|
+
const releaseTypes = new Map<string, ReleaseType>(
|
|
77
|
+
releasePRsInfo.map((pr) => {
|
|
78
|
+
return [pr.branch, detectReleaseType(pr.title)]
|
|
79
|
+
}),
|
|
80
|
+
)
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
const descriptions = await getJiraDescriptions()
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
selectedReleaseBranches = await checkbox({
|
|
85
|
+
required: true,
|
|
86
|
+
message: '🌿 Select release branches',
|
|
87
|
+
choices: formatBranchChoices({ branches: releasePRsList, descriptions, types: releaseTypes }),
|
|
88
|
+
})
|
|
89
|
+
}
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
// Track --all flag if all branches were selected (either via flag or interactively)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (allSelected) {
|
|
93
|
+
if (all) {
|
|
94
94
|
commandEcho.addOption('--all', true)
|
|
95
95
|
} else {
|
|
96
96
|
commandEcho.addOption(
|
|
@@ -118,7 +118,7 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// Track --yes flag if confirmation was interactive (user confirmed)
|
|
121
|
-
if (
|
|
121
|
+
if (!confirmedCommand) {
|
|
122
122
|
commandEcho.addOption('--yes', true)
|
|
123
123
|
}
|
|
124
124
|
|