ya-git-jira 1.5.0 → 2.0.0
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/.opencode/skills/architecture/SKILL.md +45 -0
- package/.opencode/skills/code-style/SKILL.md +76 -0
- package/.opencode/skills/git-confluence/SKILL.md +82 -0
- package/.opencode/skills/git-jira/SKILL.md +63 -0
- package/.opencode/skills/git-lab/SKILL.md +102 -0
- package/AGENTS.md +50 -0
- package/README.md +121 -71
- package/bin/git-api.ts +70 -0
- package/bin/git-confluence-page-search.ts +58 -0
- package/bin/git-confluence-page-show.ts +61 -0
- package/bin/git-confluence-page-update.ts +77 -0
- package/bin/git-confluence-page.ts +28 -0
- package/bin/git-confluence-space-list.ts +34 -0
- package/bin/git-confluence-space.ts +24 -0
- package/bin/git-confluence-whoami.ts +33 -0
- package/bin/git-confluence.ts +27 -0
- package/bin/git-jira-start.ts +1 -1
- package/bin/git-jira-whoami.ts +32 -0
- package/bin/git-jira.ts +2 -0
- package/bin/git-lab-project-mr-list.ts +57 -0
- package/bin/git-lab-project-mr.ts +24 -0
- package/bin/git-lab-project-pipeline-jobs.ts +46 -0
- package/bin/git-lab-project-pipeline-latest.ts +47 -0
- package/bin/git-lab-project-pipeline-log.ts +49 -0
- package/bin/git-lab-project-pipeline.ts +6 -0
- package/bin/git-lab-project.ts +5 -1
- package/bin/gitj-install-skills.ts +126 -0
- package/bin/gitj.ts +12 -0
- package/dist/bin/git-api.js +2156 -0
- package/dist/bin/git-bump.js +136 -125
- package/dist/bin/git-confluence-page-search.js +2079 -0
- package/dist/bin/{git-lab-projects.js → git-confluence-page-show.js} +294 -250
- package/dist/bin/{git-lab-projects-whereami.js → git-confluence-page-update.js} +300 -206
- package/dist/bin/git-confluence-page.js +2186 -0
- package/dist/bin/{git-lab-groups.js → git-confluence-space-list.js} +279 -210
- package/dist/bin/git-confluence-space.js +2073 -0
- package/dist/bin/git-confluence-whoami.js +2060 -0
- package/dist/bin/git-confluence.js +2251 -0
- package/dist/bin/git-jira-issue-list.js +144 -129
- package/dist/bin/git-jira-issue-show.js +144 -129
- package/dist/bin/git-jira-issue.js +148 -133
- package/dist/bin/git-jira-start.js +146 -131
- package/dist/bin/{git-lab-namespaces.js → git-jira-whoami.js} +214 -226
- package/dist/bin/git-jira.js +178 -143
- package/dist/bin/git-lab-group-list.js +326 -394
- package/dist/bin/git-lab-group.js +328 -396
- package/dist/bin/git-lab-merge-active.js +326 -394
- package/dist/bin/git-lab-merge-todo.js +326 -394
- package/dist/bin/git-lab-merge-train-list.js +294 -388
- package/dist/bin/git-lab-merge-train.js +296 -390
- package/dist/bin/git-lab-merge.js +335 -403
- package/dist/bin/git-lab-namespace-list.js +145 -135
- package/dist/bin/git-lab-namespace.js +147 -137
- package/dist/bin/git-lab-project-list.js +293 -387
- package/dist/bin/git-lab-project-mr-list.js +2740 -0
- package/dist/bin/git-lab-project-mr.js +2752 -0
- package/dist/bin/git-lab-project-pipeline-jobs.js +2734 -0
- package/dist/bin/git-lab-project-pipeline-latest.js +2736 -0
- package/dist/bin/git-lab-project-pipeline-list.js +328 -396
- package/dist/bin/git-lab-project-pipeline-log.js +2739 -0
- package/dist/bin/git-lab-project-pipeline.js +442 -407
- package/dist/bin/git-lab-project-whereami.js +297 -391
- package/dist/bin/git-lab-project.js +568 -403
- package/dist/bin/git-lab-whoami.js +149 -139
- package/dist/bin/git-lab.js +581 -454
- package/dist/bin/{git-lab-projects-list.js → gitj-install-skills.js} +226 -268
- package/dist/bin/gitj.js +1384 -578
- package/dist/index.js +379 -300
- package/index.ts +1 -0
- package/lib/api.ts +177 -0
- package/lib/confluence/api.ts +132 -0
- package/lib/confluence/config.ts +25 -0
- package/lib/confluence/index.ts +3 -0
- package/lib/confluence/types.ts +59 -0
- package/lib/git.ts +3 -3
- package/lib/gitlab/config.ts +5 -5
- package/lib/gitlab/index.ts +1 -0
- package/lib/gitlab/job.ts +31 -0
- package/lib/gitlab/merge-request.ts +20 -0
- package/lib/gitlab/pipeline.ts +28 -1
- package/lib/gitlab/project.ts +14 -5
- package/lib/help.ts +40 -0
- package/lib/jira.ts +11 -6
- package/lib/spawn.ts +3 -3
- package/package.json +18 -2
- package/tests/all-help.test.ts +6 -1
- package/tests/gitj.test.ts +1 -1
- package/tests/help-all.test.ts +29 -0
- package/bun.lockb +0 -0
package/bin/git-api.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import { apiRequest, apiPaginate, serviceNames } from '../lib/api.ts'
|
|
7
|
+
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
const httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
|
|
11
|
+
|
|
12
|
+
export function create(): Command {
|
|
13
|
+
const program: Command = new Command()
|
|
14
|
+
program
|
|
15
|
+
.version(version)
|
|
16
|
+
.name('api')
|
|
17
|
+
.description('make an authenticated API request')
|
|
18
|
+
.argument('<service>', `service name (${serviceNames.join(', ')})`)
|
|
19
|
+
.argument('<endpoint>', 'API endpoint path (e.g. /user, /myself)')
|
|
20
|
+
.option('-X, --method <method>', 'HTTP method (default: GET, auto-promotes to POST with --data)')
|
|
21
|
+
.option('-d, --data <json>', 'request body as JSON string')
|
|
22
|
+
.option('--raw', 'don\'t prepend the default base path')
|
|
23
|
+
.option('--paginate', 'follow pagination links and return all results')
|
|
24
|
+
.option('-v, --verbose', 'show response status and headers on stderr')
|
|
25
|
+
.action(async (service: string, endpoint: string, options) => {
|
|
26
|
+
let method = options.method?.toUpperCase() ?? (options.data ? 'POST' : 'GET')
|
|
27
|
+
if (!httpMethods.includes(method)) {
|
|
28
|
+
console.error(`Unknown HTTP method: ${method}`)
|
|
29
|
+
process.exit(1)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (options.paginate && method !== 'GET') {
|
|
33
|
+
console.error('--paginate only works with GET requests')
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const requestOptions = {
|
|
38
|
+
raw: options.raw,
|
|
39
|
+
data: options.data,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let result
|
|
43
|
+
if (options.paginate) {
|
|
44
|
+
result = await apiPaginate(service, endpoint, requestOptions)
|
|
45
|
+
} else {
|
|
46
|
+
result = await apiRequest(service, method, endpoint, requestOptions)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (options.verbose) {
|
|
50
|
+
console.error(`HTTP ${result.status}`)
|
|
51
|
+
result.headers.forEach((value, key) => {
|
|
52
|
+
console.error(`${key}: ${value}`)
|
|
53
|
+
})
|
|
54
|
+
console.error('')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(JSON.stringify(result.body, null, 2))
|
|
58
|
+
|
|
59
|
+
if (result.status >= 400) {
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
return program
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default create
|
|
67
|
+
|
|
68
|
+
if (isMain('git-api')) {
|
|
69
|
+
await create().parseAsync(Bun.argv)
|
|
70
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { confluenceApi, confluenceSearch } from '../lib/confluence'
|
|
6
|
+
import { getConfluenceConfig } from '../lib/confluence'
|
|
7
|
+
import type { Page, SearchResult } from '../lib/confluence'
|
|
8
|
+
import { isMain } from '../lib/is_main'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('search')
|
|
16
|
+
.description('Search for Confluence pages by title (fuzzy by default)')
|
|
17
|
+
.argument('query', 'Search query')
|
|
18
|
+
.option('-v, --verbose', 'Verbose output')
|
|
19
|
+
.option('--exact', 'Exact title match (uses v2 API)')
|
|
20
|
+
.option('--full-text', 'Search page body content in addition to title')
|
|
21
|
+
.action(async (query: string, options) => {
|
|
22
|
+
const { host } = await getConfluenceConfig()
|
|
23
|
+
|
|
24
|
+
if (options.exact) {
|
|
25
|
+
const pages = await confluenceApi(`pages?title=${encodeURIComponent(query)}`) as Array<Page>
|
|
26
|
+
if (options.verbose) {
|
|
27
|
+
console.log(pages)
|
|
28
|
+
} else {
|
|
29
|
+
for (const page of pages) {
|
|
30
|
+
const url = `https://${host}/wiki/spaces/${page.spaceId}/pages/${page.id}`
|
|
31
|
+
console.log(`${page.id}\t${page.title}\t${url}`)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const field = options.fullText ? 'text' : 'title'
|
|
38
|
+
const cql = `type=page AND ${field} ~ "${query}"`
|
|
39
|
+
const results = await confluenceSearch(cql) as Array<SearchResult>
|
|
40
|
+
if (options.verbose) {
|
|
41
|
+
console.log(results)
|
|
42
|
+
} else {
|
|
43
|
+
for (const result of results) {
|
|
44
|
+
const id = result.content.id
|
|
45
|
+
const title = result.content.title
|
|
46
|
+
const url = `https://${host}${result.url}`
|
|
47
|
+
console.log(`${id}\t${title}\t${url}`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
return program
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default create
|
|
55
|
+
|
|
56
|
+
if (isMain('git-confluence-page-search')) {
|
|
57
|
+
await create().parseAsync(Bun.argv)
|
|
58
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { confluenceApi } from '../lib/confluence'
|
|
6
|
+
import { getConfluenceConfig } from '../lib/confluence'
|
|
7
|
+
import type { Page } from '../lib/confluence'
|
|
8
|
+
import { isMain } from '../lib/is_main'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('show')
|
|
16
|
+
.description('Show information about a Confluence page')
|
|
17
|
+
.argument('id', 'Page ID')
|
|
18
|
+
.option('-v, --verbose', 'Verbose output')
|
|
19
|
+
.option('-b, --body-format <format>', 'Include page body (storage or atlas_doc_format)')
|
|
20
|
+
.option('--body-only', 'Output only the body content value (requires --body-format)')
|
|
21
|
+
.action(async (id: string, options) => {
|
|
22
|
+
let endpoint = `pages/${id}`
|
|
23
|
+
if (options.bodyFormat) {
|
|
24
|
+
endpoint += `?body-format=${options.bodyFormat}`
|
|
25
|
+
}
|
|
26
|
+
const page = await confluenceApi(endpoint) as Page
|
|
27
|
+
if (options.bodyOnly) {
|
|
28
|
+
if (!options.bodyFormat) {
|
|
29
|
+
console.error('--body-only requires --body-format')
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
32
|
+
const body = page.body
|
|
33
|
+
const content = options.bodyFormat === 'storage'
|
|
34
|
+
? body?.storage?.value
|
|
35
|
+
: body?.atlas_doc_format?.value
|
|
36
|
+
if (content) {
|
|
37
|
+
console.log(content)
|
|
38
|
+
} else {
|
|
39
|
+
console.error('No body content returned')
|
|
40
|
+
process.exit(1)
|
|
41
|
+
}
|
|
42
|
+
} else if (options.verbose) {
|
|
43
|
+
console.log(page)
|
|
44
|
+
} else {
|
|
45
|
+
const { host } = await getConfluenceConfig()
|
|
46
|
+
const url = `https://${host}/wiki/spaces/${page.spaceId}/pages/${page.id}`
|
|
47
|
+
const result: Record<string, unknown> = { id: page.id, title: page.title, spaceId: page.spaceId, url }
|
|
48
|
+
if (page.body?.storage?.value) {
|
|
49
|
+
result.bodyLength = page.body.storage.value.length
|
|
50
|
+
}
|
|
51
|
+
console.log(result)
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
return program
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default create
|
|
58
|
+
|
|
59
|
+
if (isMain('git-confluence-page-show')) {
|
|
60
|
+
await create().parseAsync(Bun.argv)
|
|
61
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { confluenceApi, confluenceApiWrite } from '../lib/confluence'
|
|
6
|
+
import type { Page } from '../lib/confluence'
|
|
7
|
+
import type { JSONValue } from '../lib/json'
|
|
8
|
+
import { isMain } from '../lib/is_main'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
async function readStdin(): Promise<string> {
|
|
12
|
+
const chunks: Buffer[] = []
|
|
13
|
+
for await (const chunk of Bun.stdin.stream()) {
|
|
14
|
+
chunks.push(Buffer.from(chunk))
|
|
15
|
+
}
|
|
16
|
+
return Buffer.concat(chunks).toString('utf-8')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function create(): Command {
|
|
20
|
+
const program: Command = new Command()
|
|
21
|
+
program
|
|
22
|
+
.version(version)
|
|
23
|
+
.name('update')
|
|
24
|
+
.description('Update a Confluence page')
|
|
25
|
+
.argument('id', 'Page ID')
|
|
26
|
+
.option('-t, --title <title>', 'New page title (defaults to current title)')
|
|
27
|
+
.option('-f, --file <path>', 'Read body content from file (default: stdin)')
|
|
28
|
+
.option('-m, --message <message>', 'Version message')
|
|
29
|
+
.option('-v, --verbose', 'Verbose output')
|
|
30
|
+
.action(async (id: string, options) => {
|
|
31
|
+
const current = await confluenceApi(`pages/${id}`) as Page
|
|
32
|
+
|
|
33
|
+
let content: string
|
|
34
|
+
if (options.file) {
|
|
35
|
+
const file = Bun.file(options.file)
|
|
36
|
+
content = await file.text()
|
|
37
|
+
} else {
|
|
38
|
+
content = await readStdin()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!content.trim()) {
|
|
42
|
+
console.error('No content provided. Pipe content via stdin or use --file.')
|
|
43
|
+
process.exit(1)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const title = options.title || current.title
|
|
47
|
+
const nextVersion = current.version.number + 1
|
|
48
|
+
|
|
49
|
+
const body: JSONValue = {
|
|
50
|
+
id,
|
|
51
|
+
status: 'current',
|
|
52
|
+
title,
|
|
53
|
+
body: {
|
|
54
|
+
representation: 'storage',
|
|
55
|
+
value: content,
|
|
56
|
+
},
|
|
57
|
+
version: {
|
|
58
|
+
number: nextVersion,
|
|
59
|
+
message: options.message || '',
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const result = await confluenceApiWrite(`pages/${id}`, 'PUT', body) as Page
|
|
64
|
+
if (options.verbose) {
|
|
65
|
+
console.log(result)
|
|
66
|
+
} else {
|
|
67
|
+
console.log(`Updated page ${result.id} "${result.title}" to version ${result.version.number}`)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
return program
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default create
|
|
74
|
+
|
|
75
|
+
if (isMain('git-confluence-page-update')) {
|
|
76
|
+
await create().parseAsync(Bun.argv)
|
|
77
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import search from './git-confluence-page-search'
|
|
7
|
+
import show from './git-confluence-page-show'
|
|
8
|
+
import update from './git-confluence-page-update'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('page')
|
|
16
|
+
.description('Commands for working with Confluence pages')
|
|
17
|
+
.addCommand(search())
|
|
18
|
+
.addCommand(show())
|
|
19
|
+
.addCommand(update())
|
|
20
|
+
.action(() => program.help())
|
|
21
|
+
return program
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default create
|
|
25
|
+
|
|
26
|
+
if (isMain('git-confluence-page')) {
|
|
27
|
+
await create().parseAsync(Bun.argv)
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { confluenceApi } from '../lib/confluence'
|
|
6
|
+
import type { Space } from '../lib/confluence'
|
|
7
|
+
import { isMain } from '../lib/is_main'
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('list')
|
|
15
|
+
.description('List Confluence spaces')
|
|
16
|
+
.option('-v, --verbose', 'Verbose output')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const spaces = await confluenceApi('spaces') as Array<Space>
|
|
19
|
+
if (options.verbose) {
|
|
20
|
+
console.log(spaces)
|
|
21
|
+
} else {
|
|
22
|
+
for (const space of spaces) {
|
|
23
|
+
console.log(`${space.key}\t${space.name}`)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
return program
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default create
|
|
31
|
+
|
|
32
|
+
if (isMain('git-confluence-space-list')) {
|
|
33
|
+
await create().parseAsync(Bun.argv)
|
|
34
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import list from './git-confluence-space-list'
|
|
7
|
+
const version = await getPackageVersion()
|
|
8
|
+
|
|
9
|
+
export function create(): Command {
|
|
10
|
+
const program: Command = new Command()
|
|
11
|
+
program
|
|
12
|
+
.version(version)
|
|
13
|
+
.name('space')
|
|
14
|
+
.description('Commands for working with Confluence spaces')
|
|
15
|
+
.addCommand(list())
|
|
16
|
+
.action(() => program.help())
|
|
17
|
+
return program
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default create
|
|
21
|
+
|
|
22
|
+
if (isMain('git-confluence-space')) {
|
|
23
|
+
await create().parseAsync(Bun.argv)
|
|
24
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { confluenceApiV1 } from '../lib/confluence'
|
|
6
|
+
import type { ConfluenceUser } from '../lib/confluence'
|
|
7
|
+
import { isMain } from '../lib/is_main'
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('whoami')
|
|
15
|
+
.description('Show the current Confluence user')
|
|
16
|
+
.option('-v, --verbose', 'Verbose output')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const myself = await confluenceApiV1('user/current') as ConfluenceUser
|
|
19
|
+
if (options.verbose) {
|
|
20
|
+
console.log(myself)
|
|
21
|
+
} else {
|
|
22
|
+
const { displayName, email, accountId } = myself
|
|
23
|
+
console.log({ displayName, email, accountId })
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
return program
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default create
|
|
30
|
+
|
|
31
|
+
if (isMain('git-confluence-whoami')) {
|
|
32
|
+
await create().parseAsync(Bun.argv)
|
|
33
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import whoami from './git-confluence-whoami'
|
|
7
|
+
import space from './git-confluence-space'
|
|
8
|
+
import page from './git-confluence-page'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('confluence')
|
|
16
|
+
.description('Commands for working with Confluence')
|
|
17
|
+
.addCommand(whoami())
|
|
18
|
+
.addCommand(space())
|
|
19
|
+
.addCommand(page())
|
|
20
|
+
return program
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default create
|
|
24
|
+
|
|
25
|
+
if (isMain('git-confluence')) {
|
|
26
|
+
await create().parseAsync(Bun.argv)
|
|
27
|
+
}
|
package/bin/git-jira-start.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { isMain } from '../lib/is_main'
|
|
|
8
8
|
const version = await getPackageVersion()
|
|
9
9
|
|
|
10
10
|
function toKebab(s: string): string {
|
|
11
|
-
return s.replace(/([a-z]+)([A-Z]+)/g, "$
|
|
11
|
+
return s.replace(/([a-z]+)([A-Z]+)/g, "$1_$2").toLowerCase()
|
|
12
12
|
.replace(/(\W+)/g, "-")
|
|
13
13
|
.replace(/-$/, "")
|
|
14
14
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getMyself } from '../lib/jira'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
const version = await getPackageVersion()
|
|
8
|
+
|
|
9
|
+
export function create(): Command {
|
|
10
|
+
const program: Command = new Command()
|
|
11
|
+
program
|
|
12
|
+
.version(version)
|
|
13
|
+
.name('whoami')
|
|
14
|
+
.description('Show the current Jira user')
|
|
15
|
+
.option('-v, --verbose', 'Verbose output')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
const myself = await getMyself()
|
|
18
|
+
if (options.verbose) {
|
|
19
|
+
console.log(myself)
|
|
20
|
+
} else {
|
|
21
|
+
const { displayName, emailAddress, accountId } = myself as any
|
|
22
|
+
console.log({ displayName, emailAddress, accountId })
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
return program
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default create
|
|
29
|
+
|
|
30
|
+
if (isMain('git-jira-whoami')) {
|
|
31
|
+
await create().parseAsync(Bun.argv)
|
|
32
|
+
}
|
package/bin/git-jira.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { isMain } from '../lib/is_main'
|
|
|
6
6
|
import start from './git-jira-start'
|
|
7
7
|
import issue from './git-jira-issue'
|
|
8
8
|
import issues from './git-jira-issue-list'
|
|
9
|
+
import whoami from './git-jira-whoami'
|
|
9
10
|
const version = await getPackageVersion()
|
|
10
11
|
|
|
11
12
|
export function create(): Command {
|
|
@@ -17,6 +18,7 @@ export function create(): Command {
|
|
|
17
18
|
.addCommand(start())
|
|
18
19
|
.addCommand(issue())
|
|
19
20
|
.addCommand(issues())
|
|
21
|
+
.addCommand(whoami())
|
|
20
22
|
return program
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getMergeRequestsByBranch, type MergeRequest } from "../lib/gitlab"
|
|
6
|
+
import { findProject } from '../lib/gitlab/project'
|
|
7
|
+
import { getRemote, getCurrentBranch } from '../lib/git'
|
|
8
|
+
import { isMain } from '../lib/is_main'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('list')
|
|
16
|
+
.description('List open merge requests for a project and branch')
|
|
17
|
+
.option('-v, --verbose', 'Verbose output')
|
|
18
|
+
.option('-p, --project <path>', 'Project path (e.g. etagen-internal/eta-lib/base). Defaults to current directory remote.')
|
|
19
|
+
.option('-b, --branch <branch>', 'Source branch to filter on. Defaults to current branch.')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
let projectPath = options.project
|
|
22
|
+
if (!projectPath) {
|
|
23
|
+
const remote = await getRemote()
|
|
24
|
+
const project = await findProject(remote)
|
|
25
|
+
if (!project) {
|
|
26
|
+
console.error(`Could not resolve project from remote: ${remote}`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
projectPath = project.path_with_namespace
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const branch = options.branch || await getCurrentBranch()
|
|
33
|
+
|
|
34
|
+
const mrs: Array<MergeRequest> = await getMergeRequestsByBranch(projectPath, branch)
|
|
35
|
+
if (!mrs.length) {
|
|
36
|
+
console.error(`No open MRs for branch '${branch}' in ${projectPath}`)
|
|
37
|
+
process.exit(0)
|
|
38
|
+
}
|
|
39
|
+
if (options.verbose) {
|
|
40
|
+
console.log(mrs)
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const filtered = mrs.map(m => {
|
|
44
|
+
const { iid, title, web_url, source_branch, target_branch, state, draft } = m
|
|
45
|
+
return { iid, title, web_url, source_branch, target_branch, state, draft }
|
|
46
|
+
})
|
|
47
|
+
console.log(filtered)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
return program
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default create
|
|
54
|
+
|
|
55
|
+
if (isMain('git-lab-project-mr-list')) {
|
|
56
|
+
await create().parseAsync(Bun.argv)
|
|
57
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import list from './git-lab-project-mr-list'
|
|
7
|
+
const version = await getPackageVersion()
|
|
8
|
+
|
|
9
|
+
export function create(): Command {
|
|
10
|
+
const program: Command = new Command()
|
|
11
|
+
program
|
|
12
|
+
.version(version)
|
|
13
|
+
.name('mr')
|
|
14
|
+
.description('Commands for working with merge requests')
|
|
15
|
+
.addCommand(list())
|
|
16
|
+
.action(() => program.help())
|
|
17
|
+
return program
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default create
|
|
21
|
+
|
|
22
|
+
if (isMain('git-lab-project-mr')) {
|
|
23
|
+
await create().parseAsync(Bun.argv)
|
|
24
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getPipelineJobs, type Job } from '../lib/gitlab'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('jobs')
|
|
15
|
+
.description('List jobs for a pipeline')
|
|
16
|
+
.requiredOption('-p, --pipeline <id>', 'Pipeline ID')
|
|
17
|
+
.option('-v, --verbose', 'Verbose output')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const pipelineId = parseInt(options.pipeline, 10)
|
|
20
|
+
if (isNaN(pipelineId)) {
|
|
21
|
+
console.error(`Invalid pipeline ID: ${options.pipeline}`)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
const jobs: Array<Job> = await getPipelineJobs(pipelineId)
|
|
25
|
+
if (!jobs || jobs.length === 0) {
|
|
26
|
+
console.error(`No jobs found for pipeline ${pipelineId}`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
if (options.verbose) {
|
|
30
|
+
console.log(JSON.stringify(jobs, null, 2))
|
|
31
|
+
} else {
|
|
32
|
+
const filtered = jobs.map((j: Job) => {
|
|
33
|
+
const { id, name, stage, status, duration, failure_reason } = j
|
|
34
|
+
return { id, name, stage, status, duration, failure_reason }
|
|
35
|
+
})
|
|
36
|
+
console.log(JSON.stringify(filtered, null, 2))
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
return program
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default create
|
|
43
|
+
|
|
44
|
+
if (isMain('git-lab-project-pipeline-jobs')) {
|
|
45
|
+
await create().parseAsync(Bun.argv)
|
|
46
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getLatestPipeline, type Pipeline, getPipelineJobs, type Job } from '../lib/gitlab'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('latest')
|
|
15
|
+
.description('Show jobs for the latest pipeline on the current branch')
|
|
16
|
+
.option('-v, --verbose', 'Verbose output')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const pipeline: Pipeline | undefined = await getLatestPipeline()
|
|
19
|
+
if (!pipeline) {
|
|
20
|
+
console.error('No pipeline found for the current branch')
|
|
21
|
+
process.exit(1)
|
|
22
|
+
}
|
|
23
|
+
const { id, status, ref, web_url } = pipeline
|
|
24
|
+
console.log(JSON.stringify({ id, status, ref, web_url }, null, 2))
|
|
25
|
+
const jobs: Array<Job> = await getPipelineJobs(pipeline.id)
|
|
26
|
+
if (!jobs || jobs.length === 0) {
|
|
27
|
+
console.error(`No jobs found for pipeline ${pipeline.id}`)
|
|
28
|
+
process.exit(1)
|
|
29
|
+
}
|
|
30
|
+
if (options.verbose) {
|
|
31
|
+
console.log(JSON.stringify(jobs, null, 2))
|
|
32
|
+
} else {
|
|
33
|
+
const filtered = jobs.map((j: Job) => {
|
|
34
|
+
const { id, name, stage, status, duration, failure_reason } = j
|
|
35
|
+
return { id, name, stage, status, duration, failure_reason }
|
|
36
|
+
})
|
|
37
|
+
console.log(JSON.stringify(filtered, null, 2))
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
return program
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default create
|
|
44
|
+
|
|
45
|
+
if (isMain('git-lab-project-pipeline-latest')) {
|
|
46
|
+
await create().parseAsync(Bun.argv)
|
|
47
|
+
}
|