mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Merge branch 'ads-master-vscode-2020-05-31T19-47-47'
This commit is contained in:
185
.eslintrc.json
185
.eslintrc.json
@@ -63,13 +63,18 @@
|
||||
"browser": [
|
||||
"common"
|
||||
],
|
||||
"electron-main": [
|
||||
"electron-sandbox": [
|
||||
"common",
|
||||
"node"
|
||||
"browser"
|
||||
],
|
||||
"electron-browser": [
|
||||
"common",
|
||||
"browser",
|
||||
"node",
|
||||
"electron-sandbox"
|
||||
],
|
||||
"electron-main": [
|
||||
"common",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
@@ -106,6 +111,14 @@
|
||||
"rxjs/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/base/electron-sandbox/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,electron-sandbox}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/base/node/**",
|
||||
"restrictions": [
|
||||
@@ -155,13 +168,22 @@
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/base/parts/*/electron-sandbox/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,electron-sandbox}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/base/parts/*/electron-browser/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
@@ -191,10 +213,10 @@
|
||||
"typemoq",
|
||||
"sinon",
|
||||
"vs/nls",
|
||||
"azdata",
|
||||
"azdata",
|
||||
"**/{vs,sql}/base/common/**",
|
||||
"**/{vs,sql}/base/test/common/**",
|
||||
"**/{vs,sql}/base/parts/*/common/**",
|
||||
"**/{vs,sql}/base/test/common/**",
|
||||
"**/{vs,sql}/platform/*/common/**",
|
||||
"**/{vs,sql}/platform/*/test/common/**"
|
||||
]
|
||||
@@ -221,15 +243,25 @@
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/platform/*/electron-sandbox/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/platform/*/{common,browser,electron-sandbox}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/platform/*/electron-browser/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"azdata",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,node}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/*/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/*/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
@@ -442,18 +474,34 @@
|
||||
"**/{vs,sql}/**/{common,worker}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/workbench/electron-sandbox/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/platform/*/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/editor/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/editor/contrib/**", // editor/contrib is equivalent to /browser/ by convention
|
||||
"**/{vs,sql}/workbench/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/api/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/services/*/{common,browser,electron-sandbox}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/workbench/electron-browser/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/*/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/editor/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/*/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/*/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/editor/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/editor/contrib/**", // editor/contrib is equivalent to /browser/ by convention
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-browser,api}/**",
|
||||
"**/{vs,sql}/workbench/services/*/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/api/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/services/*/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
@@ -465,7 +513,7 @@
|
||||
"**/{vs,sql}/base/**",
|
||||
"**/{vs,sql}/platform/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"vs/workbench/contrib/files/common/editors/fileEditorInput",
|
||||
"**/{vs,sql}/workbench/services/**",
|
||||
"**/{vs,sql}/workbench/test/**",
|
||||
@@ -537,16 +585,30 @@
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/workbench/services/**/electron-sandbox/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/**/{common,browser,worker,electron-sandbox}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/api/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/services/**/{common,browser,electron-sandbox}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/workbench/services/**/electron-browser/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/**/{common,browser,worker,node,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/**/{common,browser,worker,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-browser,api}/**",
|
||||
"**/{vs,sql}/workbench/services/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/api/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/services/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
@@ -559,7 +621,7 @@
|
||||
"**/{vs,sql}/base/**",
|
||||
"**/{vs,sql}/platform/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/services/**",
|
||||
"**/{vs,sql}/workbench/contrib/**",
|
||||
"**/{vs,sql}/workbench/test/**",
|
||||
@@ -663,17 +725,32 @@
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/workbench/contrib/**/electron-sandbox/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/**/{common,browser,worker,electron-sandbox}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/api/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/services/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/contrib/**/{common,browser,electron-sandbox}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/workbench/contrib/**/electron-browser/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/**/{common,browser,worker,node,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/**/{common,browser,worker,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-browser,api}/**",
|
||||
"**/{vs,sql}/workbench/services/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/contrib/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/api/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/services/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/contrib/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
@@ -693,10 +770,10 @@
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/code/**/{common,browser,node,electron-browser}/**",
|
||||
"**/{vs,sql}/base/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/code/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
@@ -724,6 +801,54 @@
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/src/{vs,sql}/workbench/workbench.common.main.ts",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"**/{vs,sql}/base/**/{common,browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/**/{common,browser}/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/src/{vs,sql}/workbench/workbench.web.main.ts",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"**/{vs,sql}/base/**/{common,browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/**/{common,browser}/**",
|
||||
"**/{vs,sql}/workbench/workbench.common.main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/src/{vs,sql}/workbench/workbench.sandbox.main.ts",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"**/{vs,sql}/base/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/**/{common,browser,electron-sandbox}/**",
|
||||
"**/{vs,sql}/workbench/workbench.common.main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/src/{vs,sql}/workbench/workbench.desktop.main.ts",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"**/{vs,sql}/base/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/**/{common,browser,node,electron-sandbox,electron-browser}/**",
|
||||
"**/{vs,sql}/workbench/workbench.common.main",
|
||||
"**/{vs,sql}/workbench/workbench.sandbox.main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/extensions/**",
|
||||
"restrictions": "**/*"
|
||||
|
||||
34
.vscode/launch.json
vendored
34
.vscode/launch.json
vendored
@@ -20,10 +20,7 @@
|
||||
"port": 5870,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
"presentation": {
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
@@ -108,38 +105,11 @@
|
||||
],
|
||||
"browserLaunchLocation": "workspace"
|
||||
},
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch azuredatastudio with new notebook command",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.bat"
|
||||
},
|
||||
"osx": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
|
||||
},
|
||||
"urlFilter": "*index.html*",
|
||||
"runtimeArgs": [
|
||||
"--inspect=5875",
|
||||
"--command=notebook.command.new"
|
||||
],
|
||||
"skipFiles": [
|
||||
"**/winjs*.js"
|
||||
],
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"timeout": 45000
|
||||
},
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch ADS (Web) (TBD)",
|
||||
"runtimeExecutable": "yarn",
|
||||
"runtimeArgs": [
|
||||
"web"
|
||||
],
|
||||
"program": "${workspaceFolder}/scripts/code-web.js",
|
||||
"presentation": {
|
||||
"group": "0_vscode",
|
||||
"order": 2
|
||||
|
||||
2
.yarnrc
2
.yarnrc
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "7.2.4"
|
||||
target "7.3.0"
|
||||
runtime "electron"
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as request from 'request';
|
||||
import { createReadStream, createWriteStream, unlink, mkdir } from 'fs';
|
||||
import * as github from 'github-releases';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const BASE_URL = 'https://rink.hockeyapp.net/api/2/';
|
||||
const HOCKEY_APP_TOKEN_HEADER = 'X-HockeyAppToken';
|
||||
|
||||
export interface IVersions {
|
||||
app_versions: IVersion[];
|
||||
}
|
||||
|
||||
export interface IVersion {
|
||||
id: number;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface IApplicationAccessor {
|
||||
accessToken: string;
|
||||
appId: string;
|
||||
}
|
||||
|
||||
export interface IVersionAccessor extends IApplicationAccessor {
|
||||
id: string;
|
||||
}
|
||||
|
||||
enum Platform {
|
||||
WIN_32 = 'win32-ia32',
|
||||
WIN_64 = 'win32-x64',
|
||||
LINUX_64 = 'linux-x64',
|
||||
MAC_OS = 'darwin-x64'
|
||||
}
|
||||
|
||||
function symbolsZipName(platform: Platform, electronVersion: string, insiders: boolean): string {
|
||||
return `${insiders ? 'insiders' : 'stable'}-symbols-v${electronVersion}-${platform}.zip`;
|
||||
}
|
||||
|
||||
const SEED = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
async function tmpFile(name: string): Promise<string> {
|
||||
let res = '';
|
||||
for (let i = 0; i < 8; i++) {
|
||||
res += SEED.charAt(Math.floor(Math.random() * SEED.length));
|
||||
}
|
||||
|
||||
const tmpParent = join(tmpdir(), res);
|
||||
|
||||
await promisify(mkdir)(tmpParent);
|
||||
|
||||
return join(tmpParent, name);
|
||||
}
|
||||
|
||||
function getVersions(accessor: IApplicationAccessor): Promise<IVersions> {
|
||||
return asyncRequest<IVersions>({
|
||||
url: `${BASE_URL}/apps/${accessor.appId}/app_versions`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
[HOCKEY_APP_TOKEN_HEADER]: accessor.accessToken
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createVersion(accessor: IApplicationAccessor, version: string): Promise<IVersion> {
|
||||
return asyncRequest<IVersion>({
|
||||
url: `${BASE_URL}/apps/${accessor.appId}/app_versions/new`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
[HOCKEY_APP_TOKEN_HEADER]: accessor.accessToken
|
||||
},
|
||||
formData: {
|
||||
bundle_version: version
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateVersion(accessor: IVersionAccessor, symbolsPath: string) {
|
||||
return asyncRequest<IVersions>({
|
||||
url: `${BASE_URL}/apps/${accessor.appId}/app_versions/${accessor.id}`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
[HOCKEY_APP_TOKEN_HEADER]: accessor.accessToken
|
||||
},
|
||||
formData: {
|
||||
dsym: createReadStream(symbolsPath)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function asyncRequest<T>(options: request.UrlOptions & request.CoreOptions): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
request(options, (error, _response, body) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(JSON.parse(body));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function downloadAsset(repository: any, assetName: string, targetPath: string, electronVersion: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
repository.getReleases({ tag_name: `v${electronVersion}` }, (err: any, releases: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const asset = releases[0].assets.filter((asset: any) => asset.name === assetName)[0];
|
||||
if (!asset) {
|
||||
reject(new Error(`Asset with name ${assetName} not found`));
|
||||
} else {
|
||||
repository.downloadAsset(asset, (err: any, reader: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const writer = createWriteStream(targetPath);
|
||||
writer.on('error', reject);
|
||||
writer.on('close', resolve);
|
||||
reader.on('error', reject);
|
||||
|
||||
reader.pipe(writer);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
interface IOptions {
|
||||
repository: string;
|
||||
platform: Platform;
|
||||
versions: { code: string; insiders: boolean; electron: string; };
|
||||
access: { hockeyAppToken: string; hockeyAppId: string; githubToken: string };
|
||||
}
|
||||
|
||||
async function ensureVersionAndSymbols(options: IOptions) {
|
||||
|
||||
// Check version does not exist
|
||||
console.log(`HockeyApp: checking for existing version ${options.versions.code} (${options.platform})`);
|
||||
const versions = await getVersions({ accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId });
|
||||
if (!Array.isArray(versions.app_versions)) {
|
||||
throw new Error(`Unexpected response: ${JSON.stringify(versions)}`);
|
||||
}
|
||||
|
||||
if (versions.app_versions.some(v => v.version === options.versions.code)) {
|
||||
console.log(`HockeyApp: Returning without uploading symbols because version ${options.versions.code} (${options.platform}) was already found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Download symbols for platform and electron version
|
||||
const symbolsName = symbolsZipName(options.platform, options.versions.electron, options.versions.insiders);
|
||||
const symbolsPath = await tmpFile('symbols.zip');
|
||||
console.log(`HockeyApp: downloading symbols ${symbolsName} for electron ${options.versions.electron} (${options.platform}) into ${symbolsPath}`);
|
||||
await downloadAsset(new (github as any)({ repo: options.repository, token: options.access.githubToken }), symbolsName, symbolsPath, options.versions.electron);
|
||||
|
||||
// Create version
|
||||
console.log(`HockeyApp: creating new version ${options.versions.code} (${options.platform})`);
|
||||
const version = await createVersion({ accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId }, options.versions.code);
|
||||
|
||||
// Upload symbols
|
||||
console.log(`HockeyApp: uploading symbols for version ${options.versions.code} (${options.platform})`);
|
||||
await updateVersion({ id: String(version.id), accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId }, symbolsPath);
|
||||
|
||||
// Cleanup
|
||||
await promisify(unlink)(symbolsPath);
|
||||
}
|
||||
|
||||
// Environment
|
||||
const pakage = require('../../../package.json');
|
||||
const product = require('../../../product.json');
|
||||
const repository = product.electronRepository;
|
||||
const electronVersion = require('../../lib/electron').getElectronVersion();
|
||||
const insiders = product.quality !== 'stable';
|
||||
let codeVersion = pakage.version;
|
||||
if (insiders) {
|
||||
codeVersion = `${codeVersion}-insider`;
|
||||
}
|
||||
const githubToken = process.argv[2];
|
||||
const hockeyAppToken = process.argv[3];
|
||||
const is64 = process.argv[4] === 'x64';
|
||||
const hockeyAppId = process.argv[5];
|
||||
|
||||
if (process.argv.length !== 6) {
|
||||
throw new Error(`HockeyApp: Unexpected number of arguments. Got ${process.argv}`);
|
||||
}
|
||||
|
||||
let platform: Platform;
|
||||
if (process.platform === 'darwin') {
|
||||
platform = Platform.MAC_OS;
|
||||
} else if (process.platform === 'win32') {
|
||||
platform = is64 ? Platform.WIN_64 : Platform.WIN_32;
|
||||
} else {
|
||||
platform = Platform.LINUX_64;
|
||||
}
|
||||
|
||||
// Create version and upload symbols in HockeyApp
|
||||
if (repository && codeVersion && electronVersion && (product.quality === 'stable' || product.quality === 'insider')) {
|
||||
ensureVersionAndSymbols({
|
||||
repository,
|
||||
platform,
|
||||
versions: {
|
||||
code: codeVersion,
|
||||
insiders,
|
||||
electron: electronVersion
|
||||
},
|
||||
access: {
|
||||
githubToken,
|
||||
hockeyAppToken,
|
||||
hockeyAppId
|
||||
}
|
||||
}).then(() => {
|
||||
console.log('HockeyApp: done');
|
||||
}).catch(error => {
|
||||
console.error(`HockeyApp: error ${error} (AppID: ${hockeyAppId})`);
|
||||
|
||||
return process.exit(1);
|
||||
});
|
||||
} else {
|
||||
console.log(`HockeyApp: skipping due to unexpected context (repository: ${repository}, codeVersion: ${codeVersion}, electronVersion: ${electronVersion}, quality: ${product.quality})`);
|
||||
}
|
||||
12
build/azure-pipelines/darwin/app-entitlements.plist
Normal file
12
build/azure-pipelines/darwin/app-entitlements.plist
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -65,12 +65,13 @@ steps:
|
||||
# ./scripts/test-integration.sh --tfs "Integration Tests"
|
||||
# displayName: Run Integration Tests (Electron)
|
||||
|
||||
# - task: PublishPipelineArtifact@0
|
||||
# inputs:
|
||||
# artifactName: crash-dump-macos
|
||||
# targetPath: .build/crashes
|
||||
# displayName: 'Publish Crash Reports'
|
||||
# condition: succeededOrFailed()
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: crash-dump-macos
|
||||
targetPath: .build/crashes
|
||||
displayName: 'Publish Crash Reports'
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Tests Results
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -157,24 +157,18 @@ steps:
|
||||
artifactName: crash-dump-macos
|
||||
targetPath: .build/crashes
|
||||
displayName: 'Publish Crash Reports'
|
||||
condition: succeededOrFailed()
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-darwin
|
||||
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||
HELPER_APP_NAME="`echo $APP_NAME | sed -e 's/^Visual Studio //;s/\.app$//'`"
|
||||
APP_FRAMEWORK_PATH="$APP_ROOT/$APP_NAME/Contents/Frameworks"
|
||||
security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
|
||||
security default-keychain -s $(agent.tempdirectory)/buildagent.keychain
|
||||
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
|
||||
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
|
||||
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
|
||||
codesign -s 99FM488X57 --deep --force --options runtime --entitlements build/azure-pipelines/darwin/entitlements.plist "$APP_ROOT"/*.app
|
||||
codesign -s 99FM488X57 --force --options runtime --entitlements build/azure-pipelines/darwin/helper-gpu-entitlements.plist "$APP_FRAMEWORK_PATH/$HELPER_APP_NAME Helper (GPU).app"
|
||||
codesign -s 99FM488X57 --force --options runtime --entitlements build/azure-pipelines/darwin/helper-plugin-entitlements.plist "$APP_FRAMEWORK_PATH/$HELPER_APP_NAME Helper (Plugin).app"
|
||||
codesign -s 99FM488X57 --force --options runtime --entitlements build/azure-pipelines/darwin/helper-renderer-entitlements.plist "$APP_FRAMEWORK_PATH/$HELPER_APP_NAME Helper (Renderer).app"
|
||||
DEBUG=electron-osx-sign* node build/darwin/sign.js
|
||||
displayName: Set Hardened Entitlements
|
||||
|
||||
- script: |
|
||||
@@ -248,16 +242,28 @@ steps:
|
||||
SessionTimeout: 60
|
||||
displayName: Notarization
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-darwin
|
||||
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||
"$APP_ROOT/$APP_NAME/Contents/Resources/app/bin/code" --export-default-configuration=.build
|
||||
displayName: Verify start after signing (export configuration)
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
|
||||
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \
|
||||
./build/azure-pipelines/darwin/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
- script: |
|
||||
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
|
||||
yarn gulp upload-vscode-configuration
|
||||
displayName: Upload configuration (for Bing settings search)
|
||||
continueOnError: true
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
continueOnError: true
|
||||
|
||||
@@ -17,11 +17,3 @@ node build/azure-pipelines/common/createAsset.js \
|
||||
archive-unsigned \
|
||||
"vscode-server-darwin.zip" \
|
||||
../vscode-server-darwin.zip
|
||||
|
||||
# publish hockeyapp symbols
|
||||
# node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS"
|
||||
# Skip hockey app because build failure.
|
||||
# https://github.com/microsoft/vscode/issues/90491
|
||||
|
||||
# upload configuration
|
||||
yarn gulp upload-vscode-configuration
|
||||
|
||||
@@ -81,6 +81,14 @@ steps:
|
||||
# displayName: 'Publish Crash Reports'
|
||||
# condition: succeededOrFailed()
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: crash-dump-linux
|
||||
targetPath: .build/crashes
|
||||
displayName: 'Publish Crash Reports'
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Tests Results
|
||||
inputs:
|
||||
|
||||
@@ -107,7 +107,6 @@ steps:
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \
|
||||
./build/azure-pipelines/linux/multiarch/$(VSCODE_ARCH)/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
|
||||
@@ -145,7 +145,8 @@ steps:
|
||||
artifactName: crash-dump-linux
|
||||
targetPath: .build/crashes
|
||||
displayName: 'Publish Crash Reports'
|
||||
condition: succeededOrFailed()
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
@@ -178,7 +179,6 @@ steps:
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \
|
||||
./build/azure-pipelines/linux/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
|
||||
@@ -27,11 +27,6 @@ rm -rf $ROOT/vscode-server-*.tar.*
|
||||
|
||||
node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH"
|
||||
|
||||
# Publish hockeyapp symbols
|
||||
# node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64"
|
||||
# Skip hockey app because build failure.
|
||||
# https://github.com/microsoft/vscode/issues/90491
|
||||
|
||||
# Publish DEB
|
||||
PLATFORM_DEB="linux-deb-x64"
|
||||
DEB_ARCH="amd64"
|
||||
|
||||
@@ -12,6 +12,8 @@ const es = require('event-stream');
|
||||
const vfs = require('vinyl-fs');
|
||||
const fancyLog = require('fancy-log');
|
||||
const ansiColors = require('ansi-colors');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function main() {
|
||||
const quality = process.env['VSCODE_QUALITY'];
|
||||
@@ -21,7 +23,7 @@ function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
const productJsonFilter = filter('**/product.json', { restore: true });
|
||||
const productJsonFilter = filter(f => f.relative === 'product.json', { restore: true });
|
||||
|
||||
fancyLog(ansiColors.blue('[mixin]'), `Mixing in sources:`);
|
||||
return vfs
|
||||
@@ -29,7 +31,32 @@ function main() {
|
||||
.pipe(filter(f => !f.isDirectory()))
|
||||
.pipe(productJsonFilter)
|
||||
.pipe(buffer())
|
||||
.pipe(json(o => Object.assign({}, require('../../product.json'), o)))
|
||||
.pipe(json(o => {
|
||||
const ossProduct = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'product.json'), 'utf8'));
|
||||
let builtInExtensions = ossProduct.builtInExtensions;
|
||||
|
||||
if (Array.isArray(o.builtInExtensions)) {
|
||||
fancyLog(ansiColors.blue('[mixin]'), 'Overwriting built-in extensions:', o.builtInExtensions.map(e => e.name));
|
||||
|
||||
builtInExtensions = o.builtInExtensions;
|
||||
} else if (o.builtInExtensions) {
|
||||
const include = o.builtInExtensions['include'] || [];
|
||||
const exclude = o.builtInExtensions['exclude'] || [];
|
||||
|
||||
fancyLog(ansiColors.blue('[mixin]'), 'OSS built-in extensions:', builtInExtensions.map(e => e.name));
|
||||
fancyLog(ansiColors.blue('[mixin]'), 'Including built-in extensions:', include.map(e => e.name));
|
||||
fancyLog(ansiColors.blue('[mixin]'), 'Excluding built-in extensions:', exclude);
|
||||
|
||||
builtInExtensions = builtInExtensions.filter(ext => !include.find(e => e.name === ext.name) && !exclude.find(name => name === ext.name));
|
||||
builtInExtensions = [...builtInExtensions, ...include];
|
||||
|
||||
fancyLog(ansiColors.blue('[mixin]'), 'Final built-in extensions:', builtInExtensions.map(e => e.name));
|
||||
} else {
|
||||
fancyLog(ansiColors.blue('[mixin]'), 'Inheriting OSS built-in extensions', builtInExtensions.map(e => e.name));
|
||||
}
|
||||
|
||||
return { ...ossProduct, ...o, builtInExtensions };
|
||||
}))
|
||||
.pipe(productJsonFilter.restore)
|
||||
.pipe(es.mapSync(function (f) {
|
||||
fancyLog(ansiColors.blue('[mixin]'), f.relative, ansiColors.green('✔︎'));
|
||||
|
||||
@@ -36,6 +36,17 @@ jobs:
|
||||
steps:
|
||||
- template: win32/product-build-win32.yml
|
||||
|
||||
- job: WindowsARM64
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_ARM64'], 'true'))
|
||||
pool:
|
||||
vmImage: VS2017-Win2016
|
||||
variables:
|
||||
VSCODE_ARCH: arm64
|
||||
dependsOn:
|
||||
- Compile
|
||||
steps:
|
||||
- template: win32/product-build-win32-arm64.yml
|
||||
|
||||
- job: Linux
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
|
||||
pool:
|
||||
|
||||
@@ -72,29 +72,6 @@ steps:
|
||||
vstsFeed: 'npm-vscode'
|
||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
yarn generate-github-config
|
||||
displayName: Generate GitHub config
|
||||
condition: succeeded()
|
||||
env:
|
||||
OSS_GITHUB_ID: "a5d3c261b032765a78de"
|
||||
OSS_GITHUB_SECRET: $(oss-github-client-secret)
|
||||
INSIDERS_GITHUB_ID: "31f02627809389d9f111"
|
||||
INSIDERS_GITHUB_SECRET: $(insiders-github-client-secret)
|
||||
STABLE_GITHUB_ID: "baa8a44b5e861d918709"
|
||||
STABLE_GITHUB_SECRET: $(stable-github-client-secret)
|
||||
EXPLORATION_GITHUB_ID: "94e8376d3a90429aeaea"
|
||||
EXPLORATION_GITHUB_SECRET: $(exploration-github-client-secret)
|
||||
VSO_GITHUB_ID: "3d4be8f37a0325b5817d"
|
||||
VSO_GITHUB_SECRET: $(vso-github-client-secret)
|
||||
VSO_PPE_GITHUB_ID: "eabf35024dc2e891a492"
|
||||
VSO_PPE_GITHUB_SECRET: $(vso-ppe-github-client-secret)
|
||||
VSO_DEV_GITHUB_ID: "84383ebd8a7c5f5efc5c"
|
||||
VSO_DEV_GITHUB_SECRET: $(vso-dev-github-client-secret)
|
||||
GITHUB_APP_ID: "Iv1.ae51e546bef24ff1"
|
||||
GITHUB_APP_SECRET: $(github-app-client-secret)
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
yarn postinstall
|
||||
|
||||
@@ -72,12 +72,13 @@ steps:
|
||||
# .\scripts\test-integration.bat --tfs "Integration Tests"
|
||||
# displayName: Run Integration Tests (Electron)
|
||||
|
||||
# - task: PublishPipelineArtifact@0
|
||||
# displayName: 'Publish Crash Reports'
|
||||
# inputs:
|
||||
# artifactName: crash-dump-windows
|
||||
# targetPath: .build\crashes
|
||||
# condition: succeededOrFailed()
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Crash Reports'
|
||||
inputs:
|
||||
artifactName: crash-dump-windows
|
||||
targetPath: .build\crashes
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Tests Results
|
||||
|
||||
190
build/azure-pipelines/win32/product-build-win32-arm64.yml
Normal file
190
build/azure-pipelines/win32/product-build-win32-arm64.yml
Normal file
@@ -0,0 +1,190 @@
|
||||
steps:
|
||||
- powershell: |
|
||||
mkdir .build -ea 0
|
||||
"$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit
|
||||
"$env:VSCODE_QUALITY" | Out-File -Encoding ascii -NoNewLine .build\quality
|
||||
displayName: Prepare cache flag
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: 'build/.cachesalt, .build/commit, .build/quality'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
exit 1
|
||||
displayName: Check RestoreCache
|
||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.x"
|
||||
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '2.x'
|
||||
addToPath: true
|
||||
|
||||
- task: AzureKeyVault@1
|
||||
displayName: 'Azure Key Vault: Get Secrets'
|
||||
inputs:
|
||||
azureSubscription: 'vscode-builds-subscription'
|
||||
KeyVaultName: vscode
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
"machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII
|
||||
|
||||
exec { git config user.email "vscode@microsoft.com" }
|
||||
exec { git config user.name "VSCode" }
|
||||
|
||||
mkdir .build -ea 0
|
||||
"$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch
|
||||
displayName: Prepare tooling
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" }
|
||||
exec { git fetch distro }
|
||||
exec { git merge $(node -p "require('./package.json').distro") }
|
||||
displayName: Merge distro
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
|
||||
vstsFeed: 'npm-vscode'
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:npm_config_arch="$(VSCODE_ARCH)"
|
||||
$env:CHILD_CONCURRENCY="1"
|
||||
exec { yarn --frozen-lockfile }
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
|
||||
inputs:
|
||||
keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
|
||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
|
||||
vstsFeed: 'npm-vscode'
|
||||
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { yarn postinstall }
|
||||
displayName: Run postinstall scripts
|
||||
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { node build/azure-pipelines/mixin }
|
||||
displayName: Mix in quality
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" }
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-code-helper" }
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" }
|
||||
displayName: Build
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)'
|
||||
Pattern: '*.dll,*.exe,*.node'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "VS Code"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "https://code.visualstudio.com/"
|
||||
},
|
||||
{
|
||||
"parameterName": "Append",
|
||||
"parameterValue": "/as"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolVerify",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "VerifyAll",
|
||||
"parameterValue": "/all"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: Install ESRPClient.exe
|
||||
inputs:
|
||||
restoreSolution: 'build\azure-pipelines\win32\ESRPClient\packages.config'
|
||||
feedsToUse: config
|
||||
nugetConfigPath: 'build\azure-pipelines\win32\ESRPClient\NuGet.config'
|
||||
externalFeedCredentials: 3fc0b7f7-da09-4ae7-a9c8-d69824b1819b
|
||||
restoreDirectory: packages
|
||||
|
||||
- task: ESRPImportCertTask@1
|
||||
displayName: Import ESRP Request Signing Certificate
|
||||
inputs:
|
||||
ESRP: 'ESRP CodeSign'
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
.\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(esrp-auth-certificate) -AuthCertificateKey $(esrp-auth-certificate-key)
|
||||
displayName: Import ESRP Auth Certificate
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)"
|
||||
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
|
||||
.\build\azure-pipelines\win32\publish.ps1
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
continueOnError: true
|
||||
@@ -154,7 +154,8 @@ steps:
|
||||
artifactName: crash-dump-windows-$(VSCODE_ARCH)
|
||||
targetPath: .build\crashes
|
||||
displayName: 'Publish Crash Reports'
|
||||
condition: succeededOrFailed()
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
@@ -235,7 +236,6 @@ steps:
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)"
|
||||
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)"
|
||||
$env:VSCODE_HOCKEYAPP_TOKEN = "$(vscode-hockeyapp-token)"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
|
||||
.\build\azure-pipelines\win32\publish.ps1
|
||||
displayName: Publish
|
||||
|
||||
@@ -16,22 +16,21 @@ $ServerZip = "$Repo\.build\vscode-server-win32-$Arch.zip"
|
||||
$Build = "$Root\VSCode-win32-$Arch"
|
||||
|
||||
# Create server archive
|
||||
exec { xcopy $LegacyServer $Server /H /E /I }
|
||||
exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r }
|
||||
if ("$Arch" -ne "arm64") {
|
||||
exec { xcopy $LegacyServer $Server /H /E /I }
|
||||
exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r }
|
||||
}
|
||||
|
||||
# get version
|
||||
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
|
||||
$AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-x64" }
|
||||
$AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-$Arch" }
|
||||
|
||||
exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform-archive" archive "VSCode-win32-$Arch-$Version.zip" $Zip }
|
||||
exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform" setup "VSCodeSetup-$Arch-$Version.exe" $SystemExe }
|
||||
exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $UserExe }
|
||||
exec { node build/azure-pipelines/common/createAsset.js "server-$AssetPlatform" archive "vscode-server-win32-$Arch.zip" $ServerZip }
|
||||
|
||||
# Skip hockey app because build failure.
|
||||
# https://github.com/microsoft/vscode/issues/90491
|
||||
# publish hockeyapp symbols
|
||||
# $hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" }
|
||||
# exec { node build/azure-pipelines/common/symbols.js "$env:VSCODE_MIXIN_PASSWORD" "$env:VSCODE_HOCKEYAPP_TOKEN" "$Arch" $hockeyAppId }
|
||||
if ("$Arch" -ne "arm64") {
|
||||
exec { node build/azure-pipelines/common/createAsset.js "server-$AssetPlatform" archive "vscode-server-win32-$Arch.zip" $ServerZip }
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ const path = require('path');
|
||||
let window = null;
|
||||
|
||||
app.once('ready', () => {
|
||||
window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, webviewTag: true } });
|
||||
window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, webviewTag: true, enableWebSQL: false } });
|
||||
window.setMenuBarVisibility(false);
|
||||
window.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true }));
|
||||
// window.webContents.openDevTools();
|
||||
window.once('closed', () => window = null);
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => app.quit());
|
||||
app.on('window-all-closed', () => app.quit());
|
||||
|
||||
61
build/darwin/sign.js
Normal file
61
build/darwin/sign.js
Normal file
@@ -0,0 +1,61 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const codesign = require("electron-osx-sign");
|
||||
const path = require("path");
|
||||
const util = require("../lib/util");
|
||||
const product = require("../../product.json");
|
||||
async function main() {
|
||||
const buildDir = process.env['AGENT_BUILDDIRECTORY'];
|
||||
const tempDir = process.env['AGENT_TEMPDIRECTORY'];
|
||||
if (!buildDir) {
|
||||
throw new Error('$AGENT_BUILDDIRECTORY not set');
|
||||
}
|
||||
if (!tempDir) {
|
||||
throw new Error('$AGENT_TEMPDIRECTORY not set');
|
||||
}
|
||||
const baseDir = path.dirname(__dirname);
|
||||
const appRoot = path.join(buildDir, 'VSCode-darwin');
|
||||
const appName = product.nameLong + '.app';
|
||||
const appFrameworkPath = path.join(appRoot, appName, 'Contents', 'Frameworks');
|
||||
const helperAppBaseName = product.nameShort;
|
||||
const gpuHelperAppName = helperAppBaseName + ' Helper (GPU).app';
|
||||
const pluginHelperAppName = helperAppBaseName + ' Helper (Plugin).app';
|
||||
const rendererHelperAppName = helperAppBaseName + ' Helper (Renderer).app';
|
||||
const defaultOpts = {
|
||||
app: path.join(appRoot, appName),
|
||||
platform: 'darwin',
|
||||
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'app-entitlements.plist'),
|
||||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'app-entitlements.plist'),
|
||||
hardenedRuntime: true,
|
||||
'pre-auto-entitlements': false,
|
||||
'pre-embed-provisioning-profile': false,
|
||||
keychain: path.join(tempDir, 'buildagent.keychain'),
|
||||
version: util.getElectronVersion(),
|
||||
identity: '99FM488X57',
|
||||
'gatekeeper-assess': false
|
||||
};
|
||||
const appOpts = Object.assign(Object.assign({}, defaultOpts), {
|
||||
// TODO(deepak1556): Incorrectly declared type in electron-osx-sign
|
||||
ignore: (filePath) => {
|
||||
return filePath.includes(gpuHelperAppName) ||
|
||||
filePath.includes(pluginHelperAppName) ||
|
||||
filePath.includes(rendererHelperAppName);
|
||||
} });
|
||||
const gpuHelperOpts = Object.assign(Object.assign({}, defaultOpts), { app: path.join(appFrameworkPath, gpuHelperAppName), entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'), 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist') });
|
||||
const pluginHelperOpts = Object.assign(Object.assign({}, defaultOpts), { app: path.join(appFrameworkPath, pluginHelperAppName), entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'), 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist') });
|
||||
const rendererHelperOpts = Object.assign(Object.assign({}, defaultOpts), { app: path.join(appFrameworkPath, rendererHelperAppName), entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'), 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist') });
|
||||
await codesign.signAsync(gpuHelperOpts);
|
||||
await codesign.signAsync(pluginHelperOpts);
|
||||
await codesign.signAsync(rendererHelperOpts);
|
||||
await codesign.signAsync(appOpts);
|
||||
}
|
||||
if (require.main === module) {
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
90
build/darwin/sign.ts
Normal file
90
build/darwin/sign.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as codesign from 'electron-osx-sign';
|
||||
import * as path from 'path';
|
||||
import * as util from '../lib/util';
|
||||
import * as product from '../../product.json';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const buildDir = process.env['AGENT_BUILDDIRECTORY'];
|
||||
const tempDir = process.env['AGENT_TEMPDIRECTORY'];
|
||||
|
||||
if (!buildDir) {
|
||||
throw new Error('$AGENT_BUILDDIRECTORY not set');
|
||||
}
|
||||
|
||||
if (!tempDir) {
|
||||
throw new Error('$AGENT_TEMPDIRECTORY not set');
|
||||
}
|
||||
|
||||
const baseDir = path.dirname(__dirname);
|
||||
const appRoot = path.join(buildDir, 'VSCode-darwin');
|
||||
const appName = product.nameLong + '.app';
|
||||
const appFrameworkPath = path.join(appRoot, appName, 'Contents', 'Frameworks');
|
||||
const helperAppBaseName = product.nameShort;
|
||||
const gpuHelperAppName = helperAppBaseName + ' Helper (GPU).app';
|
||||
const pluginHelperAppName = helperAppBaseName + ' Helper (Plugin).app';
|
||||
const rendererHelperAppName = helperAppBaseName + ' Helper (Renderer).app';
|
||||
|
||||
const defaultOpts: codesign.SignOptions = {
|
||||
app: path.join(appRoot, appName),
|
||||
platform: 'darwin',
|
||||
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'app-entitlements.plist'),
|
||||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'app-entitlements.plist'),
|
||||
hardenedRuntime: true,
|
||||
'pre-auto-entitlements': false,
|
||||
'pre-embed-provisioning-profile': false,
|
||||
keychain: path.join(tempDir, 'buildagent.keychain'),
|
||||
version: util.getElectronVersion(),
|
||||
identity: '99FM488X57',
|
||||
'gatekeeper-assess': false
|
||||
};
|
||||
|
||||
const appOpts = {
|
||||
...defaultOpts,
|
||||
// TODO(deepak1556): Incorrectly declared type in electron-osx-sign
|
||||
ignore: (filePath: string) => {
|
||||
return filePath.includes(gpuHelperAppName) ||
|
||||
filePath.includes(pluginHelperAppName) ||
|
||||
filePath.includes(rendererHelperAppName);
|
||||
}
|
||||
};
|
||||
|
||||
const gpuHelperOpts: codesign.SignOptions = {
|
||||
...defaultOpts,
|
||||
app: path.join(appFrameworkPath, gpuHelperAppName),
|
||||
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'),
|
||||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'),
|
||||
};
|
||||
|
||||
const pluginHelperOpts: codesign.SignOptions = {
|
||||
...defaultOpts,
|
||||
app: path.join(appFrameworkPath, pluginHelperAppName),
|
||||
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'),
|
||||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-plugin-entitlements.plist'),
|
||||
};
|
||||
|
||||
const rendererHelperOpts: codesign.SignOptions = {
|
||||
...defaultOpts,
|
||||
app: path.join(appFrameworkPath, rendererHelperAppName),
|
||||
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'),
|
||||
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'),
|
||||
};
|
||||
|
||||
await codesign.signAsync(gpuHelperOpts);
|
||||
await codesign.signAsync(pluginHelperOpts);
|
||||
await codesign.signAsync(rendererHelperOpts);
|
||||
await codesign.signAsync(appOpts as any);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -127,6 +127,7 @@ const createESMSourcesAndResourcesTask = task.define('extract-editor-esm', () =>
|
||||
|
||||
const compileEditorESMTask = task.define('compile-editor-esm', () => {
|
||||
const KEEP_PREV_ANALYSIS = false;
|
||||
const FAIL_ON_PURPOSE = false;
|
||||
console.log(`Launching the TS compiler at ${path.join(__dirname, '../out-editor-esm')}...`);
|
||||
let result;
|
||||
if (process.platform === 'win32') {
|
||||
@@ -142,7 +143,7 @@ const compileEditorESMTask = task.define('compile-editor-esm', () => {
|
||||
console.log(result.stdout.toString());
|
||||
console.log(result.stderr.toString());
|
||||
|
||||
if (result.status !== 0) {
|
||||
if (FAIL_ON_PURPOSE || result.status !== 0) {
|
||||
console.log(`The TS Compilation failed, preparing analysis folder...`);
|
||||
const destPath = path.join(__dirname, '../../vscode-monaco-editor-esm-analysis');
|
||||
const keepPrevAnalysis = (KEEP_PREV_ANALYSIS && fs.existsSync(destPath));
|
||||
|
||||
@@ -60,6 +60,7 @@ const indentationFilter = [
|
||||
// except specific folders
|
||||
'!test/automation/out/**',
|
||||
'!test/smoke/out/**',
|
||||
'!extensions/typescript-language-features/test-workspace/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace2/**',
|
||||
'!build/monaco/**',
|
||||
@@ -85,7 +86,7 @@ const indentationFilter = [
|
||||
'!src/typings/**/*.d.ts',
|
||||
'!extensions/**/*.d.ts',
|
||||
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe,ico,icns,plist}',
|
||||
'!build/{lib,download}/**/*.js',
|
||||
'!build/{lib,download,darwin}/**/*.js',
|
||||
'!build/**/*.sh',
|
||||
'!build/azure-pipelines/**/*.js',
|
||||
'!build/azure-pipelines/**/*.config',
|
||||
|
||||
@@ -77,6 +77,7 @@ const vscodeResources = [
|
||||
'out-build/vs/base/node/languagePacks.js',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}',
|
||||
'out-build/vs/base/browser/ui/codicons/codicon/**',
|
||||
'out-build/vs/base/parts/sandbox/electron-browser/preload.js',
|
||||
'out-build/vs/workbench/browser/media/*-theme.css',
|
||||
'out-build/vs/workbench/contrib/debug/**/*.json',
|
||||
'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt',
|
||||
@@ -184,6 +185,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
||||
const out = sourceFolderName;
|
||||
|
||||
const checksums = computeChecksums(out, [
|
||||
'vs/base/parts/sandbox/electron-browser/preload.js',
|
||||
'vs/workbench/workbench.desktop.main.js',
|
||||
'vs/workbench/workbench.desktop.main.css',
|
||||
'vs/workbench/services/extensions/node/extensionHostProcess.js',
|
||||
|
||||
@@ -66,6 +66,7 @@ function buildWin32Setup(arch, target) {
|
||||
return cb => {
|
||||
const ia32AppId = target === 'system' ? product.win32AppId : product.win32UserAppId;
|
||||
const x64AppId = target === 'system' ? product.win32x64AppId : product.win32x64UserAppId;
|
||||
const arm64AppId = target === 'system' ? product.win32arm64AppId : product.win32arm64UserAppId;
|
||||
|
||||
const sourcePath = buildPath(arch);
|
||||
const outputPath = setupDir(arch, target);
|
||||
@@ -89,12 +90,12 @@ function buildWin32Setup(arch, target) {
|
||||
ShellNameShort: product.win32ShellNameShort,
|
||||
AppMutex: product.win32MutexName,
|
||||
Arch: arch,
|
||||
AppId: arch === 'ia32' ? ia32AppId : x64AppId,
|
||||
IncompatibleTargetAppId: arch === 'ia32' ? product.win32AppId : product.win32x64AppId,
|
||||
IncompatibleArchAppId: arch === 'ia32' ? x64AppId : ia32AppId,
|
||||
AppId: { 'ia32': ia32AppId, 'x64': x64AppId, 'arm64': arm64AppId }[arch],
|
||||
IncompatibleTargetAppId: { 'ia32': product.win32AppId, 'x64': product.win32x64AppId, 'arm64': product.win32arm64AppId }[arch],
|
||||
IncompatibleArchAppId: { 'ia32': x64AppId, 'x64': ia32AppId, 'arm64': ia32AppId }[arch],
|
||||
AppUserId: product.win32AppUserModelId,
|
||||
ArchitecturesAllowed: arch === 'ia32' ? '' : 'x64',
|
||||
ArchitecturesInstallIn64BitMode: arch === 'ia32' ? '' : 'x64',
|
||||
ArchitecturesAllowed: { 'ia32': '', 'x64': 'x64', 'arm64': '' }[arch],
|
||||
ArchitecturesInstallIn64BitMode: { 'ia32': '', 'x64': 'x64', 'arm64': '' }[arch],
|
||||
SourceDir: sourcePath,
|
||||
RepoDir: repoPath,
|
||||
OutputDir: outputPath,
|
||||
@@ -113,8 +114,10 @@ function defineWin32SetupTasks(arch, target) {
|
||||
|
||||
defineWin32SetupTasks('ia32', 'system');
|
||||
defineWin32SetupTasks('x64', 'system');
|
||||
defineWin32SetupTasks('arm64', 'system');
|
||||
defineWin32SetupTasks('ia32', 'user');
|
||||
defineWin32SetupTasks('x64', 'user');
|
||||
defineWin32SetupTasks('arm64', 'user');
|
||||
|
||||
function archiveWin32Setup(arch) {
|
||||
return cb => {
|
||||
@@ -146,6 +149,7 @@ function updateIcon(executablePath) {
|
||||
|
||||
gulp.task(task.define('vscode-win32-ia32-inno-updater', task.series(copyInnoUpdater('ia32'), updateIcon(path.join(buildPath('ia32'), 'tools', 'inno_updater.exe')))));
|
||||
gulp.task(task.define('vscode-win32-x64-inno-updater', task.series(copyInnoUpdater('x64'), updateIcon(path.join(buildPath('x64'), 'tools', 'inno_updater.exe')))));
|
||||
gulp.task(task.define('vscode-win32-arm64-inno-updater', task.series(copyInnoUpdater('arm64'), updateIcon(path.join(buildPath('arm64'), 'tools', 'inno_updater.exe')))));
|
||||
|
||||
// CodeHelper.exe icon
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.config = exports.getElectronVersion = void 0;
|
||||
exports.config = void 0;
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vfs = require("vinyl-fs");
|
||||
@@ -16,12 +16,6 @@ const electron = require('gulp-atom-electron');
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8'));
|
||||
const commit = util.getVersion(root);
|
||||
function getElectronVersion() {
|
||||
const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
|
||||
const target = /^target "(.*)"$/m.exec(yarnrc)[1];
|
||||
return target;
|
||||
}
|
||||
exports.getElectronVersion = getElectronVersion;
|
||||
const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8'));
|
||||
function darwinBundleDocumentType(extensions, icon) {
|
||||
return {
|
||||
@@ -33,7 +27,7 @@ function darwinBundleDocumentType(extensions, icon) {
|
||||
};
|
||||
}
|
||||
exports.config = {
|
||||
version: getElectronVersion(),
|
||||
version: util.getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2019 Microsoft. All rights reserved',
|
||||
@@ -73,7 +67,7 @@ function getElectron(arch) {
|
||||
};
|
||||
}
|
||||
async function main(arch = process.arch) {
|
||||
const version = getElectronVersion();
|
||||
const version = util.getElectronVersion();
|
||||
const electronPath = path.join(root, '.build', 'electron');
|
||||
const versionFile = path.join(electronPath, 'version');
|
||||
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`;
|
||||
|
||||
@@ -19,12 +19,6 @@ const root = path.dirname(path.dirname(__dirname));
|
||||
const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8'));
|
||||
const commit = util.getVersion(root);
|
||||
|
||||
export function getElectronVersion(): string {
|
||||
const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
|
||||
const target = /^target "(.*)"$/m.exec(yarnrc)![1];
|
||||
return target;
|
||||
}
|
||||
|
||||
const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8'));
|
||||
|
||||
function darwinBundleDocumentType(extensions: string[], icon: string) {
|
||||
@@ -38,7 +32,7 @@ function darwinBundleDocumentType(extensions: string[], icon: string) {
|
||||
}
|
||||
|
||||
export const config = {
|
||||
version: getElectronVersion(),
|
||||
version: util.getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2019 Microsoft. All rights reserved',
|
||||
@@ -81,7 +75,7 @@ function getElectron(arch: string): () => NodeJS.ReadWriteStream {
|
||||
}
|
||||
|
||||
async function main(arch = process.arch): Promise<void> {
|
||||
const version = getElectronVersion();
|
||||
const version = util.getElectronVersion();
|
||||
const electronPath = path.join(root, '.build', 'electron');
|
||||
const versionFile = path.join(electronPath, 'version');
|
||||
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`;
|
||||
|
||||
@@ -138,6 +138,10 @@
|
||||
"name": "vs/workbench/contrib/relauncher",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/sash",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/scm",
|
||||
"project": "vscode-workbench"
|
||||
@@ -338,6 +342,10 @@
|
||||
"name": "vs/workbench/services/userDataSync",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/views",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/timeline",
|
||||
"project": "vscode-workbench"
|
||||
|
||||
@@ -130,6 +130,14 @@ const RULES = [
|
||||
'lib.dom.d.ts' // no DOM
|
||||
]
|
||||
},
|
||||
// Electron (sandbox)
|
||||
{
|
||||
target: '**/vs/**/electron-sandbox/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
// Electron (renderer): skip
|
||||
{
|
||||
target: '**/{vs,sql}/**/electron-browser/**',
|
||||
|
||||
@@ -143,6 +143,15 @@ const RULES = [
|
||||
]
|
||||
},
|
||||
|
||||
// Electron (sandbox)
|
||||
{
|
||||
target: '**/vs/**/electron-sandbox/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
|
||||
// Electron (renderer): skip
|
||||
{
|
||||
target: '**/{vs,sql}/**/electron-browser/**',
|
||||
|
||||
@@ -420,7 +420,7 @@ function markNodes(languageService, options) {
|
||||
// (they can be the declaration of a module import)
|
||||
continue;
|
||||
}
|
||||
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration))) {
|
||||
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(program, checker, declaration)) {
|
||||
enqueue_black(declaration.name);
|
||||
for (let j = 0; j < declaration.members.length; j++) {
|
||||
const member = declaration.members[j];
|
||||
@@ -614,6 +614,34 @@ function generateResult(languageService, shakeLevel) {
|
||||
}
|
||||
//#endregion
|
||||
//#region Utils
|
||||
function isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(program, checker, declaration) {
|
||||
if (!program.isSourceFileDefaultLibrary(declaration.getSourceFile()) && declaration.heritageClauses) {
|
||||
for (const heritageClause of declaration.heritageClauses) {
|
||||
for (const type of heritageClause.types) {
|
||||
const symbol = findSymbolFromHeritageType(checker, type);
|
||||
if (symbol) {
|
||||
const decl = symbol.valueDeclaration || (symbol.declarations && symbol.declarations[0]);
|
||||
if (decl && program.isSourceFileDefaultLibrary(decl.getSourceFile())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function findSymbolFromHeritageType(checker, type) {
|
||||
if (ts.isExpressionWithTypeArguments(type)) {
|
||||
return findSymbolFromHeritageType(checker, type.expression);
|
||||
}
|
||||
if (ts.isIdentifier(type)) {
|
||||
return getRealNodeSymbol(checker, type)[0];
|
||||
}
|
||||
if (ts.isPropertyAccessExpression(type)) {
|
||||
return findSymbolFromHeritageType(checker, type.name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns the node's symbol and the `import` node (if the symbol resolved from a different module)
|
||||
*/
|
||||
|
||||
@@ -536,7 +536,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration))) {
|
||||
if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(program, checker, declaration)) {
|
||||
enqueue_black(declaration.name!);
|
||||
|
||||
for (let j = 0; j < declaration.members.length; j++) {
|
||||
@@ -752,6 +752,36 @@ function generateResult(languageService: ts.LanguageService, shakeLevel: ShakeLe
|
||||
|
||||
//#region Utils
|
||||
|
||||
function isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(program: ts.Program, checker: ts.TypeChecker, declaration: ts.ClassDeclaration | ts.InterfaceDeclaration): boolean {
|
||||
if (!program.isSourceFileDefaultLibrary(declaration.getSourceFile()) && declaration.heritageClauses) {
|
||||
for (const heritageClause of declaration.heritageClauses) {
|
||||
for (const type of heritageClause.types) {
|
||||
const symbol = findSymbolFromHeritageType(checker, type);
|
||||
if (symbol) {
|
||||
const decl = symbol.valueDeclaration || (symbol.declarations && symbol.declarations[0]);
|
||||
if (decl && program.isSourceFileDefaultLibrary(decl.getSourceFile())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function findSymbolFromHeritageType(checker: ts.TypeChecker, type: ts.ExpressionWithTypeArguments | ts.Expression | ts.PrivateIdentifier): ts.Symbol | null {
|
||||
if (ts.isExpressionWithTypeArguments(type)) {
|
||||
return findSymbolFromHeritageType(checker, type.expression);
|
||||
}
|
||||
if (ts.isIdentifier(type)) {
|
||||
return getRealNodeSymbol(checker, type)[0];
|
||||
}
|
||||
if (ts.isPropertyAccessExpression(type)) {
|
||||
return findSymbolFromHeritageType(checker, type.name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node's symbol and the `import` node (if the symbol resolved from a different module)
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.getVersion = exports.ensureDir = exports.rreddir = exports.rimraf = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.incremental = void 0;
|
||||
exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.getVersion = exports.ensureDir = exports.rreddir = exports.rimraf = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.incremental = void 0;
|
||||
const es = require("event-stream");
|
||||
const debounce = require("debounce");
|
||||
const _filter = require("gulp-filter");
|
||||
@@ -14,6 +14,7 @@ const fs = require("fs");
|
||||
const _rimraf = require("rimraf");
|
||||
const git = require("./git");
|
||||
const VinylFile = require("vinyl");
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
const NoCancellationToken = { isCancellationRequested: () => false };
|
||||
function incremental(streamProvider, initial, supportsCancellation) {
|
||||
const input = es.through();
|
||||
@@ -255,3 +256,9 @@ function streamToPromise(stream) {
|
||||
});
|
||||
}
|
||||
exports.streamToPromise = streamToPromise;
|
||||
function getElectronVersion() {
|
||||
const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
|
||||
const target = /^target "(.*)"$/m.exec(yarnrc)[1];
|
||||
return target;
|
||||
}
|
||||
exports.getElectronVersion = getElectronVersion;
|
||||
|
||||
@@ -18,6 +18,8 @@ import * as VinylFile from 'vinyl';
|
||||
import { ThroughStream } from 'through';
|
||||
import * as sm from 'source-map';
|
||||
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
|
||||
export interface ICancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
}
|
||||
@@ -318,3 +320,9 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise<void> {
|
||||
stream.on('end', () => c());
|
||||
});
|
||||
}
|
||||
|
||||
export function getElectronVersion(): string {
|
||||
const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
|
||||
const target = /^target "(.*)"$/m.exec(yarnrc)![1];
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -33,9 +33,10 @@ function yarnInstall(location, opts) {
|
||||
|
||||
yarnInstall('extensions'); // node modules shared by all extensions
|
||||
|
||||
yarnInstall('remote'); // node modules used by vscode server
|
||||
|
||||
yarnInstall('remote/web'); // node modules used by vscode web
|
||||
if (!(process.platform === 'win32' && process.env['npm_config_arch'] === 'arm64')) {
|
||||
yarnInstall('remote'); // node modules used by vscode server
|
||||
yarnInstall('remote/web'); // node modules used by vscode web
|
||||
}
|
||||
|
||||
const allExtensionFolders = fs.readdirSync('extensions');
|
||||
const extensions = allExtensionFolders.filter(e => {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"applicationinsights": "1.0.8",
|
||||
"azure-storage": "^2.1.0",
|
||||
"documentdb": "1.13.0",
|
||||
"electron-osx-sign": "^0.4.16",
|
||||
"github-releases": "^0.4.1",
|
||||
"gulp-bom": "^1.0.0",
|
||||
"gulp-sourcemaps": "^1.11.0",
|
||||
@@ -48,7 +49,7 @@
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"terser": "4.3.8",
|
||||
"typescript": "^3.9.1-rc",
|
||||
"typescript": "^3.9.3",
|
||||
"vsce": "1.48.0",
|
||||
"vscode-telemetry-extractor": "^1.5.4",
|
||||
"xml2js": "^0.4.17"
|
||||
|
||||
@@ -151,7 +151,7 @@ begin
|
||||
#endif
|
||||
|
||||
#if "user" == InstallTarget
|
||||
#if "ia32" == Arch
|
||||
#if "ia32" == Arch || "arm64" == Arch
|
||||
#define IncompatibleArchRootKey "HKLM32"
|
||||
#else
|
||||
#define IncompatibleArchRootKey "HKLM64"
|
||||
|
||||
@@ -634,6 +634,11 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
base64-js@^1.2.3:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
||||
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
|
||||
|
||||
base@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
||||
@@ -669,6 +674,11 @@ binary-search-bounds@2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/binary-search-bounds/-/binary-search-bounds-2.0.3.tgz#5ff8616d6dd2ca5388bc85b2d6266e2b9da502dc"
|
||||
integrity sha1-X/hhbW3SylOIvIWy1iZuK52lAtw=
|
||||
|
||||
bluebird@^3.5.0:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
boolbase@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
@@ -731,11 +741,29 @@ browserify-mime@~1.2.9:
|
||||
resolved "https://registry.yarnpkg.com/browserify-mime/-/browserify-mime-1.2.9.tgz#aeb1af28de6c0d7a6a2ce40adb68ff18422af31f"
|
||||
integrity sha1-rrGvKN5sDXpqLOQK22j/GEIq8x8=
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||
|
||||
buffer-alloc@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
||||
dependencies:
|
||||
buffer-alloc-unsafe "^1.1.0"
|
||||
buffer-fill "^1.0.0"
|
||||
|
||||
buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||
|
||||
buffer-fill@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
@@ -900,6 +928,11 @@ commander@^2.8.1:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
|
||||
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
|
||||
|
||||
compare-version@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080"
|
||||
integrity sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=
|
||||
|
||||
component-emitter@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
||||
@@ -1003,7 +1036,7 @@ debug-fabulous@0.0.X:
|
||||
lazy-debug-legacy "0.0.X"
|
||||
object-assign "4.1.0"
|
||||
|
||||
debug@2.X, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
|
||||
debug@2.X, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
@@ -1163,6 +1196,18 @@ ecc-jsbn@~0.1.1:
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
|
||||
electron-osx-sign@^0.4.16:
|
||||
version "0.4.16"
|
||||
resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.4.16.tgz#0be8e579b2d9fa4c12d2a21f063898294b3434aa"
|
||||
integrity sha512-ziMWfc3NmQlwnWLW6EaZq8nH2BWVng/atX5GWsGwhexJYpdW6hsg//MkAfRTRx1kR3Veiqkeiog1ibkbA4x0rg==
|
||||
dependencies:
|
||||
bluebird "^3.5.0"
|
||||
compare-version "^0.1.2"
|
||||
debug "^2.6.8"
|
||||
isbinaryfile "^3.0.2"
|
||||
minimist "^1.2.0"
|
||||
plist "^3.0.1"
|
||||
|
||||
end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
@@ -2004,6 +2049,13 @@ isarray@1.0.0, isarray@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isbinaryfile@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
|
||||
integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==
|
||||
dependencies:
|
||||
buffer-alloc "^1.2.0"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -2720,6 +2772,15 @@ picomatch@^2.0.5:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
|
||||
integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
|
||||
|
||||
plist@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c"
|
||||
integrity sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==
|
||||
dependencies:
|
||||
base64-js "^1.2.3"
|
||||
xmlbuilder "^9.0.7"
|
||||
xmldom "0.1.x"
|
||||
|
||||
posix-character-classes@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
@@ -3462,10 +3523,10 @@ typescript@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
||||
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
||||
|
||||
typescript@^3.9.1-rc:
|
||||
version "3.9.1-rc"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.1-rc.tgz#81d5a5a0a597e224b6e2af8dffb46524b2eaf5f3"
|
||||
integrity sha512-+cPv8L2Vd4KidCotqi2wjegBZ5n47CDRUu/QiLVu2YbeXAz78hIfcai9ziBiNI6JTGTVwUqXRug2UZxDcxhvFw==
|
||||
typescript@^3.9.3:
|
||||
version "3.9.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a"
|
||||
integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==
|
||||
|
||||
typical@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -3700,11 +3761,21 @@ xmlbuilder@0.4.3:
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58"
|
||||
integrity sha1-xGFLp04K0ZbmCcknLNnh3bKKilg=
|
||||
|
||||
xmlbuilder@^9.0.7:
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
|
||||
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
|
||||
|
||||
xmlbuilder@~9.0.1:
|
||||
version "9.0.4"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f"
|
||||
integrity sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=
|
||||
|
||||
xmldom@0.1.x:
|
||||
version "0.1.31"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
|
||||
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
|
||||
|
||||
xtend@~4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
||||
@@ -60,12 +60,12 @@
|
||||
"git": {
|
||||
"name": "electron",
|
||||
"repositoryUrl": "https://github.com/electron/electron",
|
||||
"commitHash": "0552e0d5de46ffa3b481d741f1db5c779e201565"
|
||||
"commitHash": "8f502de1dc5b6df4218a900d0857de7a40301d98"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "7.2.4"
|
||||
"version": "7.3.0"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
||||
@@ -488,7 +488,7 @@
|
||||
"t": "source.batchfile constant.character.escape.batchfile",
|
||||
"r": {
|
||||
"dark_plus": "constant.character.escape: #D7BA7D",
|
||||
"light_plus": "constant.character.escape: #FF0000",
|
||||
"light_plus": "constant.character.escape: #EE0000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
@@ -510,7 +510,7 @@
|
||||
"t": "source.batchfile constant.character.escape.batchfile",
|
||||
"r": {
|
||||
"dark_plus": "constant.character.escape: #D7BA7D",
|
||||
"light_plus": "constant.character.escape: #FF0000",
|
||||
"light_plus": "constant.character.escape: #EE0000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
"contributes": {
|
||||
"languages": [{
|
||||
"id": "dockerfile",
|
||||
"extensions": [ ".dockerfile" ],
|
||||
"filenames": [ "Dockerfile" ],
|
||||
"aliases": [ "Dockerfile" ],
|
||||
"extensions": [ ".dockerfile", ".containerfile" ],
|
||||
"filenames": [ "Dockerfile", "Containerfile" ],
|
||||
"aliases": [ "Dockerfile", "Containerfile" ],
|
||||
"configuration": "./language-configuration.json"
|
||||
}],
|
||||
"grammars": [{
|
||||
|
||||
@@ -105,6 +105,12 @@
|
||||
"category": "Git",
|
||||
"icon": "$(add)"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAllMerge",
|
||||
"title": "%command.stageAllMerge%",
|
||||
"category": "Git",
|
||||
"icon": "$(add)"
|
||||
},
|
||||
{
|
||||
"command": "git.stageSelectedRanges",
|
||||
"title": "%command.stageSelectedRanges%",
|
||||
@@ -490,6 +496,10 @@
|
||||
"command": "git.stageAllUntracked",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAllMerge",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.stageSelectedRanges",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
@@ -897,12 +907,12 @@
|
||||
],
|
||||
"scm/resourceGroup/context": [
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"command": "git.stageAllMerge",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"command": "git.stageAllMerge",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"group": "inline"
|
||||
},
|
||||
@@ -1678,10 +1688,7 @@
|
||||
"description": "%config.terminalAuthentication%"
|
||||
},
|
||||
"git.githubAuthentication": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%config.githubAuthentication%"
|
||||
"deprecationMessage": "This setting is now deprecated, please use `github.gitAuthentication` instead."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1843,26 +1850,27 @@
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.empty%",
|
||||
"when": "config.git.enabled && !git.missing && workbenchState == empty"
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == empty"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.folder%",
|
||||
"when": "config.git.enabled && !git.missing && workbenchState == folder"
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == folder"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.workspace%",
|
||||
"when": "config.git.enabled && !git.missing && workbenchState == workspace && workspaceFolderCount != 0"
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.emptyWorkspace%",
|
||||
"when": "config.git.enabled && !git.missing && workbenchState == workspace && workspaceFolderCount == 0"
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount == 0"
|
||||
},
|
||||
{
|
||||
"view": "explorer",
|
||||
"contents": "%view.workbench.cloneRepository%"
|
||||
"contents": "%view.workbench.cloneRepository%",
|
||||
"when": "config.git.enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"command.stageAll": "Stage All Changes",
|
||||
"command.stageAllTracked": "Stage All Tracked Changes",
|
||||
"command.stageAllUntracked": "Stage All Untracked Changes",
|
||||
"command.stageAllMerge": "Stage All Merge Changes",
|
||||
"command.stageSelectedRanges": "Stage Selected Ranges",
|
||||
"command.revertSelectedRanges": "Revert Selected Ranges",
|
||||
"command.stageChange": "Stage Change",
|
||||
@@ -55,7 +56,7 @@
|
||||
"command.pushToForce": "Push to... (Force)",
|
||||
"command.pushFollowTags": "Push (Follow Tags)",
|
||||
"command.pushFollowTagsForce": "Push (Follow Tags, Force)",
|
||||
"command.addRemote": "Add Remote",
|
||||
"command.addRemote": "Add Remote...",
|
||||
"command.removeRemote": "Remove Remote",
|
||||
"command.sync": "Sync",
|
||||
"command.syncRebase": "Sync (Rebase)",
|
||||
@@ -146,7 +147,6 @@
|
||||
"config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.",
|
||||
"config.showCommitInput": "Controls whether to show the commit input in the Git source control panel.",
|
||||
"config.terminalAuthentication": "Controls whether to enable VS Code to be the authentication handler for git processes spawned in the integrated terminal. Note: terminals need to be restarted to pick up a change in this setting.",
|
||||
"config.githubAuthentication": "Controls whether to enable automatic GitHub authentication for git commands within VS Code.",
|
||||
"colors.added": "Color for added resources.",
|
||||
"colors.modified": "Color for modified resources.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Model } from '../model';
|
||||
import { Repository as BaseRepository, Resource } from '../repository';
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, GitExtension, RefType, RemoteSourceProvider, CredentialsProvider } from './git';
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, GitExtension, RefType, RemoteSourceProvider, CredentialsProvider, BranchQuery } from './git';
|
||||
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode';
|
||||
import { mapEvent } from '../util';
|
||||
import { toGitUri } from '../uri';
|
||||
@@ -159,6 +159,10 @@ export class ApiRepository implements Repository {
|
||||
return this._repository.getBranch(name);
|
||||
}
|
||||
|
||||
getBranches(query: BranchQuery): Promise<Ref[]> {
|
||||
return this._repository.getBranches(query);
|
||||
}
|
||||
|
||||
setBranchUpstream(name: string, upstream: string): Promise<void> {
|
||||
return this._repository.setBranchUpstream(name, upstream);
|
||||
}
|
||||
|
||||
8
extensions/git/src/api/git.d.ts
vendored
8
extensions/git/src/api/git.d.ts
vendored
@@ -121,6 +121,7 @@ export interface RepositoryUIState {
|
||||
export interface LogOptions {
|
||||
/** Max number of log entries to retrieve. If not specified, the default is 32. */
|
||||
readonly maxEntries?: number;
|
||||
readonly path?: string;
|
||||
}
|
||||
|
||||
export interface CommitOptions {
|
||||
@@ -131,6 +132,11 @@ export interface CommitOptions {
|
||||
empty?: boolean;
|
||||
}
|
||||
|
||||
export interface BranchQuery {
|
||||
readonly remote?: boolean;
|
||||
readonly contains?: string;
|
||||
}
|
||||
|
||||
export interface Repository {
|
||||
|
||||
readonly rootUri: Uri;
|
||||
@@ -170,6 +176,7 @@ export interface Repository {
|
||||
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
|
||||
deleteBranch(name: string, force?: boolean): Promise<void>;
|
||||
getBranch(name: string): Promise<Branch>;
|
||||
getBranches(query: BranchQuery): Promise<Ref[]>;
|
||||
setBranchUpstream(name: string, upstream: string): Promise<void>;
|
||||
|
||||
getMergeBase(ref1: string, ref2: string): Promise<string>;
|
||||
@@ -202,6 +209,7 @@ export interface RemoteSourceProvider {
|
||||
readonly icon?: string; // codicon name
|
||||
readonly supportsQuery?: boolean;
|
||||
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
|
||||
publishRepository?(repository: Repository): Promise<void>;
|
||||
}
|
||||
|
||||
export interface Credentials {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, InputBoxOptions, Uri, OutputChannel, Disposable } from 'vscode';
|
||||
import { window, InputBoxOptions, Uri, OutputChannel, Disposable, workspace } from 'vscode';
|
||||
import { IDisposable, EmptyDisposable, toDisposable } from './util';
|
||||
import * as path from 'path';
|
||||
import { IIPCHandler, IIPCServer, createIPCServer } from './ipc/ipcServer';
|
||||
@@ -31,6 +31,13 @@ export class Askpass implements IIPCHandler {
|
||||
}
|
||||
|
||||
async handle({ request, host }: { request: string, host: string }): Promise<string> {
|
||||
const config = workspace.getConfiguration('git', null);
|
||||
const enabled = config.get<boolean>('enabled');
|
||||
|
||||
if (!enabled) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const uri = Uri.parse(host);
|
||||
const authority = uri.authority.replace(/^.*@/, '');
|
||||
const password = /password/i.test(request);
|
||||
|
||||
@@ -19,6 +19,7 @@ import { grep, isDescendant, pathEquals } from './util';
|
||||
import { Log, LogLevel } from './log';
|
||||
import { GitTimelineItem } from './timelineProvider';
|
||||
import { throttle, debounce } from './decorators';
|
||||
import { ApiRepository } from './api/api1';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -216,6 +217,11 @@ function createCheckoutItems(repository: Repository): CheckoutItem[] {
|
||||
return [...heads, ...tags, ...remoteHeads];
|
||||
}
|
||||
|
||||
function sanitizeRemoteName(name: string) {
|
||||
name = name.trim();
|
||||
return name && name.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, '-');
|
||||
}
|
||||
|
||||
class TagItem implements QuickPickItem {
|
||||
get label(): string { return this.ref.name ?? ''; }
|
||||
get description(): string { return this.ref.commit?.substr(0, 8) ?? ''; }
|
||||
@@ -287,6 +293,7 @@ class RemoteSourceProviderQuickPick {
|
||||
}
|
||||
} catch (err) {
|
||||
this.quickpick.items = [{ label: localize('error', "$(error) Error: {0}", err.message), alwaysShow: true }];
|
||||
console.error(err);
|
||||
} finally {
|
||||
this.quickpick.busy = false;
|
||||
}
|
||||
@@ -527,7 +534,7 @@ export class CommandCenter {
|
||||
.map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + localize('clonefrom', "Clone from {0}", provider.name), alwaysShow: true, provider }));
|
||||
|
||||
quickpick.placeholder = providers.length === 0
|
||||
? localize('provide url', "Provide repository URL.")
|
||||
? localize('provide url', "Provide repository URL")
|
||||
: localize('provide url or pick', "Provide repository URL or pick a repository source.");
|
||||
|
||||
const updatePicks = (value?: string) => {
|
||||
@@ -993,37 +1000,14 @@ export class CommandCenter {
|
||||
|
||||
@command('git.stageAll', { repository: true })
|
||||
async stageAll(repository: Repository): Promise<void> {
|
||||
const resources = repository.mergeGroup.resourceStates.filter(s => s instanceof Resource) as Resource[];
|
||||
const { merge, unresolved, deletionConflicts } = await categorizeResourceByResolution(resources);
|
||||
const resources = [...repository.workingTreeGroup.resourceStates, ...repository.untrackedGroup.resourceStates];
|
||||
const uris = resources.map(r => r.resourceUri);
|
||||
|
||||
try {
|
||||
for (const deletionConflict of deletionConflicts) {
|
||||
await this._stageDeletionConflict(repository, deletionConflict.resourceUri);
|
||||
}
|
||||
} catch (err) {
|
||||
if (/Cancelled/.test(err.message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw err;
|
||||
if (uris.length > 0) {
|
||||
const config = workspace.getConfiguration('git', Uri.file(repository.root));
|
||||
const untrackedChanges = config.get<'mixed' | 'separate' | 'hidden'>('untrackedChanges');
|
||||
await repository.add(uris, untrackedChanges === 'mixed' ? undefined : { update: true });
|
||||
}
|
||||
|
||||
if (unresolved.length > 0) {
|
||||
const message = unresolved.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", merge.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(merge[0].resourceUri.fsPath));
|
||||
|
||||
const yes = localize('yes', "Yes");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes);
|
||||
|
||||
if (pick !== yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const config = workspace.getConfiguration('git', Uri.file(repository.root));
|
||||
const untrackedChanges = config.get<'mixed' | 'separate' | 'hidden'>('untrackedChanges');
|
||||
await repository.add([], untrackedChanges === 'mixed' ? undefined : { update: true });
|
||||
}
|
||||
|
||||
private async _stageDeletionConflict(repository: Repository, uri: Uri): Promise<void> {
|
||||
@@ -1079,6 +1063,43 @@ export class CommandCenter {
|
||||
await repository.add(uris);
|
||||
}
|
||||
|
||||
@command('git.stageAllMerge', { repository: true })
|
||||
async stageAllMerge(repository: Repository): Promise<void> {
|
||||
const resources = repository.mergeGroup.resourceStates.filter(s => s instanceof Resource) as Resource[];
|
||||
const { merge, unresolved, deletionConflicts } = await categorizeResourceByResolution(resources);
|
||||
|
||||
try {
|
||||
for (const deletionConflict of deletionConflicts) {
|
||||
await this._stageDeletionConflict(repository, deletionConflict.resourceUri);
|
||||
}
|
||||
} catch (err) {
|
||||
if (/Cancelled/.test(err.message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (unresolved.length > 0) {
|
||||
const message = unresolved.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", merge.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(merge[0].resourceUri.fsPath));
|
||||
|
||||
const yes = localize('yes', "Yes");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes);
|
||||
|
||||
if (pick !== yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const uris = resources.map(r => r.resourceUri);
|
||||
|
||||
if (uris.length > 0) {
|
||||
await repository.add(uris);
|
||||
}
|
||||
}
|
||||
|
||||
@command('git.stageChange')
|
||||
async stageChange(uri: Uri, changes: LineChange[], index: number): Promise<void> {
|
||||
const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0];
|
||||
@@ -1998,9 +2019,17 @@ export class CommandCenter {
|
||||
const remotes = repository.remotes;
|
||||
|
||||
if (remotes.length === 0) {
|
||||
if (!pushOptions.silent) {
|
||||
window.showWarningMessage(localize('no remotes to push', "Your repository has no remotes configured to push to."));
|
||||
if (pushOptions.silent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const addRemote = localize('addremote', 'Add Remote');
|
||||
const result = await window.showWarningMessage(localize('no remotes to push', "Your repository has no remotes configured to push to."), addRemote);
|
||||
|
||||
if (result === addRemote) {
|
||||
await this.addRemote(repository);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2117,48 +2146,79 @@ export class CommandCenter {
|
||||
|
||||
@command('git.addRemote', { repository: true })
|
||||
async addRemote(repository: Repository): Promise<string | undefined> {
|
||||
const remotes = repository.remotes;
|
||||
const quickpick = window.createQuickPick<(QuickPickItem & { provider?: RemoteSourceProvider, url?: string })>();
|
||||
quickpick.ignoreFocusOut = true;
|
||||
|
||||
const sanitize = (name: string) => {
|
||||
name = name.trim();
|
||||
return name && name.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, '-');
|
||||
const providers = this.model.getRemoteProviders()
|
||||
.map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + localize('addfrom', "Add remote from {0}", provider.name), alwaysShow: true, provider }));
|
||||
|
||||
quickpick.placeholder = providers.length === 0
|
||||
? localize('provide url', "Provide repository URL")
|
||||
: localize('provide url or pick', "Provide repository URL or pick a repository source.");
|
||||
|
||||
const updatePicks = (value?: string) => {
|
||||
if (value) {
|
||||
quickpick.items = [{
|
||||
label: localize('addFrom', "Add remote from URL"),
|
||||
description: value,
|
||||
alwaysShow: true,
|
||||
url: value
|
||||
},
|
||||
...providers];
|
||||
} else {
|
||||
quickpick.items = providers;
|
||||
}
|
||||
};
|
||||
|
||||
quickpick.onDidChangeValue(updatePicks);
|
||||
updatePicks();
|
||||
|
||||
const result = await getQuickPickResult(quickpick);
|
||||
let url: string | undefined;
|
||||
|
||||
if (result) {
|
||||
if (result.url) {
|
||||
url = result.url;
|
||||
} else if (result.provider) {
|
||||
const quickpick = new RemoteSourceProviderQuickPick(result.provider);
|
||||
const remote = await quickpick.pick();
|
||||
|
||||
if (remote) {
|
||||
if (typeof remote.url === 'string') {
|
||||
url = remote.url;
|
||||
} else if (remote.url.length > 0) {
|
||||
url = await window.showQuickPick(remote.url, { ignoreFocusOut: true, placeHolder: localize('pick url', "Choose a URL to clone from.") });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resultName = await window.showInputBox({
|
||||
placeHolder: localize('remote name', "Remote name"),
|
||||
prompt: localize('provide remote name', "Please provide a remote name"),
|
||||
ignoreFocusOut: true,
|
||||
validateInput: (name: string) => {
|
||||
if (sanitize(name)) {
|
||||
return null;
|
||||
if (!sanitizeRemoteName(name)) {
|
||||
return localize('remote name format invalid', "Remote name format invalid");
|
||||
} else if (repository.remotes.find(r => r.name === name)) {
|
||||
return localize('remote already exists', "Remote '{0}' already exists.", name);
|
||||
}
|
||||
return localize('remote name format invalid', "Remote name format invalid");
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const name = sanitize(resultName || '');
|
||||
const name = sanitizeRemoteName(resultName || '');
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (remotes.find(r => r.name === name)) {
|
||||
window.showErrorMessage(localize('remote already exists', "Remote '{0}' already exists.", name));
|
||||
return;
|
||||
}
|
||||
|
||||
const url = await window.showInputBox({
|
||||
placeHolder: localize('remote url', "Remote URL"),
|
||||
prompt: localize('provide remote URL', "Enter URL for remote \"{0}\"", name),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.addRemote(name, url);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -2268,15 +2328,38 @@ export class CommandCenter {
|
||||
|
||||
@command('git.publish', { repository: true })
|
||||
async publish(repository: Repository): Promise<void> {
|
||||
const branchName = repository.HEAD && repository.HEAD.name || '';
|
||||
const remotes = repository.remotes;
|
||||
|
||||
if (remotes.length === 0) {
|
||||
window.showWarningMessage(localize('no remotes to publish', "Your repository has no remotes configured to publish to."));
|
||||
const providers = this.model.getRemoteProviders().filter(p => !!p.publishRepository);
|
||||
|
||||
if (providers.length === 0) {
|
||||
window.showWarningMessage(localize('no remotes to publish', "Your repository has no remotes configured to publish to."));
|
||||
return;
|
||||
}
|
||||
|
||||
let provider: RemoteSourceProvider;
|
||||
|
||||
if (providers.length === 1) {
|
||||
provider = providers[0];
|
||||
} else {
|
||||
const picks = providers
|
||||
.map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + localize('publish to', "Publish to {0}", provider.name), alwaysShow: true, provider }));
|
||||
const placeHolder = localize('pick provider', "Pick a provider to publish the branch '{0}' to:", branchName);
|
||||
const choice = await window.showQuickPick(picks, { placeHolder });
|
||||
|
||||
if (!choice) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider = choice.provider;
|
||||
}
|
||||
|
||||
await provider.publishRepository!(new ApiRepository(repository));
|
||||
return;
|
||||
}
|
||||
|
||||
const branchName = repository.HEAD && repository.HEAD.name || '';
|
||||
|
||||
if (remotes.length === 1) {
|
||||
return await repository.pushTo(remotes[0].name, branchName, true);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes,
|
||||
import { CancellationToken, Progress, Uri } from 'vscode';
|
||||
import { URI } from 'vscode-uri';
|
||||
import { detectEncoding } from './encoding';
|
||||
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status, CommitOptions } from './api/git';
|
||||
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git';
|
||||
import * as byline from 'byline';
|
||||
import { StringDecoder } from 'string_decoder';
|
||||
|
||||
@@ -848,6 +848,9 @@ export class Repository {
|
||||
async log(options?: LogOptions): Promise<Commit[]> {
|
||||
const maxEntries = options?.maxEntries ?? 32;
|
||||
const args = ['log', `-n${maxEntries}`, `--format=${COMMIT_FORMAT}`, '-z', '--'];
|
||||
if (options?.path) {
|
||||
args.push(options.path);
|
||||
}
|
||||
|
||||
const result = await this.run(args);
|
||||
if (result.exitCode) {
|
||||
@@ -1220,15 +1223,13 @@ export class Repository {
|
||||
args.push('-A');
|
||||
}
|
||||
|
||||
args.push('--');
|
||||
|
||||
if (paths && paths.length) {
|
||||
args.push.apply(args, paths.map(sanitizePath));
|
||||
for (const chunk of splitInChunks(paths, MAX_CLI_LENGTH)) {
|
||||
await this.run([...args, '--', ...chunk]);
|
||||
}
|
||||
} else {
|
||||
args.push('.');
|
||||
await this.run([...args, '--', '.']);
|
||||
}
|
||||
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async rm(paths: string[]): Promise<void> {
|
||||
@@ -1437,10 +1438,11 @@ export class Repository {
|
||||
|
||||
const limiter = new Limiter(5);
|
||||
const promises: Promise<any>[] = [];
|
||||
const args = ['clean', '-f', '-q'];
|
||||
|
||||
for (const paths of groups) {
|
||||
for (const chunk of splitInChunks(paths, MAX_CLI_LENGTH)) {
|
||||
promises.push(limiter.queue(() => this.run(['clean', '-f', '-q', '--', ...chunk])));
|
||||
promises.push(limiter.queue(() => this.run([...args, '--', ...chunk])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1472,19 +1474,19 @@ export class Repository {
|
||||
|
||||
// In case there are no branches, we must use rm --cached
|
||||
if (!result.stdout) {
|
||||
args = ['rm', '--cached', '-r', '--'];
|
||||
args = ['rm', '--cached', '-r'];
|
||||
} else {
|
||||
args = ['reset', '-q', treeish, '--'];
|
||||
}
|
||||
|
||||
if (paths && paths.length) {
|
||||
args.push.apply(args, paths.map(sanitizePath));
|
||||
} else {
|
||||
args.push('.');
|
||||
args = ['reset', '-q', treeish];
|
||||
}
|
||||
|
||||
try {
|
||||
await this.run(args);
|
||||
if (paths && paths.length > 0) {
|
||||
for (const chunk of splitInChunks(paths, MAX_CLI_LENGTH)) {
|
||||
await this.run([...args, '--', ...chunk]);
|
||||
}
|
||||
} else {
|
||||
await this.run([...args, '--', '.']);
|
||||
}
|
||||
} catch (err) {
|
||||
// In case there are merge conflicts to be resolved, git reset will output
|
||||
// some "needs merge" data. We try to get around that.
|
||||
@@ -1789,13 +1791,17 @@ export class Repository {
|
||||
.map(([ref]) => ({ name: ref, type: RefType.Head } as Branch));
|
||||
}
|
||||
|
||||
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate' }): Promise<Ref[]> {
|
||||
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate', contains?: string }): Promise<Ref[]> {
|
||||
const args = ['for-each-ref', '--format', '%(refname) %(objectname)'];
|
||||
|
||||
if (opts && opts.sort && opts.sort !== 'alphabetically') {
|
||||
args.push('--sort', `-${opts.sort}`);
|
||||
}
|
||||
|
||||
if (opts?.contains) {
|
||||
args.push('--contains', opts.contains);
|
||||
}
|
||||
|
||||
const result = await this.run(args);
|
||||
|
||||
const fn = (line: string): Ref | null => {
|
||||
@@ -1913,6 +1919,11 @@ export class Repository {
|
||||
}
|
||||
}
|
||||
|
||||
async getBranches(query: BranchQuery): Promise<Ref[]> {
|
||||
const refs = await this.getRefs({ contains: query.contains });
|
||||
return refs.filter(value => (value.type !== RefType.Tag) && (query.remote || !value.remote));
|
||||
}
|
||||
|
||||
// TODO: Support core.commentChar
|
||||
stripCommitMessageComments(message: string): string {
|
||||
return message.replace(/^\s*#.*$\n?/gm, '').trim();
|
||||
@@ -1963,10 +1974,10 @@ export class Repository {
|
||||
}
|
||||
|
||||
async updateSubmodules(paths: string[]): Promise<void> {
|
||||
const args = ['submodule', 'update', '--'];
|
||||
const args = ['submodule', 'update'];
|
||||
|
||||
for (const chunk of splitInChunks(paths.map(sanitizePath), MAX_CLI_LENGTH)) {
|
||||
await this.run([...args, ...chunk]);
|
||||
await this.run([...args, '--', ...chunk]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CredentialsProvider, Credentials } from './api/git';
|
||||
import { IDisposable, filterEvent, EmptyDisposable } from './util';
|
||||
import { workspace, Uri, AuthenticationSession, authentication } from 'vscode';
|
||||
import { Askpass } from './askpass';
|
||||
|
||||
export class GitHubCredentialProvider implements CredentialsProvider {
|
||||
|
||||
async getCredentials(host: Uri): Promise<Credentials | undefined> {
|
||||
if (!/github\.com/i.test(host.authority)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await this.getSession();
|
||||
return { username: session.account.id, password: await session.getAccessToken() };
|
||||
}
|
||||
|
||||
private async getSession(): Promise<AuthenticationSession> {
|
||||
const authenticationSessions = await authentication.getSessions('github', ['repo']);
|
||||
|
||||
if (authenticationSessions.length) {
|
||||
return await authenticationSessions[0];
|
||||
} else {
|
||||
return await authentication.login('github', ['repo']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class GithubCredentialProviderManager {
|
||||
|
||||
private providerDisposable: IDisposable = EmptyDisposable;
|
||||
private readonly disposable: IDisposable;
|
||||
|
||||
private _enabled = false;
|
||||
private set enabled(enabled: boolean) {
|
||||
if (this._enabled === enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._enabled = enabled;
|
||||
|
||||
if (enabled) {
|
||||
this.providerDisposable = this.askpass.registerCredentialsProvider(new GitHubCredentialProvider());
|
||||
} else {
|
||||
this.providerDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private readonly askpass: Askpass) {
|
||||
this.disposable = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git'))(this.refresh, this);
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
private refresh(): void {
|
||||
this.enabled = workspace.getConfiguration('git', null).get('githubAuthentication', true);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.enabled = false;
|
||||
this.disposable.dispose();
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import { GitExtensionImpl } from './api/extension';
|
||||
// import * as fs from 'fs';
|
||||
import { GitTimelineProvider } from './timelineProvider';
|
||||
import { registerAPICommands } from './api/api1';
|
||||
import { GithubCredentialProviderManager } from './github';
|
||||
import { TerminalEnvironmentManager } from './terminal';
|
||||
|
||||
const deactivateTasks: { (): Promise<any>; }[] = [];
|
||||
@@ -44,9 +43,6 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
|
||||
const terminalEnvironmentManager = new TerminalEnvironmentManager(context, env);
|
||||
disposables.push(terminalEnvironmentManager);
|
||||
|
||||
const githubCredentialProviderManager = new GithubCredentialProviderManager(askpass);
|
||||
context.subscriptions.push(githubCredentialProviderManager);
|
||||
|
||||
const git = new Git({ gitPath: info.path, version: info.version, env });
|
||||
const model = new Model(git, askpass, context.globalState, outputChannel);
|
||||
disposables.push(model);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, OutputChannel } from 'vscode';
|
||||
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, OutputChannel, commands } from 'vscode';
|
||||
import { Repository, RepositoryState } from './repository';
|
||||
import { memoize, sequentialize, debounce } from './decorators';
|
||||
import { dispose, anyEvent, filterEvent, isDescendant, firstIndex, pathEquals, toDisposable } from './util';
|
||||
@@ -12,8 +12,9 @@ import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { fromGitUri } from './uri';
|
||||
import { GitErrorCodes, APIState as State, RemoteSourceProvider, CredentialsProvider } from './api/git';
|
||||
import { APIState as State, RemoteSourceProvider, CredentialsProvider } from './api/git';
|
||||
import { Askpass } from './askpass';
|
||||
import { IRemoteSourceProviderRegistry } from './remoteProvider';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -45,7 +46,7 @@ interface OpenRepository extends Disposable {
|
||||
repository: Repository;
|
||||
}
|
||||
|
||||
export class Model {
|
||||
export class Model implements IRemoteSourceProviderRegistry {
|
||||
|
||||
private _onDidOpenRepository = new EventEmitter<Repository>();
|
||||
readonly onDidOpenRepository: Event<Repository> = this._onDidOpenRepository.event;
|
||||
@@ -73,9 +74,16 @@ export class Model {
|
||||
setState(state: State): void {
|
||||
this._state = state;
|
||||
this._onDidChangeState.fire(state);
|
||||
commands.executeCommand('setContext', 'git.state', state);
|
||||
}
|
||||
|
||||
private remoteProviders = new Set<RemoteSourceProvider>();
|
||||
private remoteSourceProviders = new Set<RemoteSourceProvider>();
|
||||
|
||||
private _onDidAddRemoteSourceProvider = new EventEmitter<RemoteSourceProvider>();
|
||||
readonly onDidAddRemoteSourceProvider = this._onDidAddRemoteSourceProvider.event;
|
||||
|
||||
private _onDidRemoveRemoteSourceProvider = new EventEmitter<RemoteSourceProvider>();
|
||||
readonly onDidRemoveRemoteSourceProvider = this._onDidRemoveRemoteSourceProvider.event;
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
@@ -92,6 +100,7 @@ export class Model {
|
||||
const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri));
|
||||
onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables);
|
||||
|
||||
this.setState('uninitialized');
|
||||
this.doInitialScan().finally(() => this.setState('initialized'));
|
||||
}
|
||||
|
||||
@@ -115,31 +124,27 @@ export class Model {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const folder of workspace.workspaceFolders || []) {
|
||||
await Promise.all((workspace.workspaceFolders || []).map(async folder => {
|
||||
const root = folder.uri.fsPath;
|
||||
const children = await new Promise<string[]>((c, e) => fs.readdir(root, (err, r) => err ? e(err) : c(r)));
|
||||
const promises = children
|
||||
.filter(child => child !== '.git')
|
||||
.map(child => this.openRepository(path.join(root, child)));
|
||||
|
||||
try {
|
||||
const children = await new Promise<string[]>((c, e) => fs.readdir(root, (err, r) => err ? e(err) : c(r)));
|
||||
const folderConfig = workspace.getConfiguration('git', folder.uri);
|
||||
const paths = folderConfig.get<string[]>('scanRepositories') || [];
|
||||
|
||||
children
|
||||
.filter(child => child !== '.git')
|
||||
.forEach(child => this.openRepository(path.join(root, child)));
|
||||
|
||||
const folderConfig = workspace.getConfiguration('git', folder.uri);
|
||||
const paths = folderConfig.get<string[]>('scanRepositories') || [];
|
||||
|
||||
for (const possibleRepositoryPath of paths) {
|
||||
if (path.isAbsolute(possibleRepositoryPath)) {
|
||||
console.warn(localize('not supported', "Absolute paths not supported in 'git.scanRepositories' setting."));
|
||||
continue;
|
||||
}
|
||||
|
||||
this.openRepository(path.join(root, possibleRepositoryPath));
|
||||
for (const possibleRepositoryPath of paths) {
|
||||
if (path.isAbsolute(possibleRepositoryPath)) {
|
||||
console.warn(localize('not supported', "Absolute paths not supported in 'git.scanRepositories' setting."));
|
||||
continue;
|
||||
}
|
||||
} catch (err) {
|
||||
// noop
|
||||
|
||||
promises.push(this.openRepository(path.join(root, possibleRepositoryPath)));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
}));
|
||||
}
|
||||
|
||||
private onPossibleGitRepositoryChange(uri: Uri): void {
|
||||
@@ -248,16 +253,12 @@ export class Model {
|
||||
}
|
||||
|
||||
const dotGit = await this.git.getRepositoryDotGit(repositoryRoot);
|
||||
const repository = new Repository(this.git.open(repositoryRoot, dotGit), this.globalState, this.outputChannel);
|
||||
const repository = new Repository(this.git.open(repositoryRoot, dotGit), this, this.globalState, this.outputChannel);
|
||||
|
||||
this.open(repository);
|
||||
await repository.status();
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
|
||||
return;
|
||||
}
|
||||
|
||||
// console.error('Failed to find repository:', err);
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,8 +452,13 @@ export class Model {
|
||||
}
|
||||
|
||||
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable {
|
||||
this.remoteProviders.add(provider);
|
||||
return toDisposable(() => this.remoteProviders.delete(provider));
|
||||
this.remoteSourceProviders.add(provider);
|
||||
this._onDidAddRemoteSourceProvider.fire(provider);
|
||||
|
||||
return toDisposable(() => {
|
||||
this.remoteSourceProviders.delete(provider);
|
||||
this._onDidRemoveRemoteSourceProvider.fire(provider);
|
||||
});
|
||||
}
|
||||
|
||||
registerCredentialsProvider(provider: CredentialsProvider): Disposable {
|
||||
@@ -460,7 +466,7 @@ export class Model {
|
||||
}
|
||||
|
||||
getRemoteProviders(): RemoteSourceProvider[] {
|
||||
return [...this.remoteProviders.values()];
|
||||
return [...this.remoteSourceProviders.values()];
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
14
extensions/git/src/remoteProvider.ts
Normal file
14
extensions/git/src/remoteProvider.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, Event } from 'vscode';
|
||||
import { RemoteSourceProvider } from './api/git';
|
||||
|
||||
export interface IRemoteSourceProviderRegistry {
|
||||
readonly onDidAddRemoteSourceProvider: Event<RemoteSourceProvider>;
|
||||
readonly onDidRemoveRemoteSourceProvider: Event<RemoteSourceProvider>;
|
||||
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable;
|
||||
getRemoteProviders(): RemoteSourceProvider[];
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, Decoration } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions } from './api/git';
|
||||
import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions, BranchQuery } from './api/git';
|
||||
import { AutoFetcher } from './autofetch';
|
||||
import { debounce, memoize, throttle } from './decorators';
|
||||
import { Commit, ForcePushMode, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions } from './git';
|
||||
@@ -16,6 +16,7 @@ import { toGitUri } from './uri';
|
||||
import { anyEvent, combinedDisposable, debounceEvent, dispose, EmptyDisposable, eventToPromise, filterEvent, find, IDisposable, isDescendant, onceEvent } from './util';
|
||||
import { IFileWatcher, watch } from './watch';
|
||||
import { Log, LogLevel } from './log';
|
||||
import { IRemoteSourceProviderRegistry } from './remoteProvider';
|
||||
|
||||
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
|
||||
|
||||
@@ -251,11 +252,13 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
|
||||
get resourceDecoration(): Decoration {
|
||||
const title = this.tooltip;
|
||||
const letter = this.letter;
|
||||
const color = this.color;
|
||||
const priority = this.priority;
|
||||
return { bubble: true, title, letter, color, priority };
|
||||
return {
|
||||
bubble: this.type !== Status.DELETED && this.type !== Status.INDEX_DELETED,
|
||||
title: this.tooltip,
|
||||
letter: this.letter,
|
||||
color: this.color,
|
||||
priority: this.priority
|
||||
};
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -279,6 +282,7 @@ export const enum Operation {
|
||||
Clean = 'Clean',
|
||||
Branch = 'Branch',
|
||||
GetBranch = 'GetBranch',
|
||||
GetBranches = 'GetBranches',
|
||||
SetBranchUpstream = 'SetBranchUpstream',
|
||||
HashObject = 'HashObject',
|
||||
Checkout = 'Checkout',
|
||||
@@ -678,6 +682,7 @@ export class Repository implements Disposable {
|
||||
|
||||
constructor(
|
||||
private readonly repository: BaseRepository,
|
||||
remoteSourceProviderRegistry: IRemoteSourceProviderRegistry,
|
||||
globalState: Memento,
|
||||
outputChannel: OutputChannel
|
||||
) {
|
||||
@@ -773,7 +778,7 @@ export class Repository implements Disposable {
|
||||
}
|
||||
}, null, this.disposables);
|
||||
|
||||
const statusBar = new StatusBarCommands(this);
|
||||
const statusBar = new StatusBarCommands(this, remoteSourceProviderRegistry);
|
||||
this.disposables.push(statusBar);
|
||||
statusBar.onDidChange(() => this._sourceControl.statusBarCommands = statusBar.commands, null, this.disposables);
|
||||
this._sourceControl.statusBarCommands = statusBar.commands;
|
||||
@@ -1049,6 +1054,10 @@ export class Repository implements Disposable {
|
||||
return await this.run(Operation.GetBranch, () => this.repository.getBranch(name));
|
||||
}
|
||||
|
||||
async getBranches(query: BranchQuery): Promise<Ref[]> {
|
||||
return await this.run(Operation.GetBranches, () => this.repository.getBranches(query));
|
||||
}
|
||||
|
||||
async setBranchUpstream(name: string, upstream: string): Promise<void> {
|
||||
await this.run(Operation.SetBranchUpstream, () => this.repository.setBranchUpstream(name, upstream));
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { Disposable, Command, EventEmitter, Event, workspace, Uri } from 'vscode
|
||||
import { Repository, Operation } from './repository';
|
||||
import { anyEvent, dispose, filterEvent } from './util';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch } from './api/git';
|
||||
import { Branch, RemoteSourceProvider } from './api/git';
|
||||
import { IRemoteSourceProviderRegistry } from './remoteProvider';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -39,41 +40,45 @@ class CheckoutStatusBar {
|
||||
}
|
||||
|
||||
interface SyncStatusBarState {
|
||||
enabled: boolean;
|
||||
isSyncRunning: boolean;
|
||||
hasRemotes: boolean;
|
||||
HEAD: Branch | undefined;
|
||||
readonly enabled: boolean;
|
||||
readonly isSyncRunning: boolean;
|
||||
readonly hasRemotes: boolean;
|
||||
readonly HEAD: Branch | undefined;
|
||||
readonly remoteSourceProviders: RemoteSourceProvider[];
|
||||
}
|
||||
|
||||
class SyncStatusBar {
|
||||
|
||||
private static StartState: SyncStatusBarState = {
|
||||
enabled: true,
|
||||
isSyncRunning: false,
|
||||
hasRemotes: false,
|
||||
HEAD: undefined
|
||||
};
|
||||
|
||||
private _onDidChange = new EventEmitter<void>();
|
||||
get onDidChange(): Event<void> { return this._onDidChange.event; }
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
private _state: SyncStatusBarState = SyncStatusBar.StartState;
|
||||
private _state: SyncStatusBarState;
|
||||
private get state() { return this._state; }
|
||||
private set state(state: SyncStatusBarState) {
|
||||
this._state = state;
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
|
||||
constructor(private repository: Repository) {
|
||||
repository.onDidRunGitStatus(this.onModelChange, this, this.disposables);
|
||||
repository.onDidChangeOperations(this.onOperationsChange, this, this.disposables);
|
||||
constructor(private repository: Repository, private remoteSourceProviderRegistry: IRemoteSourceProviderRegistry) {
|
||||
repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables);
|
||||
repository.onDidChangeOperations(this.onDidChangeOperations, this, this.disposables);
|
||||
|
||||
anyEvent(remoteSourceProviderRegistry.onDidAddRemoteSourceProvider, remoteSourceProviderRegistry.onDidRemoveRemoteSourceProvider)
|
||||
(this.onDidChangeRemoteSourceProviders, this, this.disposables);
|
||||
|
||||
const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.enableStatusBarSync'));
|
||||
onEnablementChange(this.updateEnablement, this, this.disposables);
|
||||
this.updateEnablement();
|
||||
|
||||
this._onDidChange.fire();
|
||||
this._state = {
|
||||
enabled: true,
|
||||
isSyncRunning: false,
|
||||
hasRemotes: false,
|
||||
HEAD: undefined,
|
||||
remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders()
|
||||
.filter(p => !!p.publishRepository)
|
||||
};
|
||||
}
|
||||
|
||||
private updateEnablement(): void {
|
||||
@@ -83,7 +88,7 @@ class SyncStatusBar {
|
||||
this.state = { ... this.state, enabled };
|
||||
}
|
||||
|
||||
private onOperationsChange(): void {
|
||||
private onDidChangeOperations(): void {
|
||||
const isSyncRunning = this.repository.operations.isRunning(Operation.Sync) ||
|
||||
this.repository.operations.isRunning(Operation.Push) ||
|
||||
this.repository.operations.isRunning(Operation.Pull);
|
||||
@@ -91,7 +96,7 @@ class SyncStatusBar {
|
||||
this.state = { ...this.state, isSyncRunning };
|
||||
}
|
||||
|
||||
private onModelChange(): void {
|
||||
private onDidRunGitStatus(): void {
|
||||
this.state = {
|
||||
...this.state,
|
||||
hasRemotes: this.repository.remotes.length > 0,
|
||||
@@ -99,9 +104,34 @@ class SyncStatusBar {
|
||||
};
|
||||
}
|
||||
|
||||
private onDidChangeRemoteSourceProviders(): void {
|
||||
this.state = {
|
||||
...this.state,
|
||||
remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders()
|
||||
.filter(p => !!p.publishRepository)
|
||||
};
|
||||
}
|
||||
|
||||
get command(): Command | undefined {
|
||||
if (!this.state.enabled || !this.state.hasRemotes) {
|
||||
return undefined;
|
||||
if (!this.state.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.state.hasRemotes) {
|
||||
if (this.state.remoteSourceProviders.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tooltip = this.state.remoteSourceProviders.length === 1
|
||||
? localize('publish to', "Publish to {0}", this.state.remoteSourceProviders[0].name)
|
||||
: localize('publish to...', "Publish to...");
|
||||
|
||||
return {
|
||||
command: 'git.publish',
|
||||
title: `$(cloud-upload)`,
|
||||
tooltip,
|
||||
arguments: [this.repository.sourceControl]
|
||||
};
|
||||
}
|
||||
|
||||
const HEAD = this.state.HEAD;
|
||||
@@ -152,38 +182,21 @@ class SyncStatusBar {
|
||||
|
||||
export class StatusBarCommands {
|
||||
|
||||
readonly onDidChange: Event<void>;
|
||||
|
||||
private syncStatusBar: SyncStatusBar;
|
||||
private checkoutStatusBar: CheckoutStatusBar;
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(repository: Repository) {
|
||||
this.syncStatusBar = new SyncStatusBar(repository);
|
||||
constructor(repository: Repository, remoteSourceProviderRegistry: IRemoteSourceProviderRegistry) {
|
||||
this.syncStatusBar = new SyncStatusBar(repository, remoteSourceProviderRegistry);
|
||||
this.checkoutStatusBar = new CheckoutStatusBar(repository);
|
||||
}
|
||||
|
||||
get onDidChange(): Event<void> {
|
||||
return anyEvent(
|
||||
this.syncStatusBar.onDidChange,
|
||||
this.checkoutStatusBar.onDidChange
|
||||
);
|
||||
this.onDidChange = anyEvent(this.syncStatusBar.onDidChange, this.checkoutStatusBar.onDidChange);
|
||||
}
|
||||
|
||||
get commands(): Command[] {
|
||||
const result: Command[] = [];
|
||||
|
||||
const checkout = this.checkoutStatusBar.command;
|
||||
|
||||
if (checkout) {
|
||||
result.push(checkout);
|
||||
}
|
||||
|
||||
const sync = this.syncStatusBar.command;
|
||||
|
||||
if (sync) {
|
||||
result.push(sync);
|
||||
}
|
||||
|
||||
return result;
|
||||
return [this.checkoutStatusBar.command, this.syncStatusBar.command]
|
||||
.filter((c): c is Command => !!c);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -34,7 +34,8 @@ export class TerminalEnvironmentManager {
|
||||
}
|
||||
|
||||
private refresh(): void {
|
||||
this.enabled = workspace.getConfiguration('git', null).get('terminalAuthentication', true);
|
||||
const config = workspace.getConfiguration('git', null);
|
||||
this.enabled = config.get<boolean>('enabled', true) && config.get('terminalAuthentication', true);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const schemes = ['OSS', 'INSIDERS', 'STABLE', 'EXPLORATION', 'VSO', 'VSO_PPE', 'VSO_DEV'];
|
||||
|
||||
function main() {
|
||||
let content = {};
|
||||
|
||||
for (const scheme of schemes) {
|
||||
const id = process.env[`${scheme}_GITHUB_ID`];
|
||||
const secret = process.env[`${scheme}_GITHUB_SECRET`];
|
||||
|
||||
if (id && secret) {
|
||||
content[scheme] = { id, secret };
|
||||
}
|
||||
}
|
||||
|
||||
const githubAppId = process.env.GITHUB_APP_ID;
|
||||
const githubAppSecret = process.env.GITHUB_APP_SECRET;
|
||||
|
||||
if (githubAppId && githubAppSecret) {
|
||||
content.GITHUB_APP = { id: githubAppId, secret: githubAppSecret }
|
||||
}
|
||||
|
||||
if (Object.keys(content).length > 0) {
|
||||
fs.writeFileSync(path.join(__dirname, '../src/common/config.json'), JSON.stringify(content));
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,102 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Uri, env } from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
export interface ClientDetails {
|
||||
id?: string;
|
||||
secret?: string;
|
||||
}
|
||||
|
||||
export interface ClientConfig {
|
||||
OSS: ClientDetails;
|
||||
INSIDERS: ClientDetails;
|
||||
STABLE: ClientDetails;
|
||||
EXPLORATION: ClientDetails;
|
||||
|
||||
VSO: ClientDetails;
|
||||
VSO_PPE: ClientDetails;
|
||||
VSO_DEV: ClientDetails;
|
||||
|
||||
GITHUB_APP: ClientDetails;
|
||||
}
|
||||
|
||||
export class Registrar {
|
||||
private _config: ClientConfig;
|
||||
|
||||
constructor() {
|
||||
try {
|
||||
const fileContents = fs.readFileSync(path.join(env.appRoot, 'extensions/github-authentication/src/common/config.json')).toString();
|
||||
this._config = JSON.parse(fileContents);
|
||||
} catch (e) {
|
||||
this._config = {
|
||||
OSS: {},
|
||||
INSIDERS: {},
|
||||
STABLE: {},
|
||||
EXPLORATION: {},
|
||||
VSO: {},
|
||||
VSO_PPE: {},
|
||||
VSO_DEV: {},
|
||||
GITHUB_APP: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
getGitHubAppDetails(): ClientDetails {
|
||||
if (!this._config.GITHUB_APP.id || !this._config.GITHUB_APP.secret) {
|
||||
throw new Error(`No GitHub App client configuration available`);
|
||||
}
|
||||
|
||||
return this._config.GITHUB_APP;
|
||||
}
|
||||
|
||||
getClientDetails(callbackUri: Uri): ClientDetails {
|
||||
let details: ClientDetails | undefined;
|
||||
switch (callbackUri.scheme) {
|
||||
case 'code-oss':
|
||||
details = this._config.OSS;
|
||||
break;
|
||||
|
||||
case 'vscode-insiders':
|
||||
details = this._config.INSIDERS;
|
||||
break;
|
||||
|
||||
case 'vscode':
|
||||
details = this._config.STABLE;
|
||||
break;
|
||||
|
||||
case 'vscode-exploration':
|
||||
details = this._config.EXPLORATION;
|
||||
break;
|
||||
|
||||
case 'https':
|
||||
switch (callbackUri.authority) {
|
||||
case 'online.visualstudio.com':
|
||||
details = this._config.VSO;
|
||||
break;
|
||||
case 'online-ppe.core.vsengsaas.visualstudio.com':
|
||||
details = this._config.VSO_PPE;
|
||||
break;
|
||||
case 'online.dev.core.vsengsaas.visualstudio.com':
|
||||
details = this._config.VSO_DEV;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unrecognized callback ${callbackUri}`);
|
||||
}
|
||||
|
||||
if (!details.id || !details.secret) {
|
||||
throw new Error(`No client configuration available for ${callbackUri}`);
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
}
|
||||
|
||||
const ClientRegistrar = new Registrar();
|
||||
export default ClientRegistrar;
|
||||
@@ -25,6 +25,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
vscode.authentication.registerAuthenticationProvider({
|
||||
id: 'github',
|
||||
displayName: 'GitHub',
|
||||
supportsMultipleAccounts: false,
|
||||
onDidChangeSessions: onDidChangeSessions.event,
|
||||
getSessions: () => Promise.resolve(loginService.sessions),
|
||||
login: async (scopeList: string[]) => {
|
||||
|
||||
@@ -21,20 +21,8 @@ interface SessionData {
|
||||
accessToken: string;
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
interface OldSessionData {
|
||||
id: string;
|
||||
accountName: string;
|
||||
scopes: string[];
|
||||
accessToken: string;
|
||||
}
|
||||
|
||||
function isOldSessionData(x: any): x is OldSessionData {
|
||||
return !!x.accountName;
|
||||
}
|
||||
|
||||
export class GitHubAuthenticationProvider {
|
||||
private _sessions: vscode.AuthenticationSession[] = [];
|
||||
private _sessions: vscode.AuthenticationSession2[] = [];
|
||||
private _githubServer = new GitHubServer();
|
||||
|
||||
public async initialize(): Promise<void> {
|
||||
@@ -44,14 +32,12 @@ export class GitHubAuthenticationProvider {
|
||||
// Ignore, network request failed
|
||||
}
|
||||
|
||||
// TODO revert Cannot validate tokens from auth server, no available clientId
|
||||
// await this.validateSessions();
|
||||
this.pollForChange();
|
||||
}
|
||||
|
||||
private pollForChange() {
|
||||
setTimeout(async () => {
|
||||
let storedSessions: vscode.AuthenticationSession[];
|
||||
let storedSessions: vscode.AuthenticationSession2[];
|
||||
try {
|
||||
storedSessions = await this.readSessions();
|
||||
} catch (e) {
|
||||
@@ -94,13 +80,13 @@ export class GitHubAuthenticationProvider {
|
||||
}, 1000 * 30);
|
||||
}
|
||||
|
||||
private async readSessions(): Promise<vscode.AuthenticationSession[]> {
|
||||
private async readSessions(): Promise<vscode.AuthenticationSession2[]> {
|
||||
const storedSessions = await keychain.getToken();
|
||||
if (storedSessions) {
|
||||
try {
|
||||
const sessionData: (SessionData | OldSessionData)[] = JSON.parse(storedSessions);
|
||||
const sessionPromises = sessionData.map(async (session: SessionData | OldSessionData): Promise<vscode.AuthenticationSession> => {
|
||||
const needsUserInfo = isOldSessionData(session) || !session.account;
|
||||
const sessionData: SessionData[] = JSON.parse(storedSessions);
|
||||
const sessionPromises = sessionData.map(async (session: SessionData): Promise<vscode.AuthenticationSession2> => {
|
||||
const needsUserInfo = !session.account;
|
||||
let userInfo: { id: string, accountName: string };
|
||||
if (needsUserInfo) {
|
||||
userInfo = await this._githubServer.getUserInfo(session.accessToken);
|
||||
@@ -109,15 +95,11 @@ export class GitHubAuthenticationProvider {
|
||||
return {
|
||||
id: session.id,
|
||||
account: {
|
||||
displayName: isOldSessionData(session)
|
||||
? session.accountName
|
||||
: session.account?.displayName ?? userInfo!.accountName,
|
||||
id: isOldSessionData(session)
|
||||
? userInfo!.id
|
||||
: session.account?.id ?? userInfo!.id
|
||||
displayName: session.account?.displayName ?? userInfo!.accountName,
|
||||
id: session.account?.id ?? userInfo!.id
|
||||
},
|
||||
scopes: session.scopes,
|
||||
getAccessToken: () => Promise.resolve(session.accessToken)
|
||||
accessToken: session.accessToken
|
||||
};
|
||||
});
|
||||
|
||||
@@ -136,57 +118,30 @@ export class GitHubAuthenticationProvider {
|
||||
}
|
||||
|
||||
private async storeSessions(): Promise<void> {
|
||||
const sessionData: SessionData[] = await Promise.all(this._sessions.map(async session => {
|
||||
const resolvedAccessToken = await session.getAccessToken();
|
||||
return {
|
||||
id: session.id,
|
||||
account: session.account,
|
||||
scopes: session.scopes,
|
||||
accessToken: resolvedAccessToken
|
||||
};
|
||||
}));
|
||||
|
||||
await keychain.setToken(JSON.stringify(sessionData));
|
||||
await keychain.setToken(JSON.stringify(this._sessions));
|
||||
}
|
||||
|
||||
get sessions(): vscode.AuthenticationSession[] {
|
||||
get sessions(): vscode.AuthenticationSession2[] {
|
||||
return this._sessions;
|
||||
}
|
||||
|
||||
public async login(scopes: string): Promise<vscode.AuthenticationSession> {
|
||||
const token = scopes === 'vso' ? await this.loginAndInstallApp(scopes) : await this._githubServer.login(scopes);
|
||||
public async login(scopes: string): Promise<vscode.AuthenticationSession2> {
|
||||
const token = await this._githubServer.login(scopes);
|
||||
const session = await this.tokenToSession(token, scopes.split(' '));
|
||||
await this.setToken(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
public async loginAndInstallApp(scopes: string): Promise<string> {
|
||||
const token = await this._githubServer.login(scopes);
|
||||
const hasUserInstallation = await this._githubServer.hasUserInstallation(token);
|
||||
if (hasUserInstallation) {
|
||||
return token;
|
||||
} else {
|
||||
return this._githubServer.installApp();
|
||||
}
|
||||
}
|
||||
|
||||
public async manuallyProvideToken(): Promise<void> {
|
||||
this._githubServer.manuallyProvideToken();
|
||||
}
|
||||
|
||||
private async tokenToSession(token: string, scopes: string[]): Promise<vscode.AuthenticationSession> {
|
||||
private async tokenToSession(token: string, scopes: string[]): Promise<vscode.AuthenticationSession2> {
|
||||
const userInfo = await this._githubServer.getUserInfo(token);
|
||||
return {
|
||||
id: uuid(),
|
||||
getAccessToken: () => Promise.resolve(token),
|
||||
account: {
|
||||
displayName: userInfo.accountName,
|
||||
id: userInfo.id
|
||||
},
|
||||
scopes: scopes
|
||||
};
|
||||
return new vscode.AuthenticationSession2(uuid(), token, { displayName: userInfo.accountName, id: userInfo.id }, scopes);
|
||||
}
|
||||
private async setToken(session: vscode.AuthenticationSession): Promise<void> {
|
||||
|
||||
private async setToken(session: vscode.AuthenticationSession2): Promise<void> {
|
||||
const sessionIndex = this._sessions.findIndex(s => s.id === session.id);
|
||||
if (sessionIndex > -1) {
|
||||
this._sessions.splice(sessionIndex, 1, session);
|
||||
@@ -201,14 +156,6 @@ export class GitHubAuthenticationProvider {
|
||||
const sessionIndex = this._sessions.findIndex(session => session.id === id);
|
||||
if (sessionIndex > -1) {
|
||||
this._sessions.splice(sessionIndex, 1);
|
||||
// TODO revert
|
||||
// Cannot revoke tokens from auth server, no clientId available
|
||||
// const token = await session.getAccessToken();
|
||||
// try {
|
||||
// await this._githubServer.revokeToken(token);
|
||||
// } catch (_) {
|
||||
// // ignore, should still remove from keychain
|
||||
// }
|
||||
}
|
||||
|
||||
await this.storeSessions();
|
||||
|
||||
@@ -9,7 +9,6 @@ import * as vscode from 'vscode';
|
||||
import * as uuid from 'uuid';
|
||||
import { PromiseAdapter, promiseFromEvent } from './common/utils';
|
||||
import Logger from './common/logger';
|
||||
import ClientRegistrar from './common/clientRegistrar';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -24,8 +23,8 @@ class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.
|
||||
|
||||
export const uriHandler = new UriEventHandler;
|
||||
|
||||
const exchangeCodeForToken: (state: string, host: string, getPath: (code: string) => string) => PromiseAdapter<vscode.Uri, string> =
|
||||
(state, host, getPath) => async (uri, resolve, reject) => {
|
||||
const exchangeCodeForToken: (state: string) => PromiseAdapter<vscode.Uri, string> =
|
||||
(state) => async (uri, resolve, reject) => {
|
||||
Logger.info('Exchanging code for token...');
|
||||
const query = parseQuery(uri);
|
||||
const code = query.code;
|
||||
@@ -36,8 +35,8 @@ const exchangeCodeForToken: (state: string, host: string, getPath: (code: string
|
||||
}
|
||||
|
||||
const post = https.request({
|
||||
host: host,
|
||||
path: getPath(code),
|
||||
host: AUTH_RELAY_SERVER,
|
||||
path: `/token?code=${code}&state=${state}`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
@@ -81,26 +80,13 @@ export class GitHubServer {
|
||||
|
||||
const state = uuid();
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
let uri = vscode.Uri.parse(`https://${AUTH_RELAY_SERVER}/authorize/?callbackUri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&responseType=code`);
|
||||
if (scopes === 'vso') {
|
||||
const clientDetails = ClientRegistrar.getGitHubAppDetails();
|
||||
uri = vscode.Uri.parse(`https://github.com/login/oauth/authorize?redirect_uri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&client_id=${clientDetails.id}`);
|
||||
}
|
||||
const uri = vscode.Uri.parse(`https://${AUTH_RELAY_SERVER}/authorize/?callbackUri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&responseType=code`);
|
||||
|
||||
vscode.env.openExternal(uri);
|
||||
|
||||
return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state,
|
||||
scopes === 'vso' ? 'github.com' : AUTH_RELAY_SERVER,
|
||||
(code) => {
|
||||
if (scopes === 'vso') {
|
||||
const clientDetails = ClientRegistrar.getGitHubAppDetails();
|
||||
return `/login/oauth/access_token?client_id=${clientDetails.id}&client_secret=${clientDetails.secret}&state=${state}&code=${code}`;
|
||||
} else {
|
||||
return `/token?code=${code}&state=${state}`;
|
||||
}
|
||||
})).finally(() => {
|
||||
this.updateStatusBarItem(false);
|
||||
});
|
||||
return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state)).finally(() => {
|
||||
this.updateStatusBarItem(false);
|
||||
});
|
||||
}
|
||||
|
||||
private updateStatusBarItem(isStart?: boolean) {
|
||||
@@ -130,51 +116,6 @@ export class GitHubServer {
|
||||
}
|
||||
}
|
||||
|
||||
public async hasUserInstallation(token: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Logger.info('Getting user installations...');
|
||||
const post = https.request({
|
||||
host: 'api.github.com',
|
||||
path: `/user/installations`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.machine-man-preview+json',
|
||||
Authorization: `token ${token}`,
|
||||
'User-Agent': 'Visual-Studio-Code'
|
||||
}
|
||||
}, result => {
|
||||
const buffer: Buffer[] = [];
|
||||
result.on('data', (chunk: Buffer) => {
|
||||
buffer.push(chunk);
|
||||
});
|
||||
result.on('end', () => {
|
||||
if (result.statusCode === 200) {
|
||||
const json = JSON.parse(Buffer.concat(buffer).toString());
|
||||
Logger.info('Got installation info!');
|
||||
const hasInstallation = json.installations.some((installation: { app_slug: string }) => installation.app_slug === 'microsoft-visual-studio-code');
|
||||
resolve(hasInstallation);
|
||||
} else {
|
||||
reject(new Error(result.statusMessage));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
post.end();
|
||||
post.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async installApp(): Promise<string> {
|
||||
const clientDetails = ClientRegistrar.getGitHubAppDetails();
|
||||
const state = uuid();
|
||||
const uri = vscode.Uri.parse(`https://github.com/apps/microsoft-visual-studio-code/installations/new?state=${state}`);
|
||||
|
||||
vscode.env.openExternal(uri);
|
||||
return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state, 'github.com', (code) => `/login/oauth/access_token?client_id=${clientDetails.id}&client_secret=${clientDetails.secret}&state=${state}&code=${code}`));
|
||||
}
|
||||
|
||||
public async getUserInfo(token: string): Promise<{ id: string, accountName: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Logger.info('Getting account info...');
|
||||
@@ -210,91 +151,4 @@ export class GitHubServer {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async validateToken(token: string): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
const clientDetails = ClientRegistrar.getClientDetails(callbackUri);
|
||||
const detailsString = `${clientDetails.id}:${clientDetails.secret}`;
|
||||
|
||||
const payload = JSON.stringify({ access_token: token });
|
||||
|
||||
Logger.info('Validating token...');
|
||||
const post = https.request({
|
||||
host: 'api.github.com',
|
||||
path: `/applications/${clientDetails.id}/token`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Basic ${Buffer.from(detailsString).toString('base64')}`,
|
||||
'User-Agent': 'Visual-Studio-Code',
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(payload)
|
||||
}
|
||||
}, result => {
|
||||
const buffer: Buffer[] = [];
|
||||
result.on('data', (chunk: Buffer) => {
|
||||
buffer.push(chunk);
|
||||
});
|
||||
result.on('end', () => {
|
||||
if (result.statusCode === 200) {
|
||||
Logger.info('Validated token!');
|
||||
resolve();
|
||||
} else {
|
||||
Logger.info(`Validating token failed: ${result.statusMessage}`);
|
||||
reject(new Error(result.statusMessage));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
post.write(payload);
|
||||
post.end();
|
||||
post.on('error', err => {
|
||||
Logger.error(err.message);
|
||||
reject(new Error(NETWORK_ERROR));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async revokeToken(token: string): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
const clientDetails = ClientRegistrar.getClientDetails(callbackUri);
|
||||
const detailsString = `${clientDetails.id}:${clientDetails.secret}`;
|
||||
|
||||
const payload = JSON.stringify({ access_token: token });
|
||||
|
||||
Logger.info('Revoking token...');
|
||||
const post = https.request({
|
||||
host: 'api.github.com',
|
||||
path: `/applications/${clientDetails.id}/token`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
Authorization: `Basic ${Buffer.from(detailsString).toString('base64')}`,
|
||||
'User-Agent': 'Visual-Studio-Code',
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(payload)
|
||||
}
|
||||
}, result => {
|
||||
const buffer: Buffer[] = [];
|
||||
result.on('data', (chunk: Buffer) => {
|
||||
buffer.push(chunk);
|
||||
});
|
||||
result.on('end', () => {
|
||||
if (result.statusCode === 204) {
|
||||
Logger.info('Revoked token!');
|
||||
resolve();
|
||||
} else {
|
||||
Logger.info(`Revoking token failed: ${result.statusMessage}`);
|
||||
reject(new Error(result.statusMessage));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
post.write(payload);
|
||||
post.end();
|
||||
post.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
8
extensions/github/.vscodeignore
Normal file
8
extensions/github/.vscodeignore
Normal file
@@ -0,0 +1,8 @@
|
||||
src/**
|
||||
!src/common/config.json
|
||||
out/**
|
||||
build/**
|
||||
extension.webpack.config.js
|
||||
tsconfig.json
|
||||
yarn.lock
|
||||
README.md
|
||||
7
extensions/github/README.md
Normal file
7
extensions/github/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# GitHub for Visual Studio Code
|
||||
|
||||
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
|
||||
|
||||
## Features
|
||||
|
||||
This extension provides GitHub features for VS Code.
|
||||
@@ -3,13 +3,15 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
//@ts-check
|
||||
|
||||
export interface INativeOpenDialogOptions {
|
||||
forceNewWindow?: boolean;
|
||||
'use strict';
|
||||
|
||||
defaultPath?: string;
|
||||
const withDefaults = require('../shared.webpack.config');
|
||||
|
||||
telemetryEventName?: string;
|
||||
telemetryExtraData?: ITelemetryData;
|
||||
}
|
||||
module.exports = withDefaults({
|
||||
context: __dirname,
|
||||
entry: {
|
||||
extension: './src/extension.ts'
|
||||
}
|
||||
});
|
||||
67
extensions/github/package.json
Normal file
67
extensions/github/package.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "github",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"publisher": "vscode",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.41.0"
|
||||
},
|
||||
"enableProposedApi": true,
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"extensionDependencies": [
|
||||
"vscode.git"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "github.publish",
|
||||
"title": "Publish to GitHub"
|
||||
}
|
||||
],
|
||||
"configuration": [
|
||||
{
|
||||
"title": "GitHub",
|
||||
"properties": {
|
||||
"github.gitAuthentication": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%config.gitAuthentication%"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"viewsWelcome": [
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%welcome.publishFolder%",
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == folder"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%welcome.publishWorkspaceFolder%",
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "gulp compile-extension:github",
|
||||
"watch": "gulp watch-extension:github"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/rest": "^17.9.1",
|
||||
"tunnel": "^0.0.6",
|
||||
"vscode-nls": "^4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^10.12.21"
|
||||
}
|
||||
}
|
||||
7
extensions/github/package.nls.json
Normal file
7
extensions/github/package.nls.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"displayName": "GitHub",
|
||||
"description": "GitHub",
|
||||
"config.gitAuthentication": "Controls whether to enable automatic GitHub authentication for git commands within VS Code.",
|
||||
"welcome.publishFolder": "You can also directly publish this folder to a GitHub repository.\n[$(github) Publish to GitHub](command:github.publish)",
|
||||
"welcome.publishWorkspaceFolder": "You can also directly publish a workspace folder to a GitHub repository.\n[$(github) Publish to GitHub](command:github.publish)"
|
||||
}
|
||||
60
extensions/github/src/auth.ts
Normal file
60
extensions/github/src/auth.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AuthenticationSession, authentication, window } from 'vscode';
|
||||
import { Agent, globalAgent } from 'https';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import { httpsOverHttp } from 'tunnel';
|
||||
import { URL } from 'url';
|
||||
|
||||
function getAgent(url: string | undefined = process.env.HTTPS_PROXY): Agent {
|
||||
if (!url) {
|
||||
return globalAgent;
|
||||
}
|
||||
|
||||
try {
|
||||
const { hostname, port, username, password } = new URL(url);
|
||||
const auth = username && password && `${username}:${password}`;
|
||||
return httpsOverHttp({ proxy: { host: hostname, port, proxyAuth: auth } });
|
||||
} catch (e) {
|
||||
window.showErrorMessage(`HTTPS_PROXY environment variable ignored: ${e.message}`);
|
||||
return globalAgent;
|
||||
}
|
||||
}
|
||||
|
||||
const scopes = ['repo'];
|
||||
|
||||
export async function getSession(): Promise<AuthenticationSession> {
|
||||
const authenticationSessions = await authentication.getSessions('github', scopes);
|
||||
|
||||
if (authenticationSessions.length) {
|
||||
return await authenticationSessions[0];
|
||||
} else {
|
||||
return await authentication.login('github', scopes);
|
||||
}
|
||||
}
|
||||
|
||||
let _octokit: Promise<Octokit> | undefined;
|
||||
|
||||
export function getOctokit(): Promise<Octokit> {
|
||||
if (!_octokit) {
|
||||
_octokit = getSession().then(async session => {
|
||||
const token = await session.getAccessToken();
|
||||
const agent = getAgent();
|
||||
|
||||
return new Octokit({
|
||||
request: { agent },
|
||||
userAgent: 'GitHub VSCode',
|
||||
auth: `token ${token}`
|
||||
});
|
||||
}).then(null, async err => {
|
||||
_octokit = undefined;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
return _octokit;
|
||||
}
|
||||
|
||||
22
extensions/github/src/commands.ts
Normal file
22
extensions/github/src/commands.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { API as GitAPI } from './typings/git';
|
||||
import { publishRepository } from './publish';
|
||||
|
||||
export function registerCommands(gitAPI: GitAPI): vscode.Disposable[] {
|
||||
const disposables = [];
|
||||
|
||||
disposables.push(vscode.commands.registerCommand('github.publish', async () => {
|
||||
try {
|
||||
publishRepository(gitAPI);
|
||||
} catch (err) {
|
||||
vscode.window.showErrorMessage(err.message);
|
||||
}
|
||||
}));
|
||||
|
||||
return disposables;
|
||||
}
|
||||
64
extensions/github/src/credentialProvider.ts
Normal file
64
extensions/github/src/credentialProvider.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CredentialsProvider, Credentials, API as GitAPI } from './typings/git';
|
||||
import { workspace, Uri, Disposable } from 'vscode';
|
||||
import { getSession } from './auth';
|
||||
|
||||
const EmptyDisposable: Disposable = { dispose() { } };
|
||||
|
||||
class GitHubCredentialProvider implements CredentialsProvider {
|
||||
|
||||
async getCredentials(host: Uri): Promise<Credentials | undefined> {
|
||||
if (!/github\.com/i.test(host.authority)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getSession();
|
||||
return { username: session.account.id, password: await session.getAccessToken() };
|
||||
}
|
||||
}
|
||||
|
||||
export class GithubCredentialProviderManager {
|
||||
|
||||
private providerDisposable: Disposable = EmptyDisposable;
|
||||
private readonly disposable: Disposable;
|
||||
|
||||
private _enabled = false;
|
||||
private set enabled(enabled: boolean) {
|
||||
if (this._enabled === enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._enabled = enabled;
|
||||
|
||||
if (enabled) {
|
||||
this.providerDisposable = this.gitAPI.registerCredentialsProvider(new GitHubCredentialProvider());
|
||||
} else {
|
||||
this.providerDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private gitAPI: GitAPI) {
|
||||
this.disposable = workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('github')) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
private refresh(): void {
|
||||
const config = workspace.getConfiguration('github', null);
|
||||
const enabled = config.get<boolean>('gitAuthentication', true);
|
||||
this.enabled = !!enabled;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.enabled = false;
|
||||
this.disposable.dispose();
|
||||
}
|
||||
}
|
||||
19
extensions/github/src/extension.ts
Normal file
19
extensions/github/src/extension.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { GithubRemoteSourceProvider } from './remoteSourceProvider';
|
||||
import { GitExtension } from './typings/git';
|
||||
import { registerCommands } from './commands';
|
||||
import { GithubCredentialProviderManager } from './credentialProvider';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
const gitExtension = vscode.extensions.getExtension<GitExtension>('vscode.git')!.exports;
|
||||
const gitAPI = gitExtension.getAPI(1);
|
||||
|
||||
context.subscriptions.push(...registerCommands(gitAPI));
|
||||
context.subscriptions.push(gitAPI.registerRemoteSourceProvider(new GithubRemoteSourceProvider(gitAPI)));
|
||||
context.subscriptions.push(new GithubCredentialProviderManager(gitAPI));
|
||||
}
|
||||
172
extensions/github/src/publish.ts
Normal file
172
extensions/github/src/publish.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as path from 'path';
|
||||
import { promises as fs } from 'fs';
|
||||
import { API as GitAPI, Repository } from './typings/git';
|
||||
import { getOctokit } from './auth';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
function sanitizeRepositoryName(value: string): string {
|
||||
return value.trim().replace(/[^a-z0-9_.]/ig, '-');
|
||||
}
|
||||
|
||||
function getPick<T extends vscode.QuickPickItem>(quickpick: vscode.QuickPick<T>): Promise<T | undefined> {
|
||||
return Promise.race<T | undefined>([
|
||||
new Promise<T>(c => quickpick.onDidAccept(() => quickpick.selectedItems.length > 0 && c(quickpick.selectedItems[0]))),
|
||||
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
|
||||
]);
|
||||
}
|
||||
|
||||
export async function publishRepository(gitAPI: GitAPI, repository?: Repository): Promise<void> {
|
||||
if (!vscode.workspace.workspaceFolders?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let folder: vscode.WorkspaceFolder;
|
||||
|
||||
if (vscode.workspace.workspaceFolders.length === 1) {
|
||||
folder = vscode.workspace.workspaceFolders[0];
|
||||
} else {
|
||||
const picks = vscode.workspace.workspaceFolders.map(folder => ({ label: folder.name, folder }));
|
||||
const placeHolder = localize('pick folder', "Pick a folder to publish to GitHub");
|
||||
const pick = await vscode.window.showQuickPick(picks, { placeHolder });
|
||||
|
||||
if (!pick) {
|
||||
return;
|
||||
}
|
||||
|
||||
folder = pick.folder;
|
||||
}
|
||||
|
||||
let quickpick = vscode.window.createQuickPick<vscode.QuickPickItem & { repo?: string, auth?: 'https' | 'ssh' }>();
|
||||
quickpick.ignoreFocusOut = true;
|
||||
|
||||
quickpick.placeholder = 'Repository Name';
|
||||
quickpick.value = folder.name;
|
||||
quickpick.show();
|
||||
quickpick.busy = true;
|
||||
|
||||
const octokit = await getOctokit();
|
||||
const user = await octokit.users.getAuthenticated({});
|
||||
const owner = user.data.login;
|
||||
quickpick.busy = false;
|
||||
|
||||
let repo: string | undefined;
|
||||
|
||||
const onDidChangeValue = async () => {
|
||||
const sanitizedRepo = sanitizeRepositoryName(quickpick.value);
|
||||
|
||||
if (!sanitizedRepo) {
|
||||
quickpick.items = [];
|
||||
} else {
|
||||
quickpick.items = [{ label: `$(repo) Publish to GitHub private repository`, description: `$(github) ${owner}/${sanitizedRepo}`, alwaysShow: true, repo: sanitizedRepo }];
|
||||
}
|
||||
};
|
||||
|
||||
onDidChangeValue();
|
||||
|
||||
while (true) {
|
||||
const listener = quickpick.onDidChangeValue(onDidChangeValue);
|
||||
const pick = await getPick(quickpick);
|
||||
listener.dispose();
|
||||
|
||||
repo = pick?.repo;
|
||||
|
||||
if (repo) {
|
||||
try {
|
||||
quickpick.busy = true;
|
||||
await octokit.repos.get({ owner, repo: repo });
|
||||
quickpick.items = [{ label: `$(error) GitHub repository already exists`, description: `$(github) ${owner}/${repo}`, alwaysShow: true }];
|
||||
} catch {
|
||||
break;
|
||||
} finally {
|
||||
quickpick.busy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickpick.dispose();
|
||||
|
||||
if (!repo) {
|
||||
return;
|
||||
}
|
||||
|
||||
quickpick = vscode.window.createQuickPick();
|
||||
quickpick.placeholder = localize('ignore', "Select which files should be included in the repository.");
|
||||
quickpick.canSelectMany = true;
|
||||
quickpick.show();
|
||||
|
||||
try {
|
||||
quickpick.busy = true;
|
||||
|
||||
const repositoryPath = folder.uri.fsPath;
|
||||
const currentPath = path.join(repositoryPath);
|
||||
const children = await fs.readdir(currentPath);
|
||||
quickpick.items = children.map(name => ({ label: name }));
|
||||
quickpick.selectedItems = quickpick.items;
|
||||
quickpick.busy = false;
|
||||
|
||||
const result = await Promise.race([
|
||||
new Promise<readonly vscode.QuickPickItem[]>(c => quickpick.onDidAccept(() => c(quickpick.selectedItems))),
|
||||
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
|
||||
]);
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ignored = new Set(children);
|
||||
result.forEach(c => ignored.delete(c.label));
|
||||
|
||||
const raw = [...ignored].map(i => `/${i}`).join('\n');
|
||||
await fs.writeFile(path.join(repositoryPath, '.gitignore'), raw, 'utf8');
|
||||
} finally {
|
||||
quickpick.dispose();
|
||||
}
|
||||
|
||||
const githubRepository = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, title: 'Publish to GitHub' }, async progress => {
|
||||
progress.report({ message: 'Publishing to GitHub private repository', increment: 25 });
|
||||
|
||||
const res = await octokit.repos.createForAuthenticatedUser({
|
||||
name: repo!,
|
||||
private: true
|
||||
});
|
||||
|
||||
const createdGithubRepository = res.data;
|
||||
|
||||
progress.report({ message: 'Creating first commit', increment: 25 });
|
||||
|
||||
if (!repository) {
|
||||
repository = await gitAPI.init(folder.uri) || undefined;
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.commit('first commit', { all: true });
|
||||
}
|
||||
|
||||
progress.report({ message: 'Uploading files', increment: 25 });
|
||||
await repository.addRemote('origin', createdGithubRepository.clone_url);
|
||||
await repository.push('origin', 'master', true);
|
||||
|
||||
return createdGithubRepository;
|
||||
});
|
||||
|
||||
if (!githubRepository) {
|
||||
return;
|
||||
}
|
||||
|
||||
const openInGitHub = 'Open In GitHub';
|
||||
const action = await vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub);
|
||||
|
||||
if (action === openInGitHub) {
|
||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
|
||||
}
|
||||
}
|
||||
67
extensions/github/src/remoteSourceProvider.ts
Normal file
67
extensions/github/src/remoteSourceProvider.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { API as GitAPI, RemoteSourceProvider, RemoteSource, Repository } from './typings/git';
|
||||
import { getOctokit } from './auth';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import { publishRepository } from './publish';
|
||||
|
||||
function asRemoteSource(raw: any): RemoteSource {
|
||||
return {
|
||||
name: `$(github) ${raw.full_name}`,
|
||||
description: raw.description || undefined,
|
||||
url: raw.clone_url
|
||||
};
|
||||
}
|
||||
|
||||
export class GithubRemoteSourceProvider implements RemoteSourceProvider {
|
||||
|
||||
readonly name = 'GitHub';
|
||||
readonly icon = 'github';
|
||||
readonly supportsQuery = true;
|
||||
|
||||
private userReposCache: RemoteSource[] = [];
|
||||
|
||||
constructor(private gitAPI: GitAPI) { }
|
||||
|
||||
async getRemoteSources(query?: string): Promise<RemoteSource[]> {
|
||||
const octokit = await getOctokit();
|
||||
const [fromUser, fromQuery] = await Promise.all([
|
||||
this.getUserRemoteSources(octokit, query),
|
||||
this.getQueryRemoteSources(octokit, query)
|
||||
]);
|
||||
|
||||
const userRepos = new Set(fromUser.map(r => r.name));
|
||||
|
||||
return [
|
||||
...fromUser,
|
||||
...fromQuery.filter(r => !userRepos.has(r.name))
|
||||
];
|
||||
}
|
||||
|
||||
private async getUserRemoteSources(octokit: Octokit, query?: string): Promise<RemoteSource[]> {
|
||||
if (!query) {
|
||||
const user = await octokit.users.getAuthenticated({});
|
||||
const username = user.data.login;
|
||||
const res = await octokit.repos.listForUser({ username, sort: 'updated', per_page: 100 });
|
||||
this.userReposCache = res.data.map(asRemoteSource);
|
||||
}
|
||||
|
||||
return this.userReposCache;
|
||||
}
|
||||
|
||||
private async getQueryRemoteSources(octokit: Octokit, query?: string): Promise<RemoteSource[]> {
|
||||
if (!query) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const raw = await octokit.search.repos({ q: query, sort: 'updated' });
|
||||
return raw.data.items.map(asRemoteSource);
|
||||
}
|
||||
|
||||
publishRepository(repository: Repository): Promise<void> {
|
||||
return publishRepository(this.gitAPI, repository);
|
||||
}
|
||||
}
|
||||
295
extensions/github/src/typings/git.d.ts
vendored
Normal file
295
extensions/github/src/typings/git.d.ts
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Uri, Event, Disposable, ProviderResult } from 'vscode';
|
||||
export { ProviderResult } from 'vscode';
|
||||
|
||||
export interface Git {
|
||||
readonly path: string;
|
||||
}
|
||||
|
||||
export interface InputBox {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const enum RefType {
|
||||
Head,
|
||||
RemoteHead,
|
||||
Tag
|
||||
}
|
||||
|
||||
export interface Ref {
|
||||
readonly type: RefType;
|
||||
readonly name?: string;
|
||||
readonly commit?: string;
|
||||
readonly remote?: string;
|
||||
}
|
||||
|
||||
export interface UpstreamRef {
|
||||
readonly remote: string;
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
export interface Branch extends Ref {
|
||||
readonly upstream?: UpstreamRef;
|
||||
readonly ahead?: number;
|
||||
readonly behind?: number;
|
||||
}
|
||||
|
||||
export interface Commit {
|
||||
readonly hash: string;
|
||||
readonly message: string;
|
||||
readonly parents: string[];
|
||||
readonly authorDate?: Date;
|
||||
readonly authorName?: string;
|
||||
readonly authorEmail?: string;
|
||||
readonly commitDate?: Date;
|
||||
}
|
||||
|
||||
export interface Submodule {
|
||||
readonly name: string;
|
||||
readonly path: string;
|
||||
readonly url: string;
|
||||
}
|
||||
|
||||
export interface Remote {
|
||||
readonly name: string;
|
||||
readonly fetchUrl?: string;
|
||||
readonly pushUrl?: string;
|
||||
readonly isReadOnly: boolean;
|
||||
}
|
||||
|
||||
export const enum Status {
|
||||
INDEX_MODIFIED,
|
||||
INDEX_ADDED,
|
||||
INDEX_DELETED,
|
||||
INDEX_RENAMED,
|
||||
INDEX_COPIED,
|
||||
|
||||
MODIFIED,
|
||||
DELETED,
|
||||
UNTRACKED,
|
||||
IGNORED,
|
||||
INTENT_TO_ADD,
|
||||
|
||||
ADDED_BY_US,
|
||||
ADDED_BY_THEM,
|
||||
DELETED_BY_US,
|
||||
DELETED_BY_THEM,
|
||||
BOTH_ADDED,
|
||||
BOTH_DELETED,
|
||||
BOTH_MODIFIED
|
||||
}
|
||||
|
||||
export interface Change {
|
||||
|
||||
/**
|
||||
* Returns either `originalUri` or `renameUri`, depending
|
||||
* on whether this change is a rename change. When
|
||||
* in doubt always use `uri` over the other two alternatives.
|
||||
*/
|
||||
readonly uri: Uri;
|
||||
readonly originalUri: Uri;
|
||||
readonly renameUri: Uri | undefined;
|
||||
readonly status: Status;
|
||||
}
|
||||
|
||||
export interface RepositoryState {
|
||||
readonly HEAD: Branch | undefined;
|
||||
readonly refs: Ref[];
|
||||
readonly remotes: Remote[];
|
||||
readonly submodules: Submodule[];
|
||||
readonly rebaseCommit: Commit | undefined;
|
||||
|
||||
readonly mergeChanges: Change[];
|
||||
readonly indexChanges: Change[];
|
||||
readonly workingTreeChanges: Change[];
|
||||
|
||||
readonly onDidChange: Event<void>;
|
||||
}
|
||||
|
||||
export interface RepositoryUIState {
|
||||
readonly selected: boolean;
|
||||
readonly onDidChange: Event<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log options.
|
||||
*/
|
||||
export interface LogOptions {
|
||||
/** Max number of log entries to retrieve. If not specified, the default is 32. */
|
||||
readonly maxEntries?: number;
|
||||
readonly path?: string;
|
||||
}
|
||||
|
||||
export interface CommitOptions {
|
||||
all?: boolean | 'tracked';
|
||||
amend?: boolean;
|
||||
signoff?: boolean;
|
||||
signCommit?: boolean;
|
||||
empty?: boolean;
|
||||
}
|
||||
|
||||
export interface BranchQuery {
|
||||
readonly remote?: boolean;
|
||||
readonly contains?: string;
|
||||
}
|
||||
|
||||
export interface Repository {
|
||||
|
||||
readonly rootUri: Uri;
|
||||
readonly inputBox: InputBox;
|
||||
readonly state: RepositoryState;
|
||||
readonly ui: RepositoryUIState;
|
||||
|
||||
getConfigs(): Promise<{ key: string; value: string; }[]>;
|
||||
getConfig(key: string): Promise<string>;
|
||||
setConfig(key: string, value: string): Promise<string>;
|
||||
getGlobalConfig(key: string): Promise<string>;
|
||||
|
||||
getObjectDetails(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }>;
|
||||
detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }>;
|
||||
buffer(ref: string, path: string): Promise<Buffer>;
|
||||
show(ref: string, path: string): Promise<string>;
|
||||
getCommit(ref: string): Promise<Commit>;
|
||||
|
||||
clean(paths: string[]): Promise<void>;
|
||||
|
||||
apply(patch: string, reverse?: boolean): Promise<void>;
|
||||
diff(cached?: boolean): Promise<string>;
|
||||
diffWithHEAD(): Promise<Change[]>;
|
||||
diffWithHEAD(path: string): Promise<string>;
|
||||
diffWith(ref: string): Promise<Change[]>;
|
||||
diffWith(ref: string, path: string): Promise<string>;
|
||||
diffIndexWithHEAD(): Promise<Change[]>;
|
||||
diffIndexWithHEAD(path: string): Promise<string>;
|
||||
diffIndexWith(ref: string): Promise<Change[]>;
|
||||
diffIndexWith(ref: string, path: string): Promise<string>;
|
||||
diffBlobs(object1: string, object2: string): Promise<string>;
|
||||
diffBetween(ref1: string, ref2: string): Promise<Change[]>;
|
||||
diffBetween(ref1: string, ref2: string, path: string): Promise<string>;
|
||||
|
||||
hashObject(data: string): Promise<string>;
|
||||
|
||||
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
|
||||
deleteBranch(name: string, force?: boolean): Promise<void>;
|
||||
getBranch(name: string): Promise<Branch>;
|
||||
getBranches(query: BranchQuery): Promise<Ref[]>;
|
||||
setBranchUpstream(name: string, upstream: string): Promise<void>;
|
||||
|
||||
getMergeBase(ref1: string, ref2: string): Promise<string>;
|
||||
|
||||
status(): Promise<void>;
|
||||
checkout(treeish: string): Promise<void>;
|
||||
|
||||
addRemote(name: string, url: string): Promise<void>;
|
||||
removeRemote(name: string): Promise<void>;
|
||||
renameRemote(name: string, newName: string): Promise<void>;
|
||||
|
||||
fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
|
||||
pull(unshallow?: boolean): Promise<void>;
|
||||
push(remoteName?: string, branchName?: string, setUpstream?: boolean): Promise<void>;
|
||||
|
||||
blame(path: string): Promise<string>;
|
||||
log(options?: LogOptions): Promise<Commit[]>;
|
||||
|
||||
commit(message: string, opts?: CommitOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface RemoteSource {
|
||||
readonly name: string;
|
||||
readonly description?: string;
|
||||
readonly url: string | string[];
|
||||
}
|
||||
|
||||
export interface RemoteSourceProvider {
|
||||
readonly name: string;
|
||||
readonly icon?: string; // codicon name
|
||||
readonly supportsQuery?: boolean;
|
||||
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
|
||||
publishRepository?(repository: Repository): Promise<void>;
|
||||
}
|
||||
|
||||
export interface Credentials {
|
||||
readonly username: string;
|
||||
readonly password: string;
|
||||
}
|
||||
|
||||
export interface CredentialsProvider {
|
||||
getCredentials(host: Uri): ProviderResult<Credentials>;
|
||||
}
|
||||
|
||||
export type APIState = 'uninitialized' | 'initialized';
|
||||
|
||||
export interface API {
|
||||
readonly state: APIState;
|
||||
readonly onDidChangeState: Event<APIState>;
|
||||
readonly git: Git;
|
||||
readonly repositories: Repository[];
|
||||
readonly onDidOpenRepository: Event<Repository>;
|
||||
readonly onDidCloseRepository: Event<Repository>;
|
||||
|
||||
toGitUri(uri: Uri, ref: string): Uri;
|
||||
getRepository(uri: Uri): Repository | null;
|
||||
init(root: Uri): Promise<Repository | null>;
|
||||
|
||||
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable;
|
||||
registerCredentialsProvider(provider: CredentialsProvider): Disposable;
|
||||
}
|
||||
|
||||
export interface GitExtension {
|
||||
|
||||
readonly enabled: boolean;
|
||||
readonly onDidChangeEnablement: Event<boolean>;
|
||||
|
||||
/**
|
||||
* Returns a specific API version.
|
||||
*
|
||||
* Throws error if git extension is disabled. You can listed to the
|
||||
* [GitExtension.onDidChangeEnablement](#GitExtension.onDidChangeEnablement) event
|
||||
* to know when the extension becomes enabled/disabled.
|
||||
*
|
||||
* @param version Version number.
|
||||
* @returns API instance
|
||||
*/
|
||||
getAPI(version: 1): API;
|
||||
}
|
||||
|
||||
export const enum GitErrorCodes {
|
||||
BadConfigFile = 'BadConfigFile',
|
||||
AuthenticationFailed = 'AuthenticationFailed',
|
||||
NoUserNameConfigured = 'NoUserNameConfigured',
|
||||
NoUserEmailConfigured = 'NoUserEmailConfigured',
|
||||
NoRemoteRepositorySpecified = 'NoRemoteRepositorySpecified',
|
||||
NotAGitRepository = 'NotAGitRepository',
|
||||
NotAtRepositoryRoot = 'NotAtRepositoryRoot',
|
||||
Conflict = 'Conflict',
|
||||
StashConflict = 'StashConflict',
|
||||
UnmergedChanges = 'UnmergedChanges',
|
||||
PushRejected = 'PushRejected',
|
||||
RemoteConnectionError = 'RemoteConnectionError',
|
||||
DirtyWorkTree = 'DirtyWorkTree',
|
||||
CantOpenResource = 'CantOpenResource',
|
||||
GitNotFound = 'GitNotFound',
|
||||
CantCreatePipe = 'CantCreatePipe',
|
||||
CantAccessRemote = 'CantAccessRemote',
|
||||
RepositoryNotFound = 'RepositoryNotFound',
|
||||
RepositoryIsLocked = 'RepositoryIsLocked',
|
||||
BranchNotFullyMerged = 'BranchNotFullyMerged',
|
||||
NoRemoteReference = 'NoRemoteReference',
|
||||
InvalidBranchName = 'InvalidBranchName',
|
||||
BranchAlreadyExists = 'BranchAlreadyExists',
|
||||
NoLocalChanges = 'NoLocalChanges',
|
||||
NoStashFound = 'NoStashFound',
|
||||
LocalChangesOverwritten = 'LocalChangesOverwritten',
|
||||
NoUpstreamBranch = 'NoUpstreamBranch',
|
||||
IsInSubmodule = 'IsInSubmodule',
|
||||
WrongCase = 'WrongCase',
|
||||
CantLockRef = 'CantLockRef',
|
||||
CantRebaseMultipleBranches = 'CantRebaseMultipleBranches',
|
||||
PatchDoesNotApply = 'PatchDoesNotApply',
|
||||
NoPathFound = 'NoPathFound',
|
||||
UnknownPath = 'UnknownPath',
|
||||
}
|
||||
9
extensions/github/src/typings/ref.d.ts
vendored
Normal file
9
extensions/github/src/typings/ref.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
|
||||
|
||||
declare module 'tunnel';
|
||||
305
extensions/github/yarn.lock
Normal file
305
extensions/github/yarn.lock
Normal file
@@ -0,0 +1,305 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@octokit/auth-token@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f"
|
||||
integrity sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==
|
||||
dependencies:
|
||||
"@octokit/types" "^2.0.0"
|
||||
|
||||
"@octokit/core@^2.4.3":
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-2.5.0.tgz#4706258893a7ac6ab35d58d2fb9f2d2ba19a41a5"
|
||||
integrity sha512-uvzmkemQrBgD8xuGbjhxzJN1darJk9L2cS+M99cHrDG2jlSVpxNJVhoV86cXdYBqdHCc9Z995uLCczaaHIYA6Q==
|
||||
dependencies:
|
||||
"@octokit/auth-token" "^2.4.0"
|
||||
"@octokit/graphql" "^4.3.1"
|
||||
"@octokit/request" "^5.4.0"
|
||||
"@octokit/types" "^2.0.0"
|
||||
before-after-hook "^2.1.0"
|
||||
universal-user-agent "^5.0.0"
|
||||
|
||||
"@octokit/endpoint@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.1.tgz#16d5c0e7a83e3a644d1ddbe8cded6c3d038d31d7"
|
||||
integrity sha512-pOPHaSz57SFT/m3R5P8MUu4wLPszokn5pXcB/pzavLTQf2jbU+6iayTvzaY6/BiotuRS0qyEUkx3QglT4U958A==
|
||||
dependencies:
|
||||
"@octokit/types" "^2.11.1"
|
||||
is-plain-object "^3.0.0"
|
||||
universal-user-agent "^5.0.0"
|
||||
|
||||
"@octokit/graphql@^4.3.1":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.4.0.tgz#4540b48bbf796b837b311ba6ea5104760db530ca"
|
||||
integrity sha512-Du3hAaSROQ8EatmYoSAJjzAz3t79t9Opj/WY1zUgxVUGfIKn0AEjg+hlOLscF6fv6i/4y/CeUvsWgIfwMkTccw==
|
||||
dependencies:
|
||||
"@octokit/request" "^5.3.0"
|
||||
"@octokit/types" "^2.0.0"
|
||||
universal-user-agent "^5.0.0"
|
||||
|
||||
"@octokit/plugin-paginate-rest@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.0.tgz#9ae0c14c1b90ec0d96d2ef1b44706b4505a91cee"
|
||||
integrity sha512-KoNxC3PLNar8UJwR+1VMQOw2IoOrrFdo5YOiDKnBhpVbKpw+zkBKNMNKwM44UWL25Vkn0Sl3nYIEGKY+gW5ebw==
|
||||
dependencies:
|
||||
"@octokit/types" "^2.12.1"
|
||||
|
||||
"@octokit/plugin-request-log@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e"
|
||||
integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==
|
||||
|
||||
"@octokit/plugin-rest-endpoint-methods@^3.11.1":
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.12.0.tgz#313938ece4267e98687179cdbc32bc09e06f2379"
|
||||
integrity sha512-cpUTZR0V2B8lz351oKLXx01BxBF3sMOhvm0glEMIS9XWSpkHCeQDPLPh8TQmepY8e+AhhgWxuWdn1PLDPQlTpw==
|
||||
dependencies:
|
||||
"@octokit/types" "^4.0.0"
|
||||
deprecation "^2.3.1"
|
||||
|
||||
"@octokit/request-error@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.0.tgz#94ca7293373654400fbb2995f377f9473e00834b"
|
||||
integrity sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==
|
||||
dependencies:
|
||||
"@octokit/types" "^2.0.0"
|
||||
deprecation "^2.0.0"
|
||||
once "^1.4.0"
|
||||
|
||||
"@octokit/request@^5.3.0", "@octokit/request@^5.4.0":
|
||||
version "5.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.2.tgz#74f8e5bbd39dc738a1b127629791f8ad1b3193ee"
|
||||
integrity sha512-zKdnGuQ2TQ2vFk9VU8awFT4+EYf92Z/v3OlzRaSh4RIP0H6cvW1BFPXq4XYvNez+TPQjqN+0uSkCYnMFFhcFrw==
|
||||
dependencies:
|
||||
"@octokit/endpoint" "^6.0.1"
|
||||
"@octokit/request-error" "^2.0.0"
|
||||
"@octokit/types" "^2.11.1"
|
||||
deprecation "^2.0.0"
|
||||
is-plain-object "^3.0.0"
|
||||
node-fetch "^2.3.0"
|
||||
once "^1.4.0"
|
||||
universal-user-agent "^5.0.0"
|
||||
|
||||
"@octokit/rest@^17.9.1":
|
||||
version "17.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-17.9.1.tgz#ffa31614b2a2330fac82dcff8bb5e88c63fa7cbb"
|
||||
integrity sha512-TCTqCMNs21ToN5rIx15sIETuR19WsAy9wI4GnSVY8yZxeOKzeQs8uvIeijy8Gb6DbcYGXDf+xJ1MNDePPss0DA==
|
||||
dependencies:
|
||||
"@octokit/core" "^2.4.3"
|
||||
"@octokit/plugin-paginate-rest" "^2.2.0"
|
||||
"@octokit/plugin-request-log" "^1.0.0"
|
||||
"@octokit/plugin-rest-endpoint-methods" "^3.11.1"
|
||||
|
||||
"@octokit/types@^2.0.0", "@octokit/types@^2.11.1", "@octokit/types@^2.12.1":
|
||||
version "2.16.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2"
|
||||
integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==
|
||||
dependencies:
|
||||
"@types/node" ">= 8"
|
||||
|
||||
"@octokit/types@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-4.0.0.tgz#57425d275d33b02922e8822eabf57466ef243969"
|
||||
integrity sha512-wbjL8HhCLdBOAmvPJPkMqF4bf6AWzsas78I7+slJt5LAjuAL+kTlWtXHr2V9VnOuEFItZdzfgFTpMjSBkFeVZg==
|
||||
dependencies:
|
||||
"@types/node" ">= 8"
|
||||
|
||||
"@types/node@>= 8":
|
||||
version "14.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.1.tgz#5d93e0a099cd0acd5ef3d5bde3c086e1f49ff68c"
|
||||
integrity sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==
|
||||
|
||||
"@types/node@^10.12.21":
|
||||
version "10.17.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.14.tgz#b6c60ebf2fb5e4229fdd751ff9ddfae0f5f31541"
|
||||
integrity sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw==
|
||||
|
||||
before-after-hook@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
|
||||
integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==
|
||||
|
||||
cross-spawn@^6.0.0:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
|
||||
dependencies:
|
||||
nice-try "^1.0.4"
|
||||
path-key "^2.0.1"
|
||||
semver "^5.5.0"
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
deprecation@^2.0.0, deprecation@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
|
||||
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
|
||||
|
||||
end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
execa@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
|
||||
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
|
||||
dependencies:
|
||||
cross-spawn "^6.0.0"
|
||||
get-stream "^4.0.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.0"
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
get-stream@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
|
||||
dependencies:
|
||||
pump "^3.0.0"
|
||||
|
||||
is-plain-object@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
|
||||
integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==
|
||||
dependencies:
|
||||
isobject "^4.0.0"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
isobject@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
|
||||
integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
|
||||
|
||||
macos-release@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
|
||||
integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||
|
||||
node-fetch@^2.3.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
|
||||
npm-run-path@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
|
||||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-name@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
|
||||
integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==
|
||||
dependencies:
|
||||
macos-release "^2.2.0"
|
||||
windows-release "^3.1.0"
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
||||
|
||||
path-key@^2.0.0, path-key@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
|
||||
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
|
||||
|
||||
pump@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
|
||||
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
semver@^5.5.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
|
||||
dependencies:
|
||||
shebang-regex "^1.0.0"
|
||||
|
||||
shebang-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
|
||||
|
||||
tunnel@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||
|
||||
universal-user-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-5.0.0.tgz#a3182aa758069bf0e79952570ca757de3579c1d9"
|
||||
integrity sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==
|
||||
dependencies:
|
||||
os-name "^3.1.0"
|
||||
|
||||
vscode-nls@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||
|
||||
which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
windows-release@^3.1.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.0.tgz#dce167e9f8be733f21c849ebd4d03fe66b29b9f0"
|
||||
integrity sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==
|
||||
dependencies:
|
||||
execa "^1.0.0"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
@@ -279,6 +279,9 @@
|
||||
image.classList.add('scale-to-fit');
|
||||
|
||||
image.addEventListener('load', () => {
|
||||
if (hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
hasLoadedImage = true;
|
||||
|
||||
vscode.postMessage({
|
||||
@@ -297,7 +300,11 @@
|
||||
}
|
||||
});
|
||||
|
||||
image.addEventListener('error', () => {
|
||||
image.addEventListener('error', e => {
|
||||
if (hasLoadedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasLoadedImage = true;
|
||||
document.body.classList.add('error');
|
||||
document.body.classList.remove('loading');
|
||||
|
||||
@@ -179,7 +179,7 @@ class Preview extends Disposable {
|
||||
|
||||
private async render() {
|
||||
if (this._previewState !== PreviewState.Disposed) {
|
||||
this.webviewEditor.webview.html = await this.getWebiewContents();
|
||||
this.webviewEditor.webview.html = await this.getWebviewContents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ class Preview extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private async getWebiewContents(): Promise<string> {
|
||||
private async getWebviewContents(): Promise<string> {
|
||||
const version = Date.now().toString();
|
||||
const settings = {
|
||||
isMac: process.platform === 'darwin',
|
||||
@@ -249,9 +249,9 @@ class Preview extends Disposable {
|
||||
|
||||
// Avoid adding cache busting if there is already a query string
|
||||
if (resource.query) {
|
||||
return webviewEditor.webview.asWebviewUri(resource).toString(true);
|
||||
return webviewEditor.webview.asWebviewUri(resource).toString();
|
||||
}
|
||||
return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString(true);
|
||||
return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString();
|
||||
}
|
||||
|
||||
private extensionResource(path: string) {
|
||||
|
||||
@@ -213,17 +213,13 @@ export function activate(context: ExtensionContext) {
|
||||
return Promise.reject(new Error(localize('untitled.schema', 'Unable to load {0}', uri.toString())));
|
||||
}
|
||||
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
|
||||
if (schemaDownloadEnabled) {
|
||||
return workspace.openTextDocument(uri).then(doc => {
|
||||
schemaDocuments[uri.toString()] = true;
|
||||
return doc.getText();
|
||||
}, error => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
} else {
|
||||
return Promise.reject(localize('schemaDownloadDisabled', 'Downloading schemas is disabled through setting \'{0}\'', SettingIds.enableSchemaDownload));
|
||||
}
|
||||
} else {
|
||||
return workspace.openTextDocument(uri).then(doc => {
|
||||
schemaDocuments[uri.toString()] = true;
|
||||
return doc.getText();
|
||||
}, error => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
} else if (schemaDownloadEnabled) {
|
||||
if (telemetryReporter && uri.authority === 'schema.management.azure.com') {
|
||||
/* __GDPR__
|
||||
"json.schema" : {
|
||||
@@ -242,6 +238,8 @@ export function activate(context: ExtensionContext) {
|
||||
}
|
||||
return Promise.reject(new ResponseError(error.status, getErrorStatusDescription(error.status) + '\n' + extraInfo));
|
||||
});
|
||||
} else {
|
||||
return Promise.reject(localize('schemaDownloadDisabled', 'Downloading schemas is disabled through setting \'{0}\'', SettingIds.enableSchemaDownload));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -62,14 +62,14 @@ The server supports the following settings:
|
||||
- json
|
||||
- `format`
|
||||
- `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* and `initializationOptions.provideFormatter` is not defined.
|
||||
- `schema`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content.
|
||||
- `fileMatch`: an array of file names or paths (separated by `/`). `*` can be used as a wildcard. Exclusion patterns can also be defined and start with '!'. A file matches when there at least one matching pattern and the last matching pattern is not an exclusion pattern.
|
||||
- `url`: The URL of the schema, optional when also a schema is provided.
|
||||
- `schema`: The schema content.
|
||||
- `resultLimit`: The max number foldig ranges and otline symbols to be computed (for performance reasons)
|
||||
- `schemas`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content.
|
||||
- `fileMatch`: an array of file names or paths (separated by `/`). `*` can be used as a wildcard. Exclusion patterns can also be defined and start with '!'. A file matches when there at least one matching pattern and the last matching pattern is not an exclusion pattern.
|
||||
- `url`: The URL of the schema, optional when also a schema is provided.
|
||||
- `schema`: The schema content.
|
||||
- `resultLimit`: The max number foldig ranges and otline symbols to be computed (for performance reasons)
|
||||
|
||||
```json
|
||||
{
|
||||
{
|
||||
"http": {
|
||||
"proxy": "",
|
||||
"proxyStrictSSL": true
|
||||
@@ -86,7 +86,7 @@ The server supports the following settings:
|
||||
],
|
||||
"url": "http://json.schemastore.org/foo",
|
||||
"schema": {
|
||||
"type": "array"
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
".webmanifest",
|
||||
".js.map",
|
||||
".css.map",
|
||||
".ts.map",
|
||||
".har",
|
||||
".jslintrc",
|
||||
".jsonld"
|
||||
|
||||
@@ -389,7 +389,7 @@
|
||||
"t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json constant.character.escape.json",
|
||||
"r": {
|
||||
"dark_plus": "constant.character.escape: #D7BA7D",
|
||||
"light_plus": "constant.character.escape: #FF0000",
|
||||
"light_plus": "constant.character.escape: #EE0000",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
@@ -1165,4 +1165,4 @@
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -4,10 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
html, body {
|
||||
font-family: var(--vscode-markdown-font-family, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif);
|
||||
font-size: var(--vscode-markdown-font-size, 14px);
|
||||
font-family: var(--markdown-font-family, system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif);
|
||||
font-size: var(--markdown-font-size, 14px);
|
||||
padding: 0 26px;
|
||||
line-height: var(--vscode-markdown-line-height, 22px);
|
||||
line-height: var(--markdown-line-height, 22px);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ blockquote {
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
|
||||
font-family: var(--vscode-editor-font-family, Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback");
|
||||
font-size: 1em;
|
||||
line-height: 1.357em;
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
},
|
||||
"markdown.preview.fontFamily": {
|
||||
"type": "string",
|
||||
"default": "-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif",
|
||||
"default": "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif",
|
||||
"description": "%markdown.preview.fontFamily.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"displayName": "Markdown Language Features",
|
||||
"description": "Provides rich language support for Markdown.",
|
||||
"markdown.preview.breaks.desc": "Sets how line-breaks are rendered in the markdown preview. Setting it to 'true' creates a <br> for every newline.",
|
||||
"markdown.preview.breaks.desc": "Sets how line-breaks are rendered in the markdown preview. Setting it to 'true' creates a <br> for newlines inside paragraphs.",
|
||||
"markdown.preview.linkify": "Enable or disable conversion of URL-like text to links in the markdown preview.",
|
||||
"markdown.preview.doubleClickToSwitchToEditor.desc": "Double click in the markdown preview to switch to the editor.",
|
||||
"markdown.preview.fontFamily.desc": "Controls the font family used in the markdown preview.",
|
||||
|
||||
@@ -152,9 +152,9 @@ export class MarkdownContentProvider {
|
||||
|
||||
private getSettingsOverrideStyles(config: MarkdownPreviewConfiguration): string {
|
||||
return [
|
||||
config.fontFamily ? `--vscode-markdown-font-family: ${config.fontFamily};` : '',
|
||||
isNaN(config.fontSize) ? '' : `--vscode-markdown-font-size: ${config.fontSize}px;`,
|
||||
isNaN(config.lineHeight) ? '' : `--vscode-markdown-line-height: ${config.lineHeight};`,
|
||||
config.fontFamily ? `--markdown-font-family: ${config.fontFamily};` : '',
|
||||
isNaN(config.fontSize) ? '' : `--markdown-font-size: ${config.fontSize}px;`,
|
||||
isNaN(config.lineHeight) ? '' : `--markdown-line-height: ${config.lineHeight};`,
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "vscode-account",
|
||||
"name": "microsoft-authentication",
|
||||
"publisher": "vscode",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
@@ -16,25 +16,10 @@
|
||||
],
|
||||
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"configuration": {
|
||||
"title": "Microsoft Account",
|
||||
"properties": {
|
||||
"microsoftAccount.logLevel": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"info",
|
||||
"trace"
|
||||
],
|
||||
"default": "info"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "gulp compile-extension:vscode-account",
|
||||
"watch": "gulp watch-extension:vscode-account"
|
||||
"compile": "gulp compile-extension:microsoft-authentication",
|
||||
"watch": "gulp watch-extension:microsoft-authentication"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.7.4",
|
||||
@@ -82,9 +82,6 @@ export class AzureActiveDirectoryService {
|
||||
}
|
||||
|
||||
public async initialize(): Promise<void> {
|
||||
// TODO remove, temporary migration
|
||||
await keychain.migrateToken();
|
||||
|
||||
const storedData = await keychain.getToken();
|
||||
if (storedData) {
|
||||
try {
|
||||
@@ -204,13 +201,9 @@ export class AzureActiveDirectoryService {
|
||||
}, 1000 * 30);
|
||||
}
|
||||
|
||||
private convertToSession(token: IToken): vscode.AuthenticationSession {
|
||||
return {
|
||||
id: token.sessionId,
|
||||
getAccessToken: () => this.resolveAccessToken(token),
|
||||
account: token.account,
|
||||
scopes: token.scope.split(' ')
|
||||
};
|
||||
private async convertToSession(token: IToken): Promise<vscode.AuthenticationSession2> {
|
||||
const resolvedToken = await this.resolveAccessToken(token);
|
||||
return new vscode.AuthenticationSession2(token.sessionId, resolvedToken, token.account, token.scope.split(' '));
|
||||
}
|
||||
|
||||
private async resolveAccessToken(token: IToken): Promise<string> {
|
||||
@@ -243,77 +236,81 @@ export class AzureActiveDirectoryService {
|
||||
}
|
||||
}
|
||||
|
||||
get sessions(): vscode.AuthenticationSession[] {
|
||||
return this._tokens.map(token => this.convertToSession(token));
|
||||
get sessions(): Promise<vscode.AuthenticationSession2[]> {
|
||||
return Promise.all(this._tokens.map(token => this.convertToSession(token)));
|
||||
}
|
||||
|
||||
public async login(scope: string): Promise<void> {
|
||||
public async login(scope: string): Promise<vscode.AuthenticationSession2> {
|
||||
Logger.info('Logging in...');
|
||||
|
||||
if (vscode.env.uiKind === vscode.UIKind.Web) {
|
||||
await this.loginWithoutLocalServer(scope);
|
||||
return;
|
||||
}
|
||||
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
const { server, redirectPromise, codePromise } = createServer(nonce);
|
||||
|
||||
let token: IToken | undefined;
|
||||
try {
|
||||
const port = await startServer(server);
|
||||
vscode.env.openExternal(vscode.Uri.parse(`http://localhost:${port}/signin?nonce=${encodeURIComponent(nonce)}`));
|
||||
|
||||
const redirectReq = await redirectPromise;
|
||||
if ('err' in redirectReq) {
|
||||
const { err, res } = redirectReq;
|
||||
res.writeHead(302, { Location: `/?error=${encodeURIComponent(err && err.message || 'Unknown error')}` });
|
||||
res.end();
|
||||
throw err;
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (vscode.env.uiKind === vscode.UIKind.Web) {
|
||||
resolve(this.loginWithoutLocalServer(scope));
|
||||
return;
|
||||
}
|
||||
|
||||
const host = redirectReq.req.headers.host || '';
|
||||
const updatedPortStr = (/^[^:]+:(\d+)$/.exec(Array.isArray(host) ? host[0] : host) || [])[1];
|
||||
const updatedPort = updatedPortStr ? parseInt(updatedPortStr, 10) : port;
|
||||
|
||||
const state = `${updatedPort},${encodeURIComponent(nonce)}`;
|
||||
|
||||
const codeVerifier = toBase64UrlEncoding(crypto.randomBytes(32).toString('base64'));
|
||||
const codeChallenge = toBase64UrlEncoding(crypto.createHash('sha256').update(codeVerifier).digest('base64'));
|
||||
const loginUrl = `${loginEndpointUrl}${tenant}/oauth2/v2.0/authorize?response_type=code&response_mode=query&client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(redirectUrl)}&state=${state}&scope=${encodeURIComponent(scope)}&prompt=select_account&code_challenge_method=S256&code_challenge=${codeChallenge}`;
|
||||
|
||||
await redirectReq.res.writeHead(302, { Location: loginUrl });
|
||||
redirectReq.res.end();
|
||||
|
||||
const codeRes = await codePromise;
|
||||
const res = codeRes.res;
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
const { server, redirectPromise, codePromise } = createServer(nonce);
|
||||
|
||||
let token: IToken | undefined;
|
||||
try {
|
||||
if ('err' in codeRes) {
|
||||
throw codeRes.err;
|
||||
}
|
||||
token = await this.exchangeCodeForToken(codeRes.code, codeVerifier, scope);
|
||||
this.setToken(token, scope);
|
||||
Logger.info('Login successful');
|
||||
res.writeHead(302, { Location: '/' });
|
||||
res.end();
|
||||
} catch (err) {
|
||||
res.writeHead(302, { Location: `/?error=${encodeURIComponent(err && err.message || 'Unknown error')}` });
|
||||
res.end();
|
||||
throw new Error(err.message);
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(e.message);
|
||||
const port = await startServer(server);
|
||||
vscode.env.openExternal(vscode.Uri.parse(`http://localhost:${port}/signin?nonce=${encodeURIComponent(nonce)}`));
|
||||
|
||||
// If the error was about starting the server, try directly hitting the login endpoint instead
|
||||
if (e.message === 'Error listening to server' || e.message === 'Closed' || e.message === 'Timeout waiting for port') {
|
||||
await this.loginWithoutLocalServer(scope);
|
||||
const redirectReq = await redirectPromise;
|
||||
if ('err' in redirectReq) {
|
||||
const { err, res } = redirectReq;
|
||||
res.writeHead(302, { Location: `/?error=${encodeURIComponent(err && err.message || 'Unknown error')}` });
|
||||
res.end();
|
||||
throw err;
|
||||
}
|
||||
|
||||
const host = redirectReq.req.headers.host || '';
|
||||
const updatedPortStr = (/^[^:]+:(\d+)$/.exec(Array.isArray(host) ? host[0] : host) || [])[1];
|
||||
const updatedPort = updatedPortStr ? parseInt(updatedPortStr, 10) : port;
|
||||
|
||||
const state = `${updatedPort},${encodeURIComponent(nonce)}`;
|
||||
|
||||
const codeVerifier = toBase64UrlEncoding(crypto.randomBytes(32).toString('base64'));
|
||||
const codeChallenge = toBase64UrlEncoding(crypto.createHash('sha256').update(codeVerifier).digest('base64'));
|
||||
const loginUrl = `${loginEndpointUrl}${tenant}/oauth2/v2.0/authorize?response_type=code&response_mode=query&client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(redirectUrl)}&state=${state}&scope=${encodeURIComponent(scope)}&prompt=select_account&code_challenge_method=S256&code_challenge=${codeChallenge}`;
|
||||
|
||||
await redirectReq.res.writeHead(302, { Location: loginUrl });
|
||||
redirectReq.res.end();
|
||||
|
||||
const codeRes = await codePromise;
|
||||
const res = codeRes.res;
|
||||
|
||||
try {
|
||||
if ('err' in codeRes) {
|
||||
throw codeRes.err;
|
||||
}
|
||||
token = await this.exchangeCodeForToken(codeRes.code, codeVerifier, scope);
|
||||
this.setToken(token, scope);
|
||||
Logger.info('Login successful');
|
||||
res.writeHead(302, { Location: '/' });
|
||||
const session = await this.convertToSession(token);
|
||||
resolve(session);
|
||||
res.end();
|
||||
} catch (err) {
|
||||
res.writeHead(302, { Location: `/?error=${encodeURIComponent(err && err.message || 'Unknown error')}` });
|
||||
res.end();
|
||||
reject(err.message);
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(e.message);
|
||||
|
||||
// If the error was about starting the server, try directly hitting the login endpoint instead
|
||||
if (e.message === 'Error listening to server' || e.message === 'Closed' || e.message === 'Timeout waiting for port') {
|
||||
await this.loginWithoutLocalServer(scope);
|
||||
}
|
||||
|
||||
reject(e.message);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
server.close();
|
||||
}, 5000);
|
||||
}
|
||||
throw new Error(e.message);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
server.close();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getCallbackEnvironment(callbackUri: vscode.Uri): string {
|
||||
@@ -333,8 +330,8 @@ export class AzureActiveDirectoryService {
|
||||
}
|
||||
}
|
||||
|
||||
private async loginWithoutLocalServer(scope: string): Promise<IToken> {
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.vscode-account`));
|
||||
private async loginWithoutLocalServer(scope: string): Promise<vscode.AuthenticationSession2> {
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.microsoft-authentication`));
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
const port = (callbackUri.authority.match(/:([0-9]*)$/) || [])[1] || (callbackUri.scheme === 'https' ? 443 : 80);
|
||||
const callbackEnvironment = this.getCallbackEnvironment(callbackUri);
|
||||
@@ -348,7 +345,7 @@ export class AzureActiveDirectoryService {
|
||||
});
|
||||
vscode.env.openExternal(uri);
|
||||
|
||||
const timeoutPromise = new Promise((_: (value: IToken) => void, reject) => {
|
||||
const timeoutPromise = new Promise((_: (value: vscode.AuthenticationSession2) => void, reject) => {
|
||||
const wait = setTimeout(() => {
|
||||
clearTimeout(wait);
|
||||
reject('Login timed out.');
|
||||
@@ -358,9 +355,9 @@ export class AzureActiveDirectoryService {
|
||||
return Promise.race([this.handleCodeResponse(state, codeVerifier, scope), timeoutPromise]);
|
||||
}
|
||||
|
||||
private async handleCodeResponse(state: string, codeVerifier: string, scope: string) {
|
||||
private async handleCodeResponse(state: string, codeVerifier: string, scope: string): Promise<vscode.AuthenticationSession2> {
|
||||
let uriEventListener: vscode.Disposable;
|
||||
return new Promise((resolve: (value: IToken) => void, reject) => {
|
||||
return new Promise((resolve: (value: vscode.AuthenticationSession2) => void, reject) => {
|
||||
uriEventListener = this._uriHandler.event(async (uri: vscode.Uri) => {
|
||||
try {
|
||||
const query = parseQuery(uri);
|
||||
@@ -374,7 +371,8 @@ export class AzureActiveDirectoryService {
|
||||
const token = await this.exchangeCodeForToken(code, codeVerifier, scope);
|
||||
this.setToken(token, scope);
|
||||
|
||||
resolve(token);
|
||||
const session = await this.convertToSession(token);
|
||||
resolve(session);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
@@ -20,15 +20,15 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(vscode.authentication.registerAuthenticationProvider({
|
||||
id: 'microsoft',
|
||||
displayName: 'Microsoft',
|
||||
supportsMultipleAccounts: true,
|
||||
onDidChangeSessions: onDidChangeSessions.event,
|
||||
getSessions: () => Promise.resolve(loginService.sessions),
|
||||
login: async (scopes: string[]) => {
|
||||
try {
|
||||
telemetryReporter.sendTelemetryEvent('login');
|
||||
await loginService.login(scopes.sort().join(' '));
|
||||
const session = loginService.sessions[loginService.sessions.length - 1];
|
||||
const session = await loginService.login(scopes.sort().join(' '));
|
||||
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
|
||||
return loginService.sessions[0]!;
|
||||
return session;
|
||||
} catch (e) {
|
||||
telemetryReporter.sendTelemetryEvent('loginFailed');
|
||||
throw e;
|
||||
@@ -43,26 +43,9 @@ export class Keychain {
|
||||
this.keytar = keytar;
|
||||
}
|
||||
|
||||
// TODO remove, temporary migration
|
||||
async migrateToken(): Promise<void> {
|
||||
const oldServiceId = `${vscode.env.uriScheme}-vscode.login`;
|
||||
try {
|
||||
const data = await this.keytar.getPassword(oldServiceId, ACCOUNT_ID);
|
||||
if (data) {
|
||||
Logger.info('Migrating token...');
|
||||
this.setToken(data);
|
||||
await this.keytar.deletePassword(oldServiceId, ACCOUNT_ID);
|
||||
Logger.info('Migration successful');
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(`Migrating token failed: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async setToken(token: string): Promise<void> {
|
||||
try {
|
||||
Logger.trace('Writing to keychain', token);
|
||||
return await this.keytar.setPassword(SERVICE_ID, ACCOUNT_ID, token);
|
||||
} catch (e) {
|
||||
Logger.error(`Setting token failed: ${e}`);
|
||||
@@ -85,9 +68,7 @@ export class Keychain {
|
||||
|
||||
async getToken(): Promise<string | null | undefined> {
|
||||
try {
|
||||
const result = await this.keytar.getPassword(SERVICE_ID, ACCOUNT_ID);
|
||||
Logger.trace('Reading from keychain', result);
|
||||
return result;
|
||||
return await this.keytar.getPassword(SERVICE_ID, ACCOUNT_ID);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Getting token failed: ${e}`);
|
||||
@@ -5,25 +5,13 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
type LogLevel = 'Trace' | 'Info' | 'Error';
|
||||
|
||||
enum Level {
|
||||
Trace = 'trace',
|
||||
Info = 'Info'
|
||||
}
|
||||
type LogLevel = 'Info' | 'Error';
|
||||
|
||||
class Log {
|
||||
private output: vscode.OutputChannel;
|
||||
private level: Level;
|
||||
|
||||
constructor() {
|
||||
this.output = vscode.window.createOutputChannel('Microsoft Authentication');
|
||||
this.level = vscode.workspace.getConfiguration('microsoftAccount').get('logLevel') || Level.Info;
|
||||
vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('microsoftAccount.logLevel')) {
|
||||
this.level = vscode.workspace.getConfiguration('microsoftAccount').get('logLevel') || Level.Info;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private data2String(data: any): string {
|
||||
@@ -44,12 +32,6 @@ class Log {
|
||||
this.logLevel('Error', message, data);
|
||||
}
|
||||
|
||||
public trace(message: string, data?: any): void {
|
||||
if (this.level === Level.Trace) {
|
||||
this.logLevel('Trace', message, data);
|
||||
}
|
||||
}
|
||||
|
||||
public logLevel(level: LogLevel, message: string, data?: any): void {
|
||||
this.output.appendLine(`[${level} - ${this.now()}] ${message}`);
|
||||
if (data) {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user