From a8ba7f7dd68c44176398bec89bf633f81b43fd84 Mon Sep 17 00:00:00 2001 From: TJ Kandala Date: Wed, 6 Jan 2021 16:24:23 -0500 Subject: [PATCH 1/4] fix: build task --- .vscode/tasks.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e7b2b0c8..54198850 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,5 +9,10 @@ "reveal": "never", }, }, + { + "type": "npm", + "script": "build", + "label": "build", + }, ], } From 5094740bcacb4fc0f9f0fd86d9c0d7839c0d9018 Mon Sep 17 00:00:00 2001 From: TJ Kandala Date: Wed, 6 Jan 2021 16:28:11 -0500 Subject: [PATCH 2/4] refactor: simplify gitRemoteBranch, return objects --- src/extension.ts | 4 +- src/git.ts | 120 +++++++++++++++++++++++++---------------------- 2 files changed, 65 insertions(+), 59 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index b6971c10..d5b7a1f9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -31,7 +31,7 @@ async function openCommand(): Promise { if (!editor) { throw new Error('No active editor') } - const [remoteURL, branch, fileRelative] = await repoInfo(editor.document.uri.fsPath) + const { remoteURL, branch, fileRelative } = await repoInfo(editor.document.uri.fsPath) if (remoteURL === '') { return } @@ -59,7 +59,7 @@ async function searchCommand(): Promise { if (!editor) { throw new Error('No active editor') } - const [remoteURL, branch, fileRelative] = await repoInfo(editor.document.uri.fsPath) + const { remoteURL, branch, fileRelative } = await repoInfo(editor.document.uri.fsPath) const query = editor.document.getText(editor.selection) if (query === '') { diff --git a/src/git.ts b/src/git.ts index ea892745..5669702a 100644 --- a/src/git.ts +++ b/src/git.ts @@ -4,26 +4,12 @@ import { log } from './log' import { getRemoteUrlReplacements } from './config' /** - * Returns [remote, upstream branch]. - * Empty remote is returned if the upstream branch points to a local branch. - * Empty upstream branch is returned if there is no upstream branch. + * Returns the repository root directory for any directory within the + * repository. */ -async function gitRemoteBranch(repoDirectory: string): Promise<[string, string]> { - try { - const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD@{upstream}'], { cwd: repoDirectory }) - const remoteAndBranch = stdout.split('/') - if (remoteAndBranch.length === 2) { - const [remote, branch] = remoteAndBranch - return [remote, branch] - } - if (remoteAndBranch.length === 1) { - // The upstream branch points to a local branch. - return ['', remoteAndBranch[0]] - } - return ['', ''] - } catch { - return ['', ''] - } +async function gitRootDirectory(repoDirectory: string): Promise { + const { stdout } = await execa('git', ['rev-parse', '--show-toplevel'], { cwd: repoDirectory }) + return stdout } /** @@ -38,7 +24,7 @@ async function gitRemotes(repoDirectory: string): Promise { * Returns the remote URL for the given remote name. * e.g. `origin` -> `git@github.com:foo/bar` */ -async function gitRemoteURL(repoDirectory: string, remoteName: string): Promise { +async function gitRemoteURL(repoDirectory: string, { remoteName }: RemoteName): Promise { let { stdout } = await execa('git', ['remote', 'get-url', remoteName], { cwd: repoDirectory }) const replacementsList = getRemoteUrlReplacements() @@ -51,48 +37,64 @@ async function gitRemoteURL(repoDirectory: string, remoteName: string): Promise< return stdout } +interface RemoteName { + /** + * Remote name of the upstream repository, + * or the first remote name if no upstream is found + */ + remoteName: string +} + +interface Branch { + /** + * Remote branch name, or 'HEAD' if it isn't found because + * e.g. detached HEAD state, upstream branch points to a local branch + */ + branch: string +} + /** - * Returns the remote URL. + * Returns the remote name and branch + * + * @param repoDirectory the repository root directory */ -async function gitDefaultRemoteURL(repoDirectory: string): Promise { - const [remote] = await gitRemoteBranch(repoDirectory) - if (remote !== '') { - return gitRemoteURL(repoDirectory, remote) +async function gitRemoteNameAndBranch(repoDirectory: string): Promise { + let remoteName = '' + let branch = 'HEAD' + + const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD@{upstream}'], { cwd: repoDirectory }) + const remoteAndBranch = stdout.split('/') + + if (remoteAndBranch.length === 1) { + // The upstream branch points to a local branch. + ;[remoteName] = remoteAndBranch + } + if (remoteAndBranch.length === 2) { + ;[remoteName, branch] = remoteAndBranch } // If we cannot find the remote name deterministically, we use the first // Git remote found. - const remotes = await gitRemotes(repoDirectory) - if (remotes.length === 0) { - throw new Error('no configured git remotes') - } - if (remotes.length > 1) { - log.appendLine(`using first git remote: ${remotes[0]}`) + if (!remoteName) { + const remotes = await gitRemotes(repoDirectory) + if (remotes.length === 0) { + throw new Error('no configured git remotes') + } + if (remotes.length > 1) { + log.appendLine(`using first git remote: ${remotes[0]}`) + remoteName = remotes[0] + } } - return gitRemoteURL(repoDirectory, remotes[0]) -} -/** - * Returns the repository root directory for any directory within the - * repository. - */ -async function gitRootDirectory(repoDirectory: string): Promise { - const { stdout } = await execa('git', ['rev-parse', '--show-toplevel'], { cwd: repoDirectory }) - return stdout + return { remoteName, branch } } -/** - * Returns either the current remote branch name of the repository OR in all - * other cases (e.g. detached HEAD state, upstream branch points to a local - * branch), it returns "HEAD". - */ -async function gitBranch(repoDirectory: string): Promise { - const [origin, branch] = await gitRemoteBranch(repoDirectory) - if (origin !== '') { - // The remote branch exists. - return branch - } - return 'HEAD' +interface RepositoryInfo extends Branch { + /** Git repository remote URL */ + remoteURL: string + + /** File path relative to the repository root */ + fileRelative: string } /** @@ -100,7 +102,7 @@ async function gitBranch(repoDirectory: string): Promise { * relative to the repository root. Empty strings are returned if this cannot be * determined. */ -export async function repoInfo(filePath: string): Promise<[string, string, string]> { +export async function repoInfo(filePath: string): Promise { let remoteURL = '' let branch = '' let fileRelative = '' @@ -109,10 +111,13 @@ export async function repoInfo(filePath: string): Promise<[string, string, strin const fileDirectory = path.dirname(filePath) const repoRoot = await gitRootDirectory(fileDirectory) - // Determine file path, relative to repository root. + // Determine file path relative to repository root. fileRelative = filePath.slice(repoRoot.length + 1) - remoteURL = await gitDefaultRemoteURL(repoRoot) - branch = await gitBranch(repoRoot) + + const remoteNameAndBranch = await gitRemoteNameAndBranch(repoRoot) + branch = remoteNameAndBranch.branch + remoteURL = await gitRemoteURL(repoRoot, remoteNameAndBranch) + if (process.platform === 'win32') { fileRelative = fileRelative.replace(/\\/g, '/') } @@ -120,5 +125,6 @@ export async function repoInfo(filePath: string): Promise<[string, string, strin log.appendLine(`repoInfo(${filePath}): ${error as string}`) } log.appendLine(`repoInfo(${filePath}): remoteURL="${remoteURL}" branch="${branch}" fileRel="${fileRelative}"`) - return [remoteURL, branch, fileRelative] + return { remoteURL, branch, fileRelative } } + From df1760b42b47e22712983c785b36e52fe952b633 Mon Sep 17 00:00:00 2001 From: TJ Kandala Date: Wed, 6 Jan 2021 16:38:29 -0500 Subject: [PATCH 3/4] fix: prettier --- src/git.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/git.ts b/src/git.ts index 5669702a..47a69f4d 100644 --- a/src/git.ts +++ b/src/git.ts @@ -127,4 +127,3 @@ export async function repoInfo(filePath: string): Promise { log.appendLine(`repoInfo(${filePath}): remoteURL="${remoteURL}" branch="${branch}" fileRel="${fileRelative}"`) return { remoteURL, branch, fileRelative } } - From 618ca5b21e321abb2db1c0721fd627863860b297 Mon Sep 17 00:00:00 2001 From: TJ Kandala Date: Tue, 19 Jan 2021 19:11:00 -0500 Subject: [PATCH 4/4] refactor: simplify repoInfo return type --- src/extension.ts | 11 ++++++++--- src/git.ts | 33 ++++++++++++++++----------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index d5b7a1f9..9c0361a4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -31,10 +31,11 @@ async function openCommand(): Promise { if (!editor) { throw new Error('No active editor') } - const { remoteURL, branch, fileRelative } = await repoInfo(editor.document.uri.fsPath) - if (remoteURL === '') { + const repositoryInfo = await repoInfo(editor.document.uri.fsPath) + if (!repositoryInfo) { return } + const { remoteURL, branch, fileRelative } = repositoryInfo // Open in browser. await open( @@ -59,7 +60,11 @@ async function searchCommand(): Promise { if (!editor) { throw new Error('No active editor') } - const { remoteURL, branch, fileRelative } = await repoInfo(editor.document.uri.fsPath) + const repositoryInfo = await repoInfo(editor.document.uri.fsPath) + if (!repositoryInfo) { + return + } + const { remoteURL, branch, fileRelative } = repositoryInfo const query = editor.document.getText(editor.selection) if (query === '') { diff --git a/src/git.ts b/src/git.ts index 47a69f4d..edc5a0c4 100644 --- a/src/git.ts +++ b/src/git.ts @@ -24,7 +24,7 @@ async function gitRemotes(repoDirectory: string): Promise { * Returns the remote URL for the given remote name. * e.g. `origin` -> `git@github.com:foo/bar` */ -async function gitRemoteURL(repoDirectory: string, { remoteName }: RemoteName): Promise { +async function gitRemoteURL(repoDirectory: string, remoteName: string): Promise { let { stdout } = await execa('git', ['remote', 'get-url', remoteName], { cwd: repoDirectory }) const replacementsList = getRemoteUrlReplacements() @@ -40,7 +40,7 @@ async function gitRemoteURL(repoDirectory: string, { remoteName }: RemoteName): interface RemoteName { /** * Remote name of the upstream repository, - * or the first remote name if no upstream is found + * or the first found remote name if no upstream is found */ remoteName: string } @@ -59,7 +59,7 @@ interface Branch { * @param repoDirectory the repository root directory */ async function gitRemoteNameAndBranch(repoDirectory: string): Promise { - let remoteName = '' + let remoteName: string | undefined let branch = 'HEAD' const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD@{upstream}'], { cwd: repoDirectory }) @@ -77,15 +77,17 @@ async function gitRemoteNameAndBranch(repoDirectory: string): Promise 1) { log.appendLine(`using first git remote: ${remotes[0]}`) remoteName = remotes[0] } } + // Throw if a remote still isn't found + if (!remoteName) { + throw new Error('no configured git remotes') + } + return { remoteName, branch } } @@ -99,31 +101,28 @@ interface RepositoryInfo extends Branch { /** * Returns the Git repository remote URL, the current branch, and the file path - * relative to the repository root. Empty strings are returned if this cannot be - * determined. + * relative to the repository root. Returns undefined if no remote is found */ -export async function repoInfo(filePath: string): Promise { - let remoteURL = '' - let branch = '' - let fileRelative = '' +export async function repoInfo(filePath: string): Promise { try { // Determine repository root directory. const fileDirectory = path.dirname(filePath) const repoRoot = await gitRootDirectory(fileDirectory) // Determine file path relative to repository root. - fileRelative = filePath.slice(repoRoot.length + 1) + let fileRelative = filePath.slice(repoRoot.length + 1) const remoteNameAndBranch = await gitRemoteNameAndBranch(repoRoot) - branch = remoteNameAndBranch.branch - remoteURL = await gitRemoteURL(repoRoot, remoteNameAndBranch) + const { branch, remoteName } = remoteNameAndBranch + const remoteURL = await gitRemoteURL(repoRoot, remoteName) if (process.platform === 'win32') { fileRelative = fileRelative.replace(/\\/g, '/') } + log.appendLine(`repoInfo(${filePath}): remoteURL="${remoteURL}" branch="${branch}" fileRel="${fileRelative}"`) + return { remoteURL, branch, fileRelative } } catch (error) { log.appendLine(`repoInfo(${filePath}): ${error as string}`) + return undefined } - log.appendLine(`repoInfo(${filePath}): remoteURL="${remoteURL}" branch="${branch}" fileRel="${fileRelative}"`) - return { remoteURL, branch, fileRelative } }