git-stack-cli 2.7.0 → 2.7.2

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.
@@ -17,6 +17,7 @@ test("read handles bulleted lists", () => {
17
17
  const metadata = Metadata.read(body);
18
18
 
19
19
  expect(metadata).toEqual({
20
+ subject: "[feat] implement various features",
20
21
  id: "DdKIFyufW",
21
22
  title: "saved group title",
22
23
  });
@@ -63,6 +64,7 @@ test("read handles slashes in branch name", () => {
63
64
  const metadata = Metadata.read(body);
64
65
 
65
66
  expect(metadata).toEqual({
67
+ subject: "[fix] slash in branch name",
66
68
  id: "dev/noah/fix-slash-branch",
67
69
  title: "fix slash branch",
68
70
  });
@@ -109,6 +111,7 @@ test("read handles double quotes", () => {
109
111
  const metadata = Metadata.read(body);
110
112
 
111
113
  expect(metadata).toEqual({
114
+ subject: 'Revert "[abc / 123] subject (#1234)"',
112
115
  id: "dev/noah/fix-slash-branch",
113
116
  title: 'Revert \\"[abc / 123] subject (#1234)\\"',
114
117
  });
@@ -6,6 +6,7 @@ type InputMetadataValues = {
6
6
  };
7
7
 
8
8
  type OutputMetadataValues = {
9
+ subject: null | string;
9
10
  id: null | string;
10
11
  title: null | string;
11
12
  };
@@ -28,7 +29,14 @@ export function write(message: string, values: InputMetadataValues) {
28
29
  }
29
30
 
30
31
  export function read(message: string): OutputMetadataValues {
31
- const values: OutputMetadataValues = { id: null, title: null };
32
+ const values: OutputMetadataValues = { subject: null, id: null, title: null };
33
+
34
+ const match_subject = message.match(RE.subject_line);
35
+
36
+ if (match_subject?.groups) {
37
+ values.subject = match_subject.groups["subject"];
38
+ invariant(values.subject, "subject must exist");
39
+ }
32
40
 
33
41
  const match_id = message.match(RE.stack_id);
34
42
 
@@ -69,6 +77,8 @@ const TEMPLATE = {
69
77
  };
70
78
 
71
79
  const RE = {
80
+ // https://regex101.com/r/pOrChS/1
81
+ subject_line: /^(?<subject>[^\n]*)/,
72
82
  // https://regex101.com/r/wLmGVq/1
73
83
  stack_id: new RegExp(`${TEMPLATE.stack_id("(?<id>[^\\s]+)")}`, "i"),
74
84
  group_title: new RegExp(TEMPLATE.group_title("(?<title>[^\\n^\\r]+)"), "i"),
@@ -0,0 +1,95 @@
1
+ // Bun Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`get_commits ABC..DEF:
4
+ [
5
+ {
6
+ "branch_id": null,
7
+ "full_message": "homebrew-git-stack 2.7.1",
8
+ "sha": "ba067f8ad641dda7e65e3c2acb2421c955843829",
9
+ "subject_line": "homebrew-git-stack 2.7.1",
10
+ "title": null,
11
+ },
12
+ {
13
+ "branch_id": "noah/paint-test---4gwpqhd033n6y5",
14
+ "full_message":
15
+ "Rebase: debug logs
16
+
17
+ git-stack-id: noah/paint-test---4gwpqhd033n6y5
18
+ git-stack-title: Rebase: debug logs"
19
+ ,
20
+ "sha": "7c8da9f5fe681fc7459a0e737241df631983cd3c",
21
+ "subject_line": "Rebase: debug logs",
22
+ "title": "Rebase: debug logs",
23
+ },
24
+ {
25
+ "branch_id": "noah/paint-test---4gwpqirewoudxa",
26
+ "full_message":
27
+ "CommitMetadata: track last group id
28
+
29
+ git-stack-id: noah/paint-test---4gwpqirewoudxa
30
+ git-stack-title: CommitMetadata: track last group id"
31
+ ,
32
+ "sha": "47a69d37f8c5cc796884a91fa9e93fc1db5297dd",
33
+ "subject_line": "CommitMetadata: track last group id",
34
+ "title": "CommitMetadata: track last group id",
35
+ },
36
+ {
37
+ "branch_id": "noah/paint-test---4gwpqjcpu7-isv",
38
+ "full_message":
39
+ "Github: pr_list duration timer
40
+
41
+ git-stack-id: noah/paint-test---4gwpqjcpu7-isv
42
+ git-stack-title: Github: pr_list duration timer"
43
+ ,
44
+ "sha": "8ccf42a7c72aa194fafc7c326f5874f5a0a009c6",
45
+ "subject_line": "Github: pr_list duration timer",
46
+ "title": "Github: pr_list duration timer",
47
+ },
48
+ ]
49
+ 1`] = `
50
+ [
51
+ {
52
+ "branch_id": null,
53
+ "full_message": "homebrew-git-stack 2.7.1",
54
+ "sha": "ba067f8ad641dda7e65e3c2acb2421c955843829",
55
+ "subject_line": "homebrew-git-stack 2.7.1",
56
+ "title": null,
57
+ },
58
+ {
59
+ "branch_id": "noah/paint-test---4gwpqhd033n6y5",
60
+ "full_message":
61
+ "Rebase: debug logs
62
+
63
+ git-stack-id: noah/paint-test---4gwpqhd033n6y5
64
+ git-stack-title: Rebase: debug logs"
65
+ ,
66
+ "sha": "7c8da9f5fe681fc7459a0e737241df631983cd3c",
67
+ "subject_line": "Rebase: debug logs",
68
+ "title": "Rebase: debug logs",
69
+ },
70
+ {
71
+ "branch_id": "noah/paint-test---4gwpqirewoudxa",
72
+ "full_message":
73
+ "CommitMetadata: track last group id
74
+
75
+ git-stack-id: noah/paint-test---4gwpqirewoudxa
76
+ git-stack-title: CommitMetadata: track last group id"
77
+ ,
78
+ "sha": "47a69d37f8c5cc796884a91fa9e93fc1db5297dd",
79
+ "subject_line": "CommitMetadata: track last group id",
80
+ "title": "CommitMetadata: track last group id",
81
+ },
82
+ {
83
+ "branch_id": "noah/paint-test---4gwpqjcpu7-isv",
84
+ "full_message":
85
+ "Github: pr_list duration timer
86
+
87
+ git-stack-id: noah/paint-test---4gwpqjcpu7-isv
88
+ git-stack-title: Github: pr_list duration timer"
89
+ ,
90
+ "sha": "8ccf42a7c72aa194fafc7c326f5874f5a0a009c6",
91
+ "subject_line": "Github: pr_list duration timer",
92
+ "title": "Github: pr_list duration timer",
93
+ },
94
+ ]
95
+ `;
@@ -0,0 +1,11 @@
1
+ export function get_timeout_fn(ms: number, message: string) {
2
+ return function timeout<T>(promise: Promise<T>) {
3
+ let id: ReturnType<typeof setTimeout>;
4
+
5
+ const timeout = new Promise<never>((_resolve, reject) => {
6
+ id = setTimeout(() => reject(new Error(message)), ms);
7
+ });
8
+
9
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(id));
10
+ };
11
+ }
@@ -0,0 +1,54 @@
1
+ import { test, expect } from "bun:test";
2
+
3
+ import * as git from "~/core/git";
4
+
5
+ test("get_commits ABC..DEF", async () => {
6
+ const commits = await git.get_commits("e781ede..8ccf42a");
7
+ expect(commits).toMatchSnapshot(`
8
+ [
9
+ {
10
+ "branch_id": null,
11
+ "full_message": "homebrew-git-stack 2.7.1",
12
+ "sha": "ba067f8ad641dda7e65e3c2acb2421c955843829",
13
+ "subject_line": "homebrew-git-stack 2.7.1",
14
+ "title": null,
15
+ },
16
+ {
17
+ "branch_id": "noah/paint-test---4gwpqhd033n6y5",
18
+ "full_message":
19
+ "Rebase: debug logs
20
+
21
+ git-stack-id: noah/paint-test---4gwpqhd033n6y5
22
+ git-stack-title: Rebase: debug logs"
23
+ ,
24
+ "sha": "7c8da9f5fe681fc7459a0e737241df631983cd3c",
25
+ "subject_line": "Rebase: debug logs",
26
+ "title": "Rebase: debug logs",
27
+ },
28
+ {
29
+ "branch_id": "noah/paint-test---4gwpqirewoudxa",
30
+ "full_message":
31
+ "CommitMetadata: track last group id
32
+
33
+ git-stack-id: noah/paint-test---4gwpqirewoudxa
34
+ git-stack-title: CommitMetadata: track last group id"
35
+ ,
36
+ "sha": "47a69d37f8c5cc796884a91fa9e93fc1db5297dd",
37
+ "subject_line": "CommitMetadata: track last group id",
38
+ "title": "CommitMetadata: track last group id",
39
+ },
40
+ {
41
+ "branch_id": "noah/paint-test---4gwpqjcpu7-isv",
42
+ "full_message":
43
+ "Github: pr_list duration timer
44
+
45
+ git-stack-id: noah/paint-test---4gwpqjcpu7-isv
46
+ git-stack-title: Github: pr_list duration timer"
47
+ ,
48
+ "sha": "8ccf42a7c72aa194fafc7c326f5874f5a0a009c6",
49
+ "subject_line": "Github: pr_list duration timer",
50
+ "title": "Github: pr_list duration timer",
51
+ },
52
+ ]
53
+ `);
54
+ });
@@ -0,0 +1,55 @@
1
+ import * as Metadata from "~/core/Metadata";
2
+ import { cli } from "~/core/cli";
3
+
4
+ export type Commit = Awaited<ReturnType<typeof get_commits>>[0];
5
+
6
+ export async function get_commits(dot_range: string) {
7
+ const log_result = await cli(`git log ${dot_range} --format=${FORMAT} --color=never`);
8
+
9
+ if (!log_result.stdout) {
10
+ return [];
11
+ }
12
+
13
+ const commit_list = [];
14
+
15
+ for (let record of log_result.stdout.split(SEP.record)) {
16
+ record = record.replace(/^\n/, "");
17
+ record = record.replace(/\n$/, "");
18
+
19
+ if (!record) continue;
20
+
21
+ const [sha, full_message] = record.split(SEP.field);
22
+
23
+ const metadata = Metadata.read(full_message);
24
+ const branch_id = metadata.id;
25
+ const subject_line = metadata.subject || "";
26
+ const title = metadata.title;
27
+
28
+ const commit = {
29
+ sha,
30
+ full_message,
31
+ subject_line,
32
+ branch_id,
33
+ title,
34
+ };
35
+
36
+ commit_list.push(commit);
37
+ }
38
+
39
+ commit_list.reverse();
40
+
41
+ return commit_list;
42
+ }
43
+
44
+ // Why these separators?
45
+ // - Rare in human written text
46
+ // - Supported in git %xNN to write bytes
47
+ // - Supported in javascript \xNN to write bytes
48
+ // - Used historically as separators in unicode
49
+ // https://en.wikipedia.org/wiki/C0_and_C1_control_codes#Field_separators
50
+ const SEP = {
51
+ record: "\x1e",
52
+ field: "\x1f",
53
+ };
54
+
55
+ const FORMAT = `%H${SEP.field}%B${SEP.record}`;
@@ -8,6 +8,7 @@ import * as Ink from "ink-cjs";
8
8
 
9
9
  import { Brackets } from "~/app/Brackets";
10
10
  import { Store } from "~/app/Store";
11
+ import { Timer } from "~/core/Timer";
11
12
  import { cli } from "~/core/cli";
12
13
  import { colors } from "~/core/colors";
13
14
  import { get_tmp_dir } from "~/core/get_tmp_dir";
@@ -19,6 +20,9 @@ export async function pr_list(): Promise<Array<PullRequest>> {
19
20
  const state = Store.getState();
20
21
  const actions = state.actions;
21
22
 
23
+ const timer = Timer();
24
+ actions.debug("start github.pr_list");
25
+
22
26
  const username = state.username;
23
27
  const repo_path = state.repo_path;
24
28
  invariant(username, "username must exist");
@@ -53,6 +57,8 @@ export async function pr_list(): Promise<Array<PullRequest>> {
53
57
  }
54
58
  });
55
59
 
60
+ const duration = timer.duration();
61
+ actions.debug(`end github.pr_list (duration=${duration})`);
56
62
  return result_pr_list;
57
63
  }
58
64