git-stack-cli 1.11.7 → 1.13.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.
@@ -82,6 +82,8 @@ const SINGLE_COMMIT_EXISTING_GROUP: CommitMetadata.CommitRange = {
82
82
  id: "AAWsYx1UU",
83
83
  title: "banana",
84
84
  pr: {
85
+ id: "PR_kwDOKjvFM85ghvAH",
86
+ isDraft: false,
85
87
  baseRefName: "master",
86
88
  body: "adsf\r\n\r\n#### git stack\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/47\n- 👉 `1` https://github.com/magus/git-multi-diff-playground/pull/43",
87
89
  commits: [
@@ -123,6 +125,8 @@ const SINGLE_COMMIT_EXISTING_GROUP: CommitMetadata.CommitRange = {
123
125
  id: "E63ytp5dj",
124
126
  title: "lemon color",
125
127
  pr: {
128
+ id: "PR_kwDOKjvFM85gwTkx",
129
+ isDraft: false,
126
130
  baseRefName: "AAWsYx1UU",
127
131
  body: "\r\n\r\n#### git stack\n- 👉 `3` https://github.com/magus/git-multi-diff-playground/pull/47\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/43\n- ✅ `1`\n https://github.com/magus/git-multi-diff-playground/pull/42",
128
132
  commits: [
@@ -251,6 +255,8 @@ const SINGLE_COMMIT_EXISTING_GROUP: CommitMetadata.CommitRange = {
251
255
  ],
252
256
  pr_lookup: {
253
257
  AAWsYx1UU: {
258
+ id: "PR_kwDOKjvFM85ghvAH",
259
+ isDraft: false,
254
260
  baseRefName: "master",
255
261
  body: "adsf\r\n\r\n#### git stack\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/47\n- 👉 `1` https://github.com/magus/git-multi-diff-playground/pull/43",
256
262
  commits: [
@@ -277,6 +283,8 @@ const SINGLE_COMMIT_EXISTING_GROUP: CommitMetadata.CommitRange = {
277
283
  url: "https://github.com/magus/git-multi-diff-playground/pull/43",
278
284
  },
279
285
  E63ytp5dj: {
286
+ id: "PR_kwDOKjvFM85gwTkx",
287
+ isDraft: false,
280
288
  baseRefName: "AAWsYx1UU",
281
289
  body: "\r\n\r\n#### git stack\n- 👉 `3` https://github.com/magus/git-multi-diff-playground/pull/47\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/43\n- ✅ `1`\n https://github.com/magus/git-multi-diff-playground/pull/42",
282
290
  commits: [
@@ -343,6 +351,8 @@ const SINGLE_COMMIT_NEW_GROUP: CommitMetadata.CommitRange = {
343
351
  id: "AAWsYx1UU",
344
352
  title: "banana",
345
353
  pr: {
354
+ id: "PR_kwDOKjvFM85ghvAH",
355
+ isDraft: false,
346
356
  baseRefName: "master",
347
357
  body: "adsf\r\n\r\n#### git stack\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/47\n- 👉 `1` https://github.com/magus/git-multi-diff-playground/pull/43",
348
358
  commits: [
@@ -384,6 +394,8 @@ const SINGLE_COMMIT_NEW_GROUP: CommitMetadata.CommitRange = {
384
394
  id: "E63ytp5dj",
385
395
  title: "lemon color",
386
396
  pr: {
397
+ id: "PR_kwDOKjvFM85gwTkx",
398
+ isDraft: false,
387
399
  baseRefName: "AAWsYx1UU",
388
400
  body: "\r\n\r\n#### git stack\n- 👉 `3` https://github.com/magus/git-multi-diff-playground/pull/47\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/43\n- ✅ `1`\n https://github.com/magus/git-multi-diff-playground/pull/42",
389
401
  commits: [
@@ -521,6 +533,8 @@ const SINGLE_COMMIT_NEW_GROUP: CommitMetadata.CommitRange = {
521
533
  ],
522
534
  pr_lookup: {
523
535
  AAWsYx1UU: {
536
+ id: "PR_kwDOKjvFM85ghvAH",
537
+ isDraft: false,
524
538
  baseRefName: "master",
525
539
  body: "adsf\r\n\r\n#### git stack\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/47\n- 👉 `1` https://github.com/magus/git-multi-diff-playground/pull/43",
526
540
  commits: [
@@ -547,6 +561,8 @@ const SINGLE_COMMIT_NEW_GROUP: CommitMetadata.CommitRange = {
547
561
  url: "https://github.com/magus/git-multi-diff-playground/pull/43",
548
562
  },
549
563
  E63ytp5dj: {
564
+ id: "PR_kwDOKjvFM85gwTkx",
565
+ isDraft: false,
550
566
  baseRefName: "AAWsYx1UU",
551
567
  body: "\r\n\r\n#### git stack\n- 👉 `3` https://github.com/magus/git-multi-diff-playground/pull/47\n- ⏳ `2` https://github.com/magus/git-multi-diff-playground/pull/43\n- ✅ `1`\n https://github.com/magus/git-multi-diff-playground/pull/42",
552
568
  commits: [
@@ -1,4 +1,4 @@
1
- import fs from "node:fs";
1
+ import fs from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
 
@@ -120,10 +120,10 @@ GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
120
120
  const GIT_SEQUENCE_EDITOR_SCRIPT = `process.env.GIT_SEQUENCE_EDITOR_SCRIPT`;
121
121
 
122
122
  // write script to temporary path
123
- fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
123
+ await fs.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
124
124
 
125
125
  // ensure script is executable
126
- fs.chmodSync(tmp_git_sequence_editor_path, "755");
126
+ await fs.chmod(tmp_git_sequence_editor_path, "755");
127
127
 
128
128
  const git_revise_todo = GitReviseTodo(args);
129
129
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
 
3
- import fs from "node:fs";
3
+ import fs from "node:fs/promises";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
 
@@ -12,6 +12,7 @@ import { cli } from "~/core/cli";
12
12
  import { colors } from "~/core/colors";
13
13
  import { invariant } from "~/core/invariant";
14
14
  import { safe_quote } from "~/core/safe_quote";
15
+ import { safe_rm } from "~/core/safe_rm";
15
16
 
16
17
  export async function pr_list(): Promise<Array<PullRequest>> {
17
18
  const state = Store.getState();
@@ -148,7 +149,8 @@ export async function pr_edit(args: EditPullRequestArgs) {
148
149
  const command_parts = [`gh pr edit ${args.branch} --base ${args.base}`];
149
150
 
150
151
  if (args.body) {
151
- command_parts.push(`--body-file="${body_file(args.body)}"`);
152
+ const body_file = await write_body_file(args);
153
+ command_parts.push(`--body-file="${body_file}"`);
152
154
  }
153
155
 
154
156
  const command = command_parts.join(" ");
@@ -160,8 +162,56 @@ export async function pr_edit(args: EditPullRequestArgs) {
160
162
  }
161
163
  }
162
164
 
165
+ type DraftPullRequestArgs = {
166
+ branch: string;
167
+ draft: boolean;
168
+ };
169
+
170
+ export async function pr_draft(args: DraftPullRequestArgs) {
171
+ // https://cli.github.com/manual/gh_api
172
+ // https://docs.github.com/en/graphql/reference/mutations#convertpullrequesttodraft
173
+ // https://docs.github.com/en/graphql/reference/mutations#markpullrequestreadyforreview
174
+
175
+ const mutation_name = args.draft
176
+ ? "convertPullRequestToDraft"
177
+ : "markPullRequestReadyForReview";
178
+
179
+ let query = `
180
+ mutation($id: ID!) {
181
+ ${mutation_name}(input: { pullRequestId: $id }) {
182
+ pullRequest {
183
+ id
184
+ number
185
+ isDraft
186
+ }
187
+ }
188
+ }
189
+ `;
190
+
191
+ query = query.replace(/\n/g, " ");
192
+ query = query.replace(/\s+/g, " ");
193
+ query = query.trim();
194
+
195
+ // lookup id from pr cache using args.branch
196
+ const state = Store.getState();
197
+ const cache_pr = state.pr[args.branch];
198
+ invariant(cache_pr, "cache_pr must exist");
199
+
200
+ const command_parts = [
201
+ `gh api graphql -F id="${cache_pr.id}" -f query='${query}'`,
202
+ ];
203
+
204
+ const command = command_parts.join(" ");
205
+
206
+ const cli_result = await cli(command);
207
+
208
+ if (cli_result.code !== 0) {
209
+ handle_error(cli_result.output);
210
+ }
211
+ }
212
+
163
213
  // prettier-ignore
164
- const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
214
+ const JSON_FIELDS = "--json id,number,state,baseRefName,headRefName,commits,title,body,url,isDraft";
165
215
 
166
216
  // consistent handle gh cli commands returning json
167
217
  // redirect to tmp file to avoid scrollback overflow causing scrollback to be cleared
@@ -176,7 +226,7 @@ async function gh_json<T>(command: string): Promise<T | Error> {
176
226
  }
177
227
 
178
228
  // read from file
179
- const json_str = fs.readFileSync(tmp_pr_json, "utf-8");
229
+ const json_str = await fs.readFile(tmp_pr_json, "utf-8");
180
230
  const json = JSON.parse(json_str);
181
231
  return json;
182
232
  }
@@ -193,13 +243,16 @@ function handle_error(output: string): never {
193
243
  }
194
244
 
195
245
  // convert a string to a file for use via github cli `--body-file`
196
- function body_file(body: string) {
246
+ async function write_body_file(args: EditPullRequestArgs) {
247
+ invariant(args.body, "args.body must exist");
248
+
197
249
  const temp_dir = os.tmpdir();
198
- const temp_path = path.join(temp_dir, "git-stack-body");
199
- if (fs.existsSync(temp_path)) {
200
- fs.rmSync(temp_path);
201
- }
202
- fs.writeFileSync(temp_path, body);
250
+ const temp_path = path.join(temp_dir, `git-stack-body-${args.base}`);
251
+
252
+ await safe_rm(temp_path);
253
+
254
+ await fs.writeFile(temp_path, args.body);
255
+
203
256
  return temp_path;
204
257
  }
205
258
 
@@ -220,6 +273,7 @@ type Commit = {
220
273
  };
221
274
 
222
275
  export type PullRequest = {
276
+ id: string;
223
277
  number: number;
224
278
  state: "OPEN" | "MERGED" | "CLOSED";
225
279
  baseRefName: string;
@@ -228,4 +282,5 @@ export type PullRequest = {
228
282
  title: string;
229
283
  body: string;
230
284
  url: string;
285
+ isDraft: boolean;
231
286
  };
@@ -1,8 +1,8 @@
1
- import fs from "node:fs";
1
+ import fs from "node:fs/promises";
2
2
 
3
- export function read_json<T = unknown>(path: string): null | T {
3
+ export async function read_json<T = unknown>(path: string): Promise<null | T> {
4
4
  try {
5
- const file_buffer = fs.readFileSync(path);
5
+ const file_buffer = await fs.readFile(path);
6
6
  const json_str = String(file_buffer);
7
7
  const json = JSON.parse(json_str);
8
8
  return json;
@@ -0,0 +1,10 @@
1
+ import fs from "node:fs/promises";
2
+
3
+ export async function safe_exists(filepath: string) {
4
+ try {
5
+ await fs.access(filepath);
6
+ return true;
7
+ } catch {
8
+ return false;
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ import fs from "node:fs/promises";
2
+
3
+ export async function safe_rm(filepath: string) {
4
+ try {
5
+ await fs.access(filepath);
6
+ await fs.rm(filepath);
7
+ } catch {
8
+ // if access fails there is no file to remove this is safe
9
+ }
10
+ }