-
Notifications
You must be signed in to change notification settings - Fork 537
/
Copy pathinfo.ts
116 lines (98 loc) · 3.13 KB
/
info.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
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/
import { Flags } from "@oclif/core";
import chalk from "picocolors";
import { BaseCommand } from "../../library/index.js";
/**
* An object containing merge status between two branches.
*/
interface BranchMergeInfo {
/**
* The branches being compared.
*/
branches: string[];
/**
* The number of commits difference between the branches. This will equal the length of the commits array and is
* included for convenience.
*/
commitCount: number;
/**
* The commits that are in branch 1 but not branch 2.
*/
commits: string[];
}
export default class MergeInfoCommand extends BaseCommand<typeof MergeInfoCommand> {
static readonly description =
`Get info about the merge status of branches in the repo. Uses "main" and "next" if no branch names are provided. Output the data as JSON using --json.`;
static readonly enableJsonFlag = true;
static readonly flags = {
branch: Flags.string({
char: "b",
description:
"A branch name. Use this argument multiple times to provide multiple branch names.",
multiple: true,
}),
...BaseCommand.flags,
} as const;
static readonly examples = [
{
description: "Get info about the merge status of the main and next branch in the repo.",
command: "<%= config.bin %> <%= command.id %>",
},
{
description: "Output the merge status as JSON using --json.",
command: "<%= config.bin %> <%= command.id %> --json",
},
];
public async run(): Promise<BranchMergeInfo> {
const { flags } = this;
const branchFlags = flags.branch;
let branch1: string;
let branch2: string;
// Default to main and next
if (branchFlags === undefined || branchFlags.length === 0) {
[branch1, branch2] = ["main", "next"];
} else if (branchFlags.length === 1) {
[branch1, branch2] = [branchFlags[0], "next"];
} else {
[branch1, branch2] = branchFlags;
}
if (branchFlags !== undefined && branchFlags.length > 2) {
this.warning(
`Only two branch names are used; ignoring the following arguments: ${[
branchFlags.slice(2),
]}`,
);
}
const context = await this.getContext();
const repo = await context.getGitRepository();
const remote = await repo.getRemote(repo.upstreamRemotePartialUrl);
if (remote === undefined) {
this.error(`Can't find a remote with ${repo.upstreamRemotePartialUrl}`);
}
this.verbose(`Remote is: ${remote}`);
// get merge base
const base = await repo.getMergeBaseRemote(
branch1,
remote,
`refs/remotes/${remote}/${branch2}`,
);
const rawRevs = await repo.gitClient.raw(
"rev-list",
`${base}..refs/remotes/${remote}/${branch1}`,
);
const revs = rawRevs.split(/\r?\n/);
const [b1Log, b2Log] = [chalk.bold(chalk.blue(branch1)), chalk.bold(chalk.blue(branch2))];
this.logHr();
this.log(
` The ${b2Log} branch is ${chalk.bold(revs.length.toString())} commits ${chalk.red(
"behind",
)} ${b1Log}`,
);
this.log();
// If --json is passed, this object is output to stdout JSON-serialized.
return { branches: [branch1, branch2], commits: revs, commitCount: revs.length };
}
}