Skip to content

Commit 728c19e

Browse files
committed
Improving downstream merge.
1 parent 9339efd commit 728c19e

File tree

1 file changed

+140
-126
lines changed

1 file changed

+140
-126
lines changed

src/PostSharp.Engineering.BuildTools/Tools/Git/DownstreamMerge.cs

Lines changed: 140 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,7 @@ public static bool MergeDownstream( BuildContext context, DownstreamMergeSetting
167167

168168
if ( !downstreamProductFamily.TryGetDependencyDefinition( product.ProductName, out var downstreamDependencyDefinition ) )
169169
{
170-
context.Console.WriteError(
171-
$"The '{product.ProductName}' downstream product version '{downstreamProductFamily.Version}' is not configured." );
170+
context.Console.WriteError( $"The '{product.ProductName}' downstream product version '{downstreamProductFamily.Version}' is not configured." );
172171

173172
return false;
174173
}
@@ -190,180 +189,195 @@ public static bool MergeDownstream( BuildContext context, DownstreamMergeSetting
190189
return false;
191190
}
192191

193-
context.Console.WriteImportantMessage( $"Pulling changes from '{downstreamBranch}' downstream branch" );
194-
195-
if ( !GitHelper.TryCheckoutAndPull( context, downstreamBranch ) )
192+
try
196193
{
197-
return false;
198-
}
194+
context.Console.WriteImportantMessage( $"Pulling changes from '{downstreamBranch}' downstream branch" );
199195

200-
if ( !GitHelper.TryGetCommitsCount( context, "HEAD", sourceBranch, sourceProductFamily, out var commitsCount ) )
201-
{
202-
return false;
203-
}
196+
if ( !GitHelper.TryCheckoutAndPull( context, downstreamBranch ) )
197+
{
198+
return false;
199+
}
204200

205-
if ( commitsCount < 0 )
206-
{
207-
throw new InvalidOperationException( $"Invalid commits count: {commitsCount}" );
208-
}
201+
if ( !GitHelper.TryGetCommitsCount( context, "HEAD", sourceBranch, sourceProductFamily, out var commitsCount ) )
202+
{
203+
return false;
204+
}
209205

210-
if ( commitsCount == 0 )
211-
{
212-
context.Console.WriteSuccess( $"There are no commits to merge from '{sourceBranch}' branch to '{downstreamBranch}' branch." );
206+
if ( commitsCount < 0 )
207+
{
208+
throw new InvalidOperationException( $"Invalid commits count: {commitsCount}" );
209+
}
213210

214-
return true;
215-
}
211+
if ( commitsCount == 0 )
212+
{
213+
context.Console.WriteSuccess( $"There are no commits to merge from '{sourceBranch}' branch to '{downstreamBranch}' branch." );
216214

217-
context.Console.WriteImportantMessage( $"There are {commitsCount} commits to merge from '{sourceBranch}' branch to '{downstreamBranch}' branch." );
215+
return true;
216+
}
218217

219-
var pullRequestStatusCheckBuildTypeId = downstreamDependencyDefinition.CiConfiguration.PullRequestStatusCheckBuildType;
220-
var isPullRequestRequired = pullRequestStatusCheckBuildTypeId != null;
221-
string targetBranch;
222-
bool targetBranchExistsRemotely;
218+
context.Console.WriteImportantMessage( $"There are {commitsCount} commits to merge from '{sourceBranch}' branch to '{downstreamBranch}' branch." );
223219

224-
if ( isPullRequestRequired )
225-
{
226-
targetBranch = $"merge/{downstreamProductFamily.Version}/{product.ProductFamily.Version}-{sourceCommitHash}";
220+
var pullRequestStatusCheckBuildTypeId = downstreamDependencyDefinition.CiConfiguration.PullRequestStatusCheckBuildType;
221+
var isPullRequestRequired = pullRequestStatusCheckBuildTypeId != null;
222+
string targetBranch;
223+
bool targetBranchExistsRemotely;
227224

228-
context.Console.WriteMessage(
229-
$"Checking '{product.ProductName}' product version '{downstreamProductFamily.Version}' for pending merge branches." );
225+
if ( isPullRequestRequired )
226+
{
227+
targetBranch = $"merge/{downstreamProductFamily.Version}/{product.ProductFamily.Version}-{sourceCommitHash}";
230228

231-
var filter = $"merge/{downstreamProductFamily.Version}/*";
229+
context.Console.WriteMessage(
230+
$"Checking '{product.ProductName}' product version '{downstreamProductFamily.Version}' for pending merge branches." );
232231

233-
if ( !GitHelper.TryGetRemoteReferences( context, settings, filter, out var references ) )
234-
{
235-
return false;
236-
}
232+
var filter = $"merge/{downstreamProductFamily.Version}/*";
237233

238-
var targetBranchReference = $"refs/heads/{targetBranch}";
234+
if ( !GitHelper.TryGetRemoteReferences( context, settings, filter, out var references ) )
235+
{
236+
return false;
237+
}
238+
239+
var targetBranchReference = $"refs/heads/{targetBranch}";
239240

240-
targetBranchExistsRemotely = references.Any( r => r.Reference == targetBranchReference );
241+
targetBranchExistsRemotely = references.Any( r => r.Reference == targetBranchReference );
241242

242-
var formerTargetBranchReferences = references.Where( r => r.Reference != targetBranchReference ).ToArray();
243+
var formerTargetBranchReferences = references.Where( r => r.Reference != targetBranchReference ).ToArray();
243244

244-
var reusableBranches = formerTargetBranchReferences.Where( r => r.Reference.StartsWith(
245-
$"refs/heads/merge/{downstreamProductFamily.Version}/{product.ProductFamily.Version}-",
246-
StringComparison.OrdinalIgnoreCase ) )
247-
.ToArray();
245+
var reusableBranches = formerTargetBranchReferences.Where( r => r.Reference.StartsWith(
246+
$"refs/heads/merge/{downstreamProductFamily.Version}/{product.ProductFamily.Version}-",
247+
StringComparison.OrdinalIgnoreCase ) )
248+
.ToArray();
248249

249-
if ( reusableBranches.Length == 1 )
250+
if ( reusableBranches.Length == 1 )
251+
{
252+
targetBranch = reusableBranches[0].Reference.Substring( "refs/heads/".Length );
253+
targetBranchExistsRemotely = true;
254+
}
255+
else if ( formerTargetBranchReferences.Length > 0 && !settings.Force )
256+
{
257+
ExplainUnmergedBranches(
258+
context.Console,
259+
formerTargetBranchReferences.Select( r => r.Reference ),
260+
settings.Force,
261+
targetBranchExistsRemotely
262+
? $"Until a new commit is pushed to the '{sourceBranch}' source branch, there's no need to delete the '{targetBranch}' target branch, as it will be reused next time the downstream merge is run."
263+
: null );
264+
265+
if ( !settings.Force )
266+
{
267+
return false;
268+
}
269+
}
270+
}
271+
else
250272
{
251-
targetBranch = reusableBranches[0].Reference.Substring( "refs/heads/".Length );
273+
targetBranch = downstreamBranch;
252274
targetBranchExistsRemotely = true;
253275
}
254-
else if ( formerTargetBranchReferences.Length > 0 && !settings.Force )
255-
{
256-
ExplainUnmergedBranches(
257-
context.Console,
258-
formerTargetBranchReferences.Select( r => r.Reference ),
259-
settings.Force,
260-
targetBranchExistsRemotely
261-
? $"Until a new commit is pushed to the '{sourceBranch}' source branch, there's no need to delete the '{targetBranch}' target branch, as it will be reused next time the downstream merge is run."
262-
: null );
263276

264-
if ( !settings.Force )
277+
bool targetBranchExists;
278+
279+
if ( targetBranchExistsRemotely )
280+
{
281+
targetBranchExists = true;
282+
}
283+
else
284+
{
285+
if ( !GitHelper.TryGetCurrentCommitHash( context, targetBranch, out var targetBranchCurrentCommitHash ) )
265286
{
266287
return false;
267288
}
268-
}
269-
}
270-
else
271-
{
272-
targetBranch = downstreamBranch;
273-
targetBranchExistsRemotely = true;
274-
}
275289

276-
bool targetBranchExists;
290+
targetBranchExists = targetBranchCurrentCommitHash != null;
291+
}
277292

278-
if ( targetBranchExistsRemotely )
279-
{
280-
targetBranchExists = true;
281-
}
282-
else
283-
{
284-
if ( !GitHelper.TryGetCurrentCommitHash( context, targetBranch, out var targetBranchCurrentCommitHash ) )
293+
if ( targetBranchExists )
285294
{
286-
return false;
295+
context.Console.WriteImportantMessage( $"The '{targetBranch}' target branch already exists. Let's use it." );
296+
297+
if ( !GitHelper.TryCheckoutAndPull( context, targetBranch ) )
298+
{
299+
return false;
300+
}
287301
}
302+
else
303+
{
304+
context.Console.WriteImportantMessage( $"The '{targetBranch}' target branch doesn't exits. Let's create it." );
288305

289-
targetBranchExists = targetBranchCurrentCommitHash != null;
290-
}
306+
if ( !GitHelper.TryCreateBranch( context, targetBranch ) )
307+
{
308+
return false;
309+
}
291310

292-
if ( targetBranchExists )
293-
{
294-
context.Console.WriteImportantMessage( $"The '{targetBranch}' target branch already exists. Let's use it." );
311+
context.Console.WriteImportantMessage( $"The '{targetBranch}' target was created." );
312+
}
295313

296-
if ( !GitHelper.TryCheckoutAndPull( context, targetBranch ) )
314+
// Push the branch now to avoid issues when the DownstreamMergeCommand
315+
// is executed again with the same upstream changes
316+
// or when developers are required to resolve conflicts.
317+
if ( !GitHelper.TryPush( context ) )
297318
{
298319
return false;
299320
}
300-
}
301-
else
302-
{
303-
context.Console.WriteImportantMessage( $"The '{targetBranch}' target branch doesn't exits. Let's create it." );
304321

305-
if ( !GitHelper.TryCreateBranch( context, targetBranch ) )
322+
if ( !TryMerge( context, sourceBranch, targetBranch, downstreamBranch, out var areChangesPending ) )
306323
{
307324
return false;
308325
}
309326

310-
context.Console.WriteImportantMessage( $"The '{targetBranch}' target was created." );
311-
}
312-
313-
// Push the branch now to avoid issues when the DownstreamMergeCommand
314-
// is executed again with the same upstream changes
315-
// or when developers are required to resolve conflicts.
316-
if ( !GitHelper.TryPush( context ) )
317-
{
318-
return false;
319-
}
320-
321-
if ( !TryMerge( context, sourceBranch, targetBranch, downstreamBranch, out var areChangesPending ) )
322-
{
323-
return false;
324-
}
325-
326-
if ( !areChangesPending )
327-
{
328-
// This shouldn't happen often - just when the merge conflict is solved without using the merge branch prepared by the tool.
329-
context.Console.WriteSuccess( $"There is nothing to merge from '{sourceBranch}' branch to '{downstreamBranch}' branch." );
327+
if ( !areChangesPending )
328+
{
329+
// This shouldn't happen often - just when the merge conflict is solved without using the merge branch prepared by the tool.
330+
context.Console.WriteSuccess( $"There is nothing to merge from '{sourceBranch}' branch to '{downstreamBranch}' branch." );
330331

331-
return true;
332-
}
332+
return true;
333+
}
333334

334-
context.Console.WriteSuccess( $"Changes from '{sourceBranch}' missing in '{downstreamBranch}' branch have been merged in branch '{targetBranch}'." );
335+
context.Console.WriteSuccess(
336+
$"Changes from '{sourceBranch}' missing in '{downstreamBranch}' branch have been merged in branch '{targetBranch}'." );
335337

336-
if ( isPullRequestRequired )
337-
{
338-
if ( !TryCreatePullRequest( context, targetBranch, downstreamBranch, sourceBranch, out var pullRequestUrl, out var requiresBuild ) )
338+
if ( isPullRequestRequired )
339339
{
340-
return false;
341-
}
342-
343-
if ( requiresBuild )
344-
{
345-
if ( !TryScheduleBuild(
346-
downstreamDependencyDefinition.CiConfiguration,
347-
context.Console,
348-
targetBranch,
349-
sourceBranch,
350-
pullRequestUrl,
351-
pullRequestStatusCheckBuildTypeId!, // Checked by isPullRequestRequired
352-
out var buildUrl ) )
340+
if ( !TryCreatePullRequest( context, targetBranch, downstreamBranch, sourceBranch, out var pullRequestUrl, out var requiresBuild ) )
353341
{
354342
return false;
355343
}
356344

357-
context.Console.WriteSuccess( $"Created pull request {pullRequestUrl} and scheduled build {buildUrl}." );
345+
if ( requiresBuild )
346+
{
347+
if ( !TryScheduleBuild(
348+
downstreamDependencyDefinition.CiConfiguration,
349+
context.Console,
350+
targetBranch,
351+
sourceBranch,
352+
pullRequestUrl,
353+
pullRequestStatusCheckBuildTypeId!, // Checked by isPullRequestRequired
354+
out var buildUrl ) )
355+
{
356+
return false;
357+
}
358+
359+
context.Console.WriteSuccess( $"Created pull request {pullRequestUrl} and scheduled build {buildUrl}." );
360+
}
361+
else
362+
{
363+
context.Console.WriteSuccess( $"Created and merged pull request {pullRequestUrl}." );
364+
}
358365
}
359-
else
360-
{
361-
context.Console.WriteSuccess( $"Created and merged pull request {pullRequestUrl}." );
362366

367+
return true;
368+
}
369+
finally
370+
{
371+
try
372+
{
373+
// Go back to the original branch.
374+
GitHelper.TryCheckoutAndPull( context, product.DependencyDefinition.Branch );
375+
}
376+
catch ( Exception e )
377+
{
378+
context.Console.WriteError( e.ToString() );
363379
}
364380
}
365-
366-
return true;
367381
}
368382

369383
private static bool TryMerge(

0 commit comments

Comments
 (0)