Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 (#15681)
* Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 * Fixes and cleanup * Distro * Fix hygiene yarn * delete no yarn lock changes file * Fix hygiene * Fix layer check * Fix CI * Skip lib checks * Remove tests deleted in vs code * Fix tests * Distro * Fix tests and add removed extension point * Skip failing notebook tests for now * Disable broken tests and cleanup build folder * Update yarn.lock and fix smoke tests * Bump sqlite * fix contributed actions and file spacing * Fix user data path * Update yarn.locks Co-authored-by: ADS Merger <karlb@microsoft.com>
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
|
||||
@@ -88,7 +88,7 @@ export class TextKeyValue extends KeyValue {
|
||||
this.container.addItem(this.text, this.valueFlex);
|
||||
}
|
||||
|
||||
public setValue(newValue: string) {
|
||||
public override setValue(newValue: string) {
|
||||
super.setValue(newValue);
|
||||
this.text.value = newValue;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ export abstract class BaseInputKeyValue extends KeyValue {
|
||||
this.container.addItem(inputContainer, this.valueFlex);
|
||||
}
|
||||
|
||||
public setValue(newValue: string) {
|
||||
public override setValue(newValue: string) {
|
||||
super.setValue(newValue);
|
||||
this.input.value = newValue;
|
||||
}
|
||||
@@ -161,7 +161,7 @@ export class LinkKeyValue extends KeyValue {
|
||||
this.container.addItem(this.link, this.valueFlex);
|
||||
}
|
||||
|
||||
public setValue(newValue: string) {
|
||||
public override setValue(newValue: string) {
|
||||
super.setValue(newValue);
|
||||
this.link.label = newValue;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export class ControllerDashboard extends Dashboard {
|
||||
super(loc.arcControllerDashboard(_controllerModel.info.name), 'ArcDataControllerDashboard');
|
||||
}
|
||||
|
||||
public async showDashboard(): Promise<void> {
|
||||
public override async showDashboard(): Promise<void> {
|
||||
await super.showDashboard();
|
||||
// Kick off the model refresh but don't wait on it since that's all handled with callbacks anyways
|
||||
this._controllerModel.refresh(false).catch(err => console.log(`Error refreshing Controller dashboard ${err}`));
|
||||
|
||||
@@ -32,7 +32,7 @@ export class MiaaComputeAndStoragePage extends DashboardPage {
|
||||
|
||||
private readonly _azdataApi: azdataExt.IExtension;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _miaaModel: MiaaModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _miaaModel: MiaaModel) {
|
||||
super(modelView, dashboard);
|
||||
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export class MiaaDashboard extends Dashboard {
|
||||
super(loc.miaaDashboard(_miaaModel.info.name), 'ArcMiaaDashboard');
|
||||
}
|
||||
|
||||
public async showDashboard(): Promise<void> {
|
||||
public override async showDashboard(): Promise<void> {
|
||||
await super.showDashboard();
|
||||
// Kick off the model refreshes but don't wait on it since that's all handled with callbacks anyways
|
||||
this._controllerModel.refresh().catch(err => console.log(`Error refreshing controller model for MIAA dashboard ${err}`));
|
||||
|
||||
@@ -47,7 +47,7 @@ export class PostgresComputeAndStoragePage extends DashboardPage {
|
||||
|
||||
private readonly _azdataApi: azdataExt.IExtension;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export class PostgresConnectionStringsPage extends DashboardPage {
|
||||
private keyValueContainer?: KeyValueContainer;
|
||||
private connectionStringsLoading!: azdata.LoadingComponent;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
|
||||
this.disposables.push(this._postgresModel.onConfigUpdated(
|
||||
|
||||
@@ -24,7 +24,7 @@ export class PostgresDashboard extends Dashboard {
|
||||
super(loc.postgresDashboard(_postgresModel.info.name), 'ArcPgDashboard');
|
||||
}
|
||||
|
||||
public async showDashboard(): Promise<void> {
|
||||
public override async showDashboard(): Promise<void> {
|
||||
await super.showDashboard();
|
||||
|
||||
// Kick off the model refresh but don't wait on it since that's all handled with callbacks anyways
|
||||
|
||||
@@ -37,7 +37,7 @@ export class PostgresOverviewPage extends DashboardPage {
|
||||
|
||||
private readonly _azdataApi: azdataExt.IExtension;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export abstract class PostgresParametersPage extends DashboardPage {
|
||||
|
||||
protected readonly _azdataApi: azdataExt.IExtension;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, protected _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, protected _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
|
||||
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
|
||||
|
||||
@@ -17,7 +17,7 @@ export class PostgresPropertiesPage extends DashboardPage {
|
||||
private loading?: azdata.LoadingComponent;
|
||||
private keyValueContainer?: KeyValueContainer;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
|
||||
this.disposables.push(this._postgresModel.onConfigUpdated(
|
||||
|
||||
@@ -36,7 +36,7 @@ export class PostgresResourceHealthPage extends DashboardPage {
|
||||
private coordinatorData: PodHealthModel[] = [];
|
||||
private podsData: PodHealthModel[] = [];
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
|
||||
this.disposables.push(
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ResourceType } from 'arc';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
|
||||
export class PostgresSupportRequestPage extends DashboardPage {
|
||||
constructor(protected modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(modelView, dashboard);
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ export class ConnectToControllerDialog extends ControllerDialogBase {
|
||||
return this.namespaceInputBox;
|
||||
}
|
||||
|
||||
protected getComponents() {
|
||||
protected override getComponents() {
|
||||
return [
|
||||
...super.getComponents(),
|
||||
{
|
||||
@@ -221,7 +221,7 @@ export class ConnectToControllerDialog extends ControllerDialogBase {
|
||||
}];
|
||||
}
|
||||
|
||||
protected initializeFields(controllerInfo: ControllerInfo | undefined, password: string | undefined) {
|
||||
protected override initializeFields(controllerInfo: ControllerInfo | undefined, password: string | undefined) {
|
||||
super.initializeFields(controllerInfo, password);
|
||||
this.rememberPwCheckBox = this.modelBuilder.checkBox()
|
||||
.withProperties<azdata.CheckBoxProperties>({
|
||||
@@ -282,7 +282,7 @@ export class PasswordToControllerDialog extends ControllerDialogBase {
|
||||
return this.passwordInputBox;
|
||||
}
|
||||
|
||||
protected readonlyFields(): azdata.Component[] {
|
||||
protected override readonlyFields(): azdata.Component[] {
|
||||
return [
|
||||
this.urlInputBox,
|
||||
...this.kubeConfigInputBox.items,
|
||||
@@ -331,7 +331,7 @@ export class PasswordToControllerDialog extends ControllerDialogBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
public showDialog(controllerInfo?: ControllerInfo): azdata.window.Dialog {
|
||||
public override showDialog(controllerInfo?: ControllerInfo): azdata.window.Dialog {
|
||||
const dialog = super.showDialog(controllerInfo);
|
||||
dialog.okButton.label = loc.ok;
|
||||
return dialog;
|
||||
|
||||
@@ -37,7 +37,7 @@ export class ControllerTreeNode extends TreeNode {
|
||||
});
|
||||
}
|
||||
|
||||
public async getChildren(): Promise<TreeNode[]> {
|
||||
public override async getChildren(): Promise<TreeNode[]> {
|
||||
try {
|
||||
await this.model.refresh(false);
|
||||
this.updateChildren(this.model.registrations);
|
||||
@@ -60,7 +60,7 @@ export class ControllerTreeNode extends TreeNode {
|
||||
return this._children.length > 0 ? this._children : [new NoInstancesTreeNode()];
|
||||
}
|
||||
|
||||
public async openDashboard(): Promise<void> {
|
||||
public override async openDashboard(): Promise<void> {
|
||||
const controllerDashboard = new ControllerDashboard(this.model);
|
||||
await controllerDashboard.showDashboard();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export class MiaaTreeNode extends ResourceTreeNode<MiaaModel> {
|
||||
super(model.info.name, vscode.TreeItemCollapsibleState.None, ResourceType.sqlManagedInstances, model);
|
||||
}
|
||||
|
||||
public async openDashboard(): Promise<void> {
|
||||
public override async openDashboard(): Promise<void> {
|
||||
const miaaDashboard = new MiaaDashboard(this._controllerModel, this.model);
|
||||
await miaaDashboard.showDashboard();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export class PostgresTreeNode extends ResourceTreeNode<PostgresModel> {
|
||||
super(model.info.name, vscode.TreeItemCollapsibleState.None, ResourceType.postgresInstances, model);
|
||||
}
|
||||
|
||||
public async openDashboard(): Promise<void> {
|
||||
public override async openDashboard(): Promise<void> {
|
||||
const postgresDashboard = new PostgresDashboard(this._context, this._controllerModel, this.model);
|
||||
await postgresDashboard.showDashboard();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export class RefreshTreeNode extends TreeNode {
|
||||
super(loc.refreshToEnterCredentials, vscode.TreeItemCollapsibleState.None, '');
|
||||
}
|
||||
|
||||
public command: vscode.Command = {
|
||||
public override command: vscode.Command = {
|
||||
command: refreshActionId,
|
||||
title: loc.refreshToEnterCredentials,
|
||||
arguments: [this._parent]
|
||||
|
||||
@@ -20,6 +20,6 @@ export abstract class TreeNode extends vscode.TreeItem {
|
||||
|
||||
public async openDashboard(): Promise<void> { }
|
||||
|
||||
iconPath = getResourceTypeIcon(this.resourceType);
|
||||
contextValue = this.resourceType;
|
||||
override iconPath = getResourceTypeIcon(this.resourceType);
|
||||
override contextValue = this.resourceType;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
|
||||
@@ -142,7 +142,7 @@ export class AzureDeviceCode extends AzureAuth {
|
||||
}
|
||||
|
||||
|
||||
public async autoOAuthCancelled(): Promise<void> {
|
||||
public override async autoOAuthCancelled(): Promise<void> {
|
||||
return azdata.accounts.endAutoOAuthDeviceCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"strict": false,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"vscode": "^1.52.0"
|
||||
},
|
||||
"scripts": {
|
||||
"update-grammar": "node ../node_modules/.bin/vscode-grammar-updater mmims/language-batchfile grammars/batchfile.cson ./syntaxes/batchfile.tmLanguage.json"
|
||||
"update-grammar": "node ../node_modules/vscode-grammar-updater/bin mmims/language-batchfile grammars/batchfile.cson ./syntaxes/batchfile.tmLanguage.json"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [
|
||||
|
||||
@@ -32,7 +32,7 @@ export class KerberosAuth extends SslAuth implements Authentication {
|
||||
super();
|
||||
}
|
||||
|
||||
applyToRequest(requestOptions: request.Options): void {
|
||||
override applyToRequest(requestOptions: request.Options): void {
|
||||
super.applyToRequest(requestOptions);
|
||||
if (requestOptions && requestOptions.headers) {
|
||||
requestOptions.headers['Authorization'] = `Negotiate ${this.kerberosToken}`;
|
||||
@@ -45,7 +45,7 @@ export class BasicAuth extends SslAuth implements Authentication {
|
||||
super();
|
||||
}
|
||||
|
||||
applyToRequest(requestOptions: request.Options): void {
|
||||
override applyToRequest(requestOptions: request.Options): void {
|
||||
super.applyToRequest(requestOptions);
|
||||
requestOptions.auth = {
|
||||
username: this.username, password: this.password
|
||||
@@ -56,7 +56,7 @@ export class BasicAuth extends SslAuth implements Authentication {
|
||||
export class OAuthWithSsl extends SslAuth implements Authentication {
|
||||
public accessToken: string = '';
|
||||
|
||||
applyToRequest(requestOptions: request.Options): void {
|
||||
override applyToRequest(requestOptions: request.Options): void {
|
||||
super.applyToRequest(requestOptions);
|
||||
if (requestOptions && requestOptions.headers) {
|
||||
requestOptions.headers['Authorization'] = `Bearer ${this.accessToken}`;
|
||||
|
||||
@@ -28,7 +28,7 @@ abstract class ControllerTreeNode extends TreeNode {
|
||||
return this.children as ControllerTreeNode[];
|
||||
}
|
||||
|
||||
public refresh(): void {
|
||||
public override refresh(): void {
|
||||
super.refresh();
|
||||
this.treeChangeHandler.notifyNodeChanged(this);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export class ControllerRootNode extends ControllerTreeNode {
|
||||
super('root', undefined, treeChangeHandler, undefined, BdcItemType.controllerRoot);
|
||||
}
|
||||
|
||||
public async getChildren(): Promise<ControllerNode[]> {
|
||||
public override async getChildren(): Promise<ControllerNode[]> {
|
||||
return this.children as ControllerNode[];
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ export class ControllerNode extends ControllerTreeNode {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public async getChildren(): Promise<ControllerTreeNode[] | undefined> {
|
||||
public override async getChildren(): Promise<ControllerTreeNode[] | undefined> {
|
||||
if (this.children && this.children.length > 0) {
|
||||
this.clearChildren();
|
||||
}
|
||||
@@ -209,7 +209,7 @@ export class ControllerNode extends ControllerTreeNode {
|
||||
this._password = pw;
|
||||
}
|
||||
|
||||
public set label(label: string) {
|
||||
public override set label(label: string) {
|
||||
super.label = label || this.generateLabel();
|
||||
}
|
||||
|
||||
@@ -229,15 +229,15 @@ export class ControllerNode extends ControllerTreeNode {
|
||||
return label;
|
||||
}
|
||||
|
||||
public get label(): string {
|
||||
public override get label(): string {
|
||||
return super.label;
|
||||
}
|
||||
|
||||
public set description(description: string) {
|
||||
public override set description(description: string) {
|
||||
super.description = description || super.label;
|
||||
}
|
||||
|
||||
public get description(): string {
|
||||
public override get description(): string {
|
||||
return super.description;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../../shared.tsconfig.json",
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"outDir": "./out"
|
||||
|
||||
BIN
extensions/configuration-editing/images/icon.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
@@ -8,6 +8,7 @@
|
||||
"engines": {
|
||||
"vscode": "^1.0.0"
|
||||
},
|
||||
"icon": "images/icon.png",
|
||||
"activationEvents": [
|
||||
"onLanguage:json",
|
||||
"onLanguage:jsonc"
|
||||
@@ -22,6 +23,12 @@
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"vscode-nls": "^4.1.1"
|
||||
},
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
@@ -40,8 +47,12 @@
|
||||
"keybindings.json",
|
||||
"extensions.json",
|
||||
"argv.json",
|
||||
"profiles.json"
|
||||
]
|
||||
"profiles.json",
|
||||
".devcontainer.json"
|
||||
],
|
||||
"filenamePatterns": [
|
||||
"**/.devcontainer/devcontainer.json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"jsonValidation": [
|
||||
|
||||
@@ -19,6 +19,93 @@
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": ["notify", "openBrowser", "openPreview", "silent", "ignore"],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [{ "body": { "onAutoForward": "ignore" } }],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "vscode://schemas/settings/machine",
|
||||
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time."
|
||||
|
||||
@@ -127,6 +127,106 @@
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
@@ -326,6 +426,106 @@
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
@@ -501,6 +701,106 @@
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
@@ -642,6 +942,106 @@
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
@@ -752,6 +1152,106 @@
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
|
||||
@@ -33,6 +33,105 @@
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"portsAttributes": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"(^\\d+(\\-\\d+)?$)|(.+)": {
|
||||
"type": "object",
|
||||
"description": "A port, range of ports (ex. \"40000-55000\"), or regular expression (ex. \".+\\\\/server.js\"). For a port number or range, the attributes will apply to that port number or range of port numbers. Attributes which use a regular expression will apply to ports whose associated process command line matches the expression.",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdownDescription": "Set default properties that are applied when a specific port number is forwarded. For example:\n\n```\n\"3000\": {\n \"label\": \"Application\"\n},\n\"40000-55000\": {\n \"onAutoForward\": \"ignore\"\n},\n\".+\\\\/server.js\": {\n \"onAutoForward\": \"openPreview\"\n}\n```",
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"${1:3000}": {
|
||||
"label": "${2:Application}",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
"Opens a preview in the same window when the port is automatically forwarded.",
|
||||
"Shows no notification and takes no action when this port is automatically forwarded.",
|
||||
"This port will not be automatically forwarded."
|
||||
],
|
||||
"description": "Defines the action that occurs when the port is discovered for automatic forwarding",
|
||||
"default": "notify"
|
||||
},
|
||||
"elevateIfNeeded": {
|
||||
"type": "boolean",
|
||||
"description": "Automatically prompt for elevation (if needed) when this port is forwarded. Elevate is required if the local port is a privileged port.",
|
||||
"default": false
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
@@ -205,7 +304,7 @@
|
||||
"$ref": "#/definitions/buildOptions"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"build"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { getLocation, parse, visit } from 'jsonc-parser';
|
||||
import { getLocation, JSONPath, parse, visit } from 'jsonc-parser';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { SettingsDocument } from './settingsDocumentHelper';
|
||||
@@ -22,6 +22,9 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
|
||||
// task.json variable suggestions
|
||||
context.subscriptions.push(registerVariableCompletions('**/tasks.json'));
|
||||
|
||||
// keybindings.json/package.json context key suggestions
|
||||
context.subscriptions.push(registerContextKeyCompletions());
|
||||
}
|
||||
|
||||
function registerSettingsCompletions(): vscode.Disposable {
|
||||
@@ -136,3 +139,83 @@ vscode.languages.registerDocumentSymbolProvider({ pattern: '**/launch.json', lan
|
||||
return result;
|
||||
}
|
||||
}, { label: 'Launch Targets' });
|
||||
|
||||
function registerContextKeyCompletions(): vscode.Disposable {
|
||||
type ContextKeyInfo = { key: string, type?: string, description?: string };
|
||||
|
||||
const paths = new Map<vscode.DocumentFilter, JSONPath[]>([
|
||||
[{ language: 'jsonc', pattern: '**/keybindings.json' }, [
|
||||
['*', 'when']
|
||||
]],
|
||||
[{ language: 'json', pattern: '**/package.json' }, [
|
||||
['contributes', 'menus', '*', '*', 'when'],
|
||||
['contributes', 'views', '*', '*', 'when'],
|
||||
['contributes', 'viewsWelcome', '*', 'when'],
|
||||
['contributes', 'keybindings', '*', 'when'],
|
||||
['contributes', 'keybindings', 'when'],
|
||||
]]
|
||||
]);
|
||||
|
||||
return vscode.languages.registerCompletionItemProvider(
|
||||
[...paths.keys()],
|
||||
{
|
||||
async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) {
|
||||
|
||||
const location = getLocation(document.getText(), document.offsetAt(position));
|
||||
|
||||
if (location.isAtPropertyKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isValidLocation = false;
|
||||
for (const [key, value] of paths) {
|
||||
if (vscode.languages.match(key, document)) {
|
||||
if (value.some(location.matches.bind(location))) {
|
||||
isValidLocation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidLocation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// for JSON everything with quotes is a word
|
||||
const jsonWord = document.getWordRangeAtPosition(position);
|
||||
if (!jsonWord || jsonWord.start.isEqual(position) || jsonWord.end.isEqual(position)) {
|
||||
// we aren't inside a "JSON word" or on its quotes
|
||||
return;
|
||||
}
|
||||
|
||||
let replacing: vscode.Range | undefined;
|
||||
if (jsonWord.end.character - jsonWord.start.character === 2 || document.getWordRangeAtPosition(position, /\s+/)) {
|
||||
// empty json word or on whitespace
|
||||
replacing = new vscode.Range(position, position);
|
||||
} else {
|
||||
replacing = document.getWordRangeAtPosition(position, /[a-zA-Z.]+/);
|
||||
}
|
||||
|
||||
if (!replacing) {
|
||||
return;
|
||||
}
|
||||
const inserting = replacing.with(undefined, position);
|
||||
|
||||
const data = await vscode.commands.executeCommand<ContextKeyInfo[]>('getContextKeyInfo');
|
||||
if (token.isCancellationRequested || !data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = new vscode.CompletionList();
|
||||
for (const item of data) {
|
||||
const completion = new vscode.CompletionItem(item.key, vscode.CompletionItemKind.Constant);
|
||||
completion.detail = item.type;
|
||||
completion.range = { replacing, inserting };
|
||||
completion.documentation = item.description;
|
||||
result.items.push(completion);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,3 +33,28 @@ export function provideInstalledExtensionProposals(existing: string[], additiona
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function provideWorkspaceTrustExtensionProposals(existing: string[], range: vscode.Range): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
if (Array.isArray(existing)) {
|
||||
const extensions = vscode.extensions.all.filter(e => e.packageJSON.main);
|
||||
const extensionProposals = extensions.filter(e => existing.indexOf(e.id) === -1);
|
||||
if (extensionProposals.length) {
|
||||
return extensionProposals.map(e => {
|
||||
const item = new vscode.CompletionItem(e.id);
|
||||
const insertText = `"${e.id}": {\n\t"supported": false,\n\t"version": "${e.packageJSON.version}"\n}`;
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
item.insertText = insertText;
|
||||
item.range = range;
|
||||
item.filterText = insertText;
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
const example = new vscode.CompletionItem(localize('exampleExtension', "Example"));
|
||||
example.insertText = '"vscode.csharp: {\n\t"supported": false,\n\t"version": "0.0.0"\n}`;"';
|
||||
example.kind = vscode.CompletionItemKind.Value;
|
||||
example.range = range;
|
||||
return [example];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { getLocation, Location, parse } from 'jsonc-parser';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { provideInstalledExtensionProposals } from './extensionsProposals';
|
||||
import { provideInstalledExtensionProposals, provideWorkspaceTrustExtensionProposals } from './extensionsProposals';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -60,6 +60,15 @@ export class SettingsDocument {
|
||||
return provideInstalledExtensionProposals(alreadyConfigured, `: [\n\t"ui"\n]`, range, true);
|
||||
}
|
||||
|
||||
// extensions.supportUntrustedWorkspaces
|
||||
if (location.path[0] === 'extensions.supportUntrustedWorkspaces' && location.path.length === 2 && location.isAtPropertyKey) {
|
||||
let alreadyConfigured: string[] = [];
|
||||
try {
|
||||
alreadyConfigured = Object.keys(parse(this.document.getText())['extensions.supportUntrustedWorkspaces']);
|
||||
} catch (e) {/* ignore error */ }
|
||||
return provideWorkspaceTrustExtensionProposals(alreadyConfigured, range);
|
||||
}
|
||||
|
||||
return this.provideLanguageOverridesCompletionItems(location, position);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out"
|
||||
},
|
||||
|
||||
@@ -39,7 +39,8 @@ export function createContext(): TestContext {
|
||||
globalStorageUri: undefined,
|
||||
logUri: undefined,
|
||||
storageUri: undefined,
|
||||
secrets: undefined
|
||||
secrets: undefined,
|
||||
extension: undefined
|
||||
},
|
||||
viewContext: viewContext
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ export class DacFxSummaryPage extends BasePage {
|
||||
return true;
|
||||
}
|
||||
|
||||
async onPageLeave(): Promise<boolean> {
|
||||
override async onPageLeave(): Promise<boolean> {
|
||||
this.instance.wizard.generateScriptButton.hidden = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ export class DeployConfigPage extends DacFxConfigPage {
|
||||
};
|
||||
}
|
||||
|
||||
protected async populateDatabaseDropdown(): Promise<boolean> {
|
||||
protected override async populateDatabaseDropdown(): Promise<boolean> {
|
||||
this.databaseLoader.loading = true;
|
||||
this.databaseDropdown.updateProperties({ values: [] });
|
||||
if (!this.model.server) {
|
||||
|
||||
@@ -286,7 +286,7 @@ export class DeployPlanPage extends DacFxConfigPage {
|
||||
};
|
||||
}
|
||||
|
||||
public setupNavigationValidator() {
|
||||
public override setupNavigationValidator() {
|
||||
this.instance.registerNavigationValidator(() => {
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -44,12 +44,12 @@ export class ExportConfigPage extends DacFxConfigPage {
|
||||
}
|
||||
|
||||
|
||||
async onPageLeave(): Promise<boolean> {
|
||||
override async onPageLeave(): Promise<boolean> {
|
||||
this.appendFileExtensionIfNeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
public setupNavigationValidator() {
|
||||
public override setupNavigationValidator() {
|
||||
this.instance.registerNavigationValidator(() => {
|
||||
if (this.databaseLoader.loading) {
|
||||
return false;
|
||||
|
||||
@@ -46,12 +46,12 @@ export class ExtractConfigPage extends DacFxConfigPage {
|
||||
return r1 && r2;
|
||||
}
|
||||
|
||||
async onPageLeave(): Promise<boolean> {
|
||||
override async onPageLeave(): Promise<boolean> {
|
||||
this.appendFileExtensionIfNeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
public setupNavigationValidator(): void {
|
||||
public override setupNavigationValidator(): void {
|
||||
this.instance.registerNavigationValidator(() => {
|
||||
if (this.databaseLoader.loading) {
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"strict": false,
|
||||
|
||||
@@ -62,7 +62,7 @@ export class NewProjectDialog extends DialogBase {
|
||||
}
|
||||
}
|
||||
|
||||
async onComplete(): Promise<void> {
|
||||
override async onComplete(): Promise<void> {
|
||||
try {
|
||||
const validateWorkspace = await this.workspaceService.validateWorkspace();
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ export class OpenExistingDialog extends DialogBase {
|
||||
}
|
||||
}
|
||||
|
||||
async onComplete(): Promise<void> {
|
||||
override async onComplete(): Promise<void> {
|
||||
try {
|
||||
if (this.targetTypeRadioCardGroup?.selectedCardId === constants.Workspace) {
|
||||
// capture that workspace was selected, also if there's already an open workspace that's being replaced
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"noUnusedParameters": false
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"vscode": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"update-grammar": "node ../node_modules/.bin/vscode-grammar-updater moby/moby contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage ./syntaxes/docker.tmLanguage.json"
|
||||
"update-grammar": "node ../node_modules/vscode-grammar-updater/bin moby/moby contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage ./syntaxes/docker.tmLanguage.json"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [
|
||||
|
||||
BIN
extensions/extension-editing/images/icon.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
@@ -8,6 +8,7 @@
|
||||
"engines": {
|
||||
"vscode": "^1.4.0"
|
||||
},
|
||||
"icon": "images/icon.png",
|
||||
"activationEvents": [
|
||||
"onLanguage:json",
|
||||
"onLanguage:markdown",
|
||||
@@ -15,13 +16,19 @@
|
||||
],
|
||||
"main": "./out/extensionEditingMain",
|
||||
"browser": "./dist/browser/extensionEditingBrowserMain",
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:extension-editing",
|
||||
"watch": "gulp watch-extension:extension-editing"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"markdown-it": "^8.3.1",
|
||||
"markdown-it": "^12.0.4",
|
||||
"parse5": "^3.0.2",
|
||||
"vscode-nls": "^4.1.1"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"typeRoots": [
|
||||
@@ -9,4 +9,4 @@
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,40 +17,38 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.78.tgz#5d4a3f579c1524e01ee21bf474e6fba09198f470"
|
||||
integrity sha512-+vD6E8ixntRzzZukoF3uP1iV+ZjVN3koTcaeK+BEoc/kSfGbLDIGC7RmCaUgVpUfN6cWvfczFRERCyKM9mkvXg==
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
|
||||
integrity sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
entities@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
|
||||
integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA=
|
||||
entities@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
|
||||
integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
|
||||
|
||||
jsonc-parser@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
|
||||
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
|
||||
|
||||
linkify-it@^2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f"
|
||||
integrity sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=
|
||||
linkify-it@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8"
|
||||
integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==
|
||||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
markdown-it@^8.3.1:
|
||||
version "8.4.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d"
|
||||
integrity sha512-tNuOCCfunY5v5uhcO2AUMArvKAyKMygX8tfup/JrgnsDqcCATQsAExBq7o5Ml9iMmO82bk6jYNLj6khcrl0JGA==
|
||||
markdown-it@^12.0.4:
|
||||
version "12.0.4"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.0.4.tgz#eec8247d296327eac3ba9746bdeec9cfcc751e33"
|
||||
integrity sha512-34RwOXZT8kyuOJy25oJNJoulO8L0bTHYWXcdZBYZqFnjIy3NgjeoM3FmPXIOFQ26/lSHYMr8oc62B6adxXcb3Q==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
entities "~1.1.1"
|
||||
linkify-it "^2.0.0"
|
||||
argparse "^2.0.1"
|
||||
entities "~2.1.0"
|
||||
linkify-it "^3.0.1"
|
||||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.3"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
mdurl@^1.0.1:
|
||||
version "1.0.1"
|
||||
@@ -64,16 +62,16 @@ parse5@^3.0.2:
|
||||
dependencies:
|
||||
"@types/node" "^6.0.46"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
uc.micro@^1.0.1, uc.micro@^1.0.3:
|
||||
uc.micro@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
|
||||
integrity sha1-ftUNXg+an7ClczeSWfKndFjVAZI=
|
||||
|
||||
uc.micro@^1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||
|
||||
vscode-nls@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
src/**
|
||||
test/**
|
||||
out/**
|
||||
tsconfig.json
|
||||
build/**
|
||||
extension.webpack.config.js
|
||||
cgmanifest.json
|
||||
yarn.lock
|
||||
@@ -1,7 +0,0 @@
|
||||
# Git UI integration for Visual Studio Code
|
||||
|
||||
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
|
||||
|
||||
## Features
|
||||
|
||||
See [Git support in VS Code](https://code.visualstudio.com/docs/editor/versioncontrol#_git-support) to learn about the features of this extension.
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"registrations": [],
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "git-ui",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"publisher": "vscode",
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"engines": {
|
||||
"vscode": "^1.5.0"
|
||||
},
|
||||
"extensionKind": [
|
||||
"ui"
|
||||
],
|
||||
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
|
||||
"enableProposedApi": true,
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onCommand:git.credential"
|
||||
],
|
||||
"main": "./out/main",
|
||||
"icon": "resources/icons/git.png",
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:git-ui",
|
||||
"watch": "gulp watch-extension:git-ui"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.19.9"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode.git"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"displayName": "Git UI",
|
||||
"description": "Git SCM UI Integration"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,58 +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 { ExtensionContext, commands } from 'vscode';
|
||||
|
||||
import * as cp from 'child_process';
|
||||
|
||||
export async function deactivate(): Promise<any> {
|
||||
}
|
||||
|
||||
export async function activate(context: ExtensionContext): Promise<void> {
|
||||
context.subscriptions.push(commands.registerCommand('git.credential', async (_data: any) => {
|
||||
return { stdout: '', stderr: '', code: 0 };
|
||||
// try {
|
||||
// const { stdout, stderr } = await exec(`git credential ${data.command}`, {
|
||||
// stdin: data.stdin,
|
||||
// env: Object.assign(process.env, { GIT_TERMINAL_PROMPT: '0' })
|
||||
// });
|
||||
// return { stdout, stderr, code: 0 };
|
||||
// } catch ({ stdout, stderr, error }) {
|
||||
// const code = error.code || 0;
|
||||
// if (stderr.indexOf('terminal prompts disabled') !== -1) {
|
||||
// stderr = '';
|
||||
// }
|
||||
// return { stdout, stderr, code };
|
||||
// }
|
||||
}));
|
||||
}
|
||||
|
||||
export interface ExecResult {
|
||||
error: Error | null;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
|
||||
export function exec(command: string, options: cp.ExecOptions & { stdin?: string } = {}) {
|
||||
return new Promise<ExecResult>((resolve, reject) => {
|
||||
const child = cp.exec(command, options, (error, stdout, stderr) => {
|
||||
(error ? reject : resolve)({ error, stdout, stderr });
|
||||
});
|
||||
if (options.stdin) {
|
||||
child.stdin!.write(options.stdin, (err: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
child.stdin!.end((err: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
8
extensions/git-ui/src/typings/refs.d.ts
vendored
@@ -1,8 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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'/>
|
||||
/// <reference types='@types/node'/>
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@^12.19.9":
|
||||
version "12.19.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679"
|
||||
integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==
|
||||
@@ -26,6 +26,12 @@
|
||||
"update-grammar": "node ./build/update-grammars.js",
|
||||
"test": "node ../../node_modules/mocha/bin/mocha"
|
||||
},
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
@@ -495,6 +501,16 @@
|
||||
"title": "%command.timelineCopyCommitMessage%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.selectForCompare",
|
||||
"title": "%command.timelineSelectForCompare%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.compareWithSelected",
|
||||
"title": "%command.timelineCompareWithSelected%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.rebaseAbort",
|
||||
"title": "%command.rebaseAbort%",
|
||||
@@ -874,6 +890,14 @@
|
||||
{
|
||||
"command": "git.timeline.copyCommitMessage",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.selectForCompare",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.compareWithSelected",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"scm/title": [
|
||||
@@ -964,7 +988,7 @@
|
||||
{
|
||||
"command": "git.stageAllMerge",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
@@ -974,7 +998,7 @@
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAll",
|
||||
@@ -989,12 +1013,12 @@
|
||||
{
|
||||
"command": "git.cleanAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges == mixed",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges == mixed",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAllTracked",
|
||||
@@ -1009,12 +1033,12 @@
|
||||
{
|
||||
"command": "git.cleanAllTracked",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges != mixed",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAllTracked",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges != mixed",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAllUntracked",
|
||||
@@ -1029,12 +1053,12 @@
|
||||
{
|
||||
"command": "git.cleanAllUntracked",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAllUntracked",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
}
|
||||
],
|
||||
"scm/resourceFolder/context": [
|
||||
@@ -1046,7 +1070,7 @@
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.unstage",
|
||||
@@ -1056,7 +1080,7 @@
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
@@ -1071,12 +1095,12 @@
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.ignore",
|
||||
@@ -1091,7 +1115,7 @@
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.clean",
|
||||
@@ -1101,7 +1125,7 @@
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.ignore",
|
||||
@@ -1123,7 +1147,7 @@
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.revealInExplorer",
|
||||
@@ -1133,12 +1157,12 @@
|
||||
{
|
||||
"command": "git.openFile2",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge && config.git.showInlineOpenFileAction && !config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
@@ -1163,7 +1187,7 @@
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.revealInExplorer",
|
||||
@@ -1173,12 +1197,12 @@
|
||||
{
|
||||
"command": "git.openFile2",
|
||||
"when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction && !config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
@@ -1208,22 +1232,22 @@
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.openFile2",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.showInlineOpenFileAction && !config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.ignore",
|
||||
@@ -1263,22 +1287,22 @@
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked && !gitFreshRepository",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked",
|
||||
"group": "inline"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "git.openFile2",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmResourceGroup == untracked && config.git.showInlineOpenFileAction && !config.git.openDiffOnClick",
|
||||
"group": "inline0"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "git.ignore",
|
||||
@@ -1349,17 +1373,27 @@
|
||||
{
|
||||
"command": "git.timeline.openDiff",
|
||||
"group": "1_actions",
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file\\b/"
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file\\b/ && !listMultiSelection"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.compareWithSelected",
|
||||
"group": "3_compare@1",
|
||||
"when": "config.git.enabled && !git.missing && git.timeline.selectedForCompare && timelineItem =~ /git:file\\b/ && !listMultiSelection"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.selectForCompare",
|
||||
"group": "3_compare@2",
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file\\b/ && !listMultiSelection"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.copyCommitId",
|
||||
"group": "5_copy@1",
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/"
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/ && !listMultiSelection"
|
||||
},
|
||||
{
|
||||
"command": "git.timeline.copyCommitMessage",
|
||||
"group": "5_copy@2",
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/"
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/ && !listMultiSelection"
|
||||
}
|
||||
],
|
||||
"git.commit": [
|
||||
@@ -1519,13 +1553,17 @@
|
||||
"command": "git.branchFrom",
|
||||
"group": "branch@4"
|
||||
},
|
||||
{
|
||||
"command": "git.renameBranch",
|
||||
"group": "branch@5"
|
||||
},
|
||||
{
|
||||
"command": "git.renameBranch",
|
||||
"group": "branch@5"
|
||||
"command": "git.deleteBranch",
|
||||
"group": "branch@6"
|
||||
},
|
||||
{
|
||||
"command": "git.publish",
|
||||
"group": "branch@6"
|
||||
"group": "branch@7"
|
||||
}
|
||||
],
|
||||
"git.remotes": [
|
||||
@@ -1654,19 +1692,10 @@
|
||||
"default": true
|
||||
},
|
||||
"git.autofetch": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"all"
|
||||
]
|
||||
}
|
||||
],
|
||||
"type": ["boolean", "string"],
|
||||
"enum": [true, false, "all"],
|
||||
"scope": "resource",
|
||||
"description": "%config.autofetch%",
|
||||
"markdownDescription": "%config.autofetch%",
|
||||
"default": false,
|
||||
"tags": [
|
||||
"usesOnlineServices"
|
||||
@@ -1675,7 +1704,7 @@
|
||||
"git.autofetchPeriod": {
|
||||
"type": "number",
|
||||
"scope": "resource",
|
||||
"description": "%config.autofetchPeriod%",
|
||||
"markdownDescription": "%config.autofetchPeriod%",
|
||||
"default": 180
|
||||
},
|
||||
"git.branchValidationRegex": {
|
||||
@@ -2140,6 +2169,15 @@
|
||||
"highContrast": "#c74e39"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.renamedResourceForeground",
|
||||
"description": "%colors.renamed%",
|
||||
"defaults": {
|
||||
"light": "#007100",
|
||||
"dark": "#73C991",
|
||||
"highContrast": "#73C991"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.untrackedResourceForeground",
|
||||
"description": "%colors.untracked%",
|
||||
@@ -2162,9 +2200,9 @@
|
||||
"id": "gitDecoration.conflictingResourceForeground",
|
||||
"description": "%colors.conflict%",
|
||||
"defaults": {
|
||||
"light": "#6c6cc4",
|
||||
"dark": "#6c6cc4",
|
||||
"highContrast": "#6c6cc4"
|
||||
"light": "#ad0707",
|
||||
"dark": "#e4676b",
|
||||
"highContrast": "#c74e39"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2305,6 +2343,13 @@
|
||||
"when": "config.git.enabled",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "5_scm@1"
|
||||
},
|
||||
{
|
||||
"view": "explorer",
|
||||
"contents": "%view.workbench.learnMore%",
|
||||
"when": "config.git.enabled",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "5_scm@10"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -2312,8 +2357,8 @@
|
||||
"byline": "^5.0.0",
|
||||
"file-type": "^7.2.0",
|
||||
"iconv-lite-umd": "0.6.8",
|
||||
"jschardet": "2.2.1",
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"jschardet": "2.3.0",
|
||||
"vscode-extension-telemetry": "0.1.7",
|
||||
"vscode-nls": "^4.0.0",
|
||||
"vscode-uri": "^2.0.0",
|
||||
"which": "^1.3.0"
|
||||
|
||||
@@ -90,6 +90,8 @@
|
||||
"command.timelineOpenDiff": "Open Changes",
|
||||
"command.timelineCopyCommitId": "Copy Commit ID",
|
||||
"command.timelineCopyCommitMessage": "Copy Commit Message",
|
||||
"command.timelineSelectForCompare": "Select for Compare",
|
||||
"command.timelineCompareWithSelected": "Compare with Selected",
|
||||
"config.enabled": "Whether git is enabled.",
|
||||
"config.path": "Path and filename of the git executable, e.g. `C:\\Program Files\\Git\\bin\\git.exe` (Windows). This can also be an array of string values containing multiple paths to look up.",
|
||||
"config.autoRepositoryDetection": "Configures when repositories should be automatically detected.",
|
||||
@@ -98,8 +100,8 @@
|
||||
"config.autoRepositoryDetection.subFolders": "Scan for subfolders of the currently opened folder.",
|
||||
"config.autoRepositoryDetection.openEditors": "Scan for parent folders of open files.",
|
||||
"config.autorefresh": "Whether auto refreshing is enabled.",
|
||||
"config.autofetch": "When set to true, commits will automatically be fetched from the default remote of the current Git repository. Setting to `all` will fetch from all remotes",
|
||||
"config.autofetchPeriod": "Duration in seconds between each automatic git fetch, when `git.autofetch` is enabled.",
|
||||
"config.autofetch": "When set to true, commits will automatically be fetched from the default remote of the current Git repository. Setting to `all` will fetch from all remotes.",
|
||||
"config.autofetchPeriod": "Duration in seconds between each automatic git fetch, when `#git.autofetch#` is enabled.",
|
||||
"config.confirmSync": "Confirm before synchronizing git repositories.",
|
||||
"config.countBadge": "Controls the Git count badge.",
|
||||
"config.countBadge.all": "Count all changes.",
|
||||
@@ -124,7 +126,7 @@
|
||||
"config.suggestSmartCommit": "Suggests to enable smart commit (commit all changes when there are no staged changes).",
|
||||
"config.enableCommitSigning": "Enables commit signing with GPG or X.509.",
|
||||
"config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run.",
|
||||
"config.decorations.enabled": "Controls whether Git contributes colors and badges to the explorer and the open editors view.",
|
||||
"config.decorations.enabled": "Controls whether Git contributes colors and badges to the Explorer and the Open Editors view.",
|
||||
"config.enableStatusBarSync": "Controls whether the Git Sync command appears in the status bar.",
|
||||
"config.followTagsWhenSync": "Follow push all tags when running the sync command.",
|
||||
"config.promptToSaveFilesBeforeStash": "Controls whether Git should check for unsaved files before stashing changes.",
|
||||
@@ -175,11 +177,11 @@
|
||||
"config.untrackedChanges.mixed": "All changes, tracked and untracked, appear together and behave equally.",
|
||||
"config.untrackedChanges.separate": "Untracked changes appear separately in the Source Control view. They are also excluded from several actions.",
|
||||
"config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.",
|
||||
"config.requireGitUserConfig": "Controls whether to require explicit Git user configuration or allow Git to guess if missing",
|
||||
"config.requireGitUserConfig": "Controls whether to require explicit Git user configuration or allow Git to guess if missing.",
|
||||
"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.timeline.showAuthor": "Controls whether to show the commit author in the Timeline view",
|
||||
"config.timeline.date": "Controls which date to use for items in the Timeline view",
|
||||
"config.timeline.showAuthor": "Controls whether to show the commit author in the Timeline view.",
|
||||
"config.timeline.date": "Controls which date to use for items in the Timeline view.",
|
||||
"config.timeline.date.committed": "Use the committed date",
|
||||
"config.timeline.date.authored": "Use the authored date",
|
||||
"config.useCommitInputAsStashMessage": "Controls whether to use the message from the commit input box as the default stash message.",
|
||||
@@ -196,6 +198,7 @@
|
||||
"colors.added": "Color for added resources.",
|
||||
"colors.modified": "Color for modified resources.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
"colors.renamed": "Color for renamed or copied resources.",
|
||||
"colors.untracked": "Color for untracked resources.",
|
||||
"colors.ignored": "Color for ignored resources.",
|
||||
"colors.conflict": "Color for resources with conflicts.",
|
||||
@@ -206,5 +209,6 @@
|
||||
"view.workbench.scm.folder": "The folder currently open doesn't have a git repository. You can initialize a repository which will enable source control features powered by git.\n[Initialize Repository](command:git.init?%5Btrue%5D)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).",
|
||||
"view.workbench.scm.workspace": "The workspace currently open doesn't have any folders containing git repositories. You can initialize a repository on a folder which will enable source control features powered by git.\n[Initialize Repository](command:git.init)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).",
|
||||
"view.workbench.scm.emptyWorkspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Add Folder to Workspace](command:workbench.action.addRootFolder)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).",
|
||||
"view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone 'Clone a repository once the git extension has activated')"
|
||||
"view.workbench.cloneRepository": "You can clone a repository locally.\n[Clone Repository](command:git.clone 'Clone a repository once the git extension has activated')",
|
||||
"view.workbench.learnMore": "To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm)."
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Model } from '../model';
|
||||
import { Repository as BaseRepository, Resource } from '../repository';
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, RemoteSourceProvider, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, ICloneOptions } from './git'; // {{SQL CARBON EDIT}} add ICloneOptions
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, RemoteSourceProvider, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, ICloneOptions } from './git'; // {{SQL CARBON EDIT}} add ICloneOptions
|
||||
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands, CancellationToken } from 'vscode'; // {{SQL CARBON EDIT}} add CancellationToken
|
||||
import { mapEvent } from '../util';
|
||||
import { toGitUri } from '../uri';
|
||||
@@ -193,8 +193,16 @@ export class ApiRepository implements Repository {
|
||||
return this._repository.renameRemote(name, newName);
|
||||
}
|
||||
|
||||
fetch(remote?: string | undefined, ref?: string | undefined, depth?: number | undefined): Promise<void> {
|
||||
return this._repository.fetch(remote, ref, depth);
|
||||
fetch(arg0?: FetchOptions | string | undefined,
|
||||
ref?: string | undefined,
|
||||
depth?: number | undefined,
|
||||
prune?: boolean | undefined
|
||||
): Promise<void> {
|
||||
if (arg0 !== undefined && typeof arg0 !== 'string') {
|
||||
return this._repository.fetch(arg0);
|
||||
}
|
||||
|
||||
return this._repository.fetch({ remote: arg0, ref, depth, prune });
|
||||
}
|
||||
|
||||
pull(unshallow?: boolean): Promise<void> {
|
||||
|
||||
9
extensions/git/src/api/git.d.ts
vendored
@@ -139,6 +139,14 @@ export interface CommitOptions {
|
||||
requireUserConfig?: boolean;
|
||||
}
|
||||
|
||||
export interface FetchOptions {
|
||||
remote?: string;
|
||||
ref?: string;
|
||||
all?: boolean;
|
||||
prune?: boolean;
|
||||
depth?: number;
|
||||
}
|
||||
|
||||
export interface BranchQuery {
|
||||
readonly remote?: boolean;
|
||||
readonly pattern?: string;
|
||||
@@ -197,6 +205,7 @@ export interface Repository {
|
||||
removeRemote(name: string): Promise<void>;
|
||||
renameRemote(name: string, newName: string): Promise<void>;
|
||||
|
||||
fetch(options?: FetchOptions): Promise<void>;
|
||||
fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
|
||||
pull(unshallow?: boolean): Promise<void>;
|
||||
push(remoteName?: string, branchName?: string, setUpstream?: boolean, force?: ForcePushMode): Promise<void>;
|
||||
|
||||
@@ -30,7 +30,7 @@ function main(argv: string[]): void {
|
||||
|
||||
const output = process.env['VSCODE_GIT_ASKPASS_PIPE'] as string;
|
||||
const request = argv[2];
|
||||
const host = argv[4].replace(/^["']+|["']+$/g, '');
|
||||
const host = argv[4].replace(/^["']+|["':]+$/g, '');
|
||||
const ipcClient = new IPCClient('askpass');
|
||||
|
||||
ipcClient.call({ request, host }).then(res => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider } from 'vscode';
|
||||
import { Command, commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider } from 'vscode';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, ForcePushMode, GitErrorCodes, Ref, RefType, Status, CommitOptions, RemoteSourceProvider } from './api/git';
|
||||
@@ -43,18 +43,18 @@ class CheckoutItem implements QuickPickItem {
|
||||
|
||||
class CheckoutTagItem extends CheckoutItem {
|
||||
|
||||
get description(): string {
|
||||
override get description(): string {
|
||||
return localize('tag at', "Tag at {0}", this.shortCommit);
|
||||
}
|
||||
}
|
||||
|
||||
class CheckoutRemoteHeadItem extends CheckoutItem {
|
||||
|
||||
get description(): string {
|
||||
override get description(): string {
|
||||
return localize('remote branch at', "Remote branch at {0}", this.shortCommit);
|
||||
}
|
||||
|
||||
async run(repository: Repository, opts?: { detached?: boolean }): Promise<void> {
|
||||
override async run(repository: Repository, opts?: { detached?: boolean }): Promise<void> {
|
||||
if (!this.ref.name) {
|
||||
return;
|
||||
}
|
||||
@@ -153,21 +153,21 @@ class AddRemoteItem implements QuickPickItem {
|
||||
}
|
||||
}
|
||||
|
||||
interface CommandOptions {
|
||||
interface ScmCommandOptions {
|
||||
repository?: boolean;
|
||||
diff?: boolean;
|
||||
}
|
||||
|
||||
interface Command {
|
||||
interface ScmCommand {
|
||||
commandId: string;
|
||||
key: string;
|
||||
method: Function;
|
||||
options: CommandOptions;
|
||||
options: ScmCommandOptions;
|
||||
}
|
||||
|
||||
const Commands: Command[] = [];
|
||||
const Commands: ScmCommand[] = [];
|
||||
|
||||
function command(commandId: string, options: CommandOptions = {}): Function {
|
||||
function command(commandId: string, options: ScmCommandOptions = {}): Function {
|
||||
return (_target: any, key: string, descriptor: any) => {
|
||||
if (!(typeof descriptor.value === 'function')) {
|
||||
throw new Error('not supported');
|
||||
@@ -797,7 +797,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
const from = path.relative(repository.root, fromUri.path);
|
||||
const from = path.relative(repository.root, fromUri.fsPath);
|
||||
let to = await window.showInputBox({
|
||||
value: from,
|
||||
valueSelection: [from.length - path.basename(from).length, from.length]
|
||||
@@ -2247,8 +2247,8 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.addRemote(name, url);
|
||||
await repository.fetch(name);
|
||||
await repository.addRemote(name, url.trim());
|
||||
await repository.fetch({ remote: name });
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -2613,6 +2613,22 @@ export class CommandCenter {
|
||||
|
||||
@command('git.timeline.openDiff', { repository: false })
|
||||
async timelineOpenDiff(item: TimelineItem, uri: Uri | undefined, _source: string) {
|
||||
const cmd = this.resolveTimelineOpenDiffCommand(
|
||||
item, uri,
|
||||
{
|
||||
preserveFocus: true,
|
||||
preview: true,
|
||||
viewColumn: ViewColumn.Active
|
||||
},
|
||||
);
|
||||
if (cmd === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return commands.executeCommand(cmd.command, ...(cmd.arguments ?? []));
|
||||
}
|
||||
|
||||
resolveTimelineOpenDiffCommand(item: TimelineItem, uri: Uri | undefined, options?: TextDocumentShowOptions): Command | undefined {
|
||||
if (uri === undefined || uri === null || !GitTimelineItem.is(item)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -2629,13 +2645,11 @@ export class CommandCenter {
|
||||
title = localize('git.title.diffRefs', '{0} ({1}) ⟷ {0} ({2})', basename, item.shortPreviousRef, item.shortRef);
|
||||
}
|
||||
|
||||
const options: TextDocumentShowOptions = {
|
||||
preserveFocus: true,
|
||||
preview: true,
|
||||
viewColumn: ViewColumn.Active
|
||||
return {
|
||||
command: 'vscode.diff',
|
||||
title: 'Open Comparison',
|
||||
arguments: [toGitUri(uri, item.previousRef), item.ref === '' ? uri : toGitUri(uri, item.ref), title, options]
|
||||
};
|
||||
|
||||
return commands.executeCommand('vscode.diff', toGitUri(uri, item.previousRef), item.ref === '' ? uri : toGitUri(uri, item.ref), title, options);
|
||||
}
|
||||
|
||||
@command('git.timeline.copyCommitId', { repository: false })
|
||||
@@ -2656,6 +2670,52 @@ export class CommandCenter {
|
||||
env.clipboard.writeText(item.message);
|
||||
}
|
||||
|
||||
private _selectedForCompare: { uri: Uri, item: GitTimelineItem } | undefined;
|
||||
|
||||
@command('git.timeline.selectForCompare', { repository: false })
|
||||
async timelineSelectForCompare(item: TimelineItem, uri: Uri | undefined, _source: string) {
|
||||
if (!GitTimelineItem.is(item) || !uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._selectedForCompare = { uri, item };
|
||||
await commands.executeCommand('setContext', 'git.timeline.selectedForCompare', true);
|
||||
}
|
||||
|
||||
@command('git.timeline.compareWithSelected', { repository: false })
|
||||
async timelineCompareWithSelected(item: TimelineItem, uri: Uri | undefined, _source: string) {
|
||||
if (!GitTimelineItem.is(item) || !uri || !this._selectedForCompare || uri.toString() !== this._selectedForCompare.uri.toString()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { item: selected } = this._selectedForCompare;
|
||||
|
||||
const basename = path.basename(uri.fsPath);
|
||||
let leftTitle;
|
||||
if ((selected.previousRef === 'HEAD' || selected.previousRef === '~') && selected.ref === '') {
|
||||
leftTitle = localize('git.title.workingTree', '{0} (Working Tree)', basename);
|
||||
}
|
||||
else if (selected.previousRef === 'HEAD' && selected.ref === '~') {
|
||||
leftTitle = localize('git.title.index', '{0} (Index)', basename);
|
||||
} else {
|
||||
leftTitle = localize('git.title.ref', '{0} ({1})', basename, selected.shortRef);
|
||||
}
|
||||
|
||||
let rightTitle;
|
||||
if ((item.previousRef === 'HEAD' || item.previousRef === '~') && item.ref === '') {
|
||||
rightTitle = localize('git.title.workingTree', '{0} (Working Tree)', basename);
|
||||
}
|
||||
else if (item.previousRef === 'HEAD' && item.ref === '~') {
|
||||
rightTitle = localize('git.title.index', '{0} (Index)', basename);
|
||||
} else {
|
||||
rightTitle = localize('git.title.ref', '{0} ({1})', basename, item.shortRef);
|
||||
}
|
||||
|
||||
|
||||
const title = localize('git.title.diff', '{0} ⟷ {1}', leftTitle, rightTitle);
|
||||
await commands.executeCommand('vscode.diff', selected.ref === '' ? uri : toGitUri(uri, selected.ref), item.ref === '' ? uri : toGitUri(uri, item.ref), title);
|
||||
}
|
||||
|
||||
@command('git.rebaseAbort', { repository: true })
|
||||
async rebaseAbort(repository: Repository): Promise<void> {
|
||||
if (repository.rebaseCommit) {
|
||||
@@ -2665,7 +2725,7 @@ export class CommandCenter {
|
||||
}
|
||||
}
|
||||
|
||||
private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any {
|
||||
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
|
||||
const result = (...args: any[]) => {
|
||||
let result: Promise<any>;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as which from 'which';
|
||||
import { EventEmitter } from 'events';
|
||||
import * as iconv from 'iconv-lite-umd';
|
||||
import * as filetype from 'file-type';
|
||||
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util';
|
||||
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter, Versions } from './util';
|
||||
import { CancellationToken, Uri } from 'vscode';
|
||||
import { detectEncoding } from './encoding';
|
||||
import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery, ICloneOptions } from './api/git'; // {{SQL CARBON EDIT}} add ICloneOptions
|
||||
@@ -377,6 +377,10 @@ export class Git {
|
||||
this.env = options.env || {};
|
||||
}
|
||||
|
||||
compareGitVersionTo(version: string): -1 | 0 | 1 {
|
||||
return Versions.compare(Versions.fromString(this.version), Versions.fromString(version));
|
||||
}
|
||||
|
||||
open(repository: string, dotGit: string): Repository {
|
||||
return new Repository(this, repository, dotGit);
|
||||
}
|
||||
@@ -1638,7 +1642,7 @@ export class Repository {
|
||||
err.gitErrorCode = GitErrorCodes.NoUserNameConfigured;
|
||||
} else if (/Could not read from remote repository/.test(err.stderr || '')) {
|
||||
err.gitErrorCode = GitErrorCodes.RemoteConnectionError;
|
||||
} else if (/Pull is not possible because you have unmerged files|Cannot pull with rebase: You have unstaged changes|Your local changes to the following files would be overwritten|Please, commit your changes before you can merge/i.test(err.stderr)) {
|
||||
} else if (/Pull(?:ing)? is not possible because you have unmerged files|Cannot pull with rebase: You have unstaged changes|Your local changes to the following files would be overwritten|Please, commit your changes before you can merge/i.test(err.stderr)) {
|
||||
err.stderr = err.stderr.replace(/Cannot pull with rebase: You have unstaged changes/i, 'Cannot pull with rebase, you have unstaged changes');
|
||||
err.gitErrorCode = GitErrorCodes.DirtyWorkTree;
|
||||
} else if (/cannot lock ref|unable to update local ref/i.test(err.stderr || '')) {
|
||||
@@ -1977,7 +1981,16 @@ export class Repository {
|
||||
return this.getHEAD();
|
||||
}
|
||||
|
||||
const args = ['for-each-ref', '--format=%(refname)%00%(upstream:short)%00%(upstream:track)%00%(objectname)'];
|
||||
const args = ['for-each-ref'];
|
||||
|
||||
let supportsAheadBehind = true;
|
||||
if (this._git.compareGitVersionTo('1.9.0') === -1) {
|
||||
args.push('--format=%(refname)%00%(upstream:short)%00%(objectname)');
|
||||
supportsAheadBehind = false;
|
||||
} else {
|
||||
args.push('--format=%(refname)%00%(upstream:short)%00%(objectname)%00%(upstream:track)');
|
||||
}
|
||||
|
||||
if (/^refs\/(head|remotes)\//i.test(name)) {
|
||||
args.push(name);
|
||||
} else {
|
||||
@@ -1986,7 +1999,7 @@ export class Repository {
|
||||
|
||||
const result = await this.exec(args);
|
||||
const branches: Branch[] = result.stdout.trim().split('\n').map<Branch | undefined>(line => {
|
||||
let [branchName, upstream, status, ref] = line.trim().split('\0');
|
||||
let [branchName, upstream, ref, status] = line.trim().split('\0');
|
||||
|
||||
if (branchName.startsWith('refs/heads/')) {
|
||||
branchName = branchName.substring(11);
|
||||
@@ -2026,7 +2039,19 @@ export class Repository {
|
||||
}).filter((b?: Branch): b is Branch => !!b);
|
||||
|
||||
if (branches.length) {
|
||||
return branches[0];
|
||||
const [branch] = branches;
|
||||
|
||||
if (!supportsAheadBehind && branch.upstream) {
|
||||
try {
|
||||
const result = await this.exec(['rev-list', '--left-right', '--count', `${branch.name}...${branch.upstream.remote}/${branch.upstream.name}`]);
|
||||
const [ahead, behind] = result.stdout.trim().split('\t');
|
||||
|
||||
(branch as any).ahead = Number(ahead) || 0;
|
||||
(branch as any).behind = Number(behind) || 0;
|
||||
} catch { }
|
||||
}
|
||||
|
||||
return branch;
|
||||
}
|
||||
|
||||
return Promise.reject<Branch>(new Error('No such branch'));
|
||||
|
||||
@@ -73,12 +73,13 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
|
||||
git.onOutput.addListener('log', onOutput);
|
||||
disposables.push(toDisposable(() => git.onOutput.removeListener('log', onOutput)));
|
||||
|
||||
const cc = new CommandCenter(git, model, outputChannel, telemetryReporter);
|
||||
disposables.push(
|
||||
new CommandCenter(git, model, outputChannel, telemetryReporter),
|
||||
cc,
|
||||
new GitFileSystemProvider(model),
|
||||
new GitDecorations(model),
|
||||
new GitProtocolHandler(),
|
||||
new GitTimelineProvider(model)
|
||||
new GitTimelineProvider(model, cc)
|
||||
);
|
||||
|
||||
// checkGitVersion(info); {{SQL CARBON EDIT}} Don't check git version
|
||||
|
||||
@@ -284,8 +284,9 @@ export class Model implements IRemoteSourceProviderRegistry, IPushErrorHandlerRe
|
||||
|
||||
this.open(repository);
|
||||
await repository.status();
|
||||
} catch (err) {
|
||||
} catch (ex) {
|
||||
// noop
|
||||
this.outputChannel.appendLine(`Opening repository for path='${path}' failed; ex=${ex}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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, FileDecoration, commands } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions, BranchQuery } from './api/git';
|
||||
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions, BranchQuery, FetchOptions } from './api/git';
|
||||
import { AutoFetcher } from './autofetch';
|
||||
import { debounce, memoize, throttle } from './decorators';
|
||||
import { Commit, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions } from './git';
|
||||
@@ -55,13 +55,13 @@ export class Resource implements SourceControlResourceState {
|
||||
case Status.UNTRACKED: return localize('untracked', "Untracked");
|
||||
case Status.IGNORED: return localize('ignored', "Ignored");
|
||||
case Status.INTENT_TO_ADD: return localize('intent to add', "Intent to Add");
|
||||
case Status.BOTH_DELETED: return localize('both deleted', "Both Deleted");
|
||||
case Status.ADDED_BY_US: return localize('added by us', "Added By Us");
|
||||
case Status.DELETED_BY_THEM: return localize('deleted by them', "Deleted By Them");
|
||||
case Status.ADDED_BY_THEM: return localize('added by them', "Added By Them");
|
||||
case Status.DELETED_BY_US: return localize('deleted by us', "Deleted By Us");
|
||||
case Status.BOTH_ADDED: return localize('both added', "Both Added");
|
||||
case Status.BOTH_MODIFIED: return localize('both modified', "Both Modified");
|
||||
case Status.BOTH_DELETED: return localize('both deleted', "Conflict: Both Deleted");
|
||||
case Status.ADDED_BY_US: return localize('added by us', "Conflict: Added By Us");
|
||||
case Status.DELETED_BY_THEM: return localize('deleted by them', "Conflict: Deleted By Them");
|
||||
case Status.ADDED_BY_THEM: return localize('added by them', "Conflict: Added By Them");
|
||||
case Status.DELETED_BY_US: return localize('deleted by us', "Conflict: Deleted By Us");
|
||||
case Status.BOTH_ADDED: return localize('both added', "Conflict: Both Added");
|
||||
case Status.BOTH_MODIFIED: return localize('both modified', "Conflict: Both Modified");
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
@@ -199,12 +199,13 @@ export class Resource implements SourceControlResourceState {
|
||||
case Status.DELETED_BY_US:
|
||||
return 'D';
|
||||
case Status.INDEX_COPIED:
|
||||
return 'C';
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.ADDED_BY_THEM:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return 'C';
|
||||
return '!'; // Using ! instead of ⚠, because the latter looks really bad on windows
|
||||
default:
|
||||
throw new Error('Unknown git status: ' + this.type);
|
||||
}
|
||||
@@ -223,12 +224,13 @@ export class Resource implements SourceControlResourceState {
|
||||
case Status.INDEX_ADDED:
|
||||
case Status.INTENT_TO_ADD:
|
||||
return new ThemeColor('gitDecoration.addedResourceForeground');
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
return new ThemeColor('gitDecoration.renamedResourceForeground');
|
||||
case Status.UNTRACKED:
|
||||
return new ThemeColor('gitDecoration.untrackedResourceForeground');
|
||||
case Status.IGNORED:
|
||||
return new ThemeColor('gitDecoration.ignoredResourceForeground');
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
@@ -246,10 +248,10 @@ export class Resource implements SourceControlResourceState {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
case Status.INDEX_COPIED:
|
||||
return 2;
|
||||
case Status.IGNORED:
|
||||
return 3;
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
@@ -1317,8 +1319,8 @@ export class Repository implements Disposable {
|
||||
await this._fetch({ all: true });
|
||||
}
|
||||
|
||||
async fetch(remote?: string, ref?: string, depth?: number): Promise<void> {
|
||||
await this._fetch({ remote, ref, depth });
|
||||
async fetch(options: FetchOptions): Promise<void> {
|
||||
await this._fetch(options);
|
||||
}
|
||||
|
||||
private async _fetch(options: { remote?: string, ref?: string, all?: boolean, prune?: boolean, depth?: number, silent?: boolean; } = {}): Promise<void> {
|
||||
@@ -1833,7 +1835,10 @@ export class Repository implements Disposable {
|
||||
// noop
|
||||
}
|
||||
|
||||
const sort = config.get<'alphabetically' | 'committerdate'>('branchSortOrder') || 'alphabetically';
|
||||
let sort = config.get<'alphabetically' | 'committerdate'>('branchSortOrder') || 'alphabetically';
|
||||
if (sort !== 'alphabetically' && sort !== 'committerdate') {
|
||||
sort = 'alphabetically';
|
||||
}
|
||||
const [refs, remotes, submodules, rebaseCommit] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit()]);
|
||||
|
||||
this._HEAD = HEAD;
|
||||
|
||||
@@ -8,7 +8,7 @@ const testRunner = require('../../../../test/integration/electron/testrunner');
|
||||
|
||||
const options: any = {
|
||||
ui: 'tdd',
|
||||
useColors: (!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY && process.platform !== 'win32'),
|
||||
color: true,
|
||||
timeout: 60000
|
||||
};
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@ suite('git smoke test', function () {
|
||||
cp.execSync('git init', { cwd });
|
||||
cp.execSync('git config user.name testuser', { cwd });
|
||||
cp.execSync('git config user.email monacotools@microsoft.com', { cwd });
|
||||
cp.execSync('git config commit.gpgsign false', { cwd });
|
||||
cp.execSync('git add .', { cwd });
|
||||
cp.execSync('git commit -m "initial commit"', { cwd });
|
||||
cp.execSync('git branch -m main', { cwd });
|
||||
|
||||
// make sure git is activated
|
||||
const ext = extensions.getExtension<GitExtension>('vscode.git');
|
||||
@@ -124,7 +126,7 @@ suite('git smoke test', function () {
|
||||
assert.equal(repository.state.workingTreeChanges.length, 0);
|
||||
assert.equal(repository.state.indexChanges.length, 0);
|
||||
});
|
||||
|
||||
|
||||
test('rename/delete conflict', async function () {
|
||||
cp.execSync('git branch test', { cwd });
|
||||
cp.execSync('git checkout test', { cwd });
|
||||
@@ -133,16 +135,16 @@ suite('git smoke test', function () {
|
||||
cp.execSync('git add .', { cwd });
|
||||
|
||||
await repository.commit('commit on test');
|
||||
cp.execSync('git checkout master', { cwd });
|
||||
cp.execSync('git checkout main', { cwd });
|
||||
|
||||
fs.renameSync(file('app.js'), file('rename.js'));
|
||||
cp.execSync('git add .', { cwd });
|
||||
await repository.commit('commit on master');
|
||||
await repository.commit('commit on main');
|
||||
|
||||
try {
|
||||
cp.execSync('git merge test', { cwd });
|
||||
} catch (e) { }
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
commands.executeCommand('workbench.scm.focus');
|
||||
}, 2e3);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Model } from './model';
|
||||
import { Repository, Resource } from './repository';
|
||||
import { debounce } from './decorators';
|
||||
import { emojify, ensureEmojis } from './emoji';
|
||||
import { CommandCenter } from './commands';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -73,7 +74,7 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
private repoDisposable: Disposable | undefined;
|
||||
private repoStatusDate: Date | undefined;
|
||||
|
||||
constructor(private readonly model: Model) {
|
||||
constructor(private readonly model: Model, private commands: CommandCenter) {
|
||||
this.disposable = Disposable.from(
|
||||
model.onDidOpenRepository(this.onRepositoriesChanged, this),
|
||||
workspace.onDidChangeConfiguration(this.onConfigurationChanged, this)
|
||||
@@ -161,16 +162,20 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
const message = emojify(c.message);
|
||||
|
||||
const item = new GitTimelineItem(c.hash, commits[i + 1]?.hash ?? `${c.hash}^`, message, date?.getTime() ?? 0, c.hash, 'git:file:commit');
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.iconPath = new ThemeIcon('git-commit');
|
||||
if (showAuthor) {
|
||||
item.description = c.authorName;
|
||||
}
|
||||
item.detail = `${c.authorName} (${c.authorEmail}) — ${c.hash.substr(0, 8)}\n${dateFormatter.format(date)}\n\n${message}`;
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [item, uri, this.id]
|
||||
};
|
||||
|
||||
const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri);
|
||||
if (cmd) {
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: cmd.command,
|
||||
arguments: cmd.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
@@ -184,14 +189,18 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
|
||||
const item = new GitTimelineItem('~', 'HEAD', localize('git.timeline.stagedChanges', 'Staged Changes'), date.getTime(), 'index', 'git:file:index');
|
||||
// TODO@eamodio: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.iconPath = new ThemeIcon('git-commit');
|
||||
item.description = '';
|
||||
item.detail = localize('git.timeline.detail', '{0} — {1}\n{2}\n\n{3}', you, localize('git.index', 'Index'), dateFormatter.format(date), Resource.getStatusText(index.type));
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [item, uri, this.id]
|
||||
};
|
||||
|
||||
const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri);
|
||||
if (cmd) {
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: cmd.command,
|
||||
arguments: cmd.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
items.splice(0, 0, item);
|
||||
}
|
||||
@@ -202,14 +211,18 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
|
||||
const item = new GitTimelineItem('', index ? '~' : 'HEAD', localize('git.timeline.uncommitedChanges', 'Uncommitted Changes'), date.getTime(), 'working', 'git:file:working');
|
||||
// TODO@eamodio: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.iconPath = new ThemeIcon('git-commit');
|
||||
item.description = '';
|
||||
item.detail = localize('git.timeline.detail', '{0} — {1}\n{2}\n\n{3}', you, localize('git.workingTree', 'Working Tree'), dateFormatter.format(date), Resource.getStatusText(working.type));
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [item, uri, this.id]
|
||||
};
|
||||
|
||||
const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri);
|
||||
if (cmd) {
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: cmd.command,
|
||||
arguments: cmd.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
items.splice(0, 0, item);
|
||||
}
|
||||
|
||||
@@ -414,3 +414,56 @@ export class PromiseSource<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Versions {
|
||||
declare type VersionComparisonResult = -1 | 0 | 1;
|
||||
|
||||
export interface Version {
|
||||
major: number;
|
||||
minor: number;
|
||||
patch: number;
|
||||
pre?: string;
|
||||
}
|
||||
|
||||
export function compare(v1: string | Version, v2: string | Version): VersionComparisonResult {
|
||||
if (typeof v1 === 'string') {
|
||||
v1 = fromString(v1);
|
||||
}
|
||||
if (typeof v2 === 'string') {
|
||||
v2 = fromString(v2);
|
||||
}
|
||||
|
||||
if (v1.major > v2.major) { return 1; }
|
||||
if (v1.major < v2.major) { return -1; }
|
||||
|
||||
if (v1.minor > v2.minor) { return 1; }
|
||||
if (v1.minor < v2.minor) { return -1; }
|
||||
|
||||
if (v1.patch > v2.patch) { return 1; }
|
||||
if (v1.patch < v2.patch) { return -1; }
|
||||
|
||||
if (v1.pre === undefined && v2.pre !== undefined) { return 1; }
|
||||
if (v1.pre !== undefined && v2.pre === undefined) { return -1; }
|
||||
|
||||
if (v1.pre !== undefined && v2.pre !== undefined) {
|
||||
return v1.pre.localeCompare(v2.pre) as VersionComparisonResult;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function from(major: string | number, minor: string | number, patch?: string | number, pre?: string): Version {
|
||||
return {
|
||||
major: typeof major === 'string' ? parseInt(major, 10) : major,
|
||||
minor: typeof minor === 'string' ? parseInt(minor, 10) : minor,
|
||||
patch: patch === undefined || patch === null ? 0 : typeof patch === 'string' ? parseInt(patch, 10) : patch,
|
||||
pre: pre,
|
||||
};
|
||||
}
|
||||
|
||||
export function fromString(version: string): Version {
|
||||
const [ver, pre] = version.split('-');
|
||||
const [major, minor, patch] = ver.split('.');
|
||||
return from(major, minor, patch, pre);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true,
|
||||
@@ -10,4 +10,4 @@
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,14 +41,30 @@ ansi-regex@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
applicationinsights@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5"
|
||||
integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg==
|
||||
applicationinsights@1.7.4:
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.7.4.tgz#e7d96435594d893b00cf49f70a5927105dbb8749"
|
||||
integrity sha512-XFLsNlcanpjFhHNvVWEfcm6hr7lu9znnb6Le1Lk5RE03YUV9X2B2n2MfM4kJZRrUdV+C0hdHxvWyv+vWoLfY7A==
|
||||
dependencies:
|
||||
cls-hooked "^4.2.2"
|
||||
continuation-local-storage "^3.2.1"
|
||||
diagnostic-channel "0.2.0"
|
||||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
diagnostic-channel-publishers "^0.3.3"
|
||||
|
||||
async-hook-jl@^1.7.6:
|
||||
version "1.7.6"
|
||||
resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68"
|
||||
integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==
|
||||
dependencies:
|
||||
stack-chain "^1.3.7"
|
||||
|
||||
async-listener@^0.6.0:
|
||||
version "0.6.10"
|
||||
resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc"
|
||||
integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
shimmer "^1.1.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -78,6 +94,15 @@ charenc@~0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||
|
||||
cls-hooked@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908"
|
||||
integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==
|
||||
dependencies:
|
||||
async-hook-jl "^1.7.6"
|
||||
emitter-listener "^1.0.1"
|
||||
semver "^5.4.1"
|
||||
|
||||
commander@2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
|
||||
@@ -90,6 +115,14 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
continuation-local-storage@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb"
|
||||
integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==
|
||||
dependencies:
|
||||
async-listener "^0.6.0"
|
||||
emitter-listener "^1.1.1"
|
||||
|
||||
crypt@~0.0.1:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
||||
@@ -110,16 +143,16 @@ debug@^2.2.0:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
|
||||
diagnostic-channel-publishers@^0.3.3:
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536"
|
||||
integrity sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ==
|
||||
|
||||
diagnostic-channel@0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -133,6 +166,13 @@ diff@3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
|
||||
integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k=
|
||||
|
||||
emitter-listener@^1.0.1, emitter-listener@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8"
|
||||
integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==
|
||||
dependencies:
|
||||
shimmer "^1.2.0"
|
||||
|
||||
escape-string-regexp@1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
@@ -208,10 +248,10 @@ isexe@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
jschardet@2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.2.1.tgz#03b0264669a90c7a5c436a68c5a7d4e4cb0c9823"
|
||||
integrity sha512-Ks2JNuUJoc7PGaZ7bVFtSEvOcr0rBq6Q1J5/7+zKWLT+g+4zziL63O0jg7y2jxhzIa1LVsHUbPXrbaWmz9iwDw==
|
||||
jschardet@2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.3.0.tgz#06e2636e16c8ada36feebbdc08aa34e6a9b3ff75"
|
||||
integrity sha512-6I6xT7XN/7sBB7q8ObzKbmv5vN+blzLcboDE1BNEsEfmRXJValMxO6OIRT69ylPBRemS3rw6US+CMCar0OBc9g==
|
||||
|
||||
json3@3.3.2:
|
||||
version "3.3.2"
|
||||
@@ -371,6 +411,21 @@ semver@^5.3.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
|
||||
|
||||
semver@^5.4.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
shimmer@^1.1.0, shimmer@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337"
|
||||
integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==
|
||||
|
||||
stack-chain@^1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285"
|
||||
integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
@@ -385,12 +440,12 @@ supports-color@3.1.2:
|
||||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
vscode-extension-telemetry@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
|
||||
integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA==
|
||||
vscode-extension-telemetry@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.7.tgz#18389bc24127c89dade29cd2b71ba69a6ee6ad26"
|
||||
integrity sha512-pZuZTHO9OpsrwlerOKotWBRLRYJ53DobYb7aWiRAXjlqkuqE+YJJaP+2WEy8GrLIF1EnitXTDMaTAKsmLQ5ORQ==
|
||||
dependencies:
|
||||
applicationinsights "1.0.8"
|
||||
applicationinsights "1.7.4"
|
||||
|
||||
vscode-nls@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -418,8 +473,3 @@ xml@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
|
||||
integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=
|
||||
|
||||
BIN
extensions/github-authentication/images/icon.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
@@ -8,6 +8,7 @@
|
||||
"engines": {
|
||||
"vscode": "^1.41.0"
|
||||
},
|
||||
"icon": "images/icon.png",
|
||||
"enableProposedApi": true,
|
||||
"categories": [
|
||||
"Other"
|
||||
@@ -20,6 +21,12 @@
|
||||
"activationEvents": [
|
||||
"onAuthenticationRequest:github"
|
||||
],
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
@@ -53,10 +60,11 @@
|
||||
"vscode:prepublish": "npm run compile"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": "2.6.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"uuid": "8.1.0",
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"vscode-nls": "^4.1.2"
|
||||
"vscode-extension-telemetry": "0.1.7",
|
||||
"vscode-nls": "^4.1.2",
|
||||
"vscode-tas-client": "^0.1.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.19.9",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Disposable } from 'vscode';
|
||||
import { EventEmitter, Event, Disposable } from 'vscode';
|
||||
|
||||
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
@@ -47,27 +47,54 @@ const passthrough = (value: any, resolve: (value?: any) => void) => resolve(valu
|
||||
* @param adapter controls resolution of the returned promise
|
||||
* @returns a promise that resolves or rejects as specified by the adapter
|
||||
*/
|
||||
export async function promiseFromEvent<T, U>(
|
||||
export function promiseFromEvent<T, U>(
|
||||
event: Event<T>,
|
||||
adapter: PromiseAdapter<T, U> = passthrough): Promise<U> {
|
||||
adapter: PromiseAdapter<T, U> = passthrough): { promise: Promise<U>, cancel: EventEmitter<void> } {
|
||||
let subscription: Disposable;
|
||||
return new Promise<U>((resolve, reject) =>
|
||||
subscription = event((value: T) => {
|
||||
try {
|
||||
Promise.resolve(adapter(value, resolve, reject))
|
||||
.catch(reject);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
let cancel = new EventEmitter<void>();
|
||||
return {
|
||||
promise: new Promise<U>((resolve, reject) => {
|
||||
cancel.event(_ => reject());
|
||||
subscription = event((value: T) => {
|
||||
try {
|
||||
Promise.resolve(adapter(value, resolve, reject))
|
||||
.catch(reject);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}).then(
|
||||
(result: U) => {
|
||||
subscription.dispose();
|
||||
return result;
|
||||
},
|
||||
error => {
|
||||
subscription.dispose();
|
||||
throw error;
|
||||
}
|
||||
})
|
||||
).then(
|
||||
(result: U) => {
|
||||
subscription.dispose();
|
||||
return result;
|
||||
},
|
||||
error => {
|
||||
subscription.dispose();
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
),
|
||||
cancel
|
||||
};
|
||||
}
|
||||
|
||||
export function arrayEquals<T>(one: ReadonlyArray<T> | undefined, other: ReadonlyArray<T> | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
|
||||
if (one === other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!one || !other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (one.length !== other.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0, len = one.length; i < len; i++) {
|
||||
if (!itemEquals(one[i], other[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import { getExperimentationService, IExperimentationService, IExperimentationTelemetry, TargetPopulation } from 'vscode-tas-client';
|
||||
|
||||
export class ExperimentationTelemetry implements IExperimentationTelemetry {
|
||||
private sharedProperties: Record<string, string> = {};
|
||||
|
||||
constructor(private baseReporter: TelemetryReporter) { }
|
||||
|
||||
sendTelemetryEvent(eventName: string, properties?: Record<string, string>, measurements?: Record<string, number>) {
|
||||
this.baseReporter.sendTelemetryEvent(
|
||||
eventName,
|
||||
{
|
||||
...this.sharedProperties,
|
||||
...properties,
|
||||
},
|
||||
measurements,
|
||||
);
|
||||
}
|
||||
|
||||
sendTelemetryErrorEvent(
|
||||
eventName: string,
|
||||
properties?: Record<string, string>,
|
||||
_measurements?: Record<string, number>,
|
||||
) {
|
||||
this.baseReporter.sendTelemetryErrorEvent(eventName, {
|
||||
...this.sharedProperties,
|
||||
...properties,
|
||||
});
|
||||
}
|
||||
|
||||
setSharedProperty(name: string, value: string): void {
|
||||
this.sharedProperties[name] = value;
|
||||
}
|
||||
|
||||
postEvent(eventName: string, props: Map<string, string>): void {
|
||||
const event: Record<string, string> = {};
|
||||
for (const [key, value] of props) {
|
||||
event[key] = value;
|
||||
}
|
||||
this.sendTelemetryEvent(eventName, event);
|
||||
}
|
||||
|
||||
dispose(): Promise<any> {
|
||||
return this.baseReporter.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetPopulation(): TargetPopulation {
|
||||
switch (vscode.env.uriScheme) {
|
||||
case 'vscode':
|
||||
return TargetPopulation.Public;
|
||||
case 'vscode-insiders':
|
||||
return TargetPopulation.Insiders;
|
||||
case 'vscode-exploration':
|
||||
return TargetPopulation.Internal;
|
||||
case 'code-oss':
|
||||
return TargetPopulation.Team;
|
||||
default:
|
||||
return TargetPopulation.Public;
|
||||
}
|
||||
}
|
||||
|
||||
export async function createExperimentationService(context: vscode.ExtensionContext, telemetry: ExperimentationTelemetry): Promise<IExperimentationService> {
|
||||
const id = context.extension.id;
|
||||
const version = context.extension.packageJSON.version;
|
||||
return getExperimentationService(id, version, getTargetPopulation(), telemetry, context.globalState);
|
||||
}
|
||||
@@ -8,13 +8,17 @@ import { GitHubAuthenticationProvider, onDidChangeSessions } from './github';
|
||||
import { uriHandler } from './githubServer';
|
||||
import Logger from './common/logger';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import { createExperimentationService, ExperimentationTelemetry } from './experimentationService';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
const { name, version, aiKey } = require('../package.json') as { name: string, version: string, aiKey: string };
|
||||
const telemetryReporter = new TelemetryReporter(name, version, aiKey);
|
||||
const telemetryReporter = new ExperimentationTelemetry(new TelemetryReporter(name, version, aiKey));
|
||||
|
||||
const experimentationService = await createExperimentationService(context, telemetryReporter);
|
||||
await experimentationService.initialFetch;
|
||||
|
||||
context.subscriptions.push(vscode.window.registerUriHandler(uriHandler));
|
||||
const loginService = new GitHubAuthenticationProvider(context);
|
||||
const loginService = new GitHubAuthenticationProvider(context, telemetryReporter);
|
||||
|
||||
await loginService.initialize(context);
|
||||
|
||||
@@ -24,17 +28,17 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('github', 'GitHub', {
|
||||
onDidChangeSessions: onDidChangeSessions.event,
|
||||
getSessions: () => Promise.resolve(loginService.sessions),
|
||||
login: async (scopeList: string[]) => {
|
||||
getSessions: (scopes?: string[]) => loginService.getSessions(scopes),
|
||||
createSession: async (scopeList: string[]) => {
|
||||
try {
|
||||
/* __GDPR__
|
||||
"login" : { }
|
||||
*/
|
||||
telemetryReporter.sendTelemetryEvent('login');
|
||||
|
||||
const session = await loginService.login(scopeList.sort().join(' '));
|
||||
const session = await loginService.createSession(scopeList.sort().join(' '));
|
||||
Logger.info('Login success!');
|
||||
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
|
||||
onDidChangeSessions.fire({ added: [session], removed: [], changed: [] });
|
||||
return session;
|
||||
} catch (e) {
|
||||
// If login was cancelled, do not notify user.
|
||||
@@ -56,15 +60,17 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
logout: async (id: string) => {
|
||||
removeSession: async (id: string) => {
|
||||
try {
|
||||
/* __GDPR__
|
||||
"logout" : { }
|
||||
*/
|
||||
telemetryReporter.sendTelemetryEvent('logout');
|
||||
|
||||
await loginService.logout(id);
|
||||
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
|
||||
const session = await loginService.removeSession(id);
|
||||
if (session) {
|
||||
onDidChangeSessions.fire({ added: [], removed: [session], changed: [] });
|
||||
}
|
||||
} catch (e) {
|
||||
/* __GDPR__
|
||||
"logoutFailed" : { }
|
||||
|
||||
@@ -8,6 +8,8 @@ import { v4 as uuid } from 'uuid';
|
||||
import { Keychain } from './common/keychain';
|
||||
import { GitHubServer, NETWORK_ERROR } from './githubServer';
|
||||
import Logger from './common/logger';
|
||||
import { arrayEquals } from './common/utils';
|
||||
import { ExperimentationTelemetry } from './experimentationService';
|
||||
|
||||
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
|
||||
|
||||
@@ -24,12 +26,13 @@ interface SessionData {
|
||||
|
||||
export class GitHubAuthenticationProvider {
|
||||
private _sessions: vscode.AuthenticationSession[] = [];
|
||||
private _githubServer = new GitHubServer();
|
||||
private _githubServer: GitHubServer;
|
||||
|
||||
private _keychain: Keychain;
|
||||
|
||||
constructor(context: vscode.ExtensionContext) {
|
||||
constructor(context: vscode.ExtensionContext, telemetryReporter: ExperimentationTelemetry) {
|
||||
this._keychain = new Keychain(context);
|
||||
this._githubServer = new GitHubServer(telemetryReporter);
|
||||
}
|
||||
|
||||
public async initialize(context: vscode.ExtensionContext): Promise<void> {
|
||||
@@ -43,11 +46,18 @@ export class GitHubAuthenticationProvider {
|
||||
context.subscriptions.push(context.secrets.onDidChange(() => this.checkForUpdates()));
|
||||
}
|
||||
|
||||
async getSessions(scopes?: string[]): Promise<vscode.AuthenticationSession[]> {
|
||||
return scopes
|
||||
? this._sessions.filter(session => arrayEquals(session.scopes, scopes))
|
||||
: this._sessions;
|
||||
}
|
||||
|
||||
private async verifySessions(): Promise<void> {
|
||||
const verifiedSessions: vscode.AuthenticationSession[] = [];
|
||||
const verificationPromises = this._sessions.map(async session => {
|
||||
try {
|
||||
await this._githubServer.getUserInfo(session.accessToken);
|
||||
this._githubServer.checkIsEdu(session.accessToken);
|
||||
verifiedSessions.push(session);
|
||||
} catch (e) {
|
||||
// Remove sessions that return unauthorized response
|
||||
@@ -74,8 +84,8 @@ export class GitHubAuthenticationProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
const added: string[] = [];
|
||||
const removed: string[] = [];
|
||||
const added: vscode.AuthenticationSession[] = [];
|
||||
const removed: vscode.AuthenticationSession[] = [];
|
||||
|
||||
storedSessions.forEach(session => {
|
||||
const matchesExisting = this._sessions.some(s => s.id === session.id);
|
||||
@@ -83,7 +93,7 @@ export class GitHubAuthenticationProvider {
|
||||
if (!matchesExisting) {
|
||||
Logger.info('Adding session found in keychain');
|
||||
this._sessions.push(session);
|
||||
added.push(session.id);
|
||||
added.push(session);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -97,7 +107,7 @@ export class GitHubAuthenticationProvider {
|
||||
this._sessions.splice(sessionIndex, 1);
|
||||
}
|
||||
|
||||
removed.push(session.id);
|
||||
removed.push(session);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -153,9 +163,10 @@ export class GitHubAuthenticationProvider {
|
||||
return this._sessions;
|
||||
}
|
||||
|
||||
public async login(scopes: string): Promise<vscode.AuthenticationSession> {
|
||||
public async createSession(scopes: string): Promise<vscode.AuthenticationSession> {
|
||||
const token = await this._githubServer.login(scopes);
|
||||
const session = await this.tokenToSession(token, scopes.split(' '));
|
||||
this._githubServer.checkIsEdu(token);
|
||||
await this.setToken(session);
|
||||
return session;
|
||||
}
|
||||
@@ -185,15 +196,18 @@ export class GitHubAuthenticationProvider {
|
||||
await this.storeSessions();
|
||||
}
|
||||
|
||||
public async logout(id: string) {
|
||||
public async removeSession(id: string): Promise<vscode.AuthenticationSession | undefined> {
|
||||
Logger.info(`Logging out of ${id}`);
|
||||
const sessionIndex = this._sessions.findIndex(session => session.id === id);
|
||||
let session: vscode.AuthenticationSession | undefined;
|
||||
if (sessionIndex > -1) {
|
||||
session = this._sessions[sessionIndex];
|
||||
this._sessions.splice(sessionIndex, 1);
|
||||
} else {
|
||||
Logger.error('Session not found');
|
||||
}
|
||||
|
||||
await this.storeSessions();
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@ import fetch, { Response } from 'node-fetch';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { PromiseAdapter, promiseFromEvent } from './common/utils';
|
||||
import Logger from './common/logger';
|
||||
import { ExperimentationTelemetry } from './experimentationService';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export const NETWORK_ERROR = 'network error';
|
||||
const AUTH_RELAY_SERVER = 'vscode-auth.github.com';
|
||||
// const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com';
|
||||
|
||||
class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
|
||||
public handleUri(uri: vscode.Uri) {
|
||||
@@ -39,10 +41,18 @@ export class GitHubServer {
|
||||
private _statusBarItem: vscode.StatusBarItem | undefined;
|
||||
|
||||
private _pendingStates = new Map<string, string[]>();
|
||||
private _codeExchangePromises = new Map<string, Promise<string>>();
|
||||
private _codeExchangePromises = new Map<string, { promise: Promise<string>, cancel: vscode.EventEmitter<void> }>();
|
||||
|
||||
constructor(private readonly telemetryReporter: ExperimentationTelemetry) { }
|
||||
|
||||
private isTestEnvironment(url: vscode.Uri): boolean {
|
||||
return url.authority === 'vscode-web-test-playground.azurewebsites.net' || url.authority.startsWith('localhost:');
|
||||
return /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:');
|
||||
}
|
||||
|
||||
// TODO@joaomoreno TODO@RMacfarlane
|
||||
private async isNoCorsEnvironment(): Promise<boolean> {
|
||||
const uri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
return uri.scheme === 'https' && /^vscode\./.test(uri.authority);
|
||||
}
|
||||
|
||||
public async login(scopes: string): Promise<string> {
|
||||
@@ -50,7 +60,10 @@ export class GitHubServer {
|
||||
this.updateStatusBarItem(true);
|
||||
|
||||
const state = uuid();
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
|
||||
// TODO@joaomoreno TODO@RMacfarlane
|
||||
const nocors = await this.isNoCorsEnvironment();
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate${nocors ? '?nocors=true' : ''}`));
|
||||
|
||||
if (this.isTestEnvironment(callbackUri)) {
|
||||
const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true });
|
||||
@@ -77,23 +90,30 @@ export class GitHubServer {
|
||||
const existingStates = this._pendingStates.get(scopes) || [];
|
||||
this._pendingStates.set(scopes, [...existingStates, state]);
|
||||
|
||||
const uri = vscode.Uri.parse(`https://${AUTH_RELAY_SERVER}/authorize/?callbackUri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&responseType=code&authServer=https://github.com`);
|
||||
const uri = vscode.Uri.parse(`https://${AUTH_RELAY_SERVER}/authorize/?callbackUri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&responseType=code&authServer=https://github.com${nocors ? '&nocors=true' : ''}`);
|
||||
await vscode.env.openExternal(uri);
|
||||
}
|
||||
|
||||
// Register a single listener for the URI callback, in case the user starts the login process multiple times
|
||||
// before completing it.
|
||||
let existingPromise = this._codeExchangePromises.get(scopes);
|
||||
if (!existingPromise) {
|
||||
existingPromise = promiseFromEvent(uriHandler.event, this.exchangeCodeForToken(scopes));
|
||||
this._codeExchangePromises.set(scopes, existingPromise);
|
||||
let codeExchangePromise = this._codeExchangePromises.get(scopes);
|
||||
if (!codeExchangePromise) {
|
||||
codeExchangePromise = promiseFromEvent(uriHandler.event, this.exchangeCodeForToken(scopes));
|
||||
this._codeExchangePromises.set(scopes, codeExchangePromise);
|
||||
}
|
||||
|
||||
return Promise.race([
|
||||
existingPromise,
|
||||
promiseFromEvent<string | undefined, string>(onDidManuallyProvideToken.event, (token: string | undefined): string => { if (!token) { throw new Error('Cancelled'); } return token; })
|
||||
codeExchangePromise.promise,
|
||||
promiseFromEvent<string | undefined, string>(onDidManuallyProvideToken.event, (token: string | undefined, resolve, reject): void => {
|
||||
if (!token) {
|
||||
reject('Cancelled');
|
||||
} else {
|
||||
resolve(token);
|
||||
}
|
||||
}).promise
|
||||
]).finally(() => {
|
||||
this._pendingStates.delete(scopes);
|
||||
codeExchangePromise?.cancel.fire();
|
||||
this._codeExchangePromises.delete(scopes);
|
||||
this.updateStatusBarItem(false);
|
||||
});
|
||||
@@ -111,23 +131,36 @@ export class GitHubServer {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await fetch(`https://${AUTH_RELAY_SERVER}/token?code=${code}&state=${query.state}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
}
|
||||
});
|
||||
const url = `https://${AUTH_RELAY_SERVER}/token?code=${code}&state=${query.state}`;
|
||||
|
||||
if (result.ok) {
|
||||
const json = await result.json();
|
||||
// TODO@joao: remove
|
||||
if (query.nocors) {
|
||||
try {
|
||||
const json: any = await vscode.commands.executeCommand('_workbench.fetchJSON', url, 'POST');
|
||||
Logger.info('Token exchange success!');
|
||||
resolve(json.access_token);
|
||||
} else {
|
||||
reject(result.statusText);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const result = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (result.ok) {
|
||||
const json = await result.json();
|
||||
Logger.info('Token exchange success!');
|
||||
resolve(json.access_token);
|
||||
} else {
|
||||
reject(result.statusText);
|
||||
}
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,7 +186,7 @@ export class GitHubServer {
|
||||
}
|
||||
|
||||
try {
|
||||
const uri = vscode.Uri.parse(uriOrToken);
|
||||
const uri = vscode.Uri.parse(uriOrToken.trim());
|
||||
if (!uri.scheme || uri.scheme === 'file') { throw new Error; }
|
||||
uriHandler.handleUri(uri);
|
||||
} catch (e) {
|
||||
@@ -210,4 +243,42 @@ export class GitHubServer {
|
||||
throw new Error(result.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
public async checkIsEdu(token: string): Promise<void> {
|
||||
const nocors = await this.isNoCorsEnvironment();
|
||||
|
||||
if (nocors) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await fetch('https://education.github.com/api/user', {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'faculty-check-preview': 'true',
|
||||
'User-Agent': 'Visual-Studio-Code'
|
||||
}
|
||||
});
|
||||
|
||||
if (result.ok) {
|
||||
const json: { student: boolean, faculty: boolean } = await result.json();
|
||||
|
||||
/* __GDPR__
|
||||
"session" : {
|
||||
"isEdu": { "classification": "NonIdentifiableDemographicInfo", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('session', {
|
||||
isEdu: json.student
|
||||
? 'student'
|
||||
: json.faculty
|
||||
? 'faculty'
|
||||
: 'none'
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true,
|
||||
|
||||
@@ -25,20 +25,52 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0"
|
||||
integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==
|
||||
|
||||
applicationinsights@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5"
|
||||
integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg==
|
||||
applicationinsights@1.7.4:
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.7.4.tgz#e7d96435594d893b00cf49f70a5927105dbb8749"
|
||||
integrity sha512-XFLsNlcanpjFhHNvVWEfcm6hr7lu9znnb6Le1Lk5RE03YUV9X2B2n2MfM4kJZRrUdV+C0hdHxvWyv+vWoLfY7A==
|
||||
dependencies:
|
||||
cls-hooked "^4.2.2"
|
||||
continuation-local-storage "^3.2.1"
|
||||
diagnostic-channel "0.2.0"
|
||||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
diagnostic-channel-publishers "^0.3.3"
|
||||
|
||||
async-hook-jl@^1.7.6:
|
||||
version "1.7.6"
|
||||
resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68"
|
||||
integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==
|
||||
dependencies:
|
||||
stack-chain "^1.3.7"
|
||||
|
||||
async-listener@^0.6.0:
|
||||
version "0.6.10"
|
||||
resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc"
|
||||
integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
shimmer "^1.1.0"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
cls-hooked@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908"
|
||||
integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==
|
||||
dependencies:
|
||||
async-hook-jl "^1.7.6"
|
||||
emitter-listener "^1.0.1"
|
||||
semver "^5.4.1"
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
@@ -46,15 +78,23 @@ combined-stream@^1.0.8:
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
continuation-local-storage@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb"
|
||||
integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==
|
||||
dependencies:
|
||||
async-listener "^0.6.0"
|
||||
emitter-listener "^1.1.1"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
|
||||
diagnostic-channel-publishers@^0.3.3:
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536"
|
||||
integrity sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ==
|
||||
|
||||
diagnostic-channel@0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -63,6 +103,18 @@ diagnostic-channel@0.2.0:
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
emitter-listener@^1.0.1, emitter-listener@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8"
|
||||
integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==
|
||||
dependencies:
|
||||
shimmer "^1.2.0"
|
||||
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.3"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
||||
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
|
||||
|
||||
form-data@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
|
||||
@@ -84,34 +136,53 @@ mime-types@^2.1.12:
|
||||
dependencies:
|
||||
mime-db "1.44.0"
|
||||
|
||||
node-fetch@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
semver@^5.3.0:
|
||||
semver@^5.3.0, semver@^5.4.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
shimmer@^1.1.0, shimmer@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337"
|
||||
integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==
|
||||
|
||||
stack-chain@^1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285"
|
||||
integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=
|
||||
|
||||
tas-client@0.1.21:
|
||||
version "0.1.21"
|
||||
resolved "https://registry.yarnpkg.com/tas-client/-/tas-client-0.1.21.tgz#62275d5f75266eaae408f7463364748cb92f220d"
|
||||
integrity sha512-7UuIwOXarCYoCTrQHY5n7M+63XuwMC0sVUdbPQzxqDB9wMjIW0JF39dnp3yoJnxr4jJUVhPtvkkXZbAD0BxCcA==
|
||||
dependencies:
|
||||
axios "^0.21.1"
|
||||
|
||||
uuid@8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
|
||||
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
|
||||
|
||||
vscode-extension-telemetry@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
|
||||
integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA==
|
||||
vscode-extension-telemetry@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.7.tgz#18389bc24127c89dade29cd2b71ba69a6ee6ad26"
|
||||
integrity sha512-pZuZTHO9OpsrwlerOKotWBRLRYJ53DobYb7aWiRAXjlqkuqE+YJJaP+2WEy8GrLIF1EnitXTDMaTAKsmLQ5ORQ==
|
||||
dependencies:
|
||||
applicationinsights "1.0.8"
|
||||
applicationinsights "1.7.4"
|
||||
|
||||
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==
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=
|
||||
vscode-tas-client@^0.1.22:
|
||||
version "0.1.22"
|
||||
resolved "https://registry.yarnpkg.com/vscode-tas-client/-/vscode-tas-client-0.1.22.tgz#2dd674b21a94ff4e97db2b6545d9efda8b5f07c3"
|
||||
integrity sha512-1sYH73nhiSRVQgfZkLQNJW7VzhKM9qNbCe8QyXgiKkLhH4GflDXRPAK4yy4P41jUgula+Fc9G7i5imj1dlKfaw==
|
||||
dependencies:
|
||||
tas-client "0.1.21"
|
||||
|
||||
BIN
extensions/github/images/icon.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
@@ -8,6 +8,7 @@
|
||||
"engines": {
|
||||
"vscode": "^1.41.0"
|
||||
},
|
||||
"icon": "images/icon.png",
|
||||
"enableProposedApi": true,
|
||||
"categories": [
|
||||
"Other"
|
||||
@@ -19,6 +20,12 @@
|
||||
"vscode.git"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": false,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
|
||||
@@ -168,7 +168,12 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
}
|
||||
|
||||
const githubRepository = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, title: 'Publish to GitHub' }, async progress => {
|
||||
progress.report({ message: `Publishing to GitHub ${isPrivate ? 'private' : 'public'} repository`, increment: 25 });
|
||||
progress.report({
|
||||
message: isPrivate
|
||||
? localize('publishing_private', "Publishing to a private GitHub repository")
|
||||
: localize('publishing_public', "Publishing to a public GitHub repository"),
|
||||
increment: 25
|
||||
});
|
||||
|
||||
const res = await octokit.repos.createForAuthenticatedUser({
|
||||
name: repo!,
|
||||
@@ -177,7 +182,7 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
|
||||
const createdGithubRepository = res.data;
|
||||
|
||||
progress.report({ message: 'Creating first commit', increment: 25 });
|
||||
progress.report({ message: localize('publishing_firstcommit', "Creating first commit"), increment: 25 });
|
||||
|
||||
if (!repository) {
|
||||
repository = await gitAPI.init(folder) || undefined;
|
||||
@@ -189,9 +194,11 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
await repository.commit('first commit', { all: true });
|
||||
}
|
||||
|
||||
progress.report({ message: 'Uploading files', increment: 25 });
|
||||
progress.report({ message: localize('publishing_uploading', "Uploading files"), increment: 25 });
|
||||
|
||||
const branch = await repository.getBranch('HEAD');
|
||||
await repository.addRemote('origin', createdGithubRepository.clone_url);
|
||||
await repository.push('origin', 'master', true);
|
||||
await repository.push('origin', branch.name, true);
|
||||
|
||||
return createdGithubRepository;
|
||||
});
|
||||
@@ -200,9 +207,9 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
return;
|
||||
}
|
||||
|
||||
const openInGitHub = 'Open In GitHub';
|
||||
vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub).then(action => {
|
||||
if (action === openInGitHub) {
|
||||
const openOnGitHub = localize('openingithub', "Open on GitHub");
|
||||
vscode.window.showInformationMessage(localize('publishing_done', "Successfully published the '{0}' repository to GitHub.", `${owner}/${repo}`), openOnGitHub).then(action => {
|
||||
if (action === openOnGitHub) {
|
||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,37 +3,69 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { PushErrorHandler, GitErrorCodes, Repository, Remote } from './typings/git';
|
||||
import { window, ProgressLocation, commands, Uri } from 'vscode';
|
||||
import { commands, env, ProgressLocation, Uri, window } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { getOctokit } from './auth';
|
||||
import { GitErrorCodes, PushErrorHandler, Remote, Repository } from './typings/git';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;
|
||||
|
||||
export function isInCodespaces(): boolean {
|
||||
return env.remoteName === 'codespaces';
|
||||
}
|
||||
|
||||
async function handlePushError(repository: Repository, remote: Remote, refspec: string, owner: string, repo: string): Promise<void> {
|
||||
const yes = localize('create a fork', "Create Fork");
|
||||
const no = localize('no', "No");
|
||||
|
||||
const answer = await window.showInformationMessage(localize('fork', "You don't have permissions to push to '{0}/{1}' on GitHub. Would you like to create a fork and push to it instead?", owner, repo), yes, no);
|
||||
|
||||
if (answer === no) {
|
||||
return;
|
||||
}
|
||||
|
||||
const match = /^([^:]*):([^:]*)$/.exec(refspec);
|
||||
const localName = match ? match[1] : refspec;
|
||||
const remoteName = match ? match[2] : refspec;
|
||||
let remoteName = match ? match[2] : refspec;
|
||||
|
||||
const [octokit, ghRepository] = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: localize('create fork', 'Create GitHub fork') }, async progress => {
|
||||
progress.report({ message: localize('forking', "Forking '{0}/{1}'...", owner, repo), increment: 33 });
|
||||
|
||||
const octokit = await getOctokit();
|
||||
|
||||
// Issue: what if the repo already exists?
|
||||
const res = await octokit.repos.createFork({ owner, repo });
|
||||
const ghRepository = res.data;
|
||||
type CreateForkResponseData = Awaited<ReturnType<typeof octokit.repos.createFork>>['data'];
|
||||
|
||||
progress.report({ message: localize('pushing', "Pushing changes..."), increment: 33 });
|
||||
// Issue: what if the repo already exists?
|
||||
let ghRepository: CreateForkResponseData;
|
||||
try {
|
||||
if (isInCodespaces()) {
|
||||
// Call into the codespaces extension to fork the repository
|
||||
const resp = await commands.executeCommand<{ repository: CreateForkResponseData, ref: string }>('github.codespaces.forkRepository');
|
||||
if (!resp) {
|
||||
throw new Error('Unable to fork respository');
|
||||
}
|
||||
|
||||
ghRepository = resp.repository;
|
||||
|
||||
if (resp.ref) {
|
||||
let ref = resp.ref;
|
||||
if (ref.startsWith('refs/heads/')) {
|
||||
ref = ref.substr(11);
|
||||
}
|
||||
|
||||
remoteName = ref;
|
||||
}
|
||||
} else {
|
||||
const resp = await octokit.repos.createFork({ owner, repo });
|
||||
ghRepository = resp.data;
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
progress.report({ message: localize('forking_pushing', "Pushing changes..."), increment: 33 });
|
||||
|
||||
// Issue: what if there's already an `upstream` repo?
|
||||
await repository.renameRemote(remote.name, 'upstream');
|
||||
@@ -55,11 +87,11 @@ async function handlePushError(repository: Repository, remote: Remote, refspec:
|
||||
|
||||
// yield
|
||||
(async () => {
|
||||
const openInGitHub = localize('openingithub', "Open In GitHub");
|
||||
const openOnGitHub = localize('openingithub', "Open on GitHub");
|
||||
const createPR = localize('createpr', "Create PR");
|
||||
const action = await window.showInformationMessage(localize('done', "The fork '{0}' was successfully created on GitHub.", ghRepository.full_name), openInGitHub, createPR);
|
||||
const action = await window.showInformationMessage(localize('forking_done', "The fork '{0}' was successfully created on GitHub.", ghRepository.full_name), openOnGitHub, createPR);
|
||||
|
||||
if (action === openInGitHub) {
|
||||
if (action === openOnGitHub) {
|
||||
await commands.executeCommand('vscode.open', Uri.parse(ghRepository.html_url));
|
||||
} else if (action === createPR) {
|
||||
const pr = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: localize('createghpr', "Creating GitHub Pull Request...") }, async _ => {
|
||||
@@ -103,13 +135,12 @@ export class GithubPushErrorHandler implements PushErrorHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!remote.pushUrl) {
|
||||
const remoteUrl = remote.pushUrl || (isInCodespaces() ? remote.fetchUrl : undefined);
|
||||
if (!remoteUrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i.exec(remote.pushUrl)
|
||||
|| /^git@github\.com:([^/]+)\/([^/]+)\.git/i.exec(remote.pushUrl);
|
||||
|
||||
const match = /^(?:https:\/\/github\.com\/|git@github\.com:)([^/]+)\/([^/.]+)(?:\.git)?$/i.exec(remoteUrl);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
|
||||
}
|
||||
|
||||
const all = await Promise.all([
|
||||
this.getQueryRemoteSources(octokit, query),
|
||||
this.getUserRemoteSources(octokit, query),
|
||||
this.getQueryRemoteSources(octokit, query)
|
||||
]);
|
||||
|
||||
const map = new Map<string, RemoteSource>();
|
||||
@@ -76,7 +76,7 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
|
||||
return [];
|
||||
}
|
||||
|
||||
const raw = await octokit.search.repos({ q: query, sort: 'updated' });
|
||||
const raw = await octokit.search.repos({ q: query, sort: 'stars' });
|
||||
return raw.data.items.map(asRemoteSource);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true,
|
||||
|
||||
@@ -125,9 +125,9 @@ is-plain-object@^3.0.0:
|
||||
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
|
||||
|
||||
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==
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
once@^1.4.0:
|
||||
version "1.4.0"
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -26,6 +26,12 @@
|
||||
"onCommand:imagePreview.zoomIn",
|
||||
"onCommand:imagePreview.zoomOut"
|
||||
],
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"contributes": {
|
||||
"customEditors": [
|
||||
{
|
||||
@@ -55,12 +61,12 @@
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "imagePreview.zoomIn",
|
||||
"when": "imagePreviewFocus",
|
||||
"when": "activeCustomEditorId == 'imagePreview.previewEditor'",
|
||||
"group": "1_imagePreview"
|
||||
},
|
||||
{
|
||||
"command": "imagePreview.zoomOut",
|
||||
"when": "imagePreviewFocus",
|
||||
"when": "activeCustomEditorId == 'imagePreview.previewEditor'",
|
||||
"group": "1_imagePreview"
|
||||
}
|
||||
]
|
||||
@@ -75,7 +81,7 @@
|
||||
"watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"vscode-extension-telemetry": "0.1.7",
|
||||
"vscode-nls": "^4.0.0"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -11,7 +11,7 @@ export abstract class PreviewStatusBarEntry extends Disposable {
|
||||
|
||||
protected readonly entry: vscode.StatusBarItem;
|
||||
|
||||
constructor(options: vscode.window.StatusBarItemOptions) {
|
||||
constructor(options: vscode.StatusBarItemOptions) {
|
||||
super();
|
||||
this.entry = this._register(vscode.window.createStatusBarItem(options));
|
||||
}
|
||||
|
||||