UNPKG

29.4 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.automatedCommentIdentifier = void 0;
4const tslib_1 = require("tslib");
5const graphql_1 = require("@octokit/graphql");
6const plugin_enterprise_compatibility_1 = require("@octokit/plugin-enterprise-compatibility");
7const path_1 = tslib_1.__importDefault(require("path"));
8const plugin_retry_1 = require("@octokit/plugin-retry");
9const plugin_throttling_1 = require("@octokit/plugin-throttling");
10const rest_1 = require("@octokit/rest");
11const gitlog_1 = require("gitlog");
12const tinycolor2_1 = tslib_1.__importDefault(require("tinycolor2"));
13const endent_1 = tslib_1.__importDefault(require("endent"));
14const await_to_js_1 = tslib_1.__importDefault(require("await-to-js"));
15const url_join_1 = tslib_1.__importDefault(require("url-join"));
16const typescript_memoize_1 = require("typescript-memoize");
17const verify_auth_1 = tslib_1.__importDefault(require("./utils/verify-auth"));
18const exec_promise_1 = tslib_1.__importDefault(require("./utils/exec-promise"));
19const logger_1 = require("./utils/logger");
20const semver_1 = require("semver");
21const match_sha_to_pr_1 = require("./match-sha-to-pr");
22/** An error originating from the GitHub */
23class GitAPIError extends Error {
24 /** Extend the base error */
25 constructor(api, args, origError) {
26 super(`Error calling github: ${api}\n\twith: ${JSON.stringify(args)}.\n\t${origError.message}`);
27 }
28}
29const taggedPackageRegex = /(\S+)@(\S+)/;
30/**
31 * Extract a version from a tag.
32 *
33 * Supports tags like:
34 *
35 * - 1.2.3
36 * - 1.2.3-beta.0
37 * - package@1.2.3-beta.0
38 * - @scope/package@1.2.3-beta.0
39 */
40function getVersionFromTag(tag) {
41 if (taggedPackageRegex.test(tag)) {
42 const [, , version] = tag.match(taggedPackageRegex);
43 return version;
44 }
45 return tag;
46}
47exports.automatedCommentIdentifier = "<!-- GITHUB_RELEASE";
48/** Make a comment to build automation in PRs off of. */
49const makeIdentifier = (type, context) => `${exports.automatedCommentIdentifier} ${type}: ${context} -->`;
50/** Make an identifier for `auto comment` */
51const makeCommentIdentifier = (context) => makeIdentifier("COMMENT", context);
52/** Make an identifier for `auto pr-body` */
53const makePrBodyIdentifier = (context) => makeIdentifier("PR BODY", context);
54/**
55 * A class to interact with the local git instance and the git remote.
56 * currently it only interfaces with GitHub.
57 */
58class Git {
59 /** Initialize the git interface and auth with GitHub */
60 constructor(options, logger = logger_1.dummyLog()) {
61 this.logger = logger;
62 this.options = options;
63 this.baseUrl = this.options.baseUrl || "https://api.github.com";
64 this.graphqlBaseUrl = this.options.baseUrl
65 ? this.options.graphqlBaseUrl || url_join_1.default(new URL(this.baseUrl).origin, "api")
66 : this.baseUrl;
67 this.logger.veryVerbose.info(`Initializing GitHub with: ${this.baseUrl}`);
68 const GitHub = rest_1.Octokit.plugin(plugin_enterprise_compatibility_1.enterpriseCompatibility)
69 .plugin(plugin_retry_1.retry)
70 .plugin(plugin_throttling_1.throttling);
71 this.github = new GitHub({
72 baseUrl: this.baseUrl,
73 auth: this.options.token,
74 previews: ["symmetra-preview"],
75 request: { agent: this.options.agent },
76 throttle: {
77 onRateLimit: (retryAfter, opts) => {
78 this.logger.log.warn(`Request quota exhausted for request ${opts.method} ${opts.url}`);
79 if (opts.request.retryCount < 5) {
80 this.logger.verbose.log(`Retrying after ${retryAfter} seconds!`);
81 return true;
82 }
83 },
84 onAbuseLimit: (_, opts) => {
85 // does not retry, only logs an error
86 this.logger.log.error(`Went over abuse rate limit ${opts.method} ${opts.url}`);
87 },
88 },
89 });
90 this.github.hook.error("request", (error) => {
91 var _a;
92 if ((_a = error === null || error === void 0 ? void 0 : error.headers) === null || _a === void 0 ? void 0 : _a.authorization) {
93 delete error.headers.authorization;
94 }
95 throw error;
96 });
97 }
98 /** Verify the write access authorization to remote repository with push dry-run. */
99 async verifyAuth(url) {
100 return verify_auth_1.default(url, this.options.baseBranch);
101 }
102 /** Get the "Latest Release" from GitHub */
103 async getLatestReleaseInfo() {
104 const latestRelease = await this.github.repos.getLatestRelease({
105 owner: this.options.owner,
106 repo: this.options.repo,
107 });
108 return latestRelease.data;
109 }
110 /** Get the "Latest Release" or the first commit SHA as a fallback */
111 async getLatestRelease() {
112 try {
113 const latestRelease = await this.getLatestReleaseInfo();
114 this.logger.veryVerbose.info('Got response for "getLatestRelease":\n', latestRelease);
115 this.logger.verbose.info("Got latest release:\n", latestRelease);
116 return latestRelease.tag_name;
117 }
118 catch (e) {
119 if (e.status === 404) {
120 this.logger.verbose.info("Couldn't find latest release on GitHub, using first commit.");
121 return this.getFirstCommit();
122 }
123 throw e;
124 }
125 }
126 /** Get the date a commit sha was created */
127 async getCommitDate(sha) {
128 const date = await exec_promise_1.default("git", ["show", "-s", "--format=%ci", sha]);
129 const [day, time, timezone] = date.split(" ");
130 return `${day}T${time}${timezone}`;
131 }
132 /** Get the first commit for the repo */
133 async getFirstCommit() {
134 const list = await exec_promise_1.default("git", ["rev-list", "HEAD"]);
135 return list.split("\n").pop();
136 }
137 /** Get the SHA of the latest commit */
138 async getSha(short) {
139 const result = await exec_promise_1.default("git", [
140 "rev-parse",
141 short && "--short",
142 "HEAD",
143 ]);
144 this.logger.verbose.info(`Got commit SHA from HEAD: ${result}`);
145 return result;
146 }
147 /** Get the SHA of the latest commit */
148 async shaExists(sha) {
149 try {
150 await exec_promise_1.default("git", ["rev-parse", "--verify", sha]);
151 return true;
152 }
153 catch (error) {
154 return false;
155 }
156 }
157 /** Get the labels for a PR */
158 async getLabels(prNumber) {
159 this.logger.verbose.info(`Getting labels for PR: ${prNumber}`);
160 const args = {
161 owner: this.options.owner,
162 repo: this.options.repo,
163 issue_number: prNumber,
164 };
165 this.logger.verbose.info("Getting issue labels using:", args);
166 try {
167 const labels = await this.github.issues.listLabelsOnIssue(args);
168 this.logger.veryVerbose.info('Got response for "listLabelsOnIssue":\n', labels);
169 this.logger.verbose.info("Found labels on PR:\n", labels.data);
170 return labels.data.map((l) => l.name);
171 }
172 catch (e) {
173 throw new GitAPIError("listLabelsOnIssue", args, e);
174 }
175 }
176 /** Get all the information about a PR or issue */
177 async getPr(prNumber) {
178 this.logger.verbose.info(`Getting info for PR: ${prNumber}`);
179 const args = {
180 owner: this.options.owner,
181 repo: this.options.repo,
182 issue_number: prNumber,
183 };
184 this.logger.verbose.info("Getting issue info using:", args);
185 try {
186 const info = await this.github.issues.get(args);
187 this.logger.veryVerbose.info('Got response for "issues.get":\n', info);
188 return info;
189 }
190 catch (e) {
191 throw new GitAPIError("getPr", args, e);
192 }
193 }
194 /** Get information about specific commit */
195 async getCommit(sha) {
196 this.logger.verbose.info(`Getting info for commit: ${sha}`);
197 try {
198 const info = await this.github.repos.getCommit({
199 owner: this.options.owner,
200 repo: this.options.repo,
201 ref: sha,
202 });
203 this.logger.veryVerbose.info('Got response for "repos.getCommit":\n', info);
204 return info;
205 }
206 catch (e) {
207 throw new GitAPIError("getCommit", [], e);
208 }
209 }
210 /** Get the labels for a the project */
211 async getProjectLabels() {
212 this.logger.verbose.info(`Getting labels for project: ${this.options.repo}`);
213 const args = {
214 owner: this.options.owner,
215 repo: this.options.repo,
216 };
217 try {
218 const labels = await this.github.paginate(this.github.issues.listLabelsForRepo, args);
219 this.logger.veryVerbose.info('Got response for "getProjectLabels":\n', labels);
220 this.logger.verbose.info("Found labels on project:\n", labels);
221 return labels.map((l) => l.name);
222 }
223 catch (e) {
224 throw new GitAPIError("getProjectLabels", args, e);
225 }
226 }
227 /** Get the git log for a range of commits */
228 async getGitLog(start, end = "HEAD") {
229 try {
230 const first = await this.getFirstCommit();
231 // This "shaExists" is just so we don't have to refactor all the tests
232 // in auto.test.ts. If the SHA doesn't really exist then the call to
233 // gitlog will fail too.
234 const startSha = (await this.shaExists(start))
235 ? await exec_promise_1.default("git", ["rev-parse", start])
236 : "";
237 const log = await gitlog_1.gitlogPromise({
238 repo: process.cwd(),
239 number: Number.MAX_SAFE_INTEGER,
240 fields: ["hash", "authorName", "authorEmail", "rawBody"],
241 // If start === firstCommit then we want to include that commit in the changelog
242 // Otherwise it was that last release and should not be included in the release.
243 branch: first === startSha ? end : `${start.trim()}..${end.trim()}`,
244 execOptions: { maxBuffer: Infinity },
245 includeMergeCommitFiles: true,
246 });
247 return log
248 .map((commit) => ({
249 hash: commit.hash,
250 authorName: commit.authorName,
251 authorEmail: commit.authorEmail,
252 subject: commit.rawBody,
253 files: (commit.files || []).map((file) => path_1.default.resolve(file)),
254 }))
255 .reduce((all, commit) => {
256 // The -m option will list a commit for each merge parent. This
257 // means two items will have the same hash. We are using -m to get all the changed files
258 // in a merge commit. The following code combines these repeated hashes into
259 // one commit
260 const current = all.find((c) => c.hash === commit.hash);
261 if (current) {
262 current.files = [...current.files, ...commit.files];
263 }
264 else {
265 all.push(commit);
266 }
267 return all;
268 }, []);
269 }
270 catch (error) {
271 console.log(error);
272 const tag = error.match(/ambiguous argument '(\S+)\.\.\S+'/);
273 if (tag) {
274 this.logger.log.error(endent_1.default `
275 Missing tag "${tag[1]}" so the command could not run.
276
277 To fix this run the following command:
278
279 git fetch --tags\n
280 `);
281 process.exit(1);
282 }
283 throw new Error(error);
284 }
285 }
286 /** Get the GitHub user for an email. Will not work if they do not have their email set to "public". */
287 async getUserByEmail(email) {
288 try {
289 const search = (await this.github.search.users({
290 q: `in:email ${email}`,
291 })).data;
292 return (search === null || search === void 0 ? void 0 : search.items.length) > 0 ? search.items[0] : {};
293 }
294 catch (error) {
295 this.logger.verbose.warn(`Could not find user by email: ${email}`);
296 }
297 }
298 /** Get collaborator permission level to the repo. */
299 async getTokenPermissionLevel() {
300 const [, user] = await await_to_js_1.default(this.github.users.getAuthenticated());
301 if (!user) {
302 return {
303 permission: "none",
304 };
305 }
306 try {
307 const { permission } = (await this.github.repos.getCollaboratorPermissionLevel({
308 owner: this.options.owner,
309 repo: this.options.repo,
310 username: user.data.login,
311 })).data;
312 return { permission, user: user.data };
313 }
314 catch (error) {
315 this.logger.verbose.error(`Could not get permissions for token`);
316 return { permission: "read", user: user.data };
317 }
318 }
319 /** Get the GitHub user for a username */
320 async getUserByUsername(username) {
321 try {
322 const user = await this.github.users.getByUsername({
323 username,
324 });
325 return user.data;
326 }
327 catch (error) {
328 this.logger.verbose.warn(`Could not find user by username: ${username}`);
329 }
330 }
331 /** Get all the information about a PR or issue */
332 async getPullRequest(pr) {
333 this.logger.verbose.info(`Getting Pull Request: ${pr}`);
334 const args = {
335 owner: this.options.owner,
336 repo: this.options.repo,
337 pull_number: pr,
338 };
339 this.logger.verbose.info("Getting pull request info using:", args);
340 const result = await this.github.pulls.get(args);
341 this.logger.veryVerbose.info("Got pull request data\n", result);
342 this.logger.verbose.info("Got pull request info");
343 return result;
344 }
345 /** Search to GitHub project's issue and pull requests */
346 async searchRepo(options) {
347 const repo = `repo:${this.options.owner}/${this.options.repo}`;
348 options.q = `${repo} ${options.q}`;
349 this.logger.verbose.info("Searching repo using:\n", options);
350 const result = await this.github.search.issuesAndPullRequests(options);
351 this.logger.veryVerbose.info("Got response from search\n", result);
352 this.logger.verbose.info("Searched repo on GitHub.");
353 return result.data;
354 }
355 /** Run a graphql query on the GitHub project */
356 async graphql(query) {
357 this.logger.verbose.info("Querying Github using GraphQL:\n", query);
358 const data = await graphql_1.graphql(query, {
359 baseUrl: this.graphqlBaseUrl,
360 request: { agent: this.options.agent },
361 headers: {
362 authorization: `token ${this.options.token}`,
363 },
364 });
365 this.logger.veryVerbose.info("Got response from query\n", data);
366 return data;
367 }
368 /** Create a status (or checkmark) on a commit */
369 async createStatus(prInfo) {
370 const args = Object.assign(Object.assign({}, prInfo), { owner: this.options.owner, repo: this.options.repo });
371 this.logger.verbose.info("Creating status using:\n", args);
372 const result = await this.github.repos.createCommitStatus(args);
373 this.logger.veryVerbose.info("Got response from createStatues\n", result);
374 this.logger.verbose.info("Created status on GitHub.");
375 return result;
376 }
377 /** Add a label to the project */
378 async createLabel(label) {
379 this.logger.verbose.info(`Creating "${label.releaseType || "general"}" label :\n${label.name}`);
380 const color = label.color
381 ? tinycolor2_1.default(label.color).toString("hex6")
382 : tinycolor2_1.default.random().toString("hex6");
383 const result = await this.github.issues.createLabel({
384 name: label.name,
385 owner: this.options.owner,
386 repo: this.options.repo,
387 color: color.replace("#", ""),
388 description: label.description,
389 });
390 this.logger.veryVerbose.info("Got response from createLabel\n", result);
391 this.logger.verbose.info("Created label on GitHub.");
392 return result;
393 }
394 /** Update a label on the project */
395 async updateLabel(label) {
396 this.logger.verbose.info(`Updating "${label.releaseType || "generic"}" label :\n${label.name}`);
397 const color = label.color
398 ? tinycolor2_1.default(label.color).toString("hex6")
399 : tinycolor2_1.default.random().toString("hex6");
400 const result = await this.github.issues.updateLabel({
401 current_name: label.name,
402 name: label.name,
403 owner: this.options.owner,
404 repo: this.options.repo,
405 color: color.replace("#", ""),
406 description: label.description,
407 });
408 this.logger.veryVerbose.info("Got response from updateLabel\n", result);
409 this.logger.verbose.info("Updated label on GitHub.");
410 return result;
411 }
412 /** Add a label to and issue or pull request */
413 async addLabelToPr(pr, label) {
414 this.logger.verbose.info(`Creating "${label}" label to PR ${pr}`);
415 const result = await this.github.issues.addLabels({
416 issue_number: pr,
417 owner: this.options.owner,
418 repo: this.options.repo,
419 labels: [label],
420 });
421 this.logger.veryVerbose.info("Got response from addLabels\n", result);
422 this.logger.verbose.info("Added labels on Pull Request.");
423 return result;
424 }
425 /** Add a label to and issue or pull request */
426 async removeLabel(pr, label) {
427 this.logger.verbose.info(`Removing "${label}" from #${pr}`);
428 const result = await this.github.issues.removeLabel({
429 issue_number: pr,
430 owner: this.options.owner,
431 repo: this.options.repo,
432 name: label,
433 });
434 this.logger.veryVerbose.info("Got response from removeLabel\n", result);
435 this.logger.verbose.info("Removed label on Pull Request.");
436 return result;
437 }
438 /** Lock an issue */
439 async lockIssue(issue) {
440 this.logger.verbose.info(`Locking #${issue} issue...`);
441 const result = await this.github.issues.lock({
442 issue_number: issue,
443 owner: this.options.owner,
444 repo: this.options.repo,
445 });
446 this.logger.veryVerbose.info("Got response from lock\n", result);
447 this.logger.verbose.info("Locked issue.");
448 return result;
449 }
450 /** Get information about the GitHub project */
451 async getProject() {
452 this.logger.verbose.info("Getting project from GitHub");
453 const result = (await this.github.repos.get({
454 owner: this.options.owner,
455 repo: this.options.repo,
456 })).data;
457 this.logger.veryVerbose.info("Got response from repos\n", result);
458 this.logger.verbose.info("Got project information.");
459 return result;
460 }
461 /** Get all the pull requests for a project */
462 async getPullRequests(options) {
463 this.logger.verbose.info("Getting pull requests...");
464 const result = (await this.github.pulls.list(Object.assign({ owner: this.options.owner.toLowerCase(), repo: this.options.repo.toLowerCase() }, options))).data;
465 this.logger.veryVerbose.info("Got response from pull requests", result);
466 this.logger.verbose.info("Got pull request");
467 return result;
468 }
469 /** Get all the commits for a PR */
470 async getCommitsForPR(pr) {
471 this.logger.verbose.info(`Getting commits for PR #${pr}`);
472 const result = await this.github.paginate(this.github.pulls.listCommits, {
473 owner: this.options.owner.toLowerCase(),
474 repo: this.options.repo.toLowerCase(),
475 pull_number: pr,
476 });
477 this.logger.veryVerbose.info(`Got response from PR #${pr}\n`, result);
478 this.logger.verbose.info(`Got commits for PR #${pr}.`);
479 return result;
480 }
481 /** Find a comment that is using the context in a PR */
482 async getCommentId(pr, context = "default") {
483 const commentIdentifier = makeCommentIdentifier(context);
484 this.logger.verbose.info("Getting previous comments on:", pr);
485 const comments = await this.github.issues.listComments({
486 owner: this.options.owner,
487 repo: this.options.repo,
488 issue_number: pr,
489 });
490 this.logger.veryVerbose.info("Got PR comments\n", comments);
491 const oldMessage = comments.data.find((comment) => comment.body.includes(commentIdentifier));
492 if (!oldMessage) {
493 return -1;
494 }
495 this.logger.verbose.info("Found previous message from same scope.");
496 return oldMessage.id;
497 }
498 /** Delete a comment on an issue or pull request */
499 async deleteComment(pr, context = "default") {
500 const commentId = await this.getCommentId(pr, context);
501 if (commentId === -1) {
502 return;
503 }
504 this.logger.verbose.info(`Deleting comment: ${commentId}`);
505 await this.github.issues.deleteComment({
506 owner: this.options.owner,
507 repo: this.options.repo,
508 comment_id: commentId,
509 });
510 this.logger.verbose.info(`Successfully deleted comment: ${commentId}`);
511 }
512 /** Create a comment on an issue or pull request */
513 async createComment(message, pr, context = "default") {
514 const commentIdentifier = makeCommentIdentifier(context);
515 this.logger.verbose.info("Using comment identifier:", commentIdentifier);
516 await this.deleteComment(pr, context);
517 this.logger.verbose.info("Creating new comment");
518 const result = await this.github.issues.createComment({
519 owner: this.options.owner,
520 repo: this.options.repo,
521 issue_number: pr,
522 body: `${commentIdentifier}\n${message}`,
523 });
524 this.logger.veryVerbose.info("Got response from creating comment\n", result);
525 this.logger.verbose.info("Successfully posted comment to PR");
526 return result;
527 }
528 /** Edit a comment on an issue or pull request */
529 async editComment(message, pr, context = "default") {
530 const commentIdentifier = makeCommentIdentifier(context);
531 this.logger.verbose.info("Using comment identifier:", commentIdentifier);
532 const commentId = await this.getCommentId(pr, context);
533 if (commentId === -1) {
534 return this.createComment(message, pr, context);
535 }
536 this.logger.verbose.info("Editing comment");
537 const result = await this.github.issues.updateComment({
538 owner: this.options.owner,
539 repo: this.options.repo,
540 comment_id: commentId,
541 body: `${commentIdentifier}\n${message}`,
542 });
543 this.logger.veryVerbose.info("Got response from editing comment\n", result);
544 this.logger.verbose.info("Successfully edited comment on PR");
545 return result;
546 }
547 /** Create a comment on a pull request body */
548 async addToPrBody(message, pr, context = "default") {
549 const id = makePrBodyIdentifier(context);
550 this.logger.verbose.info("Using PR body identifier:", id);
551 this.logger.verbose.info("Getting previous pr body on:", pr);
552 const issue = await this.github.issues.get({
553 owner: this.options.owner,
554 repo: this.options.repo,
555 issue_number: pr,
556 });
557 this.logger.veryVerbose.info("Got PR description\n", issue.data.body);
558 const regex = new RegExp(`(${id})\\s*([\\S\\s]*)\\s*(${id})`);
559 let body = issue.data.body;
560 if (!body) {
561 body = message ? `\n${id}\n${message}\n${id}\n` : "";
562 }
563 else if (body.match(regex)) {
564 this.logger.verbose.info("Found previous message from same scope.");
565 this.logger.verbose.info("Replacing pr body comment");
566 body = body.replace(regex, message ? `$1\n${message}\n$3` : "");
567 }
568 else {
569 body += message ? `\n${id}\n${message}\n${id}\n` : "";
570 }
571 this.logger.verbose.info("Creating new pr body");
572 const result = await this.github.issues.update({
573 owner: this.options.owner,
574 repo: this.options.repo,
575 issue_number: pr,
576 body,
577 });
578 this.logger.veryVerbose.info("Got response from updating body\n", result);
579 this.logger.verbose.info(`Successfully updated body of PR #${pr}`);
580 return result;
581 }
582 /** Create a release for the GitHub project */
583 async publish(releaseNotes, tag, prerelease = false) {
584 this.logger.verbose.info("Creating release on GitHub for tag:", tag);
585 const result = await this.github.repos.createRelease({
586 owner: this.options.owner,
587 repo: this.options.repo,
588 tag_name: tag,
589 name: tag,
590 body: releaseNotes,
591 prerelease,
592 });
593 this.logger.veryVerbose.info("Got response from createRelease\n", result);
594 this.logger.verbose.info("Created GitHub release.");
595 return result;
596 }
597 /** Get the latest tag in the git tree */
598 async getLatestTagInBranch(since) {
599 return exec_promise_1.default("git", ["describe", "--tags", "--abbrev=0", since]);
600 }
601 /** Get the tag before latest in the git tree */
602 async getPreviousTagInBranch() {
603 const latest = await this.getLatestTagInBranch();
604 return this.getLatestTagInBranch(`${latest}^1`);
605 }
606 /** Get all the tags for a given branch. */
607 async getTags(branch) {
608 const tags = await exec_promise_1.default("git", [
609 "tag",
610 "--sort='creatordate'",
611 "--merged",
612 branch,
613 ]);
614 return tags
615 .split("\n")
616 .map((tag) => tag.trim())
617 .filter(Boolean);
618 }
619 /** Get the a tag that isn't in the base branch */
620 async getTagNotInBaseBranch(branch, options = {}) {
621 const baseTags = (await this.getTags(`origin/${this.options.baseBranch}`)).reverse();
622 const branchTags = (await this.getTags(`heads/${branch}`)).reverse();
623 const comparator = options.first ? semver_1.lt : semver_1.gt;
624 let firstGreatestUnique;
625 branchTags.forEach((tag) => {
626 const tagVersion = getVersionFromTag(tag);
627 const greatestVersion = firstGreatestUnique
628 ? getVersionFromTag(firstGreatestUnique)
629 : undefined;
630 if (!baseTags.includes(tag) &&
631 (!greatestVersion || comparator(tagVersion, greatestVersion))) {
632 firstGreatestUnique = tag;
633 }
634 });
635 this.logger.verbose.info("Tags found in base branch:", baseTags);
636 this.logger.verbose.info("Tags found in branch:", branchTags);
637 this.logger.verbose.info(`${options.first ? "First" : "Latest"} tag in branch:`, firstGreatestUnique || "Not Found");
638 return firstGreatestUnique;
639 }
640 /** Get the last tag that isn't in the base branch */
641 async getLastTagNotInBaseBranch(branch) {
642 return this.getTagNotInBaseBranch(branch);
643 }
644 /** Determine the pull request for a commit hash */
645 async matchCommitToPr(sha) {
646 const query = match_sha_to_pr_1.buildSearchQuery(this.options.owner, this.options.repo, [
647 sha,
648 ]);
649 if (!query) {
650 return;
651 }
652 const key = `hash_${sha}`;
653 const result = await this.graphql(query);
654 if (!result || !result[key] || !result[key].edges[0]) {
655 return;
656 }
657 const pr = result[key].edges[0].node;
658 return Object.assign(Object.assign({}, pr), { labels: pr.labels ? pr.labels.edges.map((edge) => edge.node.name) : [] });
659 }
660}
661tslib_1.__decorate([
662 typescript_memoize_1.Memoize()
663], Git.prototype, "getLatestReleaseInfo", null);
664tslib_1.__decorate([
665 typescript_memoize_1.Memoize()
666], Git.prototype, "getLatestRelease", null);
667tslib_1.__decorate([
668 typescript_memoize_1.Memoize()
669], Git.prototype, "getLabels", null);
670tslib_1.__decorate([
671 typescript_memoize_1.Memoize()
672], Git.prototype, "getPr", null);
673tslib_1.__decorate([
674 typescript_memoize_1.Memoize()
675], Git.prototype, "getCommit", null);
676tslib_1.__decorate([
677 typescript_memoize_1.Memoize()
678], Git.prototype, "getGitLog", null);
679tslib_1.__decorate([
680 typescript_memoize_1.Memoize()
681], Git.prototype, "getUserByEmail", null);
682tslib_1.__decorate([
683 typescript_memoize_1.Memoize()
684], Git.prototype, "getTokenPermissionLevel", null);
685tslib_1.__decorate([
686 typescript_memoize_1.Memoize()
687], Git.prototype, "getUserByUsername", null);
688tslib_1.__decorate([
689 typescript_memoize_1.Memoize()
690], Git.prototype, "getPullRequest", null);
691tslib_1.__decorate([
692 typescript_memoize_1.Memoize()
693], Git.prototype, "getProject", null);
694tslib_1.__decorate([
695 typescript_memoize_1.Memoize()
696], Git.prototype, "getCommitsForPR", null);
697exports.default = Git;
698//# sourceMappingURL=git.js.map
\No newline at end of file