Skip to content

Commit

Permalink
Add CodeStream as a PR provider for GitLens
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Canzanella committed Jan 5, 2021
1 parent b96f70f commit 236b484
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 8 deletions.
6 changes: 5 additions & 1 deletion shared/ui/Stream/PullRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ export const PullRequest = () => {
currentPullRequestCommentId: state.context.currentPullRequest
? state.context.currentPullRequest.commentId
: undefined,
currentPullRequestSource: state.context.currentPullRequest
? state.context.currentPullRequest.source
: undefined,
currentPullRequest: currentPullRequest,
currentPullRequestLastUpdated: providerPullRequestLastUpdated,
composeCodemarkActive: state.context.composeCodemarkActive,
Expand Down Expand Up @@ -464,7 +467,8 @@ export const PullRequest = () => {
getOpenRepos();
initialFetch().then(_ => {
HostApi.instance.track("PR Details Viewed", {
Host: derivedState.currentPullRequestProviderId
Host: derivedState.currentPullRequestProviderId,
Source: derivedState.currentPullRequestSource
});
});
});
Expand Down
6 changes: 5 additions & 1 deletion shared/ui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,11 @@ function listenForEvents(store) {
});

api.on(ShowPullRequestNotificationType, async e => {
store.dispatch(setCurrentPullRequest(e.providerId, e.id, e.commentId));
if (e.url) {
store.dispatch(openPullRequestByUrl(e.url, { source: e.source }));
} else {
store.dispatch(setCurrentPullRequest(e.providerId, e.id, e.commentId, e.source));
}
});

api.on(HostDidReceiveRequestNotificationType, async e => {
Expand Down
2 changes: 2 additions & 0 deletions shared/ui/ipc/webview.protocol.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ export interface WebviewContext {
providerId: string;
id: string;
commentId?: string;
/* defined if this was triggered by an external means (like an IDE button, etc.) */
source?: string;
}
| undefined;
profileUserId?: string;
Expand Down
3 changes: 3 additions & 0 deletions shared/ui/ipc/webview.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export interface ShowPullRequestwNotification {
providerId: string;
id: string;
commentId?: string;
/* Either a providerId && id are used, OR a url */
url?: string;
source?: string;
}
export const ShowPullRequestNotificationType = new NotificationType<
ShowPullRequestwNotification,
Expand Down
11 changes: 8 additions & 3 deletions shared/ui/store/context/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,19 @@ export const setCurrentRepo = (id?: string, path?: string) =>
export const setCreatePullRequest = (reviewId?: string) =>
action(ContextActionsType.SetCreatePullRequest, { reviewId });

export const setCurrentPullRequest = (providerId: string, id: string, commentId?: string) =>
action(ContextActionsType.SetCurrentPullRequest, { providerId, id, commentId });
export const setCurrentPullRequest = (
providerId: string,
id: string,
commentId?: string,
source?: string
) => action(ContextActionsType.SetCurrentPullRequest, { providerId, id, commentId, source });

export const clearCurrentPullRequest = () =>
action(ContextActionsType.SetCurrentPullRequest, {
providerId: "",
id: "",
commentId: ""
commentId: "",
source: ""
});

export const setOnboardStep = (step: number) => action(ContextActionsType.SetOnboardStep, { step });
Expand Down
3 changes: 2 additions & 1 deletion shared/ui/store/context/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ export function reduceContext(
? {
providerId: action.payload.providerId,
id: action.payload.id,
commentId: action.payload.commentId
commentId: action.payload.commentId,
source: action.payload.source
}
: undefined,
pullRequestCheckoutBranch: false
Expand Down
10 changes: 9 additions & 1 deletion shared/ui/store/providerPullRequests/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ export const getPullRequestCommits = (providerId: string, id: string) => async (
export const openPullRequestByUrl = (
url: string,
options?: {
source?: string;
checkoutBranch?: any;
}
) => async (dispatch, getState: () => CodeStreamState) => {
Expand All @@ -329,7 +330,14 @@ export const openPullRequestByUrl = (
dispatch(setCurrentReview(""));
if (options && options.checkoutBranch)
dispatch(setCurrentPullRequestAndBranch(id as string));
dispatch(setCurrentPullRequest(providerInfo.providerId, id as string, ""));
dispatch(
setCurrentPullRequest(
providerInfo.providerId,
id as string,
"",
options ? options.source : undefined
)
);
handled = true;
}
}
Expand Down
42 changes: 42 additions & 0 deletions vscode/src/@types/gitlens.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Disposable } from "vscode";

export { Disposable } from "vscode";

export interface CreatePullRequestActionContext {
readonly type: "createPullRequest";
readonly branch: {
readonly name: string;
readonly remote?: {
readonly name: string;
readonly provider?: string;
readonly url?: string;
};
readonly repoPath: string;
};
}

export interface OpenPullRequestActionContext {
readonly type: "openPullRequest";
readonly pullRequest: {
readonly id: string;
readonly provider: string;
readonly repoPath: string;
readonly url: string;
};
}

export type ActionContext = CreatePullRequestActionContext | OpenPullRequestActionContext;
export type Action<T extends ActionContext> = T["type"];

export interface ActionRunner {
readonly label: string;

run(context: ActionContext): void | Promise<void>;
}

export interface GitLensApi {
registerActionRunner<T extends ActionContext>(
action: Action<T>,
runner: ActionRunner
): Disposable;
}
20 changes: 20 additions & 0 deletions vscode/src/controllers/webviewController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,26 @@ export class WebviewController implements Disposable {
});
}

@log()
async openPullRequestByUrl(url: string, source?: string): Promise<void> {
if (!this.visible) {
await this.show();
}

if (!this._webview) {
// it's possible that the webview is closing...
return;
}

// TODO: Change this to be a request vs a notification
this._webview!.notify(ShowPullRequestNotificationType, {
providerId: "",
id: "",
url: url,
source: source
});
}

@log()
async layoutChanged(): Promise<void> {
if (!this._webview) {
Expand Down
102 changes: 101 additions & 1 deletion vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import {
import { ScmTreeDataProvider } from "views/scmTreeDataProvider";
import { CodeStreamWebviewSidebar } from "webviews/webviewSidebar";
import { WebviewLike } from "webviews/webviewLike";

import {
CreatePullRequestActionContext,
GitLensApi,
OpenPullRequestActionContext
} from "./@types/gitlens";
import { GitExtension } from "./@types/git";
import { SessionStatusChangedEvent } from "./api/session";
import { ContextKeys, GlobalState, setContext } from "./common";
Expand All @@ -24,6 +30,7 @@ import { FileSystem, Strings, Versions } from "./system";

const extension = extensions.getExtension(extensionQualifiedId)!;
export const extensionVersion = extension.packageJSON.version;
let gitLensIntegrationInitializing = false;

interface BuildInfoMetadata {
buildNumber: string;
Expand All @@ -32,7 +39,6 @@ interface BuildInfoMetadata {

export async function activate(context: ExtensionContext) {
const start = process.hrtime();

Configuration.configure(context);
Logger.configure(context, configuration.get<TraceLevel>(configuration.name("traceLevel").value));

Expand Down Expand Up @@ -125,6 +131,100 @@ export async function activate(context: ExtensionContext) {
start
)} ms`
);

context.subscriptions.push(
Container.agent.onAgentInitialized(_ => {
if (gitLensIntegrationInitializing) return;
registerGitLensIntegration();
})
);
}

function registerGitLensIntegration() {
try {
gitLensIntegrationInitializing = true;

const getGitLens = () =>
extensions.getExtension<Promise<GitLensApi>>("eamodio.gitlens") ||
extensions.getExtension<Promise<GitLensApi>>("eamodio.gitlens-insiders");

let gitlens = getGitLens();
if (!gitlens) {
Logger.log("GitLens: Not installed.");
return;
}

let i = 0;
// NOTE: there's no event to listen to when another extension has activated
// so we have to poll to keep checking it. Open issue for that is:
// https://github.com/microsoft/vscode/issues/113783
const timeout = setTimeout(async _ => {
gitlens = getGitLens();
if (!gitlens) {
Logger.log(`GitLens: Not detected. Returning. attempt=${i}`);
clearInterval(timeout);
return;
}
if (gitlens.isActive) {
try {
const api: GitLensApi = await gitlens.exports;
api.registerActionRunner("openPullRequest", {
label: "CodeStream",
run: function(context: OpenPullRequestActionContext) {
try {
if (context.pullRequest.provider === "GitHub") {
Container.webview.openPullRequestByUrl(context.pullRequest.url, "VSC GitLens");
} else {
Logger.log(
`GitLens: openPullRequest. No provider for ${context.pullRequest.provider}`
);
}
} catch (e) {
Logger.warn(
`GitLens: openPullRequest. Failed to handle actionRunner openPullRequest e=${e}`
);
}
}
});
api.registerActionRunner("createPullRequest", {
label: "CodeStream",
run: function(context: CreatePullRequestActionContext) {
try {
if (context.branch && context.branch.remote) {
const editor = window.activeTextEditor;
Container.webview.newPullRequestRequest(
editor && editor.selection && !editor.selection.isEmpty ? editor : undefined,
"VSC GitLens"
);
} else {
Logger.log("GitLens: createPullRequest. No branch and/or remote");
}
} catch (e) {
Logger.warn(
`GitLens: createPullRequest. Failed to handle actionRunner createPullRequest e=${e}`
);
}
}
});
Logger.log(`GitLens: Found. attempt=${i}`);
Container.agent.telemetry.track("GitLens Detected", {});
} catch (e) {
Logger.warn(`GitLens: Failed to register. Giving up. attempt=${i} e=${e}`);
} finally {
clearInterval(timeout);
}
} else {
Logger.log(`GitLens: Not detected yet. attempt=${i}`);
i++;
if (i === 60) {
Logger.warn(`GitLens: Activation giving up. attempt=${i}`);
clearInterval(timeout);
}
}
}, 10000);
} catch (e) {
Logger.warn(`GitLens: generic error e=${e}`);
}
}

export async function deactivate(): Promise<void> {
Expand Down

0 comments on commit 236b484

Please sign in to comment.