Skip to content

Commit

Permalink
#34764 Consolidated public build triggering fixed.
Browse files Browse the repository at this point in the history
  • Loading branch information
prochan2 committed Sep 28, 2024
1 parent a3e5b01 commit a5f3ebb
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ public interface IBuildTrigger
/// <summary>
/// Generates the TeamCity code representing the current build trigger.
/// </summary>
void GenerateTeamcityCode( TextWriter writer, string branchFilter = "+:<default>" );
void GenerateTeamcityCode( TextWriter writer, string? branchFilter = null );
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// Copyright (c) SharpCrafters s.r.o. See the LICENSE.md file in the root directory of this repository root for details.

using JetBrains.Annotations;
using PostSharp.Engineering.BuildTools.Build.Model;
using PostSharp.Engineering.BuildTools.ContinuousIntegration.Model.Arguments;
using System.IO;

namespace PostSharp.Engineering.BuildTools.Build.Triggers;

/// <summary>
/// Generates a build trigger that triggers the build daily at 22:00 for the default branch.
/// </summary>
[PublicAPI]
public class NightlyBuildTrigger : IBuildTrigger
{
public int Hour { get; }
Expand All @@ -16,7 +19,9 @@ public class NightlyBuildTrigger : IBuildTrigger

public bool WithPendingChangesOnly { get; }

public string? BranchFilter { get; set; }
public string? BranchFilter { get; init; }

public TeamCityBuildConfigurationParameterBase[]? Parameters { get; init; }

public NightlyBuildTrigger( int hour, bool withPendingChangesOnly )
{
Expand All @@ -31,17 +36,40 @@ public NightlyBuildTrigger( int hour, int minute, bool withPendingChangesOnly )
this.WithPendingChangesOnly = withPendingChangesOnly;
}

public void GenerateTeamcityCode( TextWriter writer, string branchFilter )
public void GenerateTeamcityCode( TextWriter writer, string? branchFilter = null )
{
writer.WriteLine(
@$" schedule {{
schedulingPolicy = daily {{
hour = {this.Hour}
minute = {this.Minute}
}}
branchFilter = ""{this.BranchFilter ?? branchFilter}""
triggerBuild = always()
withPendingChangesOnly = {this.WithPendingChangesOnly.ToString().ToLowerInvariant()}
}}" );
void WriteIndented( string text )
{
writer.Write( " " );
writer.WriteLine( text );
}

writer.WriteLine( " schedule {" );

WriteIndented( "schedulingPolicy = daily {" );
WriteIndented( $" hour = {this.Hour}" );
WriteIndented( $" minute = {this.Minute}" );
WriteIndented( "}" );

branchFilter = this.BranchFilter ?? branchFilter ?? "+:<default>";
WriteIndented( $"branchFilter = \"{branchFilter}\"" );

WriteIndented( "triggerBuild = always()" );
WriteIndented( $"withPendingChangesOnly = {this.WithPendingChangesOnly.ToString().ToLowerInvariant()}" );

if ( this.Parameters != null )
{
WriteIndented( "buildParams {" );

foreach ( var parameter in this.Parameters )
{
writer.Write( " " );
writer.WriteLine( parameter.GenerateTeamCityCode() );
}

WriteIndented( "}" );
}

writer.WriteLine( " }" );
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,55 @@
// Copyright (c) SharpCrafters s.r.o. See the LICENSE.md file in the root directory of this repository root for details.

using JetBrains.Annotations;
using PostSharp.Engineering.BuildTools.Build.Model;
using PostSharp.Engineering.BuildTools.ContinuousIntegration.Model.Arguments;
using System.IO;

namespace PostSharp.Engineering.BuildTools.Build.Triggers;

/// <summary>
/// Generates a build trigger that triggers the build when the source code has changed in the default branch.
/// </summary>
[PublicAPI]
public class SourceBuildTrigger : IBuildTrigger
{
public bool WatchChangesInDependencies { get; set; } = true;
public bool WatchChangesInDependencies { get; init; } = true;

public string? BranchFilter { get; set; }
public string? BranchFilter { get; init; }

public TeamCityBuildConfigurationParameterBase[]? Parameters { get; init; }

public void GenerateTeamcityCode( TextWriter writer, string branchFilter )
public void GenerateTeamcityCode( TextWriter writer, string? branchFilter = null )
{
writer.WriteLine(
$@" vcs {{
watchChangesInDependencies = {this.WatchChangesInDependencies.ToString().ToLowerInvariant()}
branchFilter = ""{this.BranchFilter ?? branchFilter}""
// Build will not trigger automatically if the commit message contains comment value.
triggerRules = ""-:comment=<<VERSION_BUMP>>|<<DEPENDENCIES_UPDATED>>:**""
}}" );
void WriteIndented( string text )
{
writer.Write( " " );
writer.WriteLine( text );
}

writer.WriteLine( " vcs {" );

WriteIndented( $"watchChangesInDependencies = {this.WatchChangesInDependencies.ToString().ToLowerInvariant()}" );

branchFilter = this.BranchFilter ?? branchFilter ?? "+:<default>";
WriteIndented( $"branchFilter = \"{branchFilter}\"" );

WriteIndented( "// Build will not trigger automatically if the commit message contains comment value." );
WriteIndented( "triggerRules = \"-:comment=<<VERSION_BUMP>>|<<DEPENDENCIES_UPDATED>>:**\"" );

if ( this.Parameters != null )
{
WriteIndented( "buildParams {" );

foreach ( var parameter in this.Parameters )
{
writer.Write( " " );
writer.WriteLine( parameter.GenerateTeamCityCode() );
}

WriteIndented( "}" );
}

writer.WriteLine( " }" );
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Copyright (c) SharpCrafters s.r.o. See the LICENSE.md file in the root directory of this repository root for details.
// Copyright (c) SharpCrafters s.r.o.See the LICENSE.md file in the root directory of this repository root for details.

namespace PostSharp.Engineering.BuildTools.ContinuousIntegration.Model.Arguments;

public abstract class TeamCityBuildConfigurationParameter
public class TeamCityBuildConfigurationParameter : TeamCityBuildConfigurationParameterBase
{
public string Name { get; }
public string Value { get; }

protected TeamCityBuildConfigurationParameter( string name )
public TeamCityBuildConfigurationParameter( string name, string value ) : base( name )
{
this.Name = name;
this.Value = value;
}

public abstract string GenerateTeamCityCode();
public override string GenerateTeamCityCode()
=> @$" param(""{this.Name}"", ""{this.Value}"")";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) SharpCrafters s.r.o. See the LICENSE.md file in the root directory of this repository root for details.

namespace PostSharp.Engineering.BuildTools.ContinuousIntegration.Model.Arguments;

public abstract class TeamCityBuildConfigurationParameterBase
{
public string Name { get; }

protected TeamCityBuildConfigurationParameterBase( string name )
{
this.Name = name;
}

public abstract string GenerateTeamCityCode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace PostSharp.Engineering.BuildTools.ContinuousIntegration.Model.Arguments;

public class TeamCityTextBuildConfigurationParameter : TeamCityBuildConfigurationParameter
public class TeamCityTextBuildConfigurationParameterBase : TeamCityBuildConfigurationParameterBase
{
public string DefaultValue { get; }

Expand All @@ -14,7 +14,7 @@ public class TeamCityTextBuildConfigurationParameter : TeamCityBuildConfiguratio

public (string Regex, string ValidationMessage)? Validation { get; init; }

public TeamCityTextBuildConfigurationParameter( string name, string label, string description, string defaultValue = "", bool allowEmpty = false )
public TeamCityTextBuildConfigurationParameterBase( string name, string label, string description, string defaultValue = "", bool allowEmpty = false )
: base( name )
{
this.DefaultValue = defaultValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace PostSharp.Engineering.BuildTools.ContinuousIntegration.Model.BuildStep

public abstract class TeamCityBuildStep
{
public TeamCityBuildConfigurationParameter[]? BuildConfigurationParameters { get; init; }
public TeamCityBuildConfigurationParameterBase[]? BuildConfigurationParameters { get; init; }

public abstract string GenerateTeamCityCode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public TeamCityEngineeringCommandBuildStep(
{
this.BuildConfigurationParameters =
[
new TeamCityTextBuildConfigurationParameter(
new TeamCityTextBuildConfigurationParameterBase(
GetCustomArgumentsParameterName( id ),
$"{name} Arguments",
$"Arguments to append to the '{name}' build step.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ internal class TeamCityBuildConfiguration

public TimeSpan? BuildTimeOutThreshold { get; init; }

public TeamCityBuildConfigurationParameter[]? Parameters { get; init; }
public TeamCityBuildConfigurationParameterBase[]? Parameters { get; init; }

public TeamCityBuildConfiguration( string objectName, string name, string defaultBranch, string defaultBranchParameter, string vcsRootId, BuildAgentRequirements? buildAgentRequirements = null )
{
Expand Down Expand Up @@ -94,24 +94,24 @@ public void GenerateTeamcityCode( TextWriter writer )

var hasBuildSteps = this.BuildSteps is { Length: > 0 };

var buildParameters = new List<TeamCityBuildConfigurationParameter>();
var buildParameters = new List<TeamCityBuildConfigurationParameterBase>();

if ( hasBuildSteps )
{
buildParameters.AddRange(
this.BuildSteps!.SelectMany( s => s.BuildConfigurationParameters ?? Enumerable.Empty<TeamCityBuildConfigurationParameter>() ) );
this.BuildSteps!.SelectMany( s => s.BuildConfigurationParameters ?? Enumerable.Empty<TeamCityBuildConfigurationParameterBase>() ) );
}

buildParameters.Add(
new TeamCityTextBuildConfigurationParameter(
new TeamCityTextBuildConfigurationParameterBase(
this.DefaultBranchParameter,
"Default Branch",
"The default branch of this build configuration.",
this.DefaultBranch ) );

if ( this.BuildTimeOutThreshold.HasValue )
{
var timeOutParameter = new TeamCityTextBuildConfigurationParameter(
var timeOutParameter = new TeamCityTextBuildConfigurationParameterBase(
"TimeOut",
"Time-Out Threshold",
"Seconds after the duration of the last successful build.",
Expand All @@ -138,7 +138,13 @@ public void GenerateTeamcityCode( TextWriter writer )

if ( this.IsDefaultVcsRootUsed )
{
writer.WriteLine( $" {(hasBuildSteps ? @$"root(AbsoluteId(""{this.VcsRootId}""))" : "showDependenciesChanges = true")}" );
// We set the VCS root explicitly for consolidated as well builds to enable the DefaultBranch paramater.
writer.WriteLine( @$" root(AbsoluteId(""{this.VcsRootId}""))" );

if ( !hasBuildSteps )
{
writer.WriteLine( $" showDependenciesChanges = true" );
}
}

// Source dependencies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,8 @@ bool TryPopulateBuildConfgurations(
// The nightly build is done on the develop branch to find issues early and to prepare for the deployment.
// The manually triggered build is done on the release branch to allow for deployment without merge freeze.
// Any successful build of the same commit done on the develop branch is reused by TeamCity when deploying from the release branch.
BranchFilter = $"+:{defaultBranch}"
BranchFilter = $"+:{defaultBranch}",
Parameters = [new TeamCityBuildConfigurationParameter( "DefaultBranch", defaultBranch )]
}
],
MarkNuGetObjectId( publicBuildObjectName ),
Expand All @@ -989,7 +990,7 @@ bool TryPopulateBuildConfgurations(
var consolidatedVersionBumpSteps = new List<TeamCityBuildStep>();
var consolidatedVersionBumpSourceDependencies = new List<TeamCitySourceDependency>();
var bumpedProjects = new HashSet<string>();
var consolidatedVersionBumpParameters = new List<TeamCityBuildConfigurationParameter>();
var consolidatedVersionBumpParameters = new List<TeamCityBuildConfigurationParameterBase>();

var success = true;

Expand Down Expand Up @@ -1036,7 +1037,7 @@ TeamCitySourceDependency CreateSourceDependencyFromDefintion( DependencyDefiniti
if ( dependencyDefinition.VcsRepository.DefaultBranchParameter != VcsRepository.DefaultDefaultBranchParameter )
{
consolidatedVersionBumpParameters.Add(
new TeamCityTextBuildConfigurationParameter(
new TeamCityTextBuildConfigurationParameterBase(
dependencyDefinition.VcsRepository.DefaultBranchParameter,
dependencyDefinition.VcsRepository.DefaultBranchParameter,
$"Default branch of {bumpedProjectName}",
Expand All @@ -1051,21 +1052,7 @@ TeamCitySourceDependency CreateSourceDependencyFromDefintion( DependencyDefiniti
return false;
}

// Consolidated version bumps don't run for all versions at the same time to avoid build agent starvation.
var consolidatedVersionBumpBuildTriggerMinute = 0;

if ( context.Product.ProductFamily.UpstreamProductFamily != null )
{
var previousProductFamily = context.Product.ProductFamily.UpstreamProductFamily;

while ( previousProductFamily != null )
{
consolidatedVersionBumpBuildTriggerMinute += 10;
previousProductFamily = previousProductFamily.UpstreamProductFamily;
}
}

var consolidatedVersionBumpBuildTriggers = new IBuildTrigger[] { new NightlyBuildTrigger( 1, consolidatedVersionBumpBuildTriggerMinute, false ) };
var consolidatedVersionBumpBuildTriggers = new IBuildTrigger[] { new NightlyBuildTrigger( 1, false ) };

tcConfigurations.Add(
new TeamCityBuildConfiguration(
Expand Down Expand Up @@ -1094,7 +1081,7 @@ bool TryAddPreOrPostDeploymentBuildConfiguration(
List<TeamCitySourceDependency> sourceDependencies = new();
List<TeamCitySnapshotDependency> snapshotDependencies = new();
List<TeamCityBuildStep> steps = new();
List<TeamCityBuildConfigurationParameter> parameters = new();
List<TeamCityBuildConfigurationParameterBase> parameters = new();

if ( context.Product.MainVersionDependency == null )
{
Expand Down Expand Up @@ -1130,7 +1117,7 @@ bool TryAddPreOrPostDeploymentBuildConfiguration(
}

parameters.Add(
new TeamCityTextBuildConfigurationParameter(
new TeamCityTextBuildConfigurationParameterBase(
projectDependencyDefinition.VcsRepository.DefaultBranchParameter,
projectDependencyDefinition.VcsRepository.DefaultBranchParameter,
$"Default branch of {project.Name}",
Expand Down

0 comments on commit a5f3ebb

Please sign in to comment.