infra-kit 0.1.50 → 0.1.52
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/.env.example +17 -0
- package/dist/cli.js +13 -12
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +13 -12
- package/dist/mcp.js.map +4 -4
- package/package.json +2 -1
- package/src/commands/gh-merge-dev/gh-merge-dev.ts +1 -1
- package/src/commands/gh-release-create/gh-release-create.ts +73 -31
- package/src/commands/gh-release-deliver/gh-release-deliver.ts +1 -1
- package/src/commands/gh-release-deploy/gh-release-deploy.ts +1 -1
- package/src/commands/gh-release-list/gh-release-list.ts +1 -1
- package/src/commands/worktrees-add/worktrees-add.ts +1 -1
- package/src/commands/worktrees-sync/worktrees-sync.ts +1 -1
- package/src/entry/cli.ts +5 -0
- package/src/entry/mcp.ts +7 -0
- package/src/{lib → integrations/gh}/gh-release-prs/gh-release-prs.ts +32 -0
- package/src/integrations/gh/gh-release-prs/index.ts +1 -0
- package/src/integrations/gh/index.ts +1 -0
- package/src/integrations/jira/api.ts +136 -0
- package/src/integrations/jira/index.ts +7 -0
- package/src/integrations/jira/types.ts +58 -0
- package/src/lib/load-env.ts +23 -0
- package/src/lib/gh-release-prs/index.ts +0 -1
|
@@ -4,7 +4,7 @@ import { z } from 'zod'
|
|
|
4
4
|
import { $ } from 'zx'
|
|
5
5
|
|
|
6
6
|
import { ENVs } from 'src/lib/constants'
|
|
7
|
-
import { getReleasePRs } from 'src/
|
|
7
|
+
import { getReleasePRs } from 'src/integrations/gh'
|
|
8
8
|
import { logger } from 'src/lib/logger'
|
|
9
9
|
import type { ToolsExecutionResult } from 'src/types'
|
|
10
10
|
|
|
@@ -5,7 +5,7 @@ import { z } from 'zod'
|
|
|
5
5
|
import { $ } from 'zx'
|
|
6
6
|
|
|
7
7
|
import { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'
|
|
8
|
-
import { getReleasePRs } from 'src/
|
|
8
|
+
import { getReleasePRs } from 'src/integrations/gh'
|
|
9
9
|
import { getCurrentWorktrees, getProjectRoot } from 'src/lib/git-utils'
|
|
10
10
|
import { logger } from 'src/lib/logger'
|
|
11
11
|
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
|
@@ -4,7 +4,7 @@ import { z } from 'zod'
|
|
|
4
4
|
import { $ } from 'zx'
|
|
5
5
|
|
|
6
6
|
import { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'
|
|
7
|
-
import { getReleasePRs } from 'src/
|
|
7
|
+
import { getReleasePRs } from 'src/integrations/gh'
|
|
8
8
|
import { getCurrentWorktrees, getProjectRoot } from 'src/lib/git-utils'
|
|
9
9
|
import { logger } from 'src/lib/logger'
|
|
10
10
|
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
package/src/entry/cli.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { loadEnvFromGitRoot } from 'src/lib/load-env'
|
|
2
|
+
|
|
1
3
|
import { Command } from 'commander'
|
|
2
4
|
|
|
3
5
|
// Commands
|
|
@@ -13,6 +15,9 @@ import { worktreesSync } from 'src/commands/worktrees-sync'
|
|
|
13
15
|
// Integrations
|
|
14
16
|
import { validateGitHubCliAndAuth } from 'src/integrations/gh'
|
|
15
17
|
|
|
18
|
+
// Load .env before anything else
|
|
19
|
+
await loadEnvFromGitRoot()
|
|
20
|
+
|
|
16
21
|
const program = new Command()
|
|
17
22
|
|
|
18
23
|
program
|
package/src/entry/mcp.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable antfu/no-top-level-await */
|
|
2
|
+
import { loadEnvFromGitRoot } from 'src/lib/load-env'
|
|
3
|
+
|
|
1
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
2
5
|
import process from 'node:process'
|
|
3
6
|
|
|
@@ -6,10 +9,14 @@ import { initLoggerMcp } from 'src/lib/logger'
|
|
|
6
9
|
|
|
7
10
|
import { createMcpServer } from '../mcp/server'
|
|
8
11
|
|
|
12
|
+
// Load .env before anything else
|
|
13
|
+
await loadEnvFromGitRoot()
|
|
14
|
+
|
|
9
15
|
const logger = initLoggerMcp()
|
|
10
16
|
|
|
11
17
|
const startServer = async () => {
|
|
12
18
|
let server
|
|
19
|
+
|
|
13
20
|
try {
|
|
14
21
|
server = await createMcpServer()
|
|
15
22
|
|
|
@@ -39,3 +39,35 @@ export const getReleasePRs = async (): Promise<string[]> => {
|
|
|
39
39
|
process.exit(1)
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
// Function to create a release branch
|
|
44
|
+
export const createReleaseBranch = async (
|
|
45
|
+
version: string,
|
|
46
|
+
): Promise<{ branchName: string; prUrl: string }> => {
|
|
47
|
+
const branchName = `release/v${version}`
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
await $`git switch dev`
|
|
51
|
+
await $`git pull origin dev`
|
|
52
|
+
await $`git checkout -b ${branchName}`
|
|
53
|
+
await $`git push -u origin ${branchName}`
|
|
54
|
+
await $`git commit --allow-empty-message --allow-empty --message ''`
|
|
55
|
+
await $`git push origin ${branchName}`
|
|
56
|
+
|
|
57
|
+
// Create PR and capture URL
|
|
58
|
+
const prResult =
|
|
59
|
+
await $`gh pr create --title "Release v${version}" --body "Release v${version}" --base dev --head ${branchName}`
|
|
60
|
+
|
|
61
|
+
const prLink = prResult.stdout.trim()
|
|
62
|
+
|
|
63
|
+
await $`git switch dev`
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
branchName,
|
|
67
|
+
prUrl: prLink,
|
|
68
|
+
}
|
|
69
|
+
} catch (error: unknown) {
|
|
70
|
+
logger.error({ error, branchName }, `Error creating release branch ${branchName}`)
|
|
71
|
+
throw error
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createReleaseBranch, getReleasePRs } from './gh-release-prs'
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
|
|
3
|
+
import { logger } from 'src/lib/logger'
|
|
4
|
+
import type {
|
|
5
|
+
CreateJiraVersionParams,
|
|
6
|
+
CreateJiraVersionResult,
|
|
7
|
+
JiraConfig,
|
|
8
|
+
JiraVersion,
|
|
9
|
+
} from './types.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new version in Jira using the REST API
|
|
13
|
+
* @param params - Version creation parameters
|
|
14
|
+
* @param config - Jira configuration (baseUrl, token, projectId)
|
|
15
|
+
* @returns Result containing created version or error
|
|
16
|
+
*/
|
|
17
|
+
export const createJiraVersion = async (
|
|
18
|
+
params: CreateJiraVersionParams,
|
|
19
|
+
config: JiraConfig,
|
|
20
|
+
): Promise<CreateJiraVersionResult> => {
|
|
21
|
+
try {
|
|
22
|
+
const { baseUrl, token, email, projectId } = config
|
|
23
|
+
|
|
24
|
+
// Use current date if not provided
|
|
25
|
+
// const releaseDate =
|
|
26
|
+
// params.releaseDate || new Date().toISOString().split('T')[0] // 2025-12-06
|
|
27
|
+
|
|
28
|
+
// Prepare request body
|
|
29
|
+
const requestBody = {
|
|
30
|
+
name: params.name,
|
|
31
|
+
projectId: params.projectId || projectId,
|
|
32
|
+
description: params.description || '',
|
|
33
|
+
// releaseDate,
|
|
34
|
+
released: params.released ?? true,
|
|
35
|
+
archived: params.archived ?? false,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// logger.info(
|
|
39
|
+
// { version: params.name, projectId: requestBody.projectId },
|
|
40
|
+
// 'Creating Jira version',
|
|
41
|
+
// )
|
|
42
|
+
|
|
43
|
+
// Make API request
|
|
44
|
+
const url = `${baseUrl}/rest/api/3/version`
|
|
45
|
+
|
|
46
|
+
// Create Basic auth credentials
|
|
47
|
+
const credentials = btoa(`${email}:${token}`)
|
|
48
|
+
|
|
49
|
+
const response = await fetch(url, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
Accept: 'application/json',
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
Authorization: `Basic ${credentials}`,
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify(requestBody),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const errorText = await response.text()
|
|
61
|
+
logger.error(
|
|
62
|
+
{
|
|
63
|
+
status: response.status,
|
|
64
|
+
statusText: response.statusText,
|
|
65
|
+
error: errorText,
|
|
66
|
+
},
|
|
67
|
+
'Failed to create Jira version',
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const version = (await response.json()) as JiraVersion
|
|
77
|
+
|
|
78
|
+
// logger.info(
|
|
79
|
+
// { versionId: version.id, versionName: version.name },
|
|
80
|
+
// 'Successfully created Jira version',
|
|
81
|
+
// )
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
success: true,
|
|
85
|
+
version,
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
logger.error({ error }, 'Error creating Jira version')
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: error instanceof Error ? error.message : String(error),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Loads Jira configuration from environment variables
|
|
99
|
+
* @returns Jira config if all required env vars are present, null otherwise
|
|
100
|
+
*/
|
|
101
|
+
export const loadJiraConfig = (): JiraConfig | null => {
|
|
102
|
+
const baseUrl = process.env.JIRA_BASE_URL
|
|
103
|
+
const token = process.env.JIRA_TOKEN || process.env.JIRA_API_TOKEN
|
|
104
|
+
const projectIdStr = process.env.JIRA_PROJECT_ID
|
|
105
|
+
const email = process.env.JIRA_EMAIL
|
|
106
|
+
|
|
107
|
+
if (!baseUrl || !token || !projectIdStr || !email) {
|
|
108
|
+
logger.debug(
|
|
109
|
+
{
|
|
110
|
+
hasBaseUrl: !!baseUrl,
|
|
111
|
+
hasToken: !!token,
|
|
112
|
+
hasProjectId: !!projectIdStr,
|
|
113
|
+
hasEmail: !!email,
|
|
114
|
+
},
|
|
115
|
+
'Jira configuration incomplete, skipping Jira integration',
|
|
116
|
+
)
|
|
117
|
+
return null
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const projectId = Number.parseInt(projectIdStr, 10)
|
|
121
|
+
|
|
122
|
+
if (Number.isNaN(projectId)) {
|
|
123
|
+
logger.warn(
|
|
124
|
+
{ projectIdStr },
|
|
125
|
+
'Invalid JIRA_PROJECT_ID (must be numeric), skipping Jira integration',
|
|
126
|
+
)
|
|
127
|
+
return null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
baseUrl: baseUrl.replace(/\/$/, ''), // Remove trailing slash
|
|
132
|
+
token,
|
|
133
|
+
projectId,
|
|
134
|
+
email,
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jira Version API types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface JiraVersion {
|
|
6
|
+
/** ID of the version */
|
|
7
|
+
id: string
|
|
8
|
+
/** URL of the version */
|
|
9
|
+
self: string
|
|
10
|
+
/** Name of the version */
|
|
11
|
+
name: string
|
|
12
|
+
/** Description of the version */
|
|
13
|
+
description?: string
|
|
14
|
+
/** Whether the version is archived */
|
|
15
|
+
archived: boolean
|
|
16
|
+
/** Whether the version is released */
|
|
17
|
+
released: boolean
|
|
18
|
+
/** Release date in ISO format (YYYY-MM-DD) */
|
|
19
|
+
releaseDate?: string
|
|
20
|
+
/** User-friendly release date */
|
|
21
|
+
userReleaseDate?: string
|
|
22
|
+
/** Project key */
|
|
23
|
+
project?: string
|
|
24
|
+
/** Project ID */
|
|
25
|
+
projectId: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CreateJiraVersionParams {
|
|
29
|
+
/** Name of the version (e.g., "v1.2.5") */
|
|
30
|
+
name: string
|
|
31
|
+
/** Project ID (numeric) */
|
|
32
|
+
projectId: number
|
|
33
|
+
/** Description of the version */
|
|
34
|
+
description?: string
|
|
35
|
+
/** Release date in ISO format (YYYY-MM-DD). Defaults to current date if not provided */
|
|
36
|
+
releaseDate?: string
|
|
37
|
+
/** Whether the version is released. Defaults to true */
|
|
38
|
+
released?: boolean
|
|
39
|
+
/** Whether the version is archived. Defaults to false */
|
|
40
|
+
archived?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface JiraConfig {
|
|
44
|
+
/** Jira base URL (e.g., https://your-domain.atlassian.net) */
|
|
45
|
+
baseUrl: string
|
|
46
|
+
/** Jira API token */
|
|
47
|
+
token: string
|
|
48
|
+
/** Jira project ID */
|
|
49
|
+
projectId: number
|
|
50
|
+
/** Email associated with Jira account (for Basic Auth) */
|
|
51
|
+
email: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface CreateJiraVersionResult {
|
|
55
|
+
success: boolean
|
|
56
|
+
version?: JiraVersion
|
|
57
|
+
error?: string
|
|
58
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { config } from 'dotenv'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { $ } from 'zx'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load .env file from git repository root
|
|
7
|
+
* Uses git rev-parse to find the repository root, works regardless of where package is installed
|
|
8
|
+
*/
|
|
9
|
+
export async function loadEnvFromGitRoot(): Promise<void> {
|
|
10
|
+
try {
|
|
11
|
+
$.quiet = true
|
|
12
|
+
|
|
13
|
+
const result = await $`git rev-parse --show-toplevel`
|
|
14
|
+
const gitRoot = result.stdout.trim()
|
|
15
|
+
|
|
16
|
+
config({ path: resolve(gitRoot, '.env') })
|
|
17
|
+
} catch {
|
|
18
|
+
// Git command failed - not in a git repository or git not available
|
|
19
|
+
// This is acceptable, env vars might be provided another way
|
|
20
|
+
} finally {
|
|
21
|
+
$.quiet = false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { getReleasePRs } from './gh-release-prs'
|