-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pullRequestStack.ts
142 lines (116 loc) · 3.92 KB
/
pullRequestStack.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import Git from "nodegit";
import {
CommitAndBranchBoundary,
getWantedCommitsWithBranchBoundariesOurCustomImpl,
removeLocalAndRemoteRefPrefix,
} from "./git-stacked-rebase";
import { parseGithubRemoteUrl, createGithubURLForStackedPR } from "./adapter-github";
import { pickRemoteFromRepo } from "./forcePush";
import { AskQuestion, askWhichBranchEndToUseForStackedPRs } from "./util/createQuestion";
import { Triple } from "./util/tuple";
import { Termination } from "./util/error";
export type GenerateListOfURLsToCreateStackedPRsCtx = {
repo: Git.Repository;
initialBranch: Git.Reference;
currentBranch: Git.Reference;
ignoredBranches: string[];
askQuestion: AskQuestion;
};
export async function generateListOfURLsToCreateStackedPRs({
repo,
initialBranch,
currentBranch,
ignoredBranches,
askQuestion,
}: GenerateListOfURLsToCreateStackedPRsCtx): Promise<string[]> {
const branchBoundaries: CommitAndBranchBoundary[] = await getWantedCommitsWithBranchBoundariesOurCustomImpl(
repo,
initialBranch,
currentBranch
);
const stackedBranchesReadyForStackedPRs: CommitBranch[] = await getStackedBranchesReadyForStackedPRs({
branchBoundaries,
ignoredBranches,
askQuestion,
});
const remoteName: string = await pickRemoteFromRepo(repo, {
cannotDoXWhenZero: "Cannot create pull requests without any remotes.",
pleaseChooseOneFor: "creating pull requests",
});
const remote: Git.Remote = await Git.Remote.lookup(repo, remoteName);
const parsedGithubUrlData = parseGithubRemoteUrl(remote.url());
/**
* TODO:
*
* - [ ] check if some PRs already exist?
* - [ ] check if github
* - [ ] check if all branches in the same remote; otherwise ask which one to use
* - [ ]
*/
const githubURLsForCreatingPRs: string[] = [];
let prevBranch: string = stackedBranchesReadyForStackedPRs[0][1];
for (const [_commit, branch] of stackedBranchesReadyForStackedPRs.slice(1)) {
const url: string = createGithubURLForStackedPR({
repoOwner: parsedGithubUrlData.repoOwner,
repo: parsedGithubUrlData.repo,
baseBranch: prevBranch,
newBranch: branch,
});
githubURLsForCreatingPRs.push(url);
prevBranch = branch;
}
return githubURLsForCreatingPRs;
}
/**
* ---
*/
export type CommitBranch = Triple<string, string, Git.Reference>;
export type GetStackedBranchesReadyForStackedPRsCtx = {
branchBoundaries: CommitAndBranchBoundary[];
askQuestion: AskQuestion;
ignoredBranches: string[];
};
export async function getStackedBranchesReadyForStackedPRs({
branchBoundaries,
ignoredBranches,
askQuestion,
}: GetStackedBranchesReadyForStackedPRsCtx): Promise<CommitBranch[]> {
const result: CommitBranch[] = [];
let countOfCommitsWithMultipleBranches: number = 0;
for (let boundary of branchBoundaries) {
if (!boundary.branchEnd?.length) {
continue;
}
const commitSha: string = boundary.commit.sha();
const branchEnds: string[] = boundary.branchEnd
.map((b) => removeLocalAndRemoteRefPrefix(b.name())) //
.filter((b) => !ignoredBranches.some((ignoredBranchSubstr) => b.includes(ignoredBranchSubstr)));
if (branchEnds.length === 1) {
result.push([commitSha, branchEnds[0], boundary.branchEnd[0]]);
} else {
/**
* >1 branch end,
* thus need the user to pick one.
*
* we need to know which branch to use (only 1),
* because need to know on top of which to stack later PRs.
*/
const chosenBranch: string = await askWhichBranchEndToUseForStackedPRs({
branchEnds, //
commitSha,
askQuestion,
nonFirstAsk: countOfCommitsWithMultipleBranches > 0,
});
const chosenBranchRef: Git.Reference = boundary.branchEnd.find(
(be) => removeLocalAndRemoteRefPrefix(be.name()) === chosenBranch
)!;
if (!chosenBranchRef) {
const msg = `chosen branch was picked, but it's Git.Reference was not found. likely a bug.`;
throw new Termination(msg);
}
result.push([commitSha, chosenBranch, chosenBranchRef]);
countOfCommitsWithMultipleBranches++;
}
}
return result;
}