Dependencies: add consumer-side Alias for multi-version references#109
Open
gfraiteur wants to merge 2 commits intodevelop/2023.2from
Open
Dependencies: add consumer-side Alias for multi-version references#109gfraiteur wants to merge 2 commits intodevelop/2023.2from
gfraiteur wants to merge 2 commits intodevelop/2023.2from
Conversation
Adds a per-use-site `Alias` and `ArtifactPickup` (Snapshot/LastSuccessful)
on `ParametrizedDependency` so a referencing product can list the same
logical dependency under two different `ProductFamily` versions without
MSBuild property-name collisions. The alias drives the `dependencies/{Key}/`
directory layout, the generated MSBuild property prefix, and the TeamCity
artifact-rule destination. A fetch-time XML transform projects the
producer's `<{Name}.version.props>` into a `<{Alias}.version.props>` whose
producer-prefixed property/item names are renamed (using a curated
suffix list to avoid renaming transitive Feed dep properties). Transitive
dependency resolution now starts from the direct dep's family, so an
aliased Metalama 2026.0 routes its transitive `Metalama.Compiler` to
the V2026_0 definition rather than the consumer's V2026_1 family.
`Metalama.Vsx` 2026.1 now references Metalama 2026.0 alongside 2026.1,
mapped to BuildConfiguration.Public with `LastSuccessful` artifact pickup
(no snapshot dependency).
Includes a new `PostSharp.Engineering.BuildTools.Tests` project with
13 tests covering the alias semantics and the version.props transform.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds consumer-side dependency aliasing (plus artifact pickup mode) so a product can reference multiple versions of the same logical dependency without MSBuild/config key collisions, and plumbs the alias-aware key through dependency resolution, file generation, and TeamCity CI generation.
Changes:
- Introduce
ParametrizedDependency.Alias/Key/KeyWithoutDotandDependencyArtifactPickup(Snapshot vs LastSuccessful) and propagate through dependency configuration models. - Update dependency fetch/restore/local resolution to support aliased
{Key}.version.propsvia an XML transform of producer{Name}.version.props. - Add
PostSharp.Engineering.BuildTools.Tests(xUnit) covering alias semantics and the version.props transform.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/PostSharp.Engineering.BuildTools/PostSharp.Engineering.BuildTools.csproj | Exposes internals to the new test assembly. |
| src/PostSharp.Engineering.BuildTools/Dependencies/Model/ParametrizedDependency.cs | Adds alias-aware keying and artifact pickup mode + fluent helpers. |
| src/PostSharp.Engineering.BuildTools/Dependencies/Model/DependencySource.cs | Adds alias-aware restored-dependency creation overload. |
| src/PostSharp.Engineering.BuildTools/Dependencies/Model/DependencyDefinition.cs | Carries parametrized info into recursive dependency enumeration; adds WithAlias. |
| src/PostSharp.Engineering.BuildTools/Dependencies/Model/DependencyConfiguration.cs | Adds alias-aware Key/KeyWithoutDot/ArtifactPickup and custom equality. |
| src/PostSharp.Engineering.BuildTools/Dependencies/Model/DependencyArtifactPickup.cs | New enum controlling snapshot vs last-successful artifact pickup. |
| src/PostSharp.Engineering.BuildTools/Dependencies/DependenciesHelper.cs | Plumbs alias keys through fetch/restore/local resolution and adds version.props transform. |
| src/PostSharp.Engineering.BuildTools/Dependencies/Definitions/MetalamaVsxDependencies.V2026_1.cs | Demonstrates dual Metalama refs (V2026_1 + aliased V2026_0, last-successful). |
| src/PostSharp.Engineering.BuildTools/ContinuousIntegration/TeamCity/Generation/TeamCitySettingsFile.cs | Excludes non-snapshot deps from deploy/upstream-merge snapshot dependency sets. |
| src/PostSharp.Engineering.BuildTools/ContinuousIntegration/TeamCity/Generation/ConfigurationProperties.cs | Generates artifact rules keyed by alias and supports last-successful artifact dependencies. |
| src/PostSharp.Engineering.BuildTools/ContinuousIntegration/Model/PowershellAdditionalCiBuildConfiguration.cs | Uses alias-aware keys in artifact rules and version import paths. |
| src/PostSharp.Engineering.BuildTools/Build/Model/Product.cs | Updates dependency lookup to consider alias-aware keys. |
| src/PostSharp.Engineering.BuildTools/Build/Files/VersionFile.cs | Reads/validates dependency versions using alias-aware keys. |
| src/PostSharp.Engineering.BuildTools/Build/Files/DependenciesConfigurationFile.cs | Writes/reads dependency imports and version properties using alias-aware keys. |
| src/PostSharp.Engineering.BuildTools/Build/Files/ArtifactManifestFile.cs | Emits dependency lists keyed by alias-aware keys in producer manifests. |
| src/PostSharp.Engineering.BuildTools.Tests/runtimeconfig.template.json | Test runtime roll-forward configuration. |
| src/PostSharp.Engineering.BuildTools.Tests/TransformVersionPropsForAliasTests.cs | Tests for the version.props alias transform behavior. |
| src/PostSharp.Engineering.BuildTools.Tests/PostSharp.Engineering.BuildTools.Tests.csproj | New xUnit test project definition. |
| src/PostSharp.Engineering.BuildTools.Tests/ParametrizedDependencyAliasTests.cs | Tests alias key semantics, pickup mode, and config equality behavior. |
| PostSharp.Engineering.sln | Adds the test project and extra solution configurations. |
| Directory.Packages.props | Adds package versions for test dependencies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
281
to
283
| dependency = this.ParametrizedDependencies.SingleOrDefault( d => d.Key == name ) | ||
| ?? this.ParametrizedDependencies.SingleOrDefault( d => d.Name == name ); | ||
|
|
Comment on lines
301
to
305
| public bool TryGetDependencyDefinition( string name, [NotNullWhen( true )] out DependencyDefinition? dependencyDefinition ) | ||
| { | ||
| dependencyDefinition = this.ParametrizedDependencies.SingleOrDefault( d => d.Name == name )?.Definition; | ||
| dependencyDefinition = (this.ParametrizedDependencies.SingleOrDefault( d => d.Key == name ) | ||
| ?? this.ParametrizedDependencies.SingleOrDefault( d => d.Name == name ))?.Definition; | ||
|
|
Comment on lines
+524
to
+535
| var aliasDirectory = TeamCityHelper.GetRestoredDependencyDirectory( context.RepoDirectory, dependency.Key ); | ||
| var producerRestoredPath = Path.Combine( aliasDirectory, dependency.Dependency.Name + ".version.props" ); | ||
| var aliasedVersionPropsPath = Path.Combine( aliasDirectory, dependency.Key + ".version.props" ); | ||
|
|
||
| if ( File.Exists( producerRestoredPath ) && !File.Exists( aliasedVersionPropsPath ) ) | ||
| { | ||
| TransformVersionPropsForAlias( | ||
| producerRestoredPath, | ||
| aliasedVersionPropsPath, | ||
| dependency.Dependency.NameWithoutDot, | ||
| dependency.KeyWithoutDot ); | ||
| } |
Three correctness fixes from Copilot review:
- Product.TryGetDependency / TryGetDependencyDefinition: drop the
ambiguous Definition.Name fallback that would throw whenever two
ParametrizedDependency entries declare different aliases for the
same Definition.Name. Lookup is now strictly by Key (which equals
Name for unaliased entries, preserving legacy callers).
- DependenciesHelper.ResolveBuildNumbersFromBranches: use
ResolvedDependency.Parametrized directly instead of looking it up
by Definition.Name. The Name-based lookup returned the wrong
ParametrizedDependency (and its ConfigurationMapping) when the
consumer had two refs to the same Definition under different
aliases. The path is only reachable for direct deps, where
Parametrized is always populated.
- DependenciesHelper.ResolveRestoredDependencies: always re-transform
the producer's restored {Name}.version.props rather than skipping
when {Key}.version.props already exists. The previous gate left a
stale file when TeamCity restored a fresher version over an
existing dependencies/{Key}/ directory.
Adds a test covering the throw-avoidance scenario (two aliased refs
to the same Definition.Name).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AliasandArtifactPickup(Snapshot/LastSuccessful) onParametrizedDependencyso a referencing product can list the same logical dependency under twoProductFamilyversions without MSBuild property-name collisions.Key(alias-aware) through file generators (DependenciesConfigurationFile,VersionFile,ArtifactManifestFile) and CI generators (ConfigurationProperties,PowershellAdditionalCiBuildConfiguration,TeamCitySettingsFile). For unaliased dependencies,Key == Nameand behavior is unchanged (regression-verified by runningb prepareon PostSharp.Engineering itself: byte-identical generated files).{Name}.version.propsinto a{Alias}.version.propswith prefix-substituted element names. Uses a curated suffix list so transitive Feed dep properties (e.g.<MetalamaCompilerVersion>) are not renamed. Relative<Import Project=".."/>paths are absolutized so the relocated copy still resolves. Applies uniformly to BuildServer, RestoredDependency, and Local source kinds.ProductFamily, falling back to the consumer''sProductonly if not found. Required for aliased deps: a Metalama 2026.0 reference''s transitiveMetalama.Compilernow correctly routes to V2026_0.MetalamaCompiler instead of V2026_1.MetalamaCompiler.MetalamaVsxDependencies.V2026_1now referencesMetalamaDependencies.V2026_0.Metalamaalongside V2026_1, mapped toBuildConfiguration.PublicwithWithLastSuccessfulOnly()(artifact-only TeamCity dependency, no snapshot).PostSharp.Engineering.BuildTools.Testsproject (xUnit) with 13 tests covering alias semantics and the version.props transform.Backward compatibility
The alias is purely additive: when no alias is set,
Key == Nameand every code path is byte-identical to before. A regression run ofb prepareon PostSharp.Engineering produced an identicaleng/Versions.Debug.g.propsmodulo environment-specific lines (version comment, user data dir).Notes
DependencyConfigurationgot customEquals/GetHashCodeto keep(Definition, Configuration)as the equality key — the auto-generated record equality would have included the newParametrizedproperty, breakingHashSet-based deduplication inGetAllDependencies.🤖 Generated with Claude Code