Archived
1
0

Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'

This commit is contained in:
Joe Previte
2020-12-15 15:52:33 -07:00
4649 changed files with 1311795 additions and 0 deletions

View File

@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AuthenticationSession, authentication, window } from 'vscode';
import { Agent, globalAgent } from 'https';
import { Octokit } from '@octokit/rest';
import { httpsOverHttp } from 'tunnel';
import { URL } from 'url';
function getAgent(url: string | undefined = process.env.HTTPS_PROXY): Agent {
if (!url) {
return globalAgent;
}
try {
const { hostname, port, username, password } = new URL(url);
const auth = username && password && `${username}:${password}`;
return httpsOverHttp({ proxy: { host: hostname, port, proxyAuth: auth } });
} catch (e) {
window.showErrorMessage(`HTTPS_PROXY environment variable ignored: ${e.message}`);
return globalAgent;
}
}
const scopes = ['repo', 'workflow'];
export async function getSession(): Promise<AuthenticationSession> {
return await authentication.getSession('github', scopes, { createIfNone: true });
}
let _octokit: Promise<Octokit> | undefined;
export function getOctokit(): Promise<Octokit> {
if (!_octokit) {
_octokit = getSession().then(async session => {
const token = session.accessToken;
const agent = getAgent();
const { Octokit } = await import('@octokit/rest');
return new Octokit({
request: { agent },
userAgent: 'GitHub VSCode',
auth: `token ${token}`
});
}).then(null, async err => {
_octokit = undefined;
throw err;
});
}
return _octokit;
}

View File

@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* 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 { API as GitAPI } from './typings/git';
import { publishRepository } from './publish';
import { combinedDisposable } from './util';
export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
const disposables: vscode.Disposable[] = [];
disposables.push(vscode.commands.registerCommand('github.publish', async () => {
try {
publishRepository(gitAPI);
} catch (err) {
vscode.window.showErrorMessage(err.message);
}
}));
return combinedDisposable(disposables);
}

View File

@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CredentialsProvider, Credentials, API as GitAPI } from './typings/git';
import { workspace, Uri, Disposable } from 'vscode';
import { getSession } from './auth';
const EmptyDisposable: Disposable = { dispose() { } };
class GitHubCredentialProvider implements CredentialsProvider {
async getCredentials(host: Uri): Promise<Credentials | undefined> {
if (!/github\.com/i.test(host.authority)) {
return;
}
const session = await getSession();
return { username: session.account.id, password: session.accessToken };
}
}
export class GithubCredentialProviderManager {
private providerDisposable: Disposable = EmptyDisposable;
private readonly disposable: Disposable;
private _enabled = false;
private set enabled(enabled: boolean) {
if (this._enabled === enabled) {
return;
}
this._enabled = enabled;
if (enabled) {
this.providerDisposable = this.gitAPI.registerCredentialsProvider(new GitHubCredentialProvider());
} else {
this.providerDisposable.dispose();
}
}
constructor(private gitAPI: GitAPI) {
this.disposable = workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('github')) {
this.refresh();
}
});
this.refresh();
}
private refresh(): void {
const config = workspace.getConfiguration('github', null);
const enabled = config.get<boolean>('gitAuthentication', true);
this.enabled = !!enabled;
}
dispose(): void {
this.enabled = false;
this.disposable.dispose();
}
}

View File

@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, ExtensionContext, extensions } from 'vscode';
import { GithubRemoteSourceProvider } from './remoteSourceProvider';
import { GitExtension } from './typings/git';
import { registerCommands } from './commands';
import { GithubCredentialProviderManager } from './credentialProvider';
import { dispose, combinedDisposable } from './util';
import { GithubPushErrorHandler } from './pushErrorHandler';
export function activate(context: ExtensionContext): void {
const disposables = new Set<Disposable>();
context.subscriptions.push(combinedDisposable(disposables));
const init = () => {
try {
const gitAPI = gitExtension.getAPI(1);
disposables.add(registerCommands(gitAPI));
disposables.add(gitAPI.registerRemoteSourceProvider(new GithubRemoteSourceProvider(gitAPI)));
disposables.add(new GithubCredentialProviderManager(gitAPI));
disposables.add(gitAPI.registerPushErrorHandler(new GithubPushErrorHandler()));
} catch (err) {
console.error('Could not initialize GitHub extension');
console.warn(err);
}
};
const onDidChangeGitExtensionEnablement = (enabled: boolean) => {
if (!enabled) {
dispose(disposables);
disposables.clear();
} else {
init();
}
};
const gitExtension = extensions.getExtension<GitExtension>('vscode.git')!.exports;
context.subscriptions.push(gitExtension.onDidChangeEnablement(onDidChangeGitExtensionEnablement));
onDidChangeGitExtensionEnablement(gitExtension.enabled);
}

View File

@ -0,0 +1,200 @@
/*---------------------------------------------------------------------------------------------
* 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 * as nls from 'vscode-nls';
import { API as GitAPI, Repository } from './typings/git';
import { getOctokit } from './auth';
import { TextEncoder } from 'util';
import { basename } from 'path';
const localize = nls.loadMessageBundle();
function sanitizeRepositoryName(value: string): string {
return value.trim().replace(/[^a-z0-9_.]/ig, '-');
}
function getPick<T extends vscode.QuickPickItem>(quickpick: vscode.QuickPick<T>): Promise<T | undefined> {
return Promise.race<T | undefined>([
new Promise<T>(c => quickpick.onDidAccept(() => quickpick.selectedItems.length > 0 && c(quickpick.selectedItems[0]))),
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
]);
}
export async function publishRepository(gitAPI: GitAPI, repository?: Repository): Promise<void> {
if (!vscode.workspace.workspaceFolders?.length) {
return;
}
let folder: vscode.Uri;
if (repository) {
folder = repository.rootUri;
} else if (gitAPI.repositories.length === 1) {
repository = gitAPI.repositories[0];
folder = repository.rootUri;
} else if (vscode.workspace.workspaceFolders.length === 1) {
folder = vscode.workspace.workspaceFolders[0].uri;
} else {
const picks = vscode.workspace.workspaceFolders.map(folder => ({ label: folder.name, folder }));
const placeHolder = localize('pick folder', "Pick a folder to publish to GitHub");
const pick = await vscode.window.showQuickPick(picks, { placeHolder });
if (!pick) {
return;
}
folder = pick.folder.uri;
}
let quickpick = vscode.window.createQuickPick<vscode.QuickPickItem & { repo?: string, auth?: 'https' | 'ssh', isPrivate?: boolean }>();
quickpick.ignoreFocusOut = true;
quickpick.placeholder = 'Repository Name';
quickpick.value = basename(folder.fsPath);
quickpick.show();
quickpick.busy = true;
const octokit = await getOctokit();
const user = await octokit.users.getAuthenticated({});
const owner = user.data.login;
quickpick.busy = false;
let repo: string | undefined;
let isPrivate: boolean;
const onDidChangeValue = async () => {
const sanitizedRepo = sanitizeRepositoryName(quickpick.value);
if (!sanitizedRepo) {
quickpick.items = [];
} else {
quickpick.items = [
{ label: `$(repo) Publish to GitHub private repository`, description: `$(github) ${owner}/${sanitizedRepo}`, alwaysShow: true, repo: sanitizedRepo, isPrivate: true },
{ label: `$(repo) Publish to GitHub public repository`, description: `$(github) ${owner}/${sanitizedRepo}`, alwaysShow: true, repo: sanitizedRepo, isPrivate: false },
];
}
};
onDidChangeValue();
while (true) {
const listener = quickpick.onDidChangeValue(onDidChangeValue);
const pick = await getPick(quickpick);
listener.dispose();
repo = pick?.repo;
isPrivate = pick?.isPrivate ?? true;
if (repo) {
try {
quickpick.busy = true;
await octokit.repos.get({ owner, repo: repo });
quickpick.items = [{ label: `$(error) GitHub repository already exists`, description: `$(github) ${owner}/${repo}`, alwaysShow: true }];
} catch {
break;
} finally {
quickpick.busy = false;
}
}
}
quickpick.dispose();
if (!repo) {
return;
}
if (!repository) {
const gitignore = vscode.Uri.joinPath(folder, '.gitignore');
let shouldGenerateGitignore = false;
try {
await vscode.workspace.fs.stat(gitignore);
} catch (err) {
shouldGenerateGitignore = true;
}
if (shouldGenerateGitignore) {
quickpick = vscode.window.createQuickPick();
quickpick.placeholder = localize('ignore', "Select which files should be included in the repository.");
quickpick.canSelectMany = true;
quickpick.show();
try {
quickpick.busy = true;
const children = (await vscode.workspace.fs.readDirectory(folder))
.map(([name]) => name)
.filter(name => name !== '.git');
quickpick.items = children.map(name => ({ label: name }));
quickpick.selectedItems = quickpick.items;
quickpick.busy = false;
const result = await Promise.race([
new Promise<readonly vscode.QuickPickItem[]>(c => quickpick.onDidAccept(() => c(quickpick.selectedItems))),
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
]);
if (!result) {
return;
}
const ignored = new Set(children);
result.forEach(c => ignored.delete(c.label));
if (ignored.size > 0) {
const raw = [...ignored].map(i => `/${i}`).join('\n');
const encoder = new TextEncoder();
await vscode.workspace.fs.writeFile(gitignore, encoder.encode(raw));
}
} finally {
quickpick.dispose();
}
}
}
const githubRepository = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, title: 'Publish to GitHub' }, async progress => {
progress.report({ message: `Publishing to GitHub ${isPrivate ? 'private' : 'public'} repository`, increment: 25 });
const res = await octokit.repos.createForAuthenticatedUser({
name: repo!,
private: isPrivate
});
const createdGithubRepository = res.data;
progress.report({ message: 'Creating first commit', increment: 25 });
if (!repository) {
repository = await gitAPI.init(folder) || undefined;
if (!repository) {
return;
}
await repository.commit('first commit', { all: true });
}
progress.report({ message: 'Uploading files', increment: 25 });
const branch = await repository.getBranch('HEAD');
await repository.addRemote('origin', createdGithubRepository.clone_url);
await repository.push('origin', branch.name, true);
return createdGithubRepository;
});
if (!githubRepository) {
return;
}
const openInGitHub = 'Open In GitHub';
const action = await vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub);
if (action === openInGitHub) {
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
}
}

View File

@ -0,0 +1,120 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. 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 * as nls from 'vscode-nls';
import { getOctokit } from './auth';
const localize = nls.loadMessageBundle();
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;
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;
progress.report({ message: localize('pushing', "Pushing changes..."), increment: 33 });
// Issue: what if there's already an `upstream` repo?
await repository.renameRemote(remote.name, 'upstream');
// Issue: what if there's already another `origin` repo?
await repository.addRemote('origin', ghRepository.clone_url);
await repository.fetch('origin', remoteName);
await repository.setBranchUpstream(localName, `origin/${remoteName}`);
await repository.push('origin', localName, true);
return [octokit, ghRepository];
});
// yield
(async () => {
const openInGitHub = localize('openingithub', "Open In 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);
if (action === openInGitHub) {
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 _ => {
let title = `Update ${remoteName}`;
const head = repository.state.HEAD?.name;
if (head) {
const commit = await repository.getCommit(head);
title = commit.message.replace(/\n.*$/m, '');
}
const res = await octokit.pulls.create({
owner,
repo,
title,
head: `${ghRepository.owner.login}:${remoteName}`,
base: remoteName
});
await repository.setConfig(`branch.${localName}.remote`, 'upstream');
await repository.setConfig(`branch.${localName}.merge`, `refs/heads/${remoteName}`);
await repository.setConfig(`branch.${localName}.github-pr-owner-number`, `${owner}#${repo}#${pr.number}`);
return res.data;
});
const openPR = localize('openpr', "Open PR");
const action = await window.showInformationMessage(localize('donepr', "The PR '{0}/{1}#{2}' was successfully created on GitHub.", owner, repo, pr.number), openPR);
if (action === openPR) {
await commands.executeCommand('vscode.open', Uri.parse(pr.html_url));
}
}
})();
}
export class GithubPushErrorHandler implements PushErrorHandler {
async handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise<boolean> {
if (error.gitErrorCode !== GitErrorCodes.PermissionDenied) {
return false;
}
if (!remote.pushUrl) {
return false;
}
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i.exec(remote.pushUrl)
|| /^git@github\.com:([^/]+)\/([^/]+)\.git/i.exec(remote.pushUrl);
if (!match) {
return false;
}
if (/^:/.test(refspec)) {
return false;
}
const [, owner, repo] = match;
await handlePushError(repository, remote, refspec, owner, repo);
return true;
}
}

View File

@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API as GitAPI, RemoteSourceProvider, RemoteSource, Repository } from './typings/git';
import { getOctokit } from './auth';
import { Octokit } from '@octokit/rest';
import { publishRepository } from './publish';
function asRemoteSource(raw: any): RemoteSource {
return {
name: `$(github) ${raw.full_name}`,
description: raw.description || undefined,
url: raw.clone_url
};
}
export class GithubRemoteSourceProvider implements RemoteSourceProvider {
readonly name = 'GitHub';
readonly icon = 'github';
readonly supportsQuery = true;
private userReposCache: RemoteSource[] = [];
constructor(private gitAPI: GitAPI) { }
async getRemoteSources(query?: string): Promise<RemoteSource[]> {
const octokit = await getOctokit();
const [fromUser, fromQuery] = await Promise.all([
this.getUserRemoteSources(octokit, query),
this.getQueryRemoteSources(octokit, query)
]);
const userRepos = new Set(fromUser.map(r => r.name));
return [
...fromUser,
...fromQuery.filter(r => !userRepos.has(r.name))
];
}
private async getUserRemoteSources(octokit: Octokit, query?: string): Promise<RemoteSource[]> {
if (!query) {
const user = await octokit.users.getAuthenticated({});
const username = user.data.login;
const res = await octokit.repos.listForUser({ username, sort: 'updated', per_page: 100 });
this.userReposCache = res.data.map(asRemoteSource);
}
return this.userReposCache;
}
private async getQueryRemoteSources(octokit: Octokit, query?: string): Promise<RemoteSource[]> {
if (!query) {
return [];
}
const raw = await octokit.search.repos({ q: query, sort: 'updated' });
return raw.data.items.map(asRemoteSource);
}
publishRepository(repository: Repository): Promise<void> {
return publishRepository(this.gitAPI, repository);
}
}

View File

@ -0,0 +1,303 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, Event, Disposable, ProviderResult } from 'vscode';
export { ProviderResult } from 'vscode';
export interface Git {
readonly path: string;
}
export interface InputBox {
value: string;
}
export const enum RefType {
Head,
RemoteHead,
Tag
}
export interface Ref {
readonly type: RefType;
readonly name?: string;
readonly commit?: string;
readonly remote?: string;
}
export interface UpstreamRef {
readonly remote: string;
readonly name: string;
}
export interface Branch extends Ref {
readonly upstream?: UpstreamRef;
readonly ahead?: number;
readonly behind?: number;
}
export interface Commit {
readonly hash: string;
readonly message: string;
readonly parents: string[];
readonly authorDate?: Date;
readonly authorName?: string;
readonly authorEmail?: string;
readonly commitDate?: Date;
}
export interface Submodule {
readonly name: string;
readonly path: string;
readonly url: string;
}
export interface Remote {
readonly name: string;
readonly fetchUrl?: string;
readonly pushUrl?: string;
readonly isReadOnly: boolean;
}
export const enum Status {
INDEX_MODIFIED,
INDEX_ADDED,
INDEX_DELETED,
INDEX_RENAMED,
INDEX_COPIED,
MODIFIED,
DELETED,
UNTRACKED,
IGNORED,
INTENT_TO_ADD,
ADDED_BY_US,
ADDED_BY_THEM,
DELETED_BY_US,
DELETED_BY_THEM,
BOTH_ADDED,
BOTH_DELETED,
BOTH_MODIFIED
}
export interface Change {
/**
* Returns either `originalUri` or `renameUri`, depending
* on whether this change is a rename change. When
* in doubt always use `uri` over the other two alternatives.
*/
readonly uri: Uri;
readonly originalUri: Uri;
readonly renameUri: Uri | undefined;
readonly status: Status;
}
export interface RepositoryState {
readonly HEAD: Branch | undefined;
readonly refs: Ref[];
readonly remotes: Remote[];
readonly submodules: Submodule[];
readonly rebaseCommit: Commit | undefined;
readonly mergeChanges: Change[];
readonly indexChanges: Change[];
readonly workingTreeChanges: Change[];
readonly onDidChange: Event<void>;
}
export interface RepositoryUIState {
readonly selected: boolean;
readonly onDidChange: Event<void>;
}
/**
* Log options.
*/
export interface LogOptions {
/** Max number of log entries to retrieve. If not specified, the default is 32. */
readonly maxEntries?: number;
readonly path?: string;
}
export interface CommitOptions {
all?: boolean | 'tracked';
amend?: boolean;
signoff?: boolean;
signCommit?: boolean;
empty?: boolean;
}
export interface BranchQuery {
readonly remote?: boolean;
readonly pattern?: string;
readonly count?: number;
readonly contains?: string;
}
export interface Repository {
readonly rootUri: Uri;
readonly inputBox: InputBox;
readonly state: RepositoryState;
readonly ui: RepositoryUIState;
getConfigs(): Promise<{ key: string; value: string; }[]>;
getConfig(key: string): Promise<string>;
setConfig(key: string, value: string): Promise<string>;
getGlobalConfig(key: string): Promise<string>;
getObjectDetails(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }>;
detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }>;
buffer(ref: string, path: string): Promise<Buffer>;
show(ref: string, path: string): Promise<string>;
getCommit(ref: string): Promise<Commit>;
clean(paths: string[]): Promise<void>;
apply(patch: string, reverse?: boolean): Promise<void>;
diff(cached?: boolean): Promise<string>;
diffWithHEAD(): Promise<Change[]>;
diffWithHEAD(path: string): Promise<string>;
diffWith(ref: string): Promise<Change[]>;
diffWith(ref: string, path: string): Promise<string>;
diffIndexWithHEAD(): Promise<Change[]>;
diffIndexWithHEAD(path: string): Promise<string>;
diffIndexWith(ref: string): Promise<Change[]>;
diffIndexWith(ref: string, path: string): Promise<string>;
diffBlobs(object1: string, object2: string): Promise<string>;
diffBetween(ref1: string, ref2: string): Promise<Change[]>;
diffBetween(ref1: string, ref2: string, path: string): Promise<string>;
hashObject(data: string): Promise<string>;
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
deleteBranch(name: string, force?: boolean): Promise<void>;
getBranch(name: string): Promise<Branch>;
getBranches(query: BranchQuery): Promise<Ref[]>;
setBranchUpstream(name: string, upstream: string): Promise<void>;
getMergeBase(ref1: string, ref2: string): Promise<string>;
status(): Promise<void>;
checkout(treeish: string): Promise<void>;
addRemote(name: string, url: string): Promise<void>;
removeRemote(name: string): Promise<void>;
renameRemote(name: string, newName: string): Promise<void>;
fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
pull(unshallow?: boolean): Promise<void>;
push(remoteName?: string, branchName?: string, setUpstream?: boolean): Promise<void>;
blame(path: string): Promise<string>;
log(options?: LogOptions): Promise<Commit[]>;
commit(message: string, opts?: CommitOptions): Promise<void>;
}
export interface RemoteSource {
readonly name: string;
readonly description?: string;
readonly url: string | string[];
}
export interface RemoteSourceProvider {
readonly name: string;
readonly icon?: string; // codicon name
readonly supportsQuery?: boolean;
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
publishRepository?(repository: Repository): Promise<void>;
}
export interface Credentials {
readonly username: string;
readonly password: string;
}
export interface CredentialsProvider {
getCredentials(host: Uri): ProviderResult<Credentials>;
}
export interface PushErrorHandler {
handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise<boolean>;
}
export type APIState = 'uninitialized' | 'initialized';
export interface API {
readonly state: APIState;
readonly onDidChangeState: Event<APIState>;
readonly git: Git;
readonly repositories: Repository[];
readonly onDidOpenRepository: Event<Repository>;
readonly onDidCloseRepository: Event<Repository>;
toGitUri(uri: Uri, ref: string): Uri;
getRepository(uri: Uri): Repository | null;
init(root: Uri): Promise<Repository | null>;
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable;
registerCredentialsProvider(provider: CredentialsProvider): Disposable;
registerPushErrorHandler(handler: PushErrorHandler): Disposable;
}
export interface GitExtension {
readonly enabled: boolean;
readonly onDidChangeEnablement: Event<boolean>;
/**
* Returns a specific API version.
*
* Throws error if git extension is disabled. You can listed to the
* [GitExtension.onDidChangeEnablement](#GitExtension.onDidChangeEnablement) event
* to know when the extension becomes enabled/disabled.
*
* @param version Version number.
* @returns API instance
*/
getAPI(version: 1): API;
}
export const enum GitErrorCodes {
BadConfigFile = 'BadConfigFile',
AuthenticationFailed = 'AuthenticationFailed',
NoUserNameConfigured = 'NoUserNameConfigured',
NoUserEmailConfigured = 'NoUserEmailConfigured',
NoRemoteRepositorySpecified = 'NoRemoteRepositorySpecified',
NotAGitRepository = 'NotAGitRepository',
NotAtRepositoryRoot = 'NotAtRepositoryRoot',
Conflict = 'Conflict',
StashConflict = 'StashConflict',
UnmergedChanges = 'UnmergedChanges',
PushRejected = 'PushRejected',
RemoteConnectionError = 'RemoteConnectionError',
DirtyWorkTree = 'DirtyWorkTree',
CantOpenResource = 'CantOpenResource',
GitNotFound = 'GitNotFound',
CantCreatePipe = 'CantCreatePipe',
PermissionDenied = 'PermissionDenied',
CantAccessRemote = 'CantAccessRemote',
RepositoryNotFound = 'RepositoryNotFound',
RepositoryIsLocked = 'RepositoryIsLocked',
BranchNotFullyMerged = 'BranchNotFullyMerged',
NoRemoteReference = 'NoRemoteReference',
InvalidBranchName = 'InvalidBranchName',
BranchAlreadyExists = 'BranchAlreadyExists',
NoLocalChanges = 'NoLocalChanges',
NoStashFound = 'NoStashFound',
LocalChangesOverwritten = 'LocalChangesOverwritten',
NoUpstreamBranch = 'NoUpstreamBranch',
IsInSubmodule = 'IsInSubmodule',
WrongCase = 'WrongCase',
CantLockRef = 'CantLockRef',
CantRebaseMultipleBranches = 'CantRebaseMultipleBranches',
PatchDoesNotApply = 'PatchDoesNotApply',
NoPathFound = 'NoPathFound',
UnknownPath = 'UnknownPath',
}

View File

@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
declare module 'tunnel';

View File

@ -0,0 +1,24 @@
/*---------------------------------------------------------------------------------------------
* 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';
export function dispose(arg: vscode.Disposable | Iterable<vscode.Disposable>): void {
if (arg instanceof vscode.Disposable) {
arg.dispose();
} else {
for (const disposable of arg) {
disposable.dispose();
}
}
}
export function combinedDisposable(disposables: Iterable<vscode.Disposable>): vscode.Disposable {
return {
dispose() {
dispose(disposables);
}
};
}