infra-kit 0.1.55 → 0.1.56

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.
@@ -0,0 +1,106 @@
1
+ import confirm from '@inquirer/confirm'
2
+ import process from 'node:process'
3
+ import { z } from 'zod'
4
+ import { $, question } from 'zx'
5
+
6
+ import { loadJiraConfig } from 'src/integrations/jira'
7
+ import { logger } from 'src/lib/logger'
8
+ import { createSingleRelease, prepareGitForRelease } from 'src/lib/release-utils'
9
+ import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
10
+
11
+ interface ReleaseCreateArgs extends RequiredConfirmedOptionArg {
12
+ version: string
13
+ description?: string
14
+ checkout?: boolean
15
+ }
16
+
17
+ /**
18
+ * Create a single release branch for the specified version
19
+ * Includes Jira version creation and GitHub release branch creation
20
+ */
21
+ export const releaseCreate = async (args: ReleaseCreateArgs): Promise<ToolsExecutionResult> => {
22
+ const { version: inputVersion, description, confirmedCommand, checkout = true } = args
23
+
24
+ let version = inputVersion
25
+
26
+ // Load Jira config - it is now mandatory
27
+ const jiraConfig = await loadJiraConfig()
28
+
29
+ if (!version) {
30
+ version = await question('Enter version (e.g. 1.2.5): ')
31
+ }
32
+
33
+ // Validate input
34
+ if (!version || version.trim() === '') {
35
+ logger.error('No version provided. Exiting...')
36
+ process.exit(1)
37
+ }
38
+
39
+ const trimmedVersion = version.trim()
40
+
41
+ const answer = confirmedCommand
42
+ ? true
43
+ : await confirm({
44
+ message: `Are you sure you want to create release branch for version ${trimmedVersion}?`,
45
+ })
46
+
47
+ if (!answer) {
48
+ logger.info('Operation cancelled. Exiting...')
49
+ process.exit(0)
50
+ }
51
+
52
+ await prepareGitForRelease()
53
+
54
+ // Create the release
55
+ const release = await createSingleRelease(trimmedVersion, jiraConfig, description)
56
+
57
+ logger.info(`✅ Successfully created release: v${trimmedVersion}`)
58
+ logger.info(`🔗 GitHub PR: ${release.prUrl}`)
59
+ logger.info(`🔗 Jira Version: ${release.jiraVersionUrl}`)
60
+
61
+ // Checkout to the created branch by default
62
+ if (checkout) {
63
+ $.quiet = true
64
+ await $`git switch ${release.branchName}`
65
+ $.quiet = false
66
+
67
+ logger.info(`🔄 Switched to branch ${release.branchName}`)
68
+ }
69
+
70
+ const structuredContent = {
71
+ version: trimmedVersion,
72
+ branchName: release.branchName,
73
+ prUrl: release.prUrl,
74
+ jiraVersionUrl: release.jiraVersionUrl,
75
+ isCheckedOut: checkout,
76
+ }
77
+
78
+ return {
79
+ content: [
80
+ {
81
+ type: 'text',
82
+ text: JSON.stringify(structuredContent, null, 2),
83
+ },
84
+ ],
85
+ structuredContent,
86
+ }
87
+ }
88
+
89
+ // MCP Tool Registration
90
+ export const releaseCreateMcpTool = {
91
+ name: 'release-create',
92
+ description: 'Create a single release branch for specified version with Jira version creation',
93
+ inputSchema: {
94
+ version: z.string().describe('Version to create (e.g., "1.2.5")'),
95
+ description: z.string().optional().describe('Optional description for the Jira version'),
96
+ checkout: z.boolean().optional().default(true).describe('Checkout to the created branch (default: true)'),
97
+ },
98
+ outputSchema: {
99
+ version: z.string().describe('Version number'),
100
+ branchName: z.string().describe('Release branch name'),
101
+ prUrl: z.string().describe('GitHub PR URL'),
102
+ jiraVersionUrl: z.string().describe('Jira version URL'),
103
+ isCheckedOut: z.boolean().describe('Whether the branch was checked out'),
104
+ },
105
+ handler: releaseCreate,
106
+ }
@@ -0,0 +1 @@
1
+ export { releaseCreateBatch, releaseCreateBatchMcpTool } from './release-create-batch'
@@ -0,0 +1,114 @@
1
+ import confirm from '@inquirer/confirm'
2
+ import process from 'node:process'
3
+ import { z } from 'zod'
4
+ import { question } from 'zx'
5
+
6
+ import { loadJiraConfig } from 'src/integrations/jira'
7
+ import { logger } from 'src/lib/logger'
8
+ import { createSingleRelease, prepareGitForRelease } from 'src/lib/release-utils'
9
+ import type { ReleaseCreationResult } from 'src/lib/release-utils'
10
+ import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
11
+
12
+ interface ReleaseCreateBatchArgs extends RequiredConfirmedOptionArg {
13
+ versions: string
14
+ description?: string
15
+ }
16
+
17
+ /**
18
+ * Create multiple release branches for the specified versions
19
+ * Includes Jira version creation and GitHub release branch creation for each version
20
+ */
21
+ export const releaseCreateBatch = async (args: ReleaseCreateBatchArgs): Promise<ToolsExecutionResult> => {
22
+ const { versions: inputVersions, description, confirmedCommand } = args
23
+
24
+ let versionInput = inputVersions
25
+
26
+ // Load Jira config - it is now mandatory
27
+ const jiraConfig = await loadJiraConfig()
28
+
29
+ if (!versionInput) {
30
+ versionInput = await question('Enter versions by comma (e.g. 1.2.5, 1.2.6): ')
31
+ }
32
+
33
+ const versionsList = versionInput.split(',').map((version) => version.trim())
34
+
35
+ // Validate input
36
+ if (versionsList.length === 0) {
37
+ logger.error('No versions provided. Exiting...')
38
+ process.exit(1)
39
+ }
40
+
41
+ // Inform user if they only provided one version
42
+ if (versionsList.length === 1) {
43
+ logger.warn('💡 You are creating only one release. Consider using "create-release" command for single releases.')
44
+ }
45
+
46
+ const answer = confirmedCommand
47
+ ? true
48
+ : await confirm({
49
+ message: `Are you sure you want to create release branches for these versions: ${versionsList.join(', ')}?`,
50
+ })
51
+
52
+ if (!answer) {
53
+ logger.info('Operation cancelled. Exiting...')
54
+ process.exit(0)
55
+ }
56
+
57
+ await prepareGitForRelease()
58
+
59
+ const releases: ReleaseCreationResult[] = []
60
+
61
+ for (const version of versionsList) {
62
+ // Create each release
63
+ const release = await createSingleRelease(version, jiraConfig, description)
64
+
65
+ releases.push(release)
66
+
67
+ logger.info(`✅ Successfully created release: v${version}`)
68
+ logger.info(`🔗 GitHub PR: ${release.prUrl}`)
69
+ logger.info(`🔗 Jira Version: ${release.jiraVersionUrl}\n`)
70
+ }
71
+
72
+ logger.info(`${versionsList.length} release branches were created successfully.`)
73
+
74
+ const structuredContent = {
75
+ createdBranches: versionsList.map((version) => `release/v${version}`),
76
+ branchCount: versionsList.length,
77
+ releases,
78
+ }
79
+
80
+ return {
81
+ content: [
82
+ {
83
+ type: 'text',
84
+ text: JSON.stringify(structuredContent, null, 2),
85
+ },
86
+ ],
87
+ structuredContent,
88
+ }
89
+ }
90
+
91
+ // MCP Tool Registration
92
+ export const releaseCreateBatchMcpTool = {
93
+ name: 'release-create-batch',
94
+ description: 'Create multiple release branches for specified versions with Jira version creation (batch operation)',
95
+ inputSchema: {
96
+ versions: z.string().describe('Comma-separated list of versions to create (e.g., "1.2.5, 1.2.6")'),
97
+ description: z.string().optional().describe('Optional description for the Jira versions'),
98
+ },
99
+ outputSchema: {
100
+ createdBranches: z.array(z.string()).describe('List of created release branches'),
101
+ branchCount: z.number().describe('Number of branches created'),
102
+ releases: z
103
+ .array(
104
+ z.object({
105
+ version: z.string().describe('Version number'),
106
+ branchName: z.string().describe('Release branch name'),
107
+ prUrl: z.string().describe('GitHub PR URL'),
108
+ jiraVersionUrl: z.string().describe('Jira version URL'),
109
+ }),
110
+ )
111
+ .describe('Detailed information for each created release with URLs'),
112
+ },
113
+ handler: releaseCreateBatch,
114
+ }
package/src/entry/cli.ts CHANGED
@@ -2,10 +2,11 @@ import { Command } from 'commander'
2
2
 
3
3
  // Commands
4
4
  import { ghMergeDev } from 'src/commands/gh-merge-dev'
5
- import { ghReleaseCreate } from 'src/commands/gh-release-create'
6
5
  import { ghReleaseDeliver } from 'src/commands/gh-release-deliver'
7
6
  import { ghReleaseDeploy } from 'src/commands/gh-release-deploy'
8
7
  import { ghReleaseList } from 'src/commands/gh-release-list'
8
+ import { releaseCreate } from 'src/commands/release-create'
9
+ import { releaseCreateBatch } from 'src/commands/release-create-batch'
9
10
  import { worktreesAdd } from 'src/commands/worktrees-add'
10
11
  import { worktreesList } from 'src/commands/worktrees-list'
11
12
  import { worktreesRemove } from 'src/commands/worktrees-remove'
@@ -37,12 +38,32 @@ program
37
38
 
38
39
  program
39
40
  .command('release-create')
40
- .description('Create new release branches')
41
+ .description('Create a single release branch')
42
+ .option('-v, --version <version>', 'Specify the version to create, e.g. 1.2.5')
43
+ .option('-d, --description <description>', 'Optional description for the Jira version')
44
+ .option('-y, --yes', 'Skip confirmation prompt')
45
+ .option('--no-checkout', 'Do not checkout the created branch after creation (checkout is default)')
46
+ .action(async (options) => {
47
+ await releaseCreate({
48
+ version: options.version,
49
+ description: options.description,
50
+ confirmedCommand: options.yes,
51
+ checkout: options.checkout,
52
+ })
53
+ })
54
+
55
+ program
56
+ .command('release-create-batch')
57
+ .description('Create multiple release branches (batch operation)')
41
58
  .option('-v, --versions <versions>', 'Specify the versions to create by comma, e.g. 1.2.5, 1.2.6')
59
+ .option('-d, --description <description>', 'Optional description for the Jira versions')
42
60
  .option('-y, --yes', 'Skip confirmation prompt')
43
- .option('-c, --checkout', 'Checkout the created branch after creation (only works when creating a single branch)')
44
61
  .action(async (options) => {
45
- await ghReleaseCreate({ versions: options.versions, confirmedCommand: options.yes, checkout: options.checkout })
62
+ await releaseCreateBatch({
63
+ versions: options.versions,
64
+ description: options.description,
65
+ confirmedCommand: options.yes,
66
+ })
46
67
  })
47
68
 
48
69
  program
@@ -40,8 +40,17 @@ export const getReleasePRs = async (): Promise<string[]> => {
40
40
  }
41
41
  }
42
42
 
43
+ interface CreateReleaseBranchArgs {
44
+ version: string
45
+ jiraVersionUrl: string
46
+ }
47
+
43
48
  // Function to create a release branch
44
- export const createReleaseBranch = async (version: string): Promise<{ branchName: string; prUrl: string }> => {
49
+ export const createReleaseBranch = async (
50
+ args: CreateReleaseBranchArgs,
51
+ ): Promise<{ branchName: string; prUrl: string }> => {
52
+ const { version, jiraVersionUrl } = args
53
+
45
54
  const branchName = `release/v${version}`
46
55
 
47
56
  try {
@@ -54,7 +63,7 @@ export const createReleaseBranch = async (version: string): Promise<{ branchName
54
63
 
55
64
  // Create PR and capture URL
56
65
  const prResult =
57
- await $`gh pr create --title "Release v${version}" --body "Release v${version}" --base dev --head ${branchName}`
66
+ await $`gh pr create --title "Release v${version}" --body "${jiraVersionUrl} \n" --base dev --head ${branchName}`
58
67
 
59
68
  const prLink = prResult.stdout.trim()
60
69
 
@@ -36,8 +36,8 @@ export const createJiraVersion = async (
36
36
  projectId: params.projectId || projectId,
37
37
  description: params.description || '',
38
38
  // releaseDate,
39
- released: params.released ?? true,
40
- archived: params.archived ?? false,
39
+ released: params.released || false,
40
+ archived: params.archived || false,
41
41
  }
42
42
 
43
43
  // logger.info(
@@ -0,0 +1 @@
1
+ export { loadEnvFromGitRoot } from './load-env'
@@ -0,0 +1 @@
1
+ export { createSingleRelease, prepareGitForRelease, type ReleaseCreationResult } from './release-utils'
@@ -0,0 +1,66 @@
1
+ import { $ } from 'zx'
2
+
3
+ import { createReleaseBranch } from 'src/integrations/gh'
4
+ import { createJiraVersion } from 'src/integrations/jira'
5
+ import type { JiraConfig } from 'src/integrations/jira'
6
+
7
+ export interface ReleaseCreationResult {
8
+ version: string
9
+ branchName: string
10
+ prUrl: string
11
+ jiraVersionUrl: string
12
+ }
13
+
14
+ /**
15
+ * Prepare git repository for release creation
16
+ * Fetches latest changes, switches to dev branch, and pulls latest
17
+ */
18
+ export const prepareGitForRelease = async (): Promise<void> => {
19
+ $.quiet = true
20
+
21
+ await $`git fetch origin`
22
+ await $`git switch dev`
23
+ await $`git pull origin dev`
24
+
25
+ $.quiet = false
26
+ }
27
+
28
+ /**
29
+ * Create a single release by creating both Jira version and GitHub release branch
30
+ * @param version - Version number (e.g., "1.2.5")
31
+ * @param jiraConfig - Jira configuration object
32
+ * @param description - Optional description for the Jira version
33
+ * @returns Release creation result with URLs and metadata
34
+ */
35
+ export const createSingleRelease = async (
36
+ version: string,
37
+ jiraConfig: JiraConfig,
38
+ description?: string,
39
+ ): Promise<ReleaseCreationResult> => {
40
+ // 1. Create Jira version (mandatory)
41
+ const versionName = `v${version}`
42
+
43
+ const result = await createJiraVersion(
44
+ {
45
+ name: versionName,
46
+ projectId: jiraConfig.projectId,
47
+ description: description || '',
48
+ released: false,
49
+ archived: false,
50
+ },
51
+ jiraConfig,
52
+ )
53
+
54
+ // Construct user-friendly Jira URL using project key from API response
55
+ const jiraVersionUrl = `${jiraConfig.baseUrl}/projects/${result.version!.projectId}/versions/${result.version!.id}/tab/release-report-all-issues`
56
+
57
+ // 2. Create GitHub release branch
58
+ const releaseInfo = await createReleaseBranch({ version, jiraVersionUrl })
59
+
60
+ return {
61
+ version,
62
+ branchName: releaseInfo.branchName,
63
+ prUrl: releaseInfo.prUrl,
64
+ jiraVersionUrl,
65
+ }
66
+ }
@@ -1,10 +1,11 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
2
 
3
3
  import { ghMergeDevMcpTool } from 'src/commands/gh-merge-dev'
4
- import { ghReleaseCreateMcpTool } from 'src/commands/gh-release-create'
5
4
  import { ghReleaseDeliverMcpTool } from 'src/commands/gh-release-deliver'
6
5
  import { ghReleaseDeployMcpTool } from 'src/commands/gh-release-deploy'
7
6
  import { ghReleaseListMcpTool } from 'src/commands/gh-release-list'
7
+ import { releaseCreateMcpTool } from 'src/commands/release-create'
8
+ import { releaseCreateBatchMcpTool } from 'src/commands/release-create-batch'
8
9
  import { worktreesAddMcpTool } from 'src/commands/worktrees-add'
9
10
  import { worktreesListMcpTool } from 'src/commands/worktrees-list'
10
11
  import { worktreesRemoveMcpTool } from 'src/commands/worktrees-remove'
@@ -13,7 +14,8 @@ import { createToolHandler } from 'src/lib/tool-handler'
13
14
 
14
15
  const tools = [
15
16
  ghMergeDevMcpTool,
16
- ghReleaseCreateMcpTool,
17
+ releaseCreateMcpTool,
18
+ releaseCreateBatchMcpTool,
17
19
  ghReleaseDeliverMcpTool,
18
20
  ghReleaseDeployMcpTool,
19
21
  ghReleaseListMcpTool,
@@ -1,169 +0,0 @@
1
- import confirm from '@inquirer/confirm'
2
- import process from 'node:process'
3
- import { z } from 'zod'
4
- import { $, question } from 'zx'
5
-
6
- import { createReleaseBranch } from 'src/integrations/gh'
7
- import { createJiraVersion, loadJiraConfig } from 'src/integrations/jira'
8
- import { logger } from 'src/lib/logger'
9
- import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
10
-
11
- interface GhReleaseCreateArgs extends RequiredConfirmedOptionArg {
12
- versions: string
13
- checkout?: boolean
14
- }
15
-
16
- /**
17
- * Create release branches for a given version
18
- */
19
- export const ghReleaseCreate = async (args: GhReleaseCreateArgs): Promise<ToolsExecutionResult> => {
20
- const { versions, confirmedCommand, checkout } = args
21
-
22
- let versionBranches = ''
23
- let _checkout = checkout
24
-
25
- // Load Jira config - it is now mandatory
26
- const jiraConfig = await loadJiraConfig()
27
-
28
- if (versions) {
29
- versionBranches = versions
30
- } else {
31
- versionBranches = await question('Enter versions by comma (e.g. 1.2.5, 1.2.6): ')
32
- }
33
-
34
- const versionsList = versionBranches.split(',').map((version) => version.trim()) // ['1.2.5', '1.2.6']
35
-
36
- // Validate input
37
- if (versionsList.length === 0) {
38
- logger.error('No versions provided. Exiting...')
39
- process.exit(1)
40
- }
41
-
42
- // Warn user if checkout option is used with multiple branches
43
- if (_checkout && versionsList.length > 1) {
44
- logger.warn(
45
- '⚠️ Checkout option is ignored when creating multiple branches. Only works with single branch creation.',
46
- )
47
- }
48
-
49
- if (versionsList.length === 1 && !_checkout) {
50
- _checkout = await confirm({
51
- message: `Checkout to the created branch?`,
52
- })
53
- }
54
-
55
- const answer = confirmedCommand
56
- ? true
57
- : await confirm({
58
- message: `Are you sure you want to create release branches for these versions: ${versionsList.join(', ')}?`,
59
- })
60
-
61
- if (!answer) {
62
- logger.info('Operation cancelled. Exiting...')
63
- process.exit(0)
64
- }
65
-
66
- $.quiet = true
67
-
68
- await $`git fetch origin`
69
- await $`git switch dev`
70
- await $`git pull origin dev`
71
-
72
- const releases: Array<{
73
- version: string
74
- branchName: string
75
- prUrl: string
76
- jiraVersionUrl: string
77
- }> = []
78
-
79
- for (const version of versionsList) {
80
- // 1. Create Jira version (mandatory)
81
- const versionName = `v${version}`
82
-
83
- const result = await createJiraVersion(
84
- {
85
- name: versionName,
86
- projectId: jiraConfig.projectId,
87
- description: ``,
88
- released: false,
89
- archived: false,
90
- },
91
- jiraConfig,
92
- )
93
-
94
- // 2. Create GitHub release branch
95
- const releaseInfo = await createReleaseBranch(version)
96
-
97
- // Construct user-friendly Jira URL using project key from API response
98
- const jiraVersionUrl = `${jiraConfig.baseUrl}/projects/${result.version!.projectId}/versions/${result.version!.id}/tab/release-report-all-issues`
99
-
100
- releases.push({
101
- version,
102
- branchName: releaseInfo.branchName,
103
- prUrl: releaseInfo.prUrl,
104
- jiraVersionUrl,
105
- })
106
-
107
- logger.info(`✅ Successfully created release: ${versionName}`)
108
- logger.info(`🔗 GitHub PR: ${releaseInfo.prUrl}`)
109
- logger.info(`🔗 Jira Version: ${jiraVersionUrl} \n`)
110
- }
111
-
112
- // If checkout option is enabled and we created only one branch, checkout to it
113
- const isCheckedOut = _checkout && versionsList.length === 1
114
-
115
- if (isCheckedOut) {
116
- const branchName = `release/v${versionsList[0]}`
117
-
118
- await $`git switch ${branchName}`
119
-
120
- logger.info(`🔄 Switched to branch ${branchName}`)
121
- }
122
-
123
- logger.info(`${versionsList.length} release branches were created successfully.`)
124
-
125
- $.quiet = false
126
-
127
- const structuredContent = {
128
- createdBranches: versionsList.map((version) => `release/v${version}`),
129
- branchCount: versionsList.length,
130
- isCheckedOut,
131
- releases,
132
- }
133
-
134
- return {
135
- content: [
136
- {
137
- type: 'text',
138
- text: JSON.stringify(structuredContent, null, 2),
139
- },
140
- ],
141
- structuredContent,
142
- }
143
- }
144
-
145
- // MCP Tool Registration
146
- export const ghReleaseCreateMcpTool = {
147
- name: 'gh-release-create',
148
- description: 'Create new release branches for specified versions and optionally create Jira versions',
149
- inputSchema: {
150
- versions: z.string().describe('Comma-separated list of versions to create (e.g., "1.2.5, 1.2.6")'),
151
- checkout: z.boolean().optional().describe('Checkout to the created branch (only works with single version)'),
152
- },
153
- outputSchema: {
154
- createdBranches: z.array(z.string()).describe('List of created release branches'),
155
- branchCount: z.number().describe('Number of branches created'),
156
- isCheckedOut: z.boolean().describe('Whether the branch was checked out'),
157
- releases: z
158
- .array(
159
- z.object({
160
- version: z.string().describe('Version number'),
161
- branchName: z.string().describe('Release branch name'),
162
- prUrl: z.string().describe('GitHub PR URL'),
163
- jiraVersionUrl: z.string().describe('Jira version URL'),
164
- }),
165
- )
166
- .describe('Detailed information for each created release with URLs only'),
167
- },
168
- handler: ghReleaseCreate,
169
- }
@@ -1 +0,0 @@
1
- export { ghReleaseCreate, ghReleaseCreateMcpTool } from './gh-release-create'
File without changes