ya-git-jira 1.2.0 → 1.3.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/lib/gitlab.ts ADDED
@@ -0,0 +1,86 @@
1
+ import { getConfig, getRemote } from "./git"
2
+ import type { JSONValue } from "./json"
3
+ import path from 'node:path'
4
+
5
+ export interface GitlabConfig {
6
+ host: string
7
+ user: string
8
+ token: string
9
+ }
10
+
11
+ export async function getGitlabConfig(): Promise<GitlabConfig> {
12
+ const host = await getConfig("gitlab.host")
13
+ if (!host) throw new Error("gitlab.host not in git config")
14
+ const user = await getConfig("user.email")
15
+ if (!user) throw new Error("user.email not in git config")
16
+ const token = await getConfig("gitlab.token")
17
+ if (!token) throw new Error("gitlab.token not in git config")
18
+ return { host, user, token }
19
+ }
20
+
21
+ export async function get(endpoint: string): Promise<JSONValue> {
22
+ const method = "GET"
23
+ const { host, token } = await getGitlabConfig()
24
+ const base = `https://${host}/api/v4`
25
+ const uri = `${base}/${endpoint}`
26
+ const headers = new Headers()
27
+ headers.append("Accept", "application/json")
28
+ headers.append('Private-Token', token)
29
+ const options = {
30
+ method,
31
+ headers,
32
+ }
33
+ const request = new Request(uri, options)
34
+ const response = await fetch(request)
35
+ return await response.json()
36
+ }
37
+
38
+ export type User = JSONValue & {
39
+ id: number
40
+ name: string
41
+ username: string
42
+ email: string
43
+ }
44
+
45
+ export async function whoami(): Promise<User> {
46
+ return await get("/user") as User
47
+ }
48
+
49
+ export type Project = JSONValue & {
50
+ id: number
51
+ name: string
52
+ path: string
53
+ path_with_namespace: string
54
+ visibility: string
55
+ ssh_url_to_repo: string
56
+ }
57
+
58
+ export async function getProjects(paths: string[]): Promise<Array<Project>> {
59
+ let search: string = ""
60
+ if (paths.length > 0) {
61
+ search = '&search=' + paths.join(",")
62
+ }
63
+ return await get(`/projects?visibility=private&membership=true&simple=true${search}`) as Array<Project>
64
+ }
65
+
66
+ // git@gitlab.com:etagen-internal/linear-generator-config.git
67
+ export async function findProject(ssh_url: string): Promise<Project> {
68
+ const parts = ssh_url.split(':')
69
+ if (parts.length != 2) {
70
+ throw new Error(`${ssh_url} is invalid, could not be split into two parts at :`)
71
+ }
72
+ const name = path.basename(parts[1], '.git')
73
+
74
+ const projects = await getProjects([name])
75
+ const project = projects.find((p: Project): boolean => {
76
+ return p.ssh_url_to_repo === ssh_url
77
+ })
78
+ if (!project) {
79
+ throw new Error(`No project with ssh_url_to_repo ${ssh_url} found`)
80
+ }
81
+ return project
82
+ }
83
+
84
+ export async function getMergeRequest(id: string): Promise<JSONValue> {
85
+ return await get(`/merge_requests/${id}`)
86
+ }
package/lib/jira.ts CHANGED
@@ -1,12 +1,29 @@
1
1
 
2
- import { getJiraConfig } from "../lib/git"
2
+ import { getConfig } from "../lib/git"
3
+ import type { JSONValue } from "../lib/json"
3
4
 
4
- type JSONValue =
5
- | string
6
- | number
7
- | boolean
8
- | { [x: string]: JSONValue }
9
- | Array<JSONValue>
5
+ export type Issue = JSONValue & {
6
+ key: string,
7
+ self: string,
8
+ fields: {
9
+ summary: string
10
+ }
11
+ }
12
+ export interface JiraConfig {
13
+ host: string
14
+ token: string
15
+ }
16
+
17
+ export async function getJiraConfig(): Promise<JiraConfig> {
18
+ const host = await getConfig("jira.host")
19
+ if (!host) throw new Error("jira.host not in git config")
20
+ const user = await getConfig("jira.user") || await getConfig("user.email")
21
+ if (!user) throw new Error("jira.user or user.email not in git config")
22
+ const pat = await getConfig("jira.pat")
23
+ if (!pat) throw new Error("jira.pat not in git config")
24
+ const token = Buffer.from(`${user}:${pat}`).toString('base64')
25
+ return { host, token }
26
+ }
10
27
 
11
28
  export async function get(endpoint: string): Promise<JSONValue> {
12
29
  const method = "GET"
@@ -26,14 +43,6 @@ export async function get(endpoint: string): Promise<JSONValue> {
26
43
  return await response.json()
27
44
  }
28
45
 
29
- type Issue = JSONValue & {
30
- key: string,
31
- self: string,
32
- fields: {
33
- summary: string
34
- }
35
- }
36
-
37
46
  export async function getIssue(issue: string): Promise<Issue> {
38
47
  return await get(`/issue/${issue}`) as Issue
39
48
  }
package/lib/json.ts ADDED
@@ -0,0 +1,6 @@
1
+ export type JSONValue =
2
+ | string
3
+ | number
4
+ | boolean
5
+ | { [x: string]: JSONValue }
6
+ | Array<JSONValue>
package/lib/spawn.ts CHANGED
@@ -1,10 +1,36 @@
1
+ import { Subprocess } from "bun"
1
2
 
3
+ export interface SpawnResult {
4
+ out: string
5
+ err: string
6
+ code: number
7
+ }
2
8
 
3
- export async function doCommand(args: string[]): Promise<string> {
4
- const proc = Bun.spawn(args)
9
+ export interface SpawnOptions {
10
+ expectQuiet?: boolean
11
+ }
12
+
13
+ const defaultOptions: SpawnOptions = {
14
+ expectQuiet: false,
15
+ }
16
+
17
+ export async function spawn(args: string[], options: SpawnOptions = defaultOptions): Promise<SpawnResult> {
18
+ const proc: Subprocess<"ignore", "pipe", "pipe"> = Bun.spawn(args, { stdout: "pipe", stderr: "pipe" })
5
19
  const stdout = new Response(proc.stdout)
6
20
  const stderr = new Response(proc.stderr)
7
- const [out, err] = await Promise.all([stdout.text(), stderr.text()])
21
+ const [out, err, exitCode, signal] = await Promise.all([stdout.text(), stderr.text(), proc.exitCode, proc.signalCode])
22
+ let code = 0
23
+ if (exitCode !== null) {
24
+ code = exitCode
25
+ }
26
+ if (!out && !err && !options.expectQuiet) {
27
+ console.warn(`No output from ${args.join(" ")}`)
28
+ }
29
+ return { out: out.trim(), err: err.trim(), code }
30
+ }
31
+
32
+ export async function doCommand(args: string[]): Promise<string> {
33
+ const { out, err } = await spawn(args)
8
34
  if (err) console.error(err)
9
- return out.trim()
35
+ return out
10
36
  }
package/package.json CHANGED
@@ -1,18 +1,23 @@
1
1
  {
2
2
  "name": "ya-git-jira",
3
3
  "description": "git extensions for Jira integration. Assumes bun is installed.",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "module": "dist/index.js",
6
6
  "type": "module",
7
7
  "bin": {
8
- "gitj": "dist/bin/gitj.js",
9
- "git-jira": "dist/bin/git-jira.js",
10
- "git-jira-start": "dist/bin/git-jira-start.js",
8
+ "git-bump": "dist/bin/git-bump.js",
9
+ "git-jira-issue": "dist/bin/git-jira-issue.js",
11
10
  "git-jira-issues": "dist/bin/git-jira-issues.js",
12
- "git-bump": "dist/bin/git-bump.js"
11
+ "git-jira-start": "dist/bin/git-jira-start.js",
12
+ "git-jira": "dist/bin/git-jira.js",
13
+ "git-lab-projects": "dist/bin/git-lab-projects.js",
14
+ "git-lab-whoami": "dist/bin/git-lab-whoami.js",
15
+ "git-lab": "dist/bin/git-lab.js",
16
+ "gitj": "dist/bin/gitj.js"
13
17
  },
14
18
  "scripts": {
15
- "preinstall": "bun build index.ts bin/gitj.ts bin/git-jira.ts bin/git-jira-start.ts bin/git-jira-issues.ts bin/git-bump.ts --outdir dist"
19
+ "preinstall": "bun run build.ts",
20
+ "build": "bun run build.ts"
16
21
  },
17
22
  "devDependencies": {
18
23
  "@types/commander": "^2.12.2",
@@ -25,7 +30,9 @@
25
30
  "typescript": "^5.0.0"
26
31
  },
27
32
  "dependencies": {
28
- "commander": "^11.0.0"
33
+ "commander": "^11.0.0",
34
+ "cuid": "^3.0.0",
35
+ "glob": "^10.3.4"
29
36
  },
30
37
  "main": "dist/start.js dist/bump.js",
31
38
  "repository": {
@@ -0,0 +1,25 @@
1
+ import { test, expect } from "bun:test"
2
+ import { findProject, getRemote } from ".."
3
+
4
+ test("testing works", async (): Promise<void> => {
5
+ expect(true).toBe(true)
6
+ })
7
+
8
+ test("getRemote", async (): Promise<void> => {
9
+ const url = await getRemote()
10
+ expect(url).toBe("git@github.com:jimlloyd/ya-git-jira.git")
11
+ })
12
+
13
+ test("findProject linear-generator", async (): Promise<void> => {
14
+ const ssh_url = "git@gitlab.com:etagen-internal/linear-generator.git"
15
+ const project = await findProject(ssh_url)
16
+ expect(project.ssh_url_to_repo).toBe(ssh_url)
17
+ expect(project.id).toBe(4053065)
18
+ })
19
+
20
+ test("findProject eta-lib/base", async (): Promise<void> => {
21
+ const ssh_url = "git@gitlab.com:etagen-internal/eta-lib/base.git"
22
+ const project = await findProject(ssh_url)
23
+ expect(project.ssh_url_to_repo).toBe(ssh_url)
24
+ expect(project.id).toBe(42470523)
25
+ })
@@ -0,0 +1,43 @@
1
+ import { test, expect, describe, beforeEach, afterEach } from "bun:test"
2
+ import { getCurrentBranch, spawn, type SpawnResult } from ".."
3
+ import cuid from "cuid"
4
+
5
+ test("testing works", async (): Promise<void> => {
6
+ expect(true).toBe(true)
7
+ })
8
+
9
+ test("gitj works", async (): Promise<void> => {
10
+ const { out, code }: SpawnResult = await spawn(["bun", "run", "bin/gitj.ts"])
11
+ expect(out).toMatch("Usage:")
12
+ expect(out).toMatch("Bump the version number in the current branch")
13
+ expect(out).toMatch("A set of commands for working with Jira")
14
+ expect(code).toBe(0)
15
+ })
16
+
17
+ test("gitj bump --help works", async (): Promise<void> => {
18
+ const { out, code }: SpawnResult = await spawn(["bun", "run", "bin/gitj.ts", "bump", "--help"])
19
+ expect(out).toMatch("Usage:")
20
+ expect(out).toMatch("Bump the version number in the current branch")
21
+ expect(code).toBe(0)
22
+ })
23
+
24
+ describe("gitj bump", (): void => {
25
+ let priorBranch: string
26
+ let testBranch = cuid()
27
+ beforeEach(async (): Promise<void> => {
28
+ priorBranch = await getCurrentBranch()
29
+ await spawn(["git", "checkout", "-b", testBranch])
30
+ })
31
+
32
+ test("gitj bump works", async (): Promise<void> => {
33
+ const { code }: SpawnResult = await spawn(["bun", "run", "bin/gitj.ts", "bump"])
34
+ expect(code).toBe(0)
35
+ expect(await getCurrentBranch()).toMatch(testBranch + '.v1')
36
+ })
37
+
38
+ afterEach(async (): Promise<void> => {
39
+ await spawn(["git", "checkout", priorBranch])
40
+ await spawn(["git", "branch", "-D", testBranch])
41
+ await spawn(["git", "branch", "-D", testBranch + '.v1'])
42
+ })
43
+ })
package/dist/bin/bundo.js DELETED
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env bun run
2
- // @bun
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __toESM = (mod, isNodeMode, target) => {
9
- target = mod != null ? __create(__getProtoOf(mod)) : {};
10
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
- for (let key of __getOwnPropNames(mod))
12
- if (!__hasOwnProp.call(to, key))
13
- __defProp(to, key, {
14
- get: () => mod[key],
15
- enumerable: true
16
- });
17
- return to;
18
- };
19
- var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
- var __require = (id) => {
21
- return import.meta.require(id);
22
- };
23
-
24
- // lib/debug.ts
25
- function dargv() {
26
- if (Bun.env.DEBUG && Bun.env.DEBUG.toLowerCase().includes("gitjira")) {
27
- console.log(Bun.argv);
28
- }
29
- }
30
-
31
- // lib/spawn.ts
32
- async function doCommand(args) {
33
- const proc = Bun.spawn(args);
34
- const stdout = new Response(proc.stdout);
35
- const stderr = new Response(proc.stderr);
36
- const [out, err] = await Promise.all([stdout.text(), stderr.text()]);
37
- if (err)
38
- console.error(err);
39
- return out.trim();
40
- }
41
-
42
- // bin/bundo.ts
43
- dargv();
44
- var args = ["sh", "-c", ...Bun.argv.slice(2)];
45
- await doCommand(args);