Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,8 @@
"webpack-cli": "^3.3.11"
},
"dependencies": {
"@octokit/rest": "^16.21.0",
"@octokit/rest": "^18.0.0",
"@octokit/types": "^5.1.0",
"apollo-boost": "^0.1.22",
"apollo-link-context": "^1.0.12",
"debounce": "^1.2.0",
Expand Down
3 changes: 2 additions & 1 deletion preview-src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function Root({ children }) {
ctx.onchange = setPR;
setPR(ctx.pr);
}, []);
ctx.postMessage({ command: 'pr.debug', args: ('initialized ' + (pr ? 'with PR' : 'without PR'))});
ctx.postMessage({ command: 'ready' });
ctx.postMessage({ command: 'pr.debug', args: ('initialized ' + (pr ? 'with PR' : 'without PR')) });
return pr ? children(pr) : <div className='loading-indicator'>Loading...</div>;
}
4 changes: 2 additions & 2 deletions preview-src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { vscode } from './message';
import { GithubItemStateEnum, IAccount, ReviewState, ILabel, MergeMethod, MergeMethodsAvailability, PullRequestMergeability } from '../src/github/interface';
import { TimelineEvent } from '../src/common/timelineEvent';
import { ReposGetCombinedStatusForRefResponse } from '@octokit/rest';
import { ReposGetCombinedStatusForRefResponseData } from '@octokit/types';

export interface PullRequest {
number: number;
Expand Down Expand Up @@ -35,7 +35,7 @@ export interface PullRequest {
hasWritePermission: boolean;
pendingCommentText?: string;
pendingCommentDrafts?: { [key: string]: string; };
status: ReposGetCombinedStatusForRefResponse;
status: ReposGetCombinedStatusForRefResponseData;
mergeable: PullRequestMergeability;
defaultMergeMethod: MergeMethod;
mergeMethodsAvailability: MergeMethodsAvailability;
Expand Down
7 changes: 5 additions & 2 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import { Event, Disposable } from 'vscode';
import { sep } from 'path';
import moment = require('moment');
import { HookError } from '@octokit/rest';

export function uniqBy<T>(arr: T[], fn: (el: T) => string): T[] {
const seen = Object.create(null);
Expand Down Expand Up @@ -94,8 +93,12 @@ export function groupBy<T>(arr: T[], fn: (el: T) => string): { [key: string]: T[
}, Object.create(null));
}

interface HookError extends Error {
errors: any;
}

function isHookError(e: Error): e is HookError {
return !!(e as HookError).errors;
return !!(<any>e).errors;
}

function hasFieldErrors(e: any): e is (Error & { errors: { value: string, field: string, code: string }[] }) {
Expand Down
13 changes: 11 additions & 2 deletions src/gitExtensionIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { RemoteSourceProvider, RemoteSource } from './typings/git';
import { CredentialStore, GitHub } from './github/credentials';
import { OctokitCommon } from './github/common';

interface Repository {
readonly full_name: string;
Expand All @@ -13,6 +14,14 @@ interface Repository {
readonly ssh_url: string;
}

function repoResponseAsRemoteSource(raw: OctokitCommon.SearchReposResponseItem): RemoteSource {
return {
name: `$(github) ${raw.full_name}`,
description: raw.description || undefined,
url: raw.url
};
}

function asRemoteSource(raw: Repository): RemoteSource {
return {
name: `$(github) ${raw.full_name}`,
Expand Down Expand Up @@ -53,7 +62,7 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {

private async getUserRemoteSources(hub: GitHub, query?: string): Promise<RemoteSource[]> {
if (!query) {
const res = await hub.octokit.repos.list({ sort: 'pushed', per_page: 100 });
const res = await hub.octokit.repos.listForAuthenticatedUser({ sort: 'pushed', per_page: 100 });
this.userReposCache = res.data.map(asRemoteSource);
}

Expand All @@ -66,6 +75,6 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
}

const raw = await hub.octokit.search.repos({ q: query, sort: 'updated' });
return raw.data.items.map(asRemoteSource);
return raw.data.items.map(repoResponseAsRemoteSource);
}
}
2 changes: 1 addition & 1 deletion src/gitProviders/GitHubContactServiceProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class GitHubContactServiceProvider implements ContactServiceProvider {
private async getCurrentUserLogin(): Promise<string | undefined> {
const origin = await this.pullRequestManager.getOrigin();
if (origin) {
const currentUser = origin.hub.octokit.currentUser;
const currentUser = origin.hub.currentUser;
if (currentUser) {
return currentUser.login;
}
Expand Down
29 changes: 29 additions & 0 deletions src/github/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as OctokitRest from '@octokit/rest';
import * as OctokitTypes from '@octokit/types';

export namespace OctokitCommon {
export type IssuesCreateParams = OctokitRest.RestEndpointMethodTypes['issues']['create']['parameters'];
export type PullsCreateParams = OctokitRest.RestEndpointMethodTypes['pulls']['create']['parameters'];
export type ReposGetCombinedStatusForRefResponseStatusesItem = OctokitTypes.ReposGetCombinedStatusForRefResponseData['statuses'][0];
export type ReposGetResponseOrganization = OctokitTypes.ReposGetResponseData['organization'];
export type PullsListResponseItem = OctokitTypes.PullsListResponseData[0];
export type PullsListResponseItemHead = PullsListResponseItem['head'];
export type PullsListResponseItemBase = PullsListResponseItem['base'];
export type PullsListResponseItemHeadRepo = PullsListResponseItemHead['repo'];
export type PullsListResponseItemBaseRepo = PullsListResponseItemBase['repo'];
export type PullsListResponseItemUser = PullsListResponseItem['user'];
export type PullsListResponseItemAssignee = PullsListResponseItem['assignee'];
export type PullsListResponseItemAssigneesItem = PullsListResponseItem['assignees'][0];
export type PullsListResponseItemRequestedReviewersItem = PullsListResponseItem['requested_reviewers'][0];
export type PullsListResponseItemBaseUser = PullsListResponseItemBase['user'];
export type PullsListResponseItemBaseRepoOwner = PullsListResponseItemBase['repo']['owner'];
export type PullsListResponseItemHeadUser = PullsListResponseItemHead['user'];
export type PullsListResponseItemHeadRepoOwner = PullsListResponseItemHead['repo']['owner'];
export type IssuesListEventsForTimelineResponseItemActor = OctokitTypes.IssuesListEventsForTimelineResponseData[0]['actor'];
export type PullsListReviewRequestsResponseTeamsItem = OctokitTypes.PullsListRequestedReviewersResponseData['teams'][0];
export type PullsListResponseItemHeadRepoTemplateRepository = PullsListResponseItem['head']['repo']['template_repository'];
export type ReposGetResponseCodeOfConduct = OctokitTypes.ReposGetResponseData['code_of_conduct'];
export type PullsListCommitsResponseItem = OctokitTypes.PullsListCommitsResponseData[0];
export type SearchReposResponseItem = OctokitTypes.SearchReposResponseData['items'][0];

}
35 changes: 17 additions & 18 deletions src/github/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import Octokit = require('@octokit/rest');
import { Octokit } from '@octokit/rest';
import * as OctokitTypes from '@octokit/types';
import { ApolloClient, InMemoryCache, NormalizedCacheObject } from 'apollo-boost';
import { setContext } from 'apollo-link-context';
import * as vscode from 'vscode';
Expand All @@ -25,13 +26,10 @@ const PROMPT_FOR_SIGN_IN_STORAGE_KEY = 'login';
const AUTH_PROVIDER_ID = 'github';
const SCOPES = ['read:user', 'user:email', 'repo'];

export interface AnnotatedOctokit extends Octokit {
currentUser?: Octokit.PullsGetResponseUser;
}

export interface GitHub {
octokit: AnnotatedOctokit;
octokit: Octokit;
graphql: ApolloClient<NormalizedCacheObject> | null;
currentUser?: OctokitTypes.PullsGetResponseData['user'];
}

export class CredentialStore {
Expand All @@ -48,7 +46,7 @@ export class CredentialStore {
this._sessionId = session.id;
const octokit = await this.createHub(token);
this._githubAPI = octokit;
await this.setCurrentUser(octokit.octokit);
await this.setCurrentUser(octokit);
} else {
Logger.debug(`No token found.`, 'Authentication');
}
Expand Down Expand Up @@ -129,7 +127,7 @@ export class CredentialStore {

if (octokit) {
this._githubAPI = octokit;
await this.setCurrentUser(octokit.octokit);
await this.setCurrentUser(octokit);

/* __GDPR__
"auth.success" : {}
Expand All @@ -146,18 +144,18 @@ export class CredentialStore {
}

public isCurrentUser(username: string): boolean {
return this._githubAPI?.octokit?.currentUser?.login === username;
return this._githubAPI?.currentUser?.login === username;
}

public getCurrentUser(): Octokit.PullsGetResponseUser {
public getCurrentUser(): OctokitTypes.PullsGetResponseData['user'] {
const octokit = this._githubAPI?.octokit;
// TODO remove cast
return octokit && (octokit as any).currentUser;
return octokit && (this._githubAPI as any).currentUser;
}

private async setCurrentUser(octokit: AnnotatedOctokit): Promise<void> {
const user = await octokit.users.getAuthenticated({});
octokit.currentUser = user.data;
private async setCurrentUser(github: GitHub): Promise<void> {
const user = await github.octokit.users.getAuthenticated({});
github.currentUser = user.data;
}

private async getSessionOrLogin(): Promise<string> {
Expand All @@ -172,9 +170,8 @@ export class CredentialStore {
userAgent: 'GitHub VSCode Pull Requests',
// `shadow-cat-preview` is required for Draft PR API access -- https://developer.github.com/v3/previews/#draft-pull-requests
previews: ['shadow-cat-preview'],
auth() {
return `token ${token || ''}`;
}
auth: `${token || ''}`

});

const graphql = new ApolloClient({
Expand All @@ -187,10 +184,12 @@ export class CredentialStore {
}
});

return {
const github: GitHub = {
octokit,
graphql
};
await this.setCurrentUser(github);
return github;
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/github/githubRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import Octokit = require('@octokit/rest');
import { Octokit } from '@octokit/rest';
import * as OctokitTypes from '@octokit/types';
import Logger from '../common/logger';
import { Remote, parseRemote } from '../common/remote';
import { IAccount, RepoAccessAndMergeMethods, PullRequestMergeability, IMilestone } from './interface';
Expand Down Expand Up @@ -41,7 +42,7 @@ export interface MilestoneData extends ItemsData {
hasMorePages: boolean;
}

export interface IMetadata extends Octokit.ReposGetResponse {
export interface IMetadata extends OctokitTypes.ReposGetResponseData {
currentUser: any;
}

Expand Down Expand Up @@ -417,7 +418,7 @@ export class GitHubRepository implements vscode.Disposable {
per_page: PULL_REQUEST_PAGE_SIZE,
page: page || 1
});
const promises: Promise<Octokit.Response<Octokit.PullsGetResponse>>[] = [];
const promises: Promise<OctokitTypes.OctokitResponse<OctokitTypes.PullsGetResponseData>>[] = [];
data.items.forEach((item: any /** unluckily Octokit.AnyResponse */) => {
promises.push(new Promise(async (resolve, reject) => {
const prData = await octokit.pulls.get({
Expand Down
19 changes: 17 additions & 2 deletions src/github/issueOverview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import * as path from 'path';
import * as vscode from 'vscode';
import Octokit = require('@octokit/rest');
import * as OctokitTypes from '@octokit/types';
import { ILabel } from './interface';
import { formatError } from '../common/utils';
import { IComment } from '../common/comment';
Expand Down Expand Up @@ -43,6 +43,8 @@ export class IssueOverviewPanel {
protected _item: IssueModel;
protected _pullRequestManager: PullRequestManager;
protected _scrollPosition = { x: 0, y: 0 };
private _waitForReady: Promise<void>;
private _onIsReady: vscode.EventEmitter<void> = new vscode.EventEmitter();

protected readonly MESSAGE_UNHANDLED: string = 'message not handled';

Expand Down Expand Up @@ -88,6 +90,13 @@ export class IssueOverviewPanel {
]
});

this._waitForReady = new Promise(resolve => {
const disposable = this._onIsReady.event(() => {
disposable.dispose();
resolve();
});
});

// Listen for when the panel is disposed
// This happens when the user closes the panel or when the panel is closed programatically
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
Expand Down Expand Up @@ -174,6 +183,9 @@ export class IssueOverviewPanel {
}

protected async _postMessage(message: any) {
// Without the following ready check, we can end up in a state where the message handler in the webview

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it even better ( no setInterval).

// isn't ready for any of the messages we post.
await this._waitForReady;
this._panel.webview.postMessage({
res: message
});
Expand Down Expand Up @@ -224,6 +236,9 @@ export class IssueOverviewPanel {
return this.removeLabel(message);
case 'pr.debug':
return this.webviewDebug(message);
case 'ready':
this._onIsReady.fire();
return;
default:
return this.MESSAGE_UNHANDLED;
}
Expand Down Expand Up @@ -329,7 +344,7 @@ export class IssueOverviewPanel {
}

private close(message: IRequestMessage<string>): void {
vscode.commands.executeCommand<Octokit.PullsGetResponse>('pr.close', this._item, message.args).then(comment => {
vscode.commands.executeCommand<OctokitTypes.PullsGetResponseData>('pr.close', this._item, message.args).then(comment => {
if (comment) {
this._replyMessage(message, {
value: comment
Expand Down
Loading