infra-kit 0.1.50 → 0.1.51
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 +13 -0
- package/dist/cli.js +12 -12
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +12 -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 +88 -10
- 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/integrations/gh/index.ts +1 -0
- package/src/integrations/jira/api.ts +132 -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 → integrations/gh}/gh-release-prs/gh-release-prs.ts +0 -0
- /package/src/{lib → integrations/gh}/gh-release-prs/index.ts +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infra-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.51",
|
|
5
5
|
"description": "infra-kit",
|
|
6
6
|
"main": "dist/cli.js",
|
|
7
7
|
"module": "dist/cli.js",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"@inquirer/select": "^5.0.2",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.24.2",
|
|
37
37
|
"commander": "^14.0.2",
|
|
38
|
+
"dotenv": "^17.2.3",
|
|
38
39
|
"pino": "^10.1.0",
|
|
39
40
|
"pino-pretty": "^13.1.3",
|
|
40
41
|
"zod": "^3.25.76",
|
|
@@ -4,7 +4,7 @@ import process from 'node:process'
|
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
import { $ } from 'zx'
|
|
6
6
|
|
|
7
|
-
import { getReleasePRs } from 'src/
|
|
7
|
+
import { getReleasePRs } from 'src/integrations/gh'
|
|
8
8
|
import { logger } from 'src/lib/logger'
|
|
9
9
|
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
|
10
10
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable sonarjs/cognitive-complexity */
|
|
1
2
|
import confirm from '@inquirer/confirm'
|
|
2
3
|
import process from 'node:process'
|
|
3
4
|
import { z } from 'zod'
|
|
@@ -5,6 +6,7 @@ import { $, question } from 'zx'
|
|
|
5
6
|
|
|
6
7
|
import { logger } from 'src/lib/logger'
|
|
7
8
|
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
|
9
|
+
import { createJiraVersion, loadJiraConfig } from 'src/integrations/jira'
|
|
8
10
|
|
|
9
11
|
interface GhReleaseCreateArgs extends RequiredConfirmedOptionArg {
|
|
10
12
|
versions: string
|
|
@@ -20,6 +22,20 @@ export const ghReleaseCreate = async (args: GhReleaseCreateArgs): Promise<ToolsE
|
|
|
20
22
|
let versionBranches = ''
|
|
21
23
|
let _checkout = checkout
|
|
22
24
|
|
|
25
|
+
// Load Jira config - it is now mandatory
|
|
26
|
+
const jiraConfig = loadJiraConfig()
|
|
27
|
+
|
|
28
|
+
if (!jiraConfig) {
|
|
29
|
+
logger.error('Jira configuration is required but not found.')
|
|
30
|
+
logger.error('Please configure the following environment variables in your .env file:')
|
|
31
|
+
logger.error(' - JIRA_BASE_URL (e.g., https://your-domain.atlassian.net)')
|
|
32
|
+
logger.error(' - JIRA_TOKEN (your Jira API token)')
|
|
33
|
+
logger.error(' - JIRA_PROJECT_ID (numeric project ID)')
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
logger.info('Jira integration enabled - versions will be created in Jira')
|
|
38
|
+
|
|
23
39
|
if (versions) {
|
|
24
40
|
versionBranches = versions
|
|
25
41
|
} else {
|
|
@@ -61,14 +77,56 @@ export const ghReleaseCreate = async (args: GhReleaseCreateArgs): Promise<ToolsE
|
|
|
61
77
|
$.quiet = true
|
|
62
78
|
|
|
63
79
|
await $`git fetch origin`
|
|
64
|
-
|
|
65
80
|
await $`git switch dev`
|
|
66
|
-
|
|
67
81
|
await $`git pull origin dev`
|
|
68
82
|
|
|
69
|
-
|
|
83
|
+
const releases: Array<{
|
|
84
|
+
version: string
|
|
85
|
+
branchName: string
|
|
86
|
+
prUrl: string
|
|
87
|
+
jiraVersionUrl: string
|
|
88
|
+
}> = []
|
|
89
|
+
|
|
70
90
|
for (const version of versionsList) {
|
|
71
|
-
|
|
91
|
+
// 1. Create GitHub release branch
|
|
92
|
+
const releaseInfo = await createReleaseBranch(version)
|
|
93
|
+
|
|
94
|
+
// 2. Create Jira version (mandatory)
|
|
95
|
+
const versionName = `v${version}`
|
|
96
|
+
|
|
97
|
+
const result = await createJiraVersion(
|
|
98
|
+
{
|
|
99
|
+
name: versionName,
|
|
100
|
+
projectId: jiraConfig.projectId,
|
|
101
|
+
description: ``,
|
|
102
|
+
released: false,
|
|
103
|
+
archived: false,
|
|
104
|
+
},
|
|
105
|
+
jiraConfig,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if (result.success) {
|
|
109
|
+
// Construct user-friendly Jira URL using project key from API response
|
|
110
|
+
const projectKey = result.version!.project
|
|
111
|
+
const jiraVersionUrl = projectKey
|
|
112
|
+
? `${jiraConfig.baseUrl}/projects/${projectKey}/versions/${result.version!.id}/tab/release-report-all-issues`
|
|
113
|
+
: ''
|
|
114
|
+
|
|
115
|
+
releases.push({
|
|
116
|
+
version,
|
|
117
|
+
branchName: releaseInfo.branchName,
|
|
118
|
+
prUrl: releaseInfo.prUrl,
|
|
119
|
+
jiraVersionUrl,
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
logger.info(`Successfully created release: ${versionName}`)
|
|
123
|
+
logger.info(` GitHub PR: ${releaseInfo.prUrl}`)
|
|
124
|
+
logger.info(` Jira Version: ${jiraVersionUrl}`)
|
|
125
|
+
} else {
|
|
126
|
+
logger.error(`✗ Failed to create Jira version for ${versionName}: ${result.error}`)
|
|
127
|
+
logger.error('Jira version creation is mandatory. Exiting...')
|
|
128
|
+
process.exit(1)
|
|
129
|
+
}
|
|
72
130
|
}
|
|
73
131
|
|
|
74
132
|
// If checkout option is enabled and we created only one branch, checkout to it
|
|
@@ -90,6 +148,7 @@ export const ghReleaseCreate = async (args: GhReleaseCreateArgs): Promise<ToolsE
|
|
|
90
148
|
createdBranches: versionsList.map((version) => `release/v${version}`),
|
|
91
149
|
branchCount: versionsList.length,
|
|
92
150
|
isCheckedOut,
|
|
151
|
+
releases,
|
|
93
152
|
}
|
|
94
153
|
|
|
95
154
|
return {
|
|
@@ -106,25 +165,34 @@ export const ghReleaseCreate = async (args: GhReleaseCreateArgs): Promise<ToolsE
|
|
|
106
165
|
// #region Declarations
|
|
107
166
|
|
|
108
167
|
// Function to create a release branch
|
|
109
|
-
async function createReleaseBranch(
|
|
168
|
+
async function createReleaseBranch(
|
|
169
|
+
version: string,
|
|
170
|
+
): Promise<{ branchName: string; prUrl: string }> {
|
|
110
171
|
const branchName = `release/v${version}`
|
|
111
172
|
|
|
112
173
|
try {
|
|
113
174
|
await $`git switch dev`
|
|
114
175
|
await $`git pull origin dev`
|
|
115
|
-
|
|
116
176
|
await $`git checkout -b ${branchName}`
|
|
117
177
|
await $`git push -u origin ${branchName}`
|
|
118
178
|
await $`git commit --allow-empty-message --allow-empty --message ''`
|
|
119
179
|
await $`git push origin ${branchName}`
|
|
120
180
|
|
|
121
|
-
// Create PR
|
|
122
|
-
|
|
181
|
+
// Create PR and capture URL
|
|
182
|
+
const prResult =
|
|
183
|
+
await $`gh pr create --title "Release v${version}" --body "Release v${version}" --base dev --head ${branchName} --json url`
|
|
184
|
+
|
|
185
|
+
const prData = JSON.parse(prResult.stdout)
|
|
123
186
|
|
|
124
187
|
await $`git switch dev`
|
|
125
|
-
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
branchName,
|
|
191
|
+
prUrl: prData.url,
|
|
192
|
+
}
|
|
126
193
|
} catch (error: unknown) {
|
|
127
194
|
logger.error({ error, branchName }, `Error creating release branch ${branchName}`)
|
|
195
|
+
throw error
|
|
128
196
|
}
|
|
129
197
|
}
|
|
130
198
|
// #endregion Declarations
|
|
@@ -132,7 +200,7 @@ async function createReleaseBranch(version: string) {
|
|
|
132
200
|
// MCP Tool Registration
|
|
133
201
|
export const ghReleaseCreateMcpTool = {
|
|
134
202
|
name: 'gh-release-create',
|
|
135
|
-
description: 'Create new release branches for specified versions',
|
|
203
|
+
description: 'Create new release branches for specified versions and optionally create Jira versions',
|
|
136
204
|
inputSchema: {
|
|
137
205
|
versions: z.string().describe('Comma-separated list of versions to create (e.g., "1.2.5, 1.2.6")'),
|
|
138
206
|
checkout: z.boolean().optional().describe('Checkout to the created branch (only works with single version)'),
|
|
@@ -141,6 +209,16 @@ export const ghReleaseCreateMcpTool = {
|
|
|
141
209
|
createdBranches: z.array(z.string()).describe('List of created release branches'),
|
|
142
210
|
branchCount: z.number().describe('Number of branches created'),
|
|
143
211
|
isCheckedOut: z.boolean().describe('Whether the branch was checked out'),
|
|
212
|
+
releases: z
|
|
213
|
+
.array(
|
|
214
|
+
z.object({
|
|
215
|
+
version: z.string().describe('Version number'),
|
|
216
|
+
branchName: z.string().describe('Release branch name'),
|
|
217
|
+
prUrl: z.string().describe('GitHub PR URL'),
|
|
218
|
+
jiraVersionUrl: z.string().describe('Jira version URL'),
|
|
219
|
+
}),
|
|
220
|
+
)
|
|
221
|
+
.describe('Detailed information for each created release with URLs only'),
|
|
144
222
|
},
|
|
145
223
|
handler: ghReleaseCreate,
|
|
146
224
|
}
|
|
@@ -4,7 +4,7 @@ import process from 'node:process'
|
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
import { $ } from 'zx'
|
|
6
6
|
|
|
7
|
-
import { getReleasePRs } from 'src/
|
|
7
|
+
import { getReleasePRs } from 'src/integrations/gh'
|
|
8
8
|
import { logger } from 'src/lib/logger'
|
|
9
9
|
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
|
10
10
|
|
|
@@ -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
|
|
|
@@ -0,0 +1,132 @@
|
|
|
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 async function createJiraVersion(
|
|
18
|
+
params: CreateJiraVersionParams,
|
|
19
|
+
config: JiraConfig,
|
|
20
|
+
): Promise<CreateJiraVersionResult> {
|
|
21
|
+
try {
|
|
22
|
+
const { baseUrl, token, projectId } = config
|
|
23
|
+
|
|
24
|
+
// Use current date if not provided
|
|
25
|
+
const releaseDate =
|
|
26
|
+
params.releaseDate || new Date().toISOString().split('T')[0]
|
|
27
|
+
|
|
28
|
+
// Prepare request body
|
|
29
|
+
const requestBody = {
|
|
30
|
+
name: params.name,
|
|
31
|
+
projectId: params.projectId || projectId,
|
|
32
|
+
description: params.description || `Release version ${params.name}`,
|
|
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
|
+
const response = await fetch(url, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
Accept: 'application/json',
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
Authorization: `Bearer ${token}`,
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify(requestBody),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const errorText = await response.text()
|
|
58
|
+
logger.error(
|
|
59
|
+
{
|
|
60
|
+
status: response.status,
|
|
61
|
+
statusText: response.statusText,
|
|
62
|
+
error: errorText,
|
|
63
|
+
},
|
|
64
|
+
'Failed to create Jira version',
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const version = (await response.json()) as JiraVersion
|
|
74
|
+
|
|
75
|
+
logger.info(
|
|
76
|
+
{ versionId: version.id, versionName: version.name },
|
|
77
|
+
'Successfully created Jira version',
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
success: true,
|
|
82
|
+
version,
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
logger.error({ error }, 'Error creating Jira version')
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
error: error instanceof Error ? error.message : String(error),
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Loads Jira configuration from environment variables
|
|
96
|
+
* @returns Jira config if all required env vars are present, null otherwise
|
|
97
|
+
*/
|
|
98
|
+
export function loadJiraConfig(): JiraConfig | null {
|
|
99
|
+
const baseUrl = process.env.JIRA_BASE_URL
|
|
100
|
+
const token = process.env.JIRA_TOKEN || process.env.JIRA_API_TOKEN
|
|
101
|
+
const projectIdStr = process.env.JIRA_PROJECT_ID
|
|
102
|
+
const email = process.env.JIRA_EMAIL
|
|
103
|
+
|
|
104
|
+
if (!baseUrl || !token || !projectIdStr) {
|
|
105
|
+
logger.debug(
|
|
106
|
+
{
|
|
107
|
+
hasBaseUrl: !!baseUrl,
|
|
108
|
+
hasToken: !!token,
|
|
109
|
+
hasProjectId: !!projectIdStr,
|
|
110
|
+
},
|
|
111
|
+
'Jira configuration incomplete, skipping Jira integration',
|
|
112
|
+
)
|
|
113
|
+
return null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const projectId = Number.parseInt(projectIdStr, 10)
|
|
117
|
+
|
|
118
|
+
if (Number.isNaN(projectId)) {
|
|
119
|
+
logger.warn(
|
|
120
|
+
{ projectIdStr },
|
|
121
|
+
'Invalid JIRA_PROJECT_ID (must be numeric), skipping Jira integration',
|
|
122
|
+
)
|
|
123
|
+
return null
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
baseUrl: baseUrl.replace(/\/$/, ''), // Remove trailing slash
|
|
128
|
+
token,
|
|
129
|
+
projectId,
|
|
130
|
+
email,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -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
|
+
}
|
|
File without changes
|
|
File without changes
|