Skip to content

Commit

Permalink
fix: merge_requests page & sync sourcegraph repo (conwnet#551)
Browse files Browse the repository at this point in the history
  • Loading branch information
conwnet authored Feb 24, 2024
1 parent 081c786 commit 461c6e9
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 102 deletions.
4 changes: 2 additions & 2 deletions extensions/github1s/assets/pages/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const bridgeCommands = {
openDetailPage: () => postMessage('open-detail-page'),
OAuthAuthenticate: () => postMessage('oauth-authorizing'),
alertMessage: (messageArgs) => postMessage('call-vscode-message-api', messageArgs),
getUseSgApiFirst: () => postMessage('get-use-sourcegraph-api'),
setUseSgApiFirst: (value) => postMessage('set-use-sourcegraph-api', value),
getPreferSgApi: () => postMessage('get-prefer-sourcegraph-api'),
setPreferSgApi: (value) => postMessage('set-prefer-sourcegraph-api', value),
getNotice: () => postMessage('get-notice'),
};
6 changes: 1 addition & 5 deletions extensions/github1s/assets/pages/github1s-settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@

.page-description {
font-size: 12px;
margin-bottom: 10px;
}

.page-description div {
margin-bottom: 5px;
margin-bottom: 12px;
}

.description div:last-child {
Expand Down
28 changes: 14 additions & 14 deletions extensions/github1s/assets/pages/github1s-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,41 +104,41 @@ export const TokenDetailBlock = ({ token, validating, onEditClick, validateToken
};

const PageFooter = () => {
const [sgApiFirst, setSgApiFirst] = useState(false);
const [preferSgApi, setPreferSgApi] = useState(false);

const updateSgApiFirst = useCallback(() => {
bridgeCommands.getUseSgApiFirst().then((value) => {
setSgApiFirst(value);
const updatePreferSgApi = useCallback(() => {
bridgeCommands.getPreferSgApi().then((value) => {
setPreferSgApi(value);
});
}, []);

const handleCheckboxChange = useCallback(
(event) => {
bridgeCommands.setUseSgApiFirst(event.target.checked).then(() => {
updateSgApiFirst();
bridgeCommands.setPreferSgApi(event.target.checked).then(() => {
updatePreferSgApi();
});
},
[updateSgApiFirst]
[updatePreferSgApi]
);

useEffect(() => {
const handler = ({ data }) => {
if (data.type === 'use-sourcegraph-api-first-changed') {
setSgApiFirst(data.value);
if (data.type === 'prefer-sourcegraph-api-changed') {
updatePreferSgApi();
}
};
window.addEventListener('message', handler);
return () => window.removeEventListener('message', handler);
}, []);

useEffect(() => {
updateSgApiFirst();
}, [updateSgApiFirst]);
updatePreferSgApi();
}, [updatePreferSgApi]);

return html`
<div class="page-footer">
<input type="checkbox" checked=${sgApiFirst} onChange=${handleCheckboxChange} />
<span>Use Sourcegraph API first in this repository</span>
<input type="checkbox" checked=${preferSgApi} onChange=${handleCheckboxChange} />
<span>Prefer to use Sourcegraph API</span>
</div>
`;
};
Expand Down Expand Up @@ -184,7 +184,7 @@ const TokenDetailPage = ({ token, onEditClick, ...props }) => {
return html`
<div class="token-detail-page" ...${props}>
<${PageHeader} title="You have authenticated">
${validating ? html`<${VscodeLoading} dots=${8} align="left" style="height: 12px" />` : validateResult}
${validating ? html`<${VscodeLoading} dots=${8} align="left" style="height: 14px" />` : validateResult}
<//>
<${TokenDetailBlock}
token=${token}
Expand Down
6 changes: 6 additions & 0 deletions extensions/github1s/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@
"category": "GitHub1s",
"icon": "$(globe)",
"enablement": "github1s:adapters:default:platformName != 'GitHub' && github1s:adapters:default:platformName != 'GitLab' && github1s:adapters:default:platformName != 'Bitbucket' && github1s:adapters:default:platformName != 'npm'"
},
{
"command": "github1s.commands.syncSourcegraphRepository",
"title": "Sync Sourcegraph Repository",
"category": "GitHub1s",
"enablement": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)/"
}
],
"colors": [
Expand Down
2 changes: 1 addition & 1 deletion extensions/github1s/src/adapters/github1s/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const trySourcegraphApiFirst = (_target: any, propertyKey: string, descriptor: P

descriptor.value = async function <T extends (...args) => Promise<any>>(...args: Parameters<T>) {
const githubFetcher = GitHubFetcher.getInstance();
if (await githubFetcher.useSourcegraphApiFirst(args[0])) {
if (await githubFetcher.getPreferSourcegraphApi(args[0])) {
try {
return await sourcegraphDataSource[propertyKey](...args);
} catch (e) {}
Expand Down
69 changes: 36 additions & 33 deletions extensions/github1s/src/adapters/github1s/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

(self as any).global = self;
import * as vscode from 'vscode';
import { getBrowserUrl, getExtensionContext } from '@/helpers/context';
import { getExtensionContext } from '@/helpers/context';
import { Octokit } from '@octokit/core';
import { GitHub1sAuthenticationView } from './authentication';
import { GitHubTokenManager } from './token';
import { isNil } from '@/helpers/util';
import { decorate, memorize } from '@/helpers/func';
import { DEFAULT_REPO } from './parse-path';
import { getCurrentRepo } from './parse-path';
import { SourcegraphDataSource } from '../sourcegraph/data-source';

export const errorMessages = {
rateLimited: {
Expand Down Expand Up @@ -48,13 +48,13 @@ const detectErrorMessage = (response: any, authenticated: boolean) => {
return response?.data?.message || '';
};

const USE_SOURCEGRAPH_API_FIRST = 'USE_SOURCEGRAPH_API_FIRST';
const PREFER_SOURCEGRAPH_API = 'PREFER_SOURCEGRAPH_API';

export class GitHubFetcher {
private static instance: GitHubFetcher | null = null;
private _emitter = new vscode.EventEmitter<boolean | null | undefined>();
private _originalRequest: Octokit['request'] | null = null;
public onDidChangeUseSourcegraphApiFirst = this._emitter.event;
private _request: Octokit['request'] | null = null;
public onDidChangePreferSourcegraphApi = this._emitter.event;
private _currentRepoPromise: Promise<any> | null = null;

public request: Octokit['request'];
Expand All @@ -69,28 +69,29 @@ export class GitHubFetcher {

private constructor() {
this.initFetcherMethods();
this.initPreferSourcegraphApi();
GitHubTokenManager.getInstance().onDidChangeToken(() => this.initFetcherMethods());
GitHubTokenManager.getInstance().onDidChangeToken(() => this.checkCurrentRepo(true));
GitHubTokenManager.getInstance().onDidChangeToken(() => this.initPreferSourcegraphApi());
}

// initial fetcher methods in this way for correct `request/graphql` type inference
initFetcherMethods() {
const accessToken = GitHubTokenManager.getInstance().getToken();
const octokit = new Octokit({ auth: accessToken, request: { fetch }, baseUrl: GITHUB_API_PREFIX });

this._originalRequest = octokit.request;
this._request = octokit.request;
this.request = Object.assign((...args: Parameters<Octokit['request']>) => {
return octokit.request(...args).catch(async (error) => {
const errorStatus = error?.response?.status as number | undefined;
const repoNotFound = errorStatus === 404 && !(await this.checkCurrentRepo());
const repoNotFound = errorStatus === 404 && !(await this.resolveCurrentRepo());
if ((errorStatus && [401, 403].includes(errorStatus)) || repoNotFound) {
// maybe we have to acquire github access token to continue
const message = detectErrorMessage(error?.response, !!accessToken);
await GitHub1sAuthenticationView.getInstance().open(message, true);
return this._originalRequest!(...args);
return this._request!(...args);
}
});
}, this._originalRequest);
}, this._request);

this.graphql = Object.assign(async (...args: Parameters<Octokit['graphql']>) => {
if (!GitHubTokenManager.getInstance().getToken()) {
Expand All @@ -101,38 +102,40 @@ export class GitHubFetcher {
}, octokit.graphql);
}

@decorate(memorize)
private getCurrentRepo() {
return getBrowserUrl().then((browserUrl: string) => {
const pathParts = vscode.Uri.parse(browserUrl).path.split('/').filter(Boolean);
return pathParts.length >= 2 ? (pathParts.slice(0, 2) as [string, string]).join('/') : DEFAULT_REPO;
});
}

private checkCurrentRepo(forceUpdate: boolean = false) {
private resolveCurrentRepo(forceUpdate: boolean = false) {
if (this._currentRepoPromise && !forceUpdate) {
return this._currentRepoPromise;
}
return (this._currentRepoPromise = Promise.resolve(this.getCurrentRepo()).then(async (repoFullName) => {
const [owner, repo] = repoFullName.split('/');
const response = await this._originalRequest?.('GET /repos/{owner}/{repo}', { owner, repo });
response?.data?.private && (await this.setUseSourcegraphApiFirst(false));
return response?.data || null;
})).catch(() => null);
const requestPattern = '/repos/{owner}/{repo}' as const;
const getOwnerRepo = () => getCurrentRepo().then((repo) => repo.split('/'));
return (this._currentRepoPromise = Promise.resolve(getOwnerRepo())
.then(([owner, repo]) => this._request?.(requestPattern, { owner, repo }).then((res) => res.data))
.catch(() => null));
}

private async initPreferSourcegraphApi() {
if (await this.getPreferSourcegraphApi()) {
const sgDataSource = SourcegraphDataSource.getInstance('github');
if (!(await sgDataSource.provideRepository(await getCurrentRepo()))) {
this.resolveCurrentRepo(true).then((repo) => {
repo?.private && this.setPreferSourcegraphApi(false);
});
}
}
}

public async useSourcegraphApiFirst(repo?: string): Promise<boolean> {
const targetRepo = repo || (await this.getCurrentRepo());
public async getPreferSourcegraphApi(repo?: string): Promise<boolean> {
const targetRepo = repo || (await getCurrentRepo());
const globalState = getExtensionContext().globalState;
const cachedData: Record<string, boolean> | undefined = globalState.get(USE_SOURCEGRAPH_API_FIRST);
const cachedData: Record<string, boolean> | undefined = globalState.get(PREFER_SOURCEGRAPH_API);
return !isNil(cachedData?.[targetRepo]) ? !!cachedData?.[targetRepo] : true;
}

public async setUseSourcegraphApiFirst(value: boolean, repo?: string) {
const targetRepo = repo || (await this.getCurrentRepo());
public async setPreferSourcegraphApi(value: boolean, repo?: string) {
const targetRepo = repo || (await getCurrentRepo());
const globalState = getExtensionContext().globalState;
const cachedData: Record<string, boolean> | undefined = globalState.get(USE_SOURCEGRAPH_API_FIRST);
await globalState.update(USE_SOURCEGRAPH_API_FIRST, { ...cachedData, [targetRepo]: value });
const cachedData: Record<string, boolean> | undefined = globalState.get(PREFER_SOURCEGRAPH_API);
await globalState.update(PREFER_SOURCEGRAPH_API, { ...cachedData, [targetRepo]: value });
this._emitter.fire(value);
}
}
7 changes: 7 additions & 0 deletions extensions/github1s/src/adapters/github1s/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { GitHub1sRouterParser } from './router-parser';
import { GitHub1sSettingsViewProvider } from './settings';
import { GitHub1sAuthenticationView } from './authentication';
import { Adapter, CodeReviewType, PlatformName } from '../types';
import { SourcegraphDataSource } from '../sourcegraph/data-source';
import { getCurrentRepo } from './parse-path';

export class GitHub1sAdapter implements Adapter {
public scheme: string = 'github1s';
Expand Down Expand Up @@ -39,6 +41,11 @@ export class GitHub1sAdapter implements Adapter {
vscode.commands.registerCommand('github1s.commands.openGitHub1sAuthPage', () => {
return GitHub1sAuthenticationView.getInstance().open();
});
vscode.commands.registerCommand('github1s.commands.syncSourcegraphRepository', async () => {
const dataSource = SourcegraphDataSource.getInstance('github');
const randomRef = (Math.random() + 1).toString(36).slice(2);
return dataSource.provideCommit(await getCurrentRepo(), randomRef);
});
}

deactivateAsDefault() {
Expand Down
12 changes: 11 additions & 1 deletion extensions/github1s/src/adapters/github1s/parse-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@
* @author netcon
*/

import * as vscode from 'vscode';
import { parsePath } from 'history';
import { PageType, RouterState } from '@/adapters/types';
import { GitHub1sDataSource } from './data-source';
import * as queryString from 'query-string';
import { memorize } from '@/helpers/func';
import { getBrowserUrl } from '@/helpers/context';

export const DEFAULT_REPO = 'conwnet/github1s';

const getDefaultBranch = async (repo: string): Promise<string> => {
export const getCurrentRepo = memorize(() => {
return getBrowserUrl().then((browserUrl: string) => {
const pathParts = vscode.Uri.parse(browserUrl).path.split('/').filter(Boolean);
return pathParts.length >= 2 ? (pathParts.slice(0, 2) as [string, string]).join('/') : DEFAULT_REPO;
});
});

export const getDefaultBranch = async (repo: string): Promise<string> => {
const dataSource = GitHub1sDataSource.getInstance();
return dataSource.getDefaultBranch(repo);
};
Expand Down
14 changes: 7 additions & 7 deletions extensions/github1s/src/adapters/github1s/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class GitHub1sSettingsViewProvider implements vscode.WebviewViewProvider
protected tokenManager = GitHubTokenManager.getInstance();
protected apiFetcher: Pick<
GitHubFetcher,
'useSourcegraphApiFirst' | 'setUseSourcegraphApiFirst' | 'onDidChangeUseSourcegraphApiFirst'
'getPreferSourcegraphApi' | 'setPreferSourcegraphApi' | 'onDidChangePreferSourcegraphApi'
> = GitHubFetcher.getInstance();

protected pageTitle = 'GitHub1s Settings';
Expand Down Expand Up @@ -68,11 +68,11 @@ export class GitHub1sSettingsViewProvider implements vscode.WebviewViewProvider
const messageApi = messageApiMap[message.data?.level];
messageApi && messageApi(...message.data?.args).then((response) => postMessage(response));
break;
case 'get-use-sourcegraph-api':
this.apiFetcher.useSourcegraphApiFirst().then((value) => postMessage(value));
case 'get-prefer-sourcegraph-api':
this.apiFetcher.getPreferSourcegraphApi().then((value) => postMessage(value));
break;
case 'set-use-sourcegraph-api':
this.apiFetcher.setUseSourcegraphApiFirst(message.data);
case 'set-prefer-sourcegraph-api':
this.apiFetcher.setPreferSourcegraphApi(message.data);
postMessage(message.data);
break;
}
Expand All @@ -81,8 +81,8 @@ export class GitHub1sSettingsViewProvider implements vscode.WebviewViewProvider
this.tokenManager.onDidChangeToken((token) => {
webviewView.webview.postMessage({ type: 'token-changed', token });
});
this.apiFetcher.onDidChangeUseSourcegraphApiFirst((value) => {
webviewView.webview.postMessage({ type: 'use-sourcegraph-api-first-changed', value });
this.apiFetcher.onDidChangePreferSourcegraphApi((value) => {
webviewView.webview.postMessage({ type: 'prefer-sourcegraph-api-changed', value });
});
}

Expand Down
2 changes: 1 addition & 1 deletion extensions/github1s/src/adapters/gitlab1s/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const trySourcegraphApiFirst = (_target: any, propertyKey: string, descriptor: P

descriptor.value = async function <T extends (...args) => Promise<any>>(...args: Parameters<T>) {
const gitlabFetcher = GitLabFetcher.getInstance();
if (await gitlabFetcher.useSourcegraphApiFirst(args[0])) {
if (await gitlabFetcher.getPreferSourcegraphApi(args[0])) {
try {
return await sourcegraphDataSource[propertyKey](...args);
} catch (e) {}
Expand Down
Loading

0 comments on commit 461c6e9

Please sign in to comment.