浏览代码

Adds CodeStream partnership

main
Eric Amodio 3 年前
父节点
当前提交
d418897e09
共有 4 个文件被更改,包括 188 次插入1 次删除
  1. +1
    -0
      package.json
  2. +1
    -0
      src/constants.ts
  3. +168
    -1
      src/partners.ts
  4. +18
    -0
      yarn.lock

+ 1
- 0
package.json 查看文件

@ -9111,6 +9111,7 @@
"dayjs": "1.10.4",
"iconv-lite": "0.6.2",
"lodash-es": "4.17.20",
"node-fetch": "3.0.0-beta.9",
"sortablejs": "1.13.0",
"vscode-codicons": "0.0.14",
"vsls": "1.0.3015"

+ 1
- 0
src/constants.ts 查看文件

@ -14,6 +14,7 @@ export enum BuiltInCommands {
ExecuteDocumentSymbolProvider = 'vscode.executeDocumentSymbolProvider',
ExecuteCodeLensProvider = 'vscode.executeCodeLensProvider',
FocusFilesExplorer = 'workbench.files.action.focusFilesExplorer',
InstallExtension = 'workbench.extensions.installExtension',
Open = 'vscode.open',
OpenFolder = 'vscode.openFolder',
OpenInTerminal = 'openInTerminal',

+ 168
- 1
src/partners.ts 查看文件

@ -1,13 +1,158 @@
'use strict';
import { ExtensionContext } from 'vscode';
import fetch from 'node-fetch';
import {
CancellationTokenSource,
commands,
Disposable,
env,
Extension,
ExtensionContext,
extensions,
Uri,
workspace,
} from 'vscode';
import { ActionRunnerType } from './api/actionRunners';
import { ActionContext, HoverCommandsActionContext } from './api/gitlens';
import { Commands, executeCommand, InviteToLiveShareCommandArgs } from './commands';
import { BuiltInCommands } from './constants';
import { Container } from './container';
import { Strings } from './system';
export async function installExtension<T>(
extensionId: string,
tokenSource: CancellationTokenSource,
timeout: number,
vsix?: Uri,
): Promise<Extension<T> | undefined> {
try {
let timer: any = 0;
const extension = new Promise<Extension<any> | undefined>(resolve => {
const disposable = extensions.onDidChange(() => {
const extension = extensions.getExtension(extensionId);
if (extension != null) {
clearTimeout(timer);
disposable.dispose();
resolve(extension);
}
});
tokenSource.token.onCancellationRequested(() => {
disposable.dispose();
resolve(undefined);
});
});
await commands.executeCommand(BuiltInCommands.InstallExtension, vsix ?? extensionId);
// Wait for extension activation until timeout expires
timer = setTimeout(() => tokenSource.cancel(), timeout);
return extension;
} catch {
tokenSource.cancel();
return undefined;
}
}
export function registerPartnerActionRunners(context: ExtensionContext): void {
registerCodeStream(context);
registerLiveShare(context);
}
function registerCodeStream(context: ExtensionContext): void {
if (extensions.getExtension('codestream.codestream') != null) return;
const subscriptions: Disposable[] = [];
const partnerId = 'codestream';
async function runner(ctx: ActionContext) {
const hashes = [];
for (const repo of await Container.git.getRepositories()) {
const user = await Container.git.getCurrentUser(repo.path);
if (user?.email != null) {
hashes.push(Strings.sha1(`gitlens:${user.email.trim().toLowerCase()}`, 'hex'));
}
}
const config = Container.config.partners?.[partnerId];
const url = (Container.insiders && config?.url) ?? 'https://api.codestream.com/no-auth/gitlens-user';
const body: { emailHashes: string[]; machineIdHash: string; installed?: boolean } = {
emailHashes: hashes,
machineIdHash: Strings.sha1(`gitlens:${env.machineId.trim().toLowerCase()}`, 'hex'),
};
void sendPartnerJsonRequest(url, JSON.stringify(body), 0);
const tokenSource = new CancellationTokenSource();
// Re-play action when/if we can find a matching newly installed runner
const { actionRunners } = Container;
const rerunDisposable = actionRunners.onDidChange(action => {
if (action != null && action !== ctx.type) return;
const runners = actionRunners.get(ctx.type);
if (runners == null || runners.length === 0) return;
const runner = runners.find(
r => r.type === ActionRunnerType.Partner && (r.partnerId === partnerId || r.name === 'CodeStream'),
);
if (runner != null) {
rerunDisposable.dispose();
void runner.run(ctx);
}
});
tokenSource.token.onCancellationRequested(() => rerunDisposable.dispose());
const extension = await installExtension(
'codestream.codestream',
tokenSource,
30000,
Container.insiders && config?.vsix != null ? Uri.file(config.vsix) : undefined,
);
if (extension == null) {
rerunDisposable.dispose();
return;
}
void workspace.fs.writeFile(Uri.joinPath(extension.extensionUri, '.gitlens'), new Uint8Array());
// Unregister the partner runners
Disposable.from(...subscriptions).dispose();
body.installed = true;
void sendPartnerJsonRequest(url, JSON.stringify(body), 0);
// Wait for 30s for new action runner registrations
setTimeout(() => tokenSource.cancel(), 30000);
}
subscriptions.push(
Container.actionRunners.registerBuiltInPartnerInstaller(partnerId, 'createPullRequest', {
name: 'CodeStream',
label: 'Create Pull Request in VS Code',
run: runner,
}),
Container.actionRunners.registerBuiltInPartnerInstaller(partnerId, 'openPullRequest', {
name: 'CodeStream',
label: 'Open Pull Request in VS Code',
run: runner,
}),
Container.actionRunners.registerBuiltInPartnerInstaller(partnerId, 'hover.commands', {
name: 'CodeStream',
label: '$(comment) Leave a Comment',
run: runner,
}),
);
context.subscriptions.push(...subscriptions);
}
function registerLiveShare(context: ExtensionContext) {
context.subscriptions.push(
Container.actionRunners.registerBuiltInPartner<HoverCommandsActionContext>('liveshare', 'hover.commands', {
@ -40,3 +185,25 @@ function registerLiveShare(context: ExtensionContext) {
}),
);
}
async function sendPartnerJsonRequest(url: string, body: string, retryCount: number) {
try {
const response = await fetch(url, {
method: 'POST',
body: body,
headers: { 'Content-Type': 'application/json' },
});
if (response.ok) return;
throw new Error(response.statusText);
} catch (ex) {
retryCount++;
if (retryCount > 6) {
// Give up
return;
}
setTimeout(() => sendPartnerJsonRequest(url, body, retryCount), Math.pow(2, retryCount) * 2000);
}
}

+ 18
- 0
yarn.lock 查看文件

@ -1337,6 +1337,11 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
data-uri-to-buffer@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==
dayjs@1.10.4:
version "1.10.4"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2"
@ -2075,6 +2080,11 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
fetch-blob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-2.1.1.tgz#a54ab0d5ed7ccdb0691db77b6674308b23fb2237"
integrity sha512-Uf+gxPCe1hTOFXwkxYyckn8iUSk6CFXGy5VENZKifovUTZC9eUODWSBhOBS7zICGrAetKzdwLMr85KhIcePMAQ==
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@ -3503,6 +3513,14 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-fetch@3.0.0-beta.9:
version "3.0.0-beta.9"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.0.0-beta.9.tgz#0a7554cfb824380dd6812864389923c783c80d9b"
integrity sha512-RdbZCEynH2tH46+tj0ua9caUHVWrd/RHnRfvly2EVdqGmI3ndS1Vn/xjm5KuGejDt2RNDQsVRLPNd2QPwcewVg==
dependencies:
data-uri-to-buffer "^3.0.1"
fetch-blob "^2.1.1"
node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"

正在加载...
取消
保存