Skip to content

Commit e3e0b08

Browse files
Bump: download dep AutoUpdatedVersions.props from VCS when not local
Reverts the artifact-dep approach from 0cebead: AutoUpdatedVersions.props is build-independent source code, so coupling bump to a CI artifact made the version pipeline build-dependent for no reason. New behavior in AutoUpdatedVersionsFile.TryWrite: if neither local candidate path exists (source-dependencies/<dep>/<eng>/... or ../<dep>/<eng>/...), fall back to VcsRepository.TryDownloadTextFile on the dep's ReleaseBranch (or Branch when null). XML is parsed in-memory via the new TryParse helper, which TryRead now also delegates to. This unblocks bump for repos like Metalama.Vsx 2026.1 where Metalama and Metalama.Compiler are artifact-only deps and never appear under source-dependencies. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 8c6e01f commit e3e0b08

4 files changed

Lines changed: 46 additions & 43 deletions

File tree

.teamcity/settings.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ object PublicBuild : BuildType({
2929
+:artifacts/testResults/**/*=>artifacts/testResults
3030
+:artifacts/logs/**/*=>logs
3131
+:artifacts/dumps/**/*=>dumps
32-
+:eng/AutoUpdatedVersions.props=>eng
3332
"""
3433

3534
params {

src/PostSharp.Engineering.BuildTools/Build/Files/AutoUpdatedVersionsFile.cs

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,16 @@ private static bool TryRead(
3131
string path,
3232
[NotNullWhen( true )] out string? dependencyReleasedVersion,
3333
[NotNullWhen( true )] out string? releasedMainVersionPropertyValue )
34-
{
35-
var theirAutoUpdatedVersionsDocument = XDocument.Load( path );
34+
=> TryParse( context, dependency, path, XDocument.Load( path ), out dependencyReleasedVersion, out releasedMainVersionPropertyValue );
3635

36+
private static bool TryParse(
37+
BuildContext context,
38+
DependencyDefinition dependency,
39+
string source,
40+
XDocument theirAutoUpdatedVersionsDocument,
41+
[NotNullWhen( true )] out string? dependencyReleasedVersion,
42+
[NotNullWhen( true )] out string? releasedMainVersionPropertyValue )
43+
{
3744
var releasedVersionPropertyName = $"{dependency.NameWithoutDot}ReleaseVersion";
3845

3946
dependencyReleasedVersion = theirAutoUpdatedVersionsDocument.Root
@@ -43,7 +50,7 @@ private static bool TryRead(
4350

4451
if ( string.IsNullOrEmpty( dependencyReleasedVersion ) )
4552
{
46-
context.Console.WriteError( $"The '{releasedVersionPropertyName}' property in '{path}' is not defined." );
53+
context.Console.WriteError( $"The '{releasedVersionPropertyName}' property in '{source}' is not defined." );
4754

4855
releasedMainVersionPropertyValue = null;
4956
dependencyReleasedVersion = null;
@@ -60,7 +67,7 @@ private static bool TryRead(
6067

6168
if ( string.IsNullOrEmpty( releasedMainVersionPropertyValue ) )
6269
{
63-
context.Console.WriteError( $"The '{releasedMainVersionPropertyName}' property in '{path}' is not defined." );
70+
context.Console.WriteError( $"The '{releasedMainVersionPropertyName}' property in '{source}' is not defined." );
6471

6572
releasedMainVersionPropertyValue = null;
6673
dependencyReleasedVersion = null;
@@ -125,28 +132,48 @@ public static bool TryWrite(
125132
dependency.Name,
126133
dependency.EngineeringDirectory,
127134
FileName ) ),
128-
Path.GetFullPath( Path.Combine( context.RepoDirectory, "..", dependency.Name, dependency.EngineeringDirectory, FileName ) ),
129-
130-
// Artifact-dep flow: producer publishes its own AutoUpdatedVersions.props as a build artifact;
131-
// consumer pulls it to dependencies/<key>/AutoUpdatedVersions.props (see TeamCitySettingsFile and ConfigurationProperties).
132-
Path.GetFullPath( Path.Combine( context.RepoDirectory, "dependencies", dependencyConfiguration.Key, FileName ) )
135+
Path.GetFullPath( Path.Combine( context.RepoDirectory, "..", dependency.Name, dependency.EngineeringDirectory, FileName ) )
133136
];
134137

135138
var theirAutoUpdatedVersionsFilePath = filePathCandidates.FirstOrDefault( File.Exists );
136139

137-
if ( theirAutoUpdatedVersionsFilePath == null )
140+
string source;
141+
XDocument theirAutoUpdatedVersionsDocument;
142+
143+
if ( theirAutoUpdatedVersionsFilePath != null )
144+
{
145+
source = theirAutoUpdatedVersionsFilePath;
146+
theirAutoUpdatedVersionsDocument = XDocument.Load( theirAutoUpdatedVersionsFilePath );
147+
}
148+
else
138149
{
139-
context.Console.WriteError( $"None of these files exists: {string.Join( ", ", filePathCandidates.Select( x => $"'{x}'" ) )}." );
150+
// Fallback for artifact-only dependencies: AutoUpdatedVersions.props is build-independent source code,
151+
// so download it directly from the dependency's VCS repository on its release branch (or development branch
152+
// when no release branch is set). Keeps bump independent of any CI artifact pipeline.
153+
var branch = dependency.ReleaseBranch ?? dependency.Branch;
154+
var pathInRepo = $"{dependency.EngineeringDirectory.Replace( '\\', '/' )}/{FileName}";
155+
source = $"{dependency.VcsRepository}/{branch}/{pathInRepo}";
140156

141-
errors++;
157+
context.Console.WriteMessage(
158+
$"Local '{FileName}' for '{dependency.Name}' not found at any of [{string.Join( ", ", filePathCandidates.Select( x => $"'{x}'" ) )}]; downloading from '{source}'." );
142159

143-
continue;
160+
if ( !dependency.VcsRepository.TryDownloadTextFile( context.Console, branch, pathInRepo, out var text ) )
161+
{
162+
context.Console.WriteError( $"Failed to download '{source}'." );
163+
164+
errors++;
165+
166+
continue;
167+
}
168+
169+
theirAutoUpdatedVersionsDocument = XDocument.Parse( text );
144170
}
145171

146-
if ( !TryRead(
172+
if ( !TryParse(
147173
context,
148174
dependency,
149-
theirAutoUpdatedVersionsFilePath,
175+
source,
176+
theirAutoUpdatedVersionsDocument,
150177
out var dependencyReleasedVersion,
151178
out var releasedMainVersionPropertyValue ) )
152179
{

src/PostSharp.Engineering.BuildTools/ContinuousIntegration/TeamCity/Generation/ConfigurationProperties.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ public ConfigurationProperties( Product product, BuildConfiguration configuratio
3737
.Select( d => new TeamCitySnapshotDependency(
3838
d.Definition.CiConfiguration.BuildTypes[d.Configuration],
3939
true,
40-
string.Join(
41-
"\\n",
42-
$"+:{d.Definition.GetPrivateArtifactsDirectory( d.Configuration ).Replace( Path.DirectorySeparatorChar, '/' )}/**/*=>dependencies/{d.Key}",
43-
$"+:{d.Definition.EngineeringDirectory.Replace( '\\', '/' )}/AutoUpdatedVersions.props=>dependencies/{d.Key}/AutoUpdatedVersions.props" ),
40+
$"+:{d.Definition.GetPrivateArtifactsDirectory( d.Configuration ).Replace( Path.DirectorySeparatorChar, '/' )}/**/*=>dependencies/{d.Key}",
4441
ReuseBuilds: d.ArtifactPickup == DependencyArtifactPickup.LastSuccessful ? ReuseBuilds.LastSuccessful : ReuseBuilds.Default,
4542
Branch: d.ArtifactPickup == DependencyArtifactPickup.LastSuccessful && configuration == BuildConfiguration.Public
4643
? d.Definition.ReleaseBranch

src/PostSharp.Engineering.BuildTools/ContinuousIntegration/TeamCity/Generation/TeamCitySettingsFile.cs

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@ internal static bool TryWrite( BuildContext context )
5252
publishedArtifactRules += $@"\n+:{productProperties.LogsDirectory}/**/*=>logs";
5353
publishedArtifactRules += $@"\n+:{productProperties.DumpsDirectory}/**/*=>dumps";
5454

55-
// Publish AutoUpdatedVersions.props so consumers can read released versions of auto-updated dependencies
56-
// without needing them as source dependencies. Read by AutoUpdatedVersionsFile.TryRead during bump.
57-
publishedArtifactRules += $@"\n+:{product.AutoUpdatedVersionsFilePath.Replace( '\\', '/' )}=>{product.EngineeringDirectory.Replace( '\\', '/' )}";
58-
5955
var teamCityBuildConfiguration = CreateBuildConfiguration(
6056
context,
6157
productProperties,
@@ -273,27 +269,12 @@ private static TeamCityBuildConfiguration CreateUpstreamMergeConfiguration( Prod
273269

274270
private static TeamCityBuildConfiguration CreateBumpConfiguration( ProductProperties productProperties )
275271
{
276-
var product = productProperties.Product;
277-
278-
// Bump reads each auto-update dependency's AutoUpdatedVersions.props to learn its latest released version.
279-
// Pull only the props file from the dependency's last successful Public build on its release branch.
280-
var bumpDependencies = product.DependencyDefinition.GetAllDependencies( BuildConfiguration.Public )
281-
.Where( d => d.Definition.AutoUpdateVersion && d.Definition.GenerateSnapshotDependency )
282-
.Select( d => new TeamCitySnapshotDependency(
283-
d.Definition.CiConfiguration.BuildTypes[d.Configuration],
284-
true,
285-
$"+:{d.Definition.EngineeringDirectory.Replace( '\\', '/' )}/AutoUpdatedVersions.props=>dependencies/{d.Key}/AutoUpdatedVersions.props",
286-
ReuseBuilds: ReuseBuilds.LastSuccessful,
287-
Branch: d.Definition.ReleaseBranch ) )
288-
.OrderBy( d => d.ObjectId )
289-
.ToArray();
290-
291272
var bumpConfiguration = new TeamCityBuildConfiguration(
292273
objectName: "VersionBump",
293274
name: $"Version Bump",
294275
productProperties.DefaultBranch,
295276
productProperties.VcsId,
296-
buildAgentRequirements: product.ResolvedBuildAgentRequirements )
277+
buildAgentRequirements: productProperties.Product.ResolvedBuildAgentRequirements )
297278
{
298279
BuildSteps =
299280
[
@@ -302,10 +283,9 @@ private static TeamCityBuildConfiguration CreateBumpConfiguration( ProductProper
302283
"Bump",
303284
"bump",
304285
areCustomArgumentsAllowed: true,
305-
dockerSpec: product.DockerSpec,
306-
timeout: product.VersionBumpTimeout )
286+
dockerSpec: productProperties.Product.DockerSpec,
287+
timeout: productProperties.Product.VersionBumpTimeout )
307288
],
308-
SnapshotDependencies = bumpDependencies,
309289
IsSshAgentRequired = productProperties.IsRepoRemoteSsh
310290
};
311291

0 commit comments

Comments
 (0)