@@ -4,26 +4,12 @@ import { log } from './log'
44import { getRemoteUrlReplacements } from './config'
55
66/**
7- * Returns [remote, upstream branch].
8- * Empty remote is returned if the upstream branch points to a local branch.
9- * Empty upstream branch is returned if there is no upstream branch.
7+ * Returns the repository root directory for any directory within the
8+ * repository.
109 */
11- async function gitRemoteBranch ( repoDirectory : string ) : Promise < [ string , string ] > {
12- try {
13- const { stdout } = await execa ( 'git' , [ 'rev-parse' , '--abbrev-ref' , 'HEAD@{upstream}' ] , { cwd : repoDirectory } )
14- const remoteAndBranch = stdout . split ( '/' )
15- if ( remoteAndBranch . length === 2 ) {
16- const [ remote , branch ] = remoteAndBranch
17- return [ remote , branch ]
18- }
19- if ( remoteAndBranch . length === 1 ) {
20- // The upstream branch points to a local branch.
21- return [ '' , remoteAndBranch [ 0 ] ]
22- }
23- return [ '' , '' ]
24- } catch {
25- return [ '' , '' ]
26- }
10+ async function gitRootDirectory ( repoDirectory : string ) : Promise < string > {
11+ const { stdout } = await execa ( 'git' , [ 'rev-parse' , '--show-toplevel' ] , { cwd : repoDirectory } )
12+ return stdout
2713}
2814
2915/**
@@ -51,74 +37,92 @@ async function gitRemoteURL(repoDirectory: string, remoteName: string): Promise<
5137 return stdout
5238}
5339
40+ interface RemoteName {
41+ /**
42+ * Remote name of the upstream repository,
43+ * or the first found remote name if no upstream is found
44+ */
45+ remoteName : string
46+ }
47+
48+ interface Branch {
49+ /**
50+ * Remote branch name, or 'HEAD' if it isn't found because
51+ * e.g. detached HEAD state, upstream branch points to a local branch
52+ */
53+ branch : string
54+ }
55+
5456/**
55- * Returns the remote URL.
57+ * Returns the remote name and branch
58+ *
59+ * @param repoDirectory the repository root directory
5660 */
57- async function gitDefaultRemoteURL ( repoDirectory : string ) : Promise < string > {
58- const [ remote ] = await gitRemoteBranch ( repoDirectory )
59- if ( remote !== '' ) {
60- return gitRemoteURL ( repoDirectory , remote )
61+ async function gitRemoteNameAndBranch ( repoDirectory : string ) : Promise < RemoteName & Branch > {
62+ let remoteName : string | undefined
63+ let branch = 'HEAD'
64+
65+ const { stdout } = await execa ( 'git' , [ 'rev-parse' , '--abbrev-ref' , 'HEAD@{upstream}' ] , { cwd : repoDirectory } )
66+ const remoteAndBranch = stdout . split ( '/' )
67+
68+ if ( remoteAndBranch . length === 1 ) {
69+ // The upstream branch points to a local branch.
70+ ; [ remoteName ] = remoteAndBranch
71+ }
72+ if ( remoteAndBranch . length === 2 ) {
73+ ; [ remoteName , branch ] = remoteAndBranch
6174 }
6275
6376 // If we cannot find the remote name deterministically, we use the first
6477 // Git remote found.
65- const remotes = await gitRemotes ( repoDirectory )
66- if ( remotes . length === 0 ) {
67- throw new Error ( 'no configured git remotes' )
78+ if ( ! remoteName ) {
79+ const remotes = await gitRemotes ( repoDirectory )
80+ if ( remotes . length > 1 ) {
81+ log . appendLine ( `using first git remote: ${ remotes [ 0 ] } ` )
82+ remoteName = remotes [ 0 ]
83+ }
6884 }
69- if ( remotes . length > 1 ) {
70- log . appendLine ( `using first git remote: ${ remotes [ 0 ] } ` )
85+
86+ // Throw if a remote still isn't found
87+ if ( ! remoteName ) {
88+ throw new Error ( 'no configured git remotes' )
7189 }
72- return gitRemoteURL ( repoDirectory , remotes [ 0 ] )
73- }
7490
75- /**
76- * Returns the repository root directory for any directory within the
77- * repository.
78- */
79- async function gitRootDirectory ( repoDirectory : string ) : Promise < string > {
80- const { stdout } = await execa ( 'git' , [ 'rev-parse' , '--show-toplevel' ] , { cwd : repoDirectory } )
81- return stdout
91+ return { remoteName, branch }
8292}
8393
84- /**
85- * Returns either the current remote branch name of the repository OR in all
86- * other cases (e.g. detached HEAD state, upstream branch points to a local
87- * branch), it returns "HEAD".
88- */
89- async function gitBranch ( repoDirectory : string ) : Promise < string > {
90- const [ origin , branch ] = await gitRemoteBranch ( repoDirectory )
91- if ( origin !== '' ) {
92- // The remote branch exists.
93- return branch
94- }
95- return 'HEAD'
94+ interface RepositoryInfo extends Branch {
95+ /** Git repository remote URL */
96+ remoteURL : string
97+
98+ /** File path relative to the repository root */
99+ fileRelative : string
96100}
97101
98102/**
99103 * Returns the Git repository remote URL, the current branch, and the file path
100- * relative to the repository root. Empty strings are returned if this cannot be
101- * determined.
104+ * relative to the repository root. Returns undefined if no remote is found
102105 */
103- export async function repoInfo ( filePath : string ) : Promise < [ string , string , string ] > {
104- let remoteURL = ''
105- let branch = ''
106- let fileRelative = ''
106+ export async function repoInfo ( filePath : string ) : Promise < RepositoryInfo | undefined > {
107107 try {
108108 // Determine repository root directory.
109109 const fileDirectory = path . dirname ( filePath )
110110 const repoRoot = await gitRootDirectory ( fileDirectory )
111111
112- // Determine file path, relative to repository root.
113- fileRelative = filePath . slice ( repoRoot . length + 1 )
114- remoteURL = await gitDefaultRemoteURL ( repoRoot )
115- branch = await gitBranch ( repoRoot )
112+ // Determine file path relative to repository root.
113+ let fileRelative = filePath . slice ( repoRoot . length + 1 )
114+
115+ const remoteNameAndBranch = await gitRemoteNameAndBranch ( repoRoot )
116+ const { branch, remoteName } = remoteNameAndBranch
117+ const remoteURL = await gitRemoteURL ( repoRoot , remoteName )
118+
116119 if ( process . platform === 'win32' ) {
117120 fileRelative = fileRelative . replace ( / \\ / g, '/' )
118121 }
122+ log . appendLine ( `repoInfo(${ filePath } ): remoteURL="${ remoteURL } " branch="${ branch } " fileRel="${ fileRelative } "` )
123+ return { remoteURL, branch, fileRelative }
119124 } catch ( error ) {
120125 log . appendLine ( `repoInfo(${ filePath } ): ${ error as string } ` )
126+ return undefined
121127 }
122- log . appendLine ( `repoInfo(${ filePath } ): remoteURL="${ remoteURL } " branch="${ branch } " fileRel="${ fileRelative } "` )
123- return [ remoteURL , branch , fileRelative ]
124128}
0 commit comments