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/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.1.80",
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 Project: ${project}\n`)
18
- logger.info('Available Configs:')
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 (allSelected) {
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:\n')
130
- logger.info('```bash')
129
+ logger.info('📋 Manual merge script for failed branches:')
131
130
  for (const branch of failedBranches) {
132
- logger.info(`# Phase #1: Merge dev into ${branch}`)
133
- logger.info(`git switch ${branch} && git pull origin ${branch} && git merge origin/dev`)
134
- logger.info(`# Phase #2:Resolve conflicts if any, then:`)
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 MARKER_COMMENT = '# infra-kit shell functions'
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 envInit = async (): Promise<void> => {
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
- const markerIdx = content.indexOf(MARKER_COMMENT)
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 (markerIdx === -1) return content
74
+ if (legacyIdx === -1) return content
44
75
 
45
76
  // eslint-disable-next-line sonarjs/slow-regex
46
- const before = content.slice(0, markerIdx).replace(/\n+$/, '')
47
- const afterLines = content.slice(markerIdx).split('\n')
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
- MARKER_COMMENT,
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.split(',').map((version) => {
34
- return version.trim()
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
- const releasePRsInfo = await getReleasePRsWithInfo()
47
+ let selectedReleaseBranches: string[] = []
48
48
 
49
- const releasePRsList = releasePRsInfo.map((pr) => {
50
- return pr.branch
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
- const releaseTypes = new Map<string, ReleaseType>(
54
- releasePRsInfo.map((pr) => {
55
- return [pr.branch, detectReleaseType(pr.title)]
56
- }),
57
- )
56
+ const releasePRsList = releasePRsInfo.map((pr) => {
57
+ return pr.branch
58
+ })
58
59
 
59
- if (releasePRsList.length === 0) {
60
- logger.info('ℹ️ No open release branches found')
60
+ if (releasePRsList.length === 0) {
61
+ logger.info('ℹ️ No open release branches found')
61
62
 
62
- commandEcho.print()
63
+ commandEcho.print()
63
64
 
64
- return {
65
- content: [{ type: 'text', text: JSON.stringify({ createdWorktrees: [], count: 0 }, null, 2) }],
66
- structuredContent: { createdWorktrees: [], count: 0 },
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
- let selectedReleaseBranches: string[] = []
71
+ if (all) {
72
+ selectedReleaseBranches = releasePRsList
73
+ } else {
74
+ commandEcho.setInteractive()
71
75
 
72
- if (all) {
73
- selectedReleaseBranches = releasePRsList
74
- } else if (versions) {
75
- selectedReleaseBranches = versions.split(',').map((v) => {
76
- return `release/v${v.trim()}`
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
- const descriptions = await getJiraDescriptions()
82
+ const descriptions = await getJiraDescriptions()
82
83
 
83
- selectedReleaseBranches = await checkbox({
84
- required: true,
85
- message: '🌿 Select release branches',
86
- choices: formatBranchChoices({ branches: releasePRsList, descriptions, types: releaseTypes }),
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
- const allSelected = selectedReleaseBranches.length === releasePRsList.length
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 (allSelected) {
121
+ if (!confirmedCommand) {
122
122
  commandEcho.addOption('--yes', true)
123
123
  }
124
124