@@ -10,7 +10,6 @@ internal sealed class GitRepository : IMutatingGitRepository
10
10
{
11
11
private readonly ILog log ;
12
12
private readonly Lazy < IRepository > repositoryLazy ;
13
- private IRepository repositoryInstance => this . repositoryLazy . Value ;
14
13
15
14
public GitRepository ( ILog log , IGitRepositoryInfo repositoryInfo )
16
15
: this ( log , ( ) => repositoryInfo . GitRootPath )
@@ -24,6 +23,7 @@ internal GitRepository(string gitRootDirectory)
24
23
25
24
internal GitRepository ( IRepository repository )
26
25
{
26
+ repository = repository . NotNull ( ) ;
27
27
this . log = new NullLog ( ) ;
28
28
this . repositoryLazy = new Lazy < IRepository > ( ( ) => repository ) ;
29
29
}
@@ -34,133 +34,74 @@ private GitRepository(ILog log, Func<string?> getGitRootDirectory)
34
34
this . repositoryLazy = new Lazy < IRepository > ( ( ) => new Repository ( getGitRootDirectory ( ) ) ) ;
35
35
}
36
36
37
- public void Dispose ( )
38
- {
39
- if ( this . repositoryLazy . IsValueCreated ) repositoryInstance . Dispose ( ) ;
40
- }
41
-
42
- public string Path => repositoryInstance . Info . Path ;
43
- public string WorkingDirectory => repositoryInstance . Info . WorkingDirectory ;
44
- public bool IsHeadDetached => repositoryInstance . Info . IsHeadDetached ;
45
-
46
- public IBranch Head => new Branch ( repositoryInstance . Head ) ;
47
- public ITagCollection Tags => new TagCollection ( repositoryInstance . Tags ) ;
48
- public IReferenceCollection Refs => new ReferenceCollection ( repositoryInstance . Refs ) ;
49
- public IBranchCollection Branches => new BranchCollection ( repositoryInstance . Branches ) ;
50
- public ICommitCollection Commits => new CommitCollection ( repositoryInstance . Commits ) ;
51
- public IRemoteCollection Remotes => new RemoteCollection ( repositoryInstance . Network . Remotes ) ;
37
+ private IRepository RepositoryInstance => this . repositoryLazy . Value ;
38
+ public string Path => RepositoryInstance . Info . Path ;
39
+ public string WorkingDirectory => RepositoryInstance . Info . WorkingDirectory ;
40
+ public bool IsHeadDetached => RepositoryInstance . Info . IsHeadDetached ;
41
+ public IBranch Head => new Branch ( RepositoryInstance . Head ) ;
42
+ public ITagCollection Tags => new TagCollection ( RepositoryInstance . Tags ) ;
43
+ public IReferenceCollection Refs => new ReferenceCollection ( RepositoryInstance . Refs ) ;
44
+ public IBranchCollection Branches => new BranchCollection ( RepositoryInstance . Branches ) ;
45
+ public ICommitCollection Commits => new CommitCollection ( RepositoryInstance . Commits ) ;
46
+ public IRemoteCollection Remotes => new RemoteCollection ( RepositoryInstance . Network . Remotes ) ;
52
47
53
48
public ICommit ? FindMergeBase ( ICommit commit , ICommit otherCommit )
54
49
{
55
- _ = commit . NotNull ( ) ;
56
- _ = otherCommit . NotNull ( ) ;
50
+ commit = commit . NotNull ( ) ;
51
+ otherCommit = otherCommit . NotNull ( ) ;
57
52
58
53
var retryAction = new RetryAction < LockedFileException , ICommit ? > ( ) ;
59
54
return retryAction . Execute ( ( ) =>
60
55
{
61
- var mergeBase = repositoryInstance . ObjectDatabase . FindMergeBase ( ( Commit ) commit , ( Commit ) otherCommit ) ;
56
+ var first = ( Commit ) commit ;
57
+ var second = ( Commit ) otherCommit ;
58
+ var mergeBase = RepositoryInstance . ObjectDatabase . FindMergeBase ( first , second ) ;
62
59
return mergeBase == null ? null : new Commit ( mergeBase ) ;
63
60
} ) ;
64
61
}
62
+
65
63
public int GetNumberOfUncommittedChanges ( )
66
64
{
67
65
var retryAction = new RetryAction < LibGit2Sharp . LockedFileException , int > ( ) ;
68
66
return retryAction . Execute ( GetNumberOfUncommittedChangesInternal ) ;
69
67
}
70
- private int GetNumberOfUncommittedChangesInternal ( )
68
+
69
+ public void CreateBranchForPullRequestBranch ( AuthenticationInfo auth ) => RepositoryExtensions . RunSafe ( ( ) =>
71
70
{
72
- // check if we have a branch tip at all to behave properly with empty repos
73
- // => return that we have actually un-committed changes because we are apparently
74
- // running GitVersion on something which lives inside this brand new repo _/\Ö/\_
75
- if ( repositoryInstance . Head ? . Tip == null || repositoryInstance . Diff == null )
76
- {
77
- // this is a somewhat cumbersome way of figuring out the number of changes in the repo
78
- // which is more expensive than to use the Diff as it gathers more info, but
79
- // we can't use the other method when we are dealing with a new/empty repo
80
- try
81
- {
82
- var status = repositoryInstance . RetrieveStatus ( ) ;
83
- return status . Untracked . Count ( ) + status . Staged . Count ( ) ;
84
- }
85
- catch ( Exception )
86
- {
87
- return int . MaxValue ; // this should be somewhat puzzling to see,
88
- // so we may have reached our goal to show that
89
- // that repo is really "Dirty"...
90
- }
91
- }
71
+ this . log . Info ( "Fetching remote refs to see if there is a pull request ref" ) ;
92
72
93
- // gets all changes of the last commit vs Staging area and WT
94
- var changes = repositoryInstance . Diff . Compare < TreeChanges > ( repositoryInstance . Head . Tip . Tree ,
95
- DiffTargets . Index | DiffTargets . WorkingDirectory ) ;
73
+ // FIX ME: What to do when Tip is null?
74
+ if ( Head . Tip == null )
75
+ return ;
96
76
97
- return changes . Count ;
98
- }
77
+ var headTipSha = Head . Tip . Sha ;
78
+ var remote = RepositoryInstance . Network . Remotes . Single ( ) ;
79
+ var reference = GetPullRequestReference ( auth , remote , headTipSha ) ;
80
+ var canonicalName = reference . CanonicalName ;
81
+ var referenceName = ReferenceName . Parse ( reference . CanonicalName ) ;
82
+ this . log . Info ( $ "Found remote tip '{ canonicalName } ' pointing at the commit '{ headTipSha } '.") ;
99
83
100
- public void CreateBranchForPullRequestBranch ( AuthenticationInfo auth ) =>
101
- RepositoryExtensions . RunSafe ( ( ) =>
84
+ if ( referenceName . IsTag )
102
85
{
103
- var network = repositoryInstance . Network ;
104
- var remote = network . Remotes . Single ( ) ;
105
-
106
- this . log . Info ( "Fetching remote refs to see if there is a pull request ref" ) ;
107
- var credentialsProvider = GetCredentialsProvider ( auth ) ;
108
- var remoteTips = ( credentialsProvider != null
109
- ? network . ListReferences ( remote , credentialsProvider )
110
- : network . ListReferences ( remote ) )
111
- . Select ( r => r . ResolveToDirectReference ( ) ) . ToList ( ) ;
112
-
113
- this . log . Info ( $ "Remote Refs:{ System . Environment . NewLine } " + string . Join ( System . Environment . NewLine , remoteTips . Select ( r => r . CanonicalName ) ) ) ;
114
-
115
- // FIX ME: What to do when Tip is null?
116
- if ( Head . Tip != null )
117
- {
118
- var headTipSha = Head . Tip . Sha ;
119
-
120
- var refs = remoteTips . Where ( r => r . TargetIdentifier == headTipSha ) . ToList ( ) ;
121
-
122
- switch ( refs . Count )
123
- {
124
- case 0 :
125
- {
126
- var message = $ "Couldn't find any remote tips from remote '{ remote . Url } ' pointing at the commit '{ headTipSha } '.";
127
- throw new WarningException ( message ) ;
128
- }
129
- case > 1 :
130
- {
131
- var names = string . Join ( ", " , refs . Select ( r => r . CanonicalName ) ) ;
132
- var message = $ "Found more than one remote tip from remote '{ remote . Url } ' pointing at the commit '{ headTipSha } '. Unable to determine which one to use ({ names } ).";
133
- throw new WarningException ( message ) ;
134
- }
135
- }
136
-
137
- var reference = refs . First ( ) ;
138
- var canonicalName = reference . CanonicalName ;
139
- var referenceName = ReferenceName . Parse ( reference . CanonicalName ) ;
140
- this . log . Info ( $ "Found remote tip '{ canonicalName } ' pointing at the commit '{ headTipSha } '.") ;
141
-
142
- if ( referenceName . IsTag )
143
- {
144
- this . log . Info ( $ "Checking out tag '{ canonicalName } '") ;
145
- Checkout ( reference . Target . Sha ) ;
146
- }
147
- else if ( referenceName . IsPullRequest )
148
- {
149
- var fakeBranchName = canonicalName . Replace ( "refs/pull/" , "refs/heads/pull/" ) . Replace ( "refs/pull-requests/" , "refs/heads/pull-requests/" ) ;
86
+ this . log . Info ( $ "Checking out tag '{ canonicalName } '") ;
87
+ Checkout ( reference . Target . Sha ) ;
88
+ }
89
+ else if ( referenceName . IsPullRequest )
90
+ {
91
+ var fakeBranchName = canonicalName . Replace ( "refs/pull/" , "refs/heads/pull/" ) . Replace ( "refs/pull-requests/" , "refs/heads/pull-requests/" ) ;
150
92
151
- this . log . Info ( $ "Creating fake local branch '{ fakeBranchName } '.") ;
152
- Refs . Add ( fakeBranchName , headTipSha ) ;
93
+ this . log . Info ( $ "Creating fake local branch '{ fakeBranchName } '.") ;
94
+ Refs . Add ( fakeBranchName , headTipSha ) ;
153
95
154
- this . log . Info ( $ "Checking local branch '{ fakeBranchName } ' out.") ;
155
- Checkout ( fakeBranchName ) ;
156
- }
157
- else
158
- {
159
- var message = $ "Remote tip '{ canonicalName } ' from remote '{ remote . Url } ' doesn't look like a valid pull request.";
160
- throw new WarningException ( message ) ;
161
- }
162
- }
163
- } ) ;
96
+ this . log . Info ( $ "Checking local branch '{ fakeBranchName } ' out.") ;
97
+ Checkout ( fakeBranchName ) ;
98
+ }
99
+ else
100
+ {
101
+ var message = $ "Remote tip '{ canonicalName } ' from remote '{ remote . Url } ' doesn't look like a valid pull request.";
102
+ throw new WarningException ( message ) ;
103
+ }
104
+ } ) ;
164
105
165
106
public void Clone ( string ? sourceUrl , string ? workdirPath , AuthenticationInfo auth )
166
107
{
@@ -180,10 +121,12 @@ public void Clone(string? sourceUrl, string? workdirPath, AuthenticationInfo aut
180
121
{
181
122
throw new Exception ( "Unauthorized: Incorrect username/password" , ex ) ;
182
123
}
124
+
183
125
if ( message . Contains ( "403" ) )
184
126
{
185
127
throw new Exception ( "Forbidden: Possibly Incorrect username/password" , ex ) ;
186
128
}
129
+
187
130
if ( message . Contains ( "404" ) )
188
131
{
189
132
throw new Exception ( "Not found: The repository was not found" , ex ) ;
@@ -192,39 +135,95 @@ public void Clone(string? sourceUrl, string? workdirPath, AuthenticationInfo aut
192
135
throw new Exception ( "There was an unknown problem with the Git repository you provided" , ex ) ;
193
136
}
194
137
}
138
+
195
139
public void Checkout ( string commitOrBranchSpec ) =>
196
140
RepositoryExtensions . RunSafe ( ( ) =>
197
- Commands . Checkout ( repositoryInstance , commitOrBranchSpec ) ) ;
141
+ Commands . Checkout ( RepositoryInstance , commitOrBranchSpec ) ) ;
198
142
199
143
public void Fetch ( string remote , IEnumerable < string > refSpecs , AuthenticationInfo auth , string ? logMessage ) =>
200
144
RepositoryExtensions . RunSafe ( ( ) =>
201
- Commands . Fetch ( ( Repository ) repositoryInstance , remote , refSpecs , GetFetchOptions ( auth ) , logMessage ) ) ;
145
+ Commands . Fetch ( ( Repository ) RepositoryInstance , remote , refSpecs , GetFetchOptions ( auth ) , logMessage ) ) ;
146
+
147
+ private DirectReference GetPullRequestReference ( AuthenticationInfo auth , LibGit2Sharp . Remote remote , string headTipSha )
148
+ {
149
+ var network = RepositoryInstance . Network ;
150
+ var credentialsProvider = GetCredentialsProvider ( auth ) ;
151
+ var remoteTips = ( credentialsProvider != null
152
+ ? network . ListReferences ( remote , credentialsProvider )
153
+ : network . ListReferences ( remote ) )
154
+ . Select ( r => r . ResolveToDirectReference ( ) ) . ToList ( ) ;
155
+
156
+ this . log . Info ( $ "Remote Refs:{ System . Environment . NewLine } " + string . Join ( System . Environment . NewLine , remoteTips . Select ( r => r . CanonicalName ) ) ) ;
157
+ var refs = remoteTips . Where ( r => r . TargetIdentifier == headTipSha ) . ToList ( ) ;
158
+
159
+ switch ( refs . Count )
160
+ {
161
+ case 0 :
162
+ {
163
+ var message = $ "Couldn't find any remote tips from remote '{ remote . Url } ' pointing at the commit '{ headTipSha } '.";
164
+ throw new WarningException ( message ) ;
165
+ }
166
+ case > 1 :
167
+ {
168
+ var names = string . Join ( ", " , refs . Select ( r => r . CanonicalName ) ) ;
169
+ var message = $ "Found more than one remote tip from remote '{ remote . Url } ' pointing at the commit '{ headTipSha } '. Unable to determine which one to use ({ names } ).";
170
+ throw new WarningException ( message ) ;
171
+ }
172
+ }
173
+
174
+ return refs . First ( ) ;
175
+ }
176
+
177
+ public void Dispose ( )
178
+ {
179
+ if ( this . repositoryLazy . IsValueCreated ) RepositoryInstance . Dispose ( ) ;
180
+ }
181
+
182
+ private int GetNumberOfUncommittedChangesInternal ( )
183
+ {
184
+ // check if we have a branch tip at all to behave properly with empty repos
185
+ // => return that we have actually un-committed changes because we are apparently
186
+ // running GitVersion on something which lives inside this brand new repo _/\Ö/\_
187
+ if ( RepositoryInstance . Head ? . Tip == null || RepositoryInstance . Diff == null )
188
+ {
189
+ // this is a somewhat cumbersome way of figuring out the number of changes in the repo
190
+ // which is more expensive than to use the Diff as it gathers more info, but
191
+ // we can't use the other method when we are dealing with a new/empty repo
192
+ try
193
+ {
194
+ var status = RepositoryInstance . RetrieveStatus ( ) ;
195
+ return status . Untracked . Count ( ) + status . Staged . Count ( ) ;
196
+ }
197
+ catch ( Exception )
198
+ {
199
+ return int . MaxValue ; // this should be somewhat puzzling to see,
200
+ // so we may have reached our goal to show that
201
+ // that repo is really "Dirty"...
202
+ }
203
+ }
204
+
205
+ // gets all changes of the last commit vs Staging area and WT
206
+ var changes = RepositoryInstance . Diff . Compare < TreeChanges > ( RepositoryInstance . Head . Tip . Tree ,
207
+ DiffTargets . Index | DiffTargets . WorkingDirectory ) ;
208
+
209
+ return changes . Count ;
210
+ }
202
211
203
212
internal static string ? Discover ( string ? path ) => Repository . Discover ( path ) ;
204
213
205
214
private static FetchOptions GetFetchOptions ( AuthenticationInfo auth ) =>
206
- new ( )
207
- {
208
- CredentialsProvider = GetCredentialsProvider ( auth )
209
- } ;
215
+ new ( ) { CredentialsProvider = GetCredentialsProvider ( auth ) } ;
210
216
211
217
private static CloneOptions GetCloneOptions ( AuthenticationInfo auth ) =>
212
- new ( )
213
- {
214
- Checkout = false ,
215
- CredentialsProvider = GetCredentialsProvider ( auth )
216
- } ;
218
+ new ( ) { Checkout = false , CredentialsProvider = GetCredentialsProvider ( auth ) } ;
217
219
218
220
private static CredentialsHandler ? GetCredentialsProvider ( AuthenticationInfo auth )
219
221
{
220
222
if ( ! auth . Username . IsNullOrWhiteSpace ( ) )
221
223
{
222
- return ( _ , _ , _ ) => new UsernamePasswordCredentials
223
- {
224
- Username = auth . Username ,
225
- Password = auth . Password ?? string . Empty
226
- } ;
224
+ return ( _ , _ , _ ) => new UsernamePasswordCredentials { Username = auth . Username , Password = auth . Password ?? string . Empty } ;
227
225
}
226
+
228
227
return null ;
229
228
}
230
229
}
0 commit comments