@@ -4,26 +4,12 @@ import { log } from './log'
4
4
import { getRemoteUrlReplacements } from './config'
5
5
6
6
/**
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.
10
9
*/
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
27
13
}
28
14
29
15
/**
@@ -51,74 +37,92 @@ async function gitRemoteURL(repoDirectory: string, remoteName: string): Promise<
51
37
return stdout
52
38
}
53
39
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
+
54
56
/**
55
- * Returns the remote URL.
57
+ * Returns the remote name and branch
58
+ *
59
+ * @param repoDirectory the repository root directory
56
60
*/
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
61
74
}
62
75
63
76
// If we cannot find the remote name deterministically, we use the first
64
77
// 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
+ }
68
84
}
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' )
71
89
}
72
- return gitRemoteURL ( repoDirectory , remotes [ 0 ] )
73
- }
74
90
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 }
82
92
}
83
93
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
96
100
}
97
101
98
102
/**
99
103
* 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
102
105
*/
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 > {
107
107
try {
108
108
// Determine repository root directory.
109
109
const fileDirectory = path . dirname ( filePath )
110
110
const repoRoot = await gitRootDirectory ( fileDirectory )
111
111
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
+
116
119
if ( process . platform === 'win32' ) {
117
120
fileRelative = fileRelative . replace ( / \\ / g, '/' )
118
121
}
122
+ log . appendLine ( `repoInfo(${ filePath } ): remoteURL="${ remoteURL } " branch="${ branch } " fileRel="${ fileRelative } "` )
123
+ return { remoteURL, branch, fileRelative }
119
124
} catch ( error ) {
120
125
log . appendLine ( `repoInfo(${ filePath } ): ${ error as string } ` )
126
+ return undefined
121
127
}
122
- log . appendLine ( `repoInfo(${ filePath } ): remoteURL="${ remoteURL } " branch="${ branch } " fileRel="${ fileRelative } "` )
123
- return [ remoteURL , branch , fileRelative ]
124
128
}
0 commit comments