Browse Source

Supports issues or pull requests in autolinks

main
Eric Amodio 4 years ago
parent
commit
088627c899
6 changed files with 56 additions and 33 deletions
  1. +18
    -12
      src/annotations/autolinks.ts
  2. +3
    -3
      src/git/formatters/commitFormatter.ts
  3. +2
    -1
      src/git/models/issue.ts
  4. +8
    -3
      src/git/remotes/github.ts
  5. +4
    -4
      src/git/remotes/provider.ts
  6. +21
    -10
      src/github/github.ts

+ 18
- 12
src/annotations/autolinks.ts View File

@ -4,7 +4,7 @@ import { AutolinkReference, configuration } from '../configuration';
import { Container } from '../container';
import { Dates, debug, Iterables, Promises, Strings } from '../system';
import { Logger } from '../logger';
import { GitRemote, Issue } from '../git/git';
import { GitRemote, IssueOrPullRequest } from '../git/git';
import { GlyphChars } from '../constants';
const numRegex = /<num>/g;
@ -50,7 +50,7 @@ export class Autolinks implements Disposable {
}
@debug({ args: false })
async getIssueLinks(message: string, remote: GitRemote, { timeout }: { timeout?: number } = {}) {
async getIssueOrPullRequestLinks(message: string, remote: GitRemote, { timeout }: { timeout?: number } = {}) {
if (!remote.provider?.hasApi()) return undefined;
const { provider } = remote;
@ -83,10 +83,16 @@ export class Autolinks implements Disposable {
if (ids.size === 0) return undefined;
const issues = await Promises.raceAll(ids.values(), id => provider.getIssue(id), timeout);
if (issues.size === 0 || Iterables.every(issues.values(), pr => pr === undefined)) return undefined;
const issuesOrPullRequests = await Promises.raceAll(
ids.values(),
id => provider.getIssueOrPullRequest(id),
timeout
);
if (issuesOrPullRequests.size === 0 || Iterables.every(issuesOrPullRequests.values(), pr => pr === undefined)) {
return undefined;
}
return issues;
return issuesOrPullRequests;
}
@debug({ args: false })
@ -94,10 +100,10 @@ export class Autolinks implements Disposable {
text: string,
markdown: boolean,
remotes?: GitRemote[],
issues?: Map<number, Issue | Promises.CancellationError | undefined>
issuesOrPullRequests?: Map<number, IssueOrPullRequest | Promises.CancellationError | undefined>
) {
for (const ref of this._references) {
if (this.ensureAutolinkCached(ref, issues)) {
if (this.ensureAutolinkCached(ref, issuesOrPullRequests)) {
if (ref.linkify != null) {
text = ref.linkify(text, markdown);
}
@ -109,7 +115,7 @@ export class Autolinks implements Disposable {
if (r.provider === undefined) continue;
for (const ref of r.provider.autolinks) {
if (this.ensureAutolinkCached(ref, issues)) {
if (this.ensureAutolinkCached(ref, issuesOrPullRequests)) {
if (ref.linkify != null) {
text = ref.linkify(text, markdown);
}
@ -123,7 +129,7 @@ export class Autolinks implements Disposable {
private ensureAutolinkCached(
ref: CacheableAutolinkReference | DynamicAutolinkReference,
issues?: Map<number, Issue | Promises.CancellationError | undefined>
issuesOrPullRequests?: Map<number, IssueOrPullRequest | Promises.CancellationError | undefined>
): ref is CacheableAutolinkReference | DynamicAutolinkReference {
if (isDynamic(ref)) return true;
@ -137,7 +143,7 @@ export class Autolinks implements Disposable {
);
}
if (issues == null || issues.size === 0) {
if (issuesOrPullRequests == null || issuesOrPullRequests.size === 0) {
const replacement = `[$1](${ref.url.replace(numRegex, '$2')}${
ref.title ? ` "${ref.title.replace(numRegex, '$2')}"` : ''
})`;
@ -150,7 +156,7 @@ export class Autolinks implements Disposable {
ref.linkify = (text: string, markdown: boolean) => {
if (markdown) {
return text.replace(ref.messageMarkdownRegex!, (substring, linkText, number) => {
const issue = issues?.get(Number(number));
const issue = issuesOrPullRequests?.get(Number(number));
return `[${linkText}](${ref.url.replace(numRegex, number)}${
ref.title
@ -175,7 +181,7 @@ export class Autolinks implements Disposable {
let superscript;
text = text.replace(ref.messageRegex!, (substring, linkText, number) => {
const issue = issues?.get(Number(number));
const issue = issuesOrPullRequests?.get(Number(number));
if (issue == null) return linkText;
if (footnotes === undefined) {

+ 3
- 3
src/git/formatters/commitFormatter.ts View File

@ -11,7 +11,7 @@ import {
import { DateStyle, FileAnnotationType } from '../../configuration';
import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitCommit, GitLogCommit, GitRemote, GitService, GitUri, Issue, PullRequest } from '../gitService';
import { GitCommit, GitLogCommit, GitRemote, GitService, GitUri, IssueOrPullRequest, PullRequest } from '../gitService';
import { Promises, Strings } from '../../system';
import { FormatOptions, Formatter } from './formatter';
import { ContactPresence } from '../../vsls/vsls';
@ -24,7 +24,7 @@ const hasTokenRegexMap = new Map();
export interface CommitFormatOptions extends FormatOptions {
annotationType?: FileAnnotationType;
autolinkedIssues?: Map<number, Issue | Promises.CancellationError | undefined>;
autolinkedIssuesOrPullRequests?: Map<number, IssueOrPullRequest | Promises.CancellationError | undefined>;
dateStyle?: DateStyle;
getBranchAndTagTips?: (sha: string) => string | undefined;
line?: number;
@ -354,7 +354,7 @@ export class CommitFormatter extends Formatter {
this._options.markdown ? Strings.escapeMarkdown(message, { quoted: true }) : message,
this._options.markdown ?? false,
this._options.remotes,
this._options.autolinkedIssues
this._options.autolinkedIssuesOrPullRequests
);
}

+ 2
- 1
src/git/models/issue.ts View File

@ -1,6 +1,7 @@
'use strict';
export interface Issue {
export interface IssueOrPullRequest {
type: 'Issue' | 'PullRequest';
provider: string;
id: number;
date: Date;

+ 8
- 3
src/git/remotes/github.ts View File

@ -3,7 +3,7 @@ import { Disposable, env, QuickInputButton, Range, Uri, window } from 'vscode';
import { DynamicAutolinkReference } from '../../annotations/autolinks';
import { AutolinkReference } from '../../config';
import { Container } from '../../container';
import { Issue } from '../models/issue';
import { IssueOrPullRequest } from '../models/issue';
import { PullRequest } from '../models/pullRequest';
import { RemoteProviderWithApi } from './provider';
@ -136,9 +136,14 @@ export class GitHubRemote extends RemoteProviderWithApi<{ token: string }> {
return `${this.baseUrl}?path=${fileName}${line}`;
}
protected async onGetIssue({ token }: { token: string }, id: number): Promise<Issue | undefined> {
protected async onGetIssueOrPullRequest(
{ token }: { token: string },
id: number
): Promise<IssueOrPullRequest | undefined> {
const [owner, repo] = this.splitPath();
return (await Container.github)?.getIssue(this.name, token, owner, repo, id, { baseUrl: this.apiBaseUrl });
return (await Container.github)?.getIssueOrPullRequest(this.name, token, owner, repo, id, {
baseUrl: this.apiBaseUrl
});
}
protected async onGetPullRequestForCommit(

+ 4
- 4
src/git/remotes/provider.ts View File

@ -6,7 +6,7 @@ import { Container } from '../../container';
import { CredentialChangeEvent, CredentialManager } from '../../credentials';
import { Logger } from '../../logger';
import { Messages } from '../../messages';
import { Issue } from '../models/issue';
import { IssueOrPullRequest } from '../models/issue';
import { GitLogCommit } from '../models/logCommit';
import { PullRequest } from '../models/pullRequest';
import { debug, gate, Promises } from '../../system';
@ -246,14 +246,14 @@ export abstract class RemoteProviderWithApi extends
@gate()
@debug()
async getIssue(id: number): Promise<Issue | undefined> {
async getIssueOrPullRequest(id: number): Promise<IssueOrPullRequest | undefined> {
const cc = Logger.getCorrelationContext();
const connected = this.maybeConnected ?? (await this.isConnected());
if (!connected) return undefined;
try {
return await this.onGetIssue(this._credentials!, id);
return await this.onGetIssueOrPullRequest(this._credentials!, id);
} catch (ex) {
Logger.error(ex, cc);
@ -276,7 +276,7 @@ export abstract class RemoteProviderWithApi extends
return pr.then(pr => pr ?? undefined);
}
protected abstract onGetIssue(credentials: T, id: number): Promise<Issue | undefined>;
protected abstract onGetIssueOrPullRequest(credentials: T, id: number): Promise<IssueOrPullRequest | undefined>;
protected abstract onGetPullRequestForCommit(credentials: T, ref: string): Promise<PullRequest | undefined>;
protected _credentials: T | null | undefined;

+ 21
- 10
src/github/github.ts View File

@ -2,7 +2,7 @@
import { graphql } from '@octokit/graphql';
import { Logger } from '../logger';
import { debug } from '../system';
import { Issue, PullRequest, PullRequestState } from '../git/gitService';
import { IssueOrPullRequest, PullRequest, PullRequestState } from '../git/gitService';
export class GitHubApi {
@debug({
@ -86,7 +86,7 @@ export class GitHubApi {
1: token => '<token>'
}
})
async getIssue(
async getIssueOrPullRequest(
provider: string,
token: string,
owner: string,
@ -95,17 +95,26 @@ export class GitHubApi {
options?: {
baseUrl?: string;
}
): Promise<Issue | undefined> {
): Promise<IssueOrPullRequest | undefined> {
const cc = Logger.getCorrelationContext();
try {
const query = `query pr($owner: String!, $repo: String!, $number: Int!) {
repository(name: $repo, owner: $owner) {
issue(number: $number) {
createdAt
closed
closedAt
title
issueOrPullRequest(number: $number) {
__typename
... on Issue {
createdAt
closed
closedAt
title
}
... on PullRequest {
createdAt
closed
closedAt
title
}
}
}
}`;
@ -118,11 +127,12 @@ export class GitHubApi {
headers: { authorization: `token ${token}` },
...options
});
const issue = rsp?.repository?.issue as GitHubIssue | undefined;
const issue = rsp?.repository?.issueOrPullRequest as GitHubIssueOrPullRequest | undefined;
if (issue == null) return undefined;
return {
provider: provider,
type: issue.type,
id: number,
date: new Date(issue.createdAt),
title: issue.title,
@ -136,7 +146,8 @@ export class GitHubApi {
}
}
interface GitHubIssue {
interface GitHubIssueOrPullRequest {
type: 'Issue' | 'PullRequest';
number: number;
createdAt: string;
closed: boolean;

||||||
x
 
000:0
Loading…
Cancel
Save