Skip to content

Commit ee4e97f

Browse files
committed
publish command
1 parent 12b150a commit ee4e97f

3 files changed

Lines changed: 142 additions & 1 deletion

File tree

extensions/github/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@
1818
"vscode.git"
1919
],
2020
"main": "./out/extension.js",
21+
"contributes": {
22+
"commands": [
23+
{
24+
"command": "github.publish",
25+
"title": "Publish to GitHub"
26+
}
27+
]
28+
},
29+
"viewsWelcome": [
30+
{
31+
"view": "scm",
32+
"contents": "%welcome.publishFolder%",
33+
"when": "config.git.enabled && git.state == initialized && workbenchState == folder"
34+
}
35+
],
2136
"scripts": {
2237
"vscode:prepublish": "npm run compile",
2338
"compile": "gulp compile-extension:github",

extensions/github/package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"displayName": "GitHub",
3-
"description": "GitHub"
3+
"description": "GitHub",
4+
"welcome.publishFolder": "You can also directly publish this folder to a GitHub repository.\n[$(github) Publish to GitHub](command:github.publish)"
45
}

extensions/github/src/commands.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { API as GitAPI } from './typings/git';
8+
import { getOctokit } from './octokit';
9+
10+
function sanitizeRepositoryName(value: string): string {
11+
return value.trim().replace(/[^a-z0-9_.]/ig, '-');
12+
}
13+
14+
export function registerGlobalCommands(context: vscode.ExtensionContext, gitAPI: GitAPI) {
15+
async function publish(): Promise<void> {
16+
if (!vscode.workspace.workspaceFolders?.length) {
17+
return;
18+
}
19+
20+
const folder = vscode.workspace.workspaceFolders[0]; // TODO
21+
22+
const octokit = await getOctokit();
23+
const user = await octokit.users.getAuthenticated({});
24+
const owner = user.data.login;
25+
26+
const quickpick = vscode.window.createQuickPick<vscode.QuickPickItem & { repo?: string, auth?: 'https' | 'ssh' }>();
27+
quickpick.ignoreFocusOut = true;
28+
29+
quickpick.placeholder = 'Repository Name';
30+
quickpick.show();
31+
32+
let repo: string | undefined;
33+
34+
const onDidChangeValue = async () => {
35+
const sanitizedRepo = sanitizeRepositoryName(quickpick.value);
36+
37+
if (!sanitizedRepo) {
38+
quickpick.items = [];
39+
} else {
40+
quickpick.items = [{ label: `$(repo) Create private repository`, description: `$(github) ${owner}/${sanitizedRepo}`, alwaysShow: true, repo: sanitizedRepo }];
41+
}
42+
};
43+
44+
quickpick.value = folder.name;
45+
onDidChangeValue();
46+
47+
while (true) {
48+
const listener = quickpick.onDidChangeValue(onDidChangeValue);
49+
const pick = await getPick(quickpick);
50+
listener.dispose();
51+
52+
repo = pick?.repo;
53+
54+
if (repo) {
55+
try {
56+
quickpick.busy = true;
57+
await octokit.repos.get({ owner, repo: repo });
58+
quickpick.items = [{ label: `$(error) Repository already exists`, description: `$(github) ${owner}/${repo}`, alwaysShow: true }];
59+
} catch {
60+
break;
61+
} finally {
62+
quickpick.busy = false;
63+
}
64+
}
65+
}
66+
67+
quickpick.dispose();
68+
69+
if (!repo) {
70+
return;
71+
}
72+
73+
const githubRepository = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, title: 'Publish to GitHub' }, async progress => {
74+
progress.report({ message: 'Creating private repository in GitHub', increment: 25 });
75+
76+
const res = await octokit.repos.createForAuthenticatedUser({
77+
name: repo!,
78+
private: true
79+
});
80+
81+
const createdGithubRepository = res.data;
82+
83+
progress.report({ message: 'Creating first commit', increment: 25 });
84+
const repository = await gitAPI.init(folder.uri);
85+
86+
if (!repository) {
87+
return;
88+
}
89+
90+
await repository.commit('first commit', { all: true });
91+
92+
progress.report({ message: 'Uploading files', increment: 25 });
93+
await repository.addRemote('origin', createdGithubRepository.clone_url);
94+
await repository.push('origin', 'master', true);
95+
96+
return createdGithubRepository;
97+
});
98+
99+
if (!githubRepository) {
100+
return;
101+
}
102+
103+
const openInGitHub = 'Open In GitHub';
104+
const action = await vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub);
105+
106+
if (action === openInGitHub) {
107+
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
108+
}
109+
}
110+
111+
context.subscriptions.push(vscode.commands.registerCommand('github.publish', async () => {
112+
try {
113+
publish();
114+
} catch (err) {
115+
vscode.window.showErrorMessage(err.message);
116+
}
117+
}));
118+
}
119+
120+
function getPick<T extends vscode.QuickPickItem>(quickpick: vscode.QuickPick<T>): Promise<T | undefined> {
121+
return Promise.race<T | undefined>([
122+
new Promise<T>(c => quickpick.onDidAccept(() => quickpick.selectedItems.length > 0 && c(quickpick.selectedItems[0]))),
123+
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
124+
]);
125+
}

0 commit comments

Comments
 (0)