diff --git a/package.json b/package.json index 81b4c3bb62..0e7bf58327 100644 --- a/package.json +++ b/package.json @@ -421,6 +421,7 @@ "devDependencies": { "@types/chai": "^4.1.4", "@types/debounce": "^3.0.0", + "@types/graphql": "^14.0.5", "@types/keytar": "^4.0.1", "@types/lodash": "^4.14.106", "@types/markdown-it": "^0.0.5", diff --git a/src/github/credentials.ts b/src/github/credentials.ts index b34d38c1ed..cd0c133c62 100644 --- a/src/github/credentials.ts +++ b/src/github/credentials.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as Octokit from '@octokit/rest'; -import { ApolloClient, InMemoryCache, NormalizedCacheObject } from 'apollo-boost'; +import { ApolloClient, InMemoryCache, NormalizedCacheObject, gql } from 'apollo-boost'; import { setContext } from 'apollo-link-context'; import * as vscode from 'vscode'; import { agent } from '../common/net'; @@ -25,7 +25,7 @@ const AUTH_INPUT_TOKEN_CMD = 'auth.inputTokenCallback'; export interface GitHub { octokit: Octokit; - graphql: ApolloClient; + graphql: ApolloClient | null; } export class CredentialStore { @@ -74,7 +74,7 @@ export class CredentialStore { if (token) { if (await server.validate(token)) { - octokit = this.createHub({ host, token }); + octokit = await this.createHub({ host, token }); } else { Logger.debug(`Token is no longer valid for host ${host}.`, 'Authentication'); } @@ -137,7 +137,7 @@ export class CredentialStore { this.willStartLogin(authority); const login = await server.login(); if (login && login.token) { - octokit = this.createHub(login); + octokit = await this.createHub(login); await setToken(login.host, login.token, { emit: false }); vscode.window.showInformationMessage(`You are now signed in to ${authority}`); } @@ -174,7 +174,7 @@ export class CredentialStore { return octokit && (octokit as any).currentUser && (octokit as any).currentUser.login === username; } - private createHub(creds: IHostConfiguration): GitHub { + private async createHub(creds: IHostConfiguration): Promise { const baseUrl = `${HostHelper.getApiHost(creds).toString().slice(0, -1)}${HostHelper.getApiPath(creds, '')}`; let octokit = new Octokit({ agent, @@ -187,17 +187,30 @@ export class CredentialStore { token: creds.token || '', }); - return { - octokit, - graphql: new ApolloClient({ - link: link(baseUrl, creds.token || ''), - cache: new InMemoryCache, - defaultOptions: { - query: { - fetchPolicy: 'no-cache' - } + const graphql = new ApolloClient({ + link: link(baseUrl, creds.token || ''), + cache: new InMemoryCache, + defaultOptions: { + query: { + fetchPolicy: 'no-cache' } + } + }); + + let supportsGraphQL = true; + await graphql.query({ query: gql `query { viewer { login } }` }) + .then(result => { + Logger.appendLine(`${baseUrl}: GraphQL support detected`); + Logger.appendLine(JSON.stringify(result, null, 2)); }) + .catch(err => { + Logger.appendLine(`${baseUrl}: GraphQL not supported (${err.message})`); + supportsGraphQL = false; + }); + + return { + octokit, + graphql: supportsGraphQL ? graphql : null, }; } diff --git a/src/github/githubRepository.ts b/src/github/githubRepository.ts index 324fec5301..a7321df251 100644 --- a/src/github/githubRepository.ts +++ b/src/github/githubRepository.ts @@ -53,7 +53,7 @@ export class GitHubRepository implements IGitHubRepository, vscode.Disposable { } await this.ensure(); - this.commentsProvider = this.supportsGraphQl() ? new PRDocumentCommentProviderGraphQL() : new PRDocumentCommentProvider(); + this.commentsProvider = this.supportsGraphQl ? new PRDocumentCommentProviderGraphQL() : new PRDocumentCommentProvider(); this._toDispose.push(vscode.workspace.registerDocumentCommentProvider(this.commentsProvider)); } catch (e) { console.log(e); @@ -72,7 +72,7 @@ export class GitHubRepository implements IGitHubRepository, vscode.Disposable { constructor(public remote: Remote, private readonly _credentialStore: CredentialStore) { } - supportsGraphQl(): boolean { + get supportsGraphQl(): boolean { return !!(this.hub && this.hub.graphql); } @@ -279,7 +279,7 @@ export class GitHubRepository implements IGitHubRepository, vscode.Disposable { async getPullRequest(id: number): Promise { try { Logger.debug(`Fetch pull request ${id} - enter`, GitHubRepository.ID); - const { octokit, query, remote } = await this.ensure(); + const { octokit, query, remote, supportsGraphQl } = await this.ensure(); let prsResult = await octokit.pullRequests.get({ owner: remote.owner, repo: remote.repositoryName, @@ -292,7 +292,7 @@ export class GitHubRepository implements IGitHubRepository, vscode.Disposable { return; } - if (this.supportsGraphQl()) { + if (supportsGraphQl) { const { data } = await query({ query: queries.PullRequest, variables: { diff --git a/src/github/pullRequestManager.ts b/src/github/pullRequestManager.ts index 3e3ed9684e..727bd24c16 100644 --- a/src/github/pullRequestManager.ts +++ b/src/github/pullRequestManager.ts @@ -666,10 +666,10 @@ export class PullRequestManager { async getTimelineEvents(pullRequest: PullRequestModel): Promise { Logger.debug(`Fetch timeline events of PR #${pullRequest.prNumber} - enter`, PullRequestManager.ID); - const { octokit, query, remote } = await pullRequest.githubRepository.ensure(); + const { octokit, query, remote, supportsGraphQl } = await pullRequest.githubRepository.ensure(); let ret = []; - if (pullRequest.githubRepository.supportsGraphQl()) { + if (supportsGraphQl) { try { const { data } = await query({ query: queries.TimelineEvents, @@ -794,7 +794,7 @@ export class PullRequestManager { return undefined; } - if (!pullRequest.githubRepository.supportsGraphQl()) { + if (!pullRequest.githubRepository.supportsGraphQl) { return; } diff --git a/src/github/pullRequestOverview.ts b/src/github/pullRequestOverview.ts index 0c0757d313..c8a068adaa 100644 --- a/src/github/pullRequestOverview.ts +++ b/src/github/pullRequestOverview.ts @@ -163,7 +163,7 @@ export class PullRequestOverviewPanel { const isCurrentlyCheckedOut = pullRequestModel.equals(this._pullRequestManager.activePullRequest); const canEdit = this._pullRequestManager.canEditPullRequest(this._pullRequest); const defaultMergeMethod = vscode.workspace.getConfiguration('githubPullRequests').get('defaultMergeMethod'); - const supportsGraphQl = pullRequestModel.githubRepository.supportsGraphQl(); + const supportsGraphQl = pullRequestModel.githubRepository.supportsGraphQl; this._postMessage({ command: 'pr.initialize', diff --git a/src/view/reviewManager.ts b/src/view/reviewManager.ts index 1d6856a0fc..77dacd2fac 100644 --- a/src/view/reviewManager.ts +++ b/src/view/reviewManager.ts @@ -900,7 +900,7 @@ export class ReviewManager implements vscode.DecorationProvider { } private registerCommentProvider() { - const supportsGraphQL = this._prManager.activePullRequest && (this._prManager.activePullRequest as PullRequestModel).githubRepository.supportsGraphQl(); + const supportsGraphQL = this._prManager.activePullRequest && (this._prManager.activePullRequest as PullRequestModel).githubRepository.supportsGraphQl; if (supportsGraphQL) { this._localToDispose.push(onDidSubmitReview(submittedComments => { this.updateCommentPendingState(submittedComments);