提交 4bb364cc 编写于 作者: J João Moreno

github: publish workspace folder

上级 2aa9f3f2
......@@ -43,6 +43,11 @@
"view": "scm",
"contents": "%welcome.publishFolder%",
"when": "config.git.enabled && git.state == initialized && workbenchState == folder"
},
{
"view": "scm",
"contents": "%welcome.publishWorkspaceFolder%",
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0"
}
]
},
......
......@@ -2,5 +2,6 @@
"displayName": "GitHub",
"description": "GitHub",
"config.gitAuthentication": "Controls whether to enable automatic GitHub authentication for git commands within VS Code.",
"welcome.publishFolder": "You can also directly publish this folder to a GitHub repository.\n[$(github) Publish to GitHub](command:github.publish)"
"welcome.publishFolder": "You can also directly publish this folder to a GitHub repository.\n[$(github) Publish to GitHub](command:github.publish)",
"welcome.publishWorkspaceFolder": "You can also directly publish a workspace folder to a GitHub repository.\n[$(github) Publish to GitHub](command:github.publish)"
}
......@@ -5,116 +5,14 @@
import * as vscode from 'vscode';
import { API as GitAPI } from './typings/git';
import { getOctokit } from './auth';
function sanitizeRepositoryName(value: string): string {
return value.trim().replace(/[^a-z0-9_.]/ig, '-');
}
import { publishRepository } from './publish';
export function registerCommands(gitAPI: GitAPI): vscode.Disposable[] {
async function publish(): Promise<void> {
if (!vscode.workspace.workspaceFolders?.length) {
return;
}
const folder = vscode.workspace.workspaceFolders[0]; // TODO
const quickpick = vscode.window.createQuickPick<vscode.QuickPickItem & { repo?: string, auth?: 'https' | 'ssh' }>();
quickpick.ignoreFocusOut = true;
quickpick.placeholder = 'Repository Name';
quickpick.value = folder.name;
quickpick.show();
quickpick.busy = true;
const octokit = await getOctokit();
const user = await octokit.users.getAuthenticated({});
const owner = user.data.login;
quickpick.busy = false;
let repo: string | undefined;
const onDidChangeValue = async () => {
const sanitizedRepo = sanitizeRepositoryName(quickpick.value);
if (!sanitizedRepo) {
quickpick.items = [];
} else {
quickpick.items = [{ label: `$(repo) Create private repository`, description: `$(github) ${owner}/${sanitizedRepo}`, alwaysShow: true, repo: sanitizedRepo }];
}
};
onDidChangeValue();
while (true) {
const listener = quickpick.onDidChangeValue(onDidChangeValue);
const pick = await getPick(quickpick);
listener.dispose();
repo = pick?.repo;
if (repo) {
try {
quickpick.busy = true;
await octokit.repos.get({ owner, repo: repo });
quickpick.items = [{ label: `$(error) Repository already exists`, description: `$(github) ${owner}/${repo}`, alwaysShow: true }];
} catch {
break;
} finally {
quickpick.busy = false;
}
}
}
quickpick.dispose();
if (!repo) {
return;
}
const githubRepository = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, title: 'Publish to GitHub' }, async progress => {
progress.report({ message: 'Creating private repository in GitHub', increment: 25 });
const res = await octokit.repos.createForAuthenticatedUser({
name: repo!,
private: true
});
const createdGithubRepository = res.data;
progress.report({ message: 'Creating first commit', increment: 25 });
const repository = await gitAPI.init(folder.uri);
if (!repository) {
return;
}
await repository.commit('first commit', { all: true });
progress.report({ message: 'Uploading files', increment: 25 });
await repository.addRemote('origin', createdGithubRepository.clone_url);
await repository.push('origin', 'master', true);
return createdGithubRepository;
});
if (!githubRepository) {
return;
}
const openInGitHub = 'Open In GitHub';
const action = await vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub);
if (action === openInGitHub) {
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
}
}
const disposables = [];
disposables.push(vscode.commands.registerCommand('github.publish', async () => {
try {
publish();
publishRepository(gitAPI);
} catch (err) {
vscode.window.showErrorMessage(err.message);
}
......@@ -122,10 +20,3 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable[] {
return disposables;
}
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)))
]);
}
......@@ -14,6 +14,6 @@ export async function activate(context: vscode.ExtensionContext) {
const gitAPI = gitExtension.getAPI(1);
context.subscriptions.push(...registerCommands(gitAPI));
context.subscriptions.push(gitAPI.registerRemoteSourceProvider(new GithubRemoteSourceProvider()));
context.subscriptions.push(gitAPI.registerRemoteSourceProvider(new GithubRemoteSourceProvider(gitAPI)));
context.subscriptions.push(new GithubCredentialProviderManager(gitAPI));
}
/*---------------------------------------------------------------------------------------------
* 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';
const localize = nls.loadMessageBundle();
function sanitizeRepositoryName(value: string): string {
return value.trim().replace(/[^a-z0-9_.]/ig, '-');
}
function getPick<T extends vscode.QuickPickItem>(quickpick: vscode.QuickPick<T>): Promise<T | undefined> {
return Promise.race<T | undefined>([
new Promise<T>(c => quickpick.onDidAccept(() => quickpick.selectedItems.length > 0 && c(quickpick.selectedItems[0]))),
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
]);
}
export async function publishRepository(gitAPI: GitAPI, repository?: Repository): Promise<void> {
if (!vscode.workspace.workspaceFolders?.length) {
return;
}
let folder: vscode.WorkspaceFolder;
if (vscode.workspace.workspaceFolders.length === 1) {
folder = vscode.workspace.workspaceFolders[0];
} else {
const picks = vscode.workspace.workspaceFolders.map(folder => ({ label: folder.name, folder }));
const placeHolder = localize('pick folder', "Pick a folder to publish to GitHub");
const pick = await vscode.window.showQuickPick(picks, { placeHolder });
if (!pick) {
return;
}
folder = pick.folder;
}
const quickpick = vscode.window.createQuickPick<vscode.QuickPickItem & { repo?: string, auth?: 'https' | 'ssh' }>();
quickpick.ignoreFocusOut = true;
quickpick.placeholder = 'Repository Name';
quickpick.value = folder.name;
quickpick.show();
quickpick.busy = true;
const octokit = await getOctokit();
const user = await octokit.users.getAuthenticated({});
const owner = user.data.login;
quickpick.busy = false;
let repo: string | undefined;
const onDidChangeValue = async () => {
const sanitizedRepo = sanitizeRepositoryName(quickpick.value);
if (!sanitizedRepo) {
quickpick.items = [];
} else {
quickpick.items = [{ label: `$(repo) Create private repository`, description: `$(github) ${owner}/${sanitizedRepo}`, alwaysShow: true, repo: sanitizedRepo }];
}
};
onDidChangeValue();
while (true) {
const listener = quickpick.onDidChangeValue(onDidChangeValue);
const pick = await getPick(quickpick);
listener.dispose();
repo = pick?.repo;
if (repo) {
try {
quickpick.busy = true;
await octokit.repos.get({ owner, repo: repo });
quickpick.items = [{ label: `$(error) Repository already exists`, description: `$(github) ${owner}/${repo}`, alwaysShow: true }];
} catch {
break;
} finally {
quickpick.busy = false;
}
}
}
quickpick.dispose();
if (!repo) {
return;
}
const githubRepository = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, title: 'Publish to GitHub' }, async progress => {
progress.report({ message: 'Creating private repository in GitHub', increment: 25 });
const res = await octokit.repos.createForAuthenticatedUser({
name: repo!,
private: true
});
const createdGithubRepository = res.data;
progress.report({ message: 'Creating first commit', increment: 25 });
if (!repository) {
repository = await gitAPI.init(folder.uri) || undefined;
if (!repository) {
return;
}
await repository.commit('first commit', { all: true });
}
progress.report({ message: 'Uploading files', increment: 25 });
await repository.addRemote('origin', createdGithubRepository.clone_url);
await repository.push('origin', 'master', true);
return createdGithubRepository;
});
if (!githubRepository) {
return;
}
const openInGitHub = 'Open In GitHub';
const action = await vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub);
if (action === openInGitHub) {
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
}
}
......@@ -3,9 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RemoteSourceProvider, RemoteSource } from './typings/git';
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 {
......@@ -23,6 +24,8 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
private userReposCache: RemoteSource[] = [];
constructor(private gitAPI: GitAPI) { }
async getRemoteSources(query?: string): Promise<RemoteSource[]> {
const octokit = await getOctokit();
const [fromUser, fromQuery] = await Promise.all([
......@@ -57,4 +60,8 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
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);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册