116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* 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 parse(url: string): { owner: string, repo: string } | undefined {
|
|
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i.exec(url)
|
|
|| /^git@github\.com:([^/]+)\/([^/]+)\.git/i.exec(url);
|
|
return (match && { owner: match[1], repo: match[2] }) ?? undefined;
|
|
}
|
|
|
|
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();
|
|
|
|
if (query) {
|
|
const repository = parse(query);
|
|
|
|
if (repository) {
|
|
const raw = await octokit.repos.get(repository);
|
|
return [asRemoteSource(raw.data)];
|
|
}
|
|
}
|
|
|
|
const all = await Promise.all([
|
|
this.getQueryRemoteSources(octokit, query),
|
|
this.getUserRemoteSources(octokit, query),
|
|
]);
|
|
|
|
const map = new Map<string, RemoteSource>();
|
|
|
|
for (const group of all) {
|
|
for (const remoteSource of group) {
|
|
map.set(remoteSource.name, remoteSource);
|
|
}
|
|
}
|
|
|
|
return [...map.values()];
|
|
}
|
|
|
|
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: 'stars' });
|
|
return raw.data.items.map(asRemoteSource);
|
|
}
|
|
|
|
async getBranches(url: string): Promise<string[]> {
|
|
const repository = parse(url);
|
|
|
|
if (!repository) {
|
|
return [];
|
|
}
|
|
|
|
const octokit = await getOctokit();
|
|
|
|
const branches: string[] = [];
|
|
let page = 1;
|
|
|
|
while (true) {
|
|
let res = await octokit.repos.listBranches({ ...repository, per_page: 100, page });
|
|
|
|
if (res.data.length === 0) {
|
|
break;
|
|
}
|
|
|
|
branches.push(...res.data.map(b => b.name));
|
|
page++;
|
|
}
|
|
|
|
const repo = await octokit.repos.get(repository);
|
|
const defaultBranch = repo.data.default_branch;
|
|
|
|
return branches.sort((a, b) => a === defaultBranch ? -1 : b === defaultBranch ? 1 : 0);
|
|
}
|
|
|
|
publishRepository(repository: Repository): Promise<void> {
|
|
return publishRepository(this.gitAPI, repository);
|
|
}
|
|
}
|