Skip to content

[Rollout] Production rollout 2025-04-30 #4775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions src/Maestro/Maestro.DataProviders/RemoteFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,23 @@
using Maestro.Data;
using Microsoft.DotNet.DarcLib;
using Microsoft.DotNet.DarcLib.Helpers;
using Microsoft.DotNet.DarcLib.VirtualMonoRepo;
using Microsoft.DotNet.GitHub.Authentication;
using Microsoft.DotNet.Internal.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Maestro.DataProviders;

public class RemoteFactory : IRemoteFactory
{
private readonly IVersionDetailsParser _versionDetailsParser;
private readonly OperationManager _operations;
private readonly IProcessManager _processManager;
private readonly ILoggerFactory _loggerFactory;
private readonly BuildAssetRegistryContext _context;
private readonly DarcRemoteMemoryCache _cache;
private readonly IGitHubTokenProvider _gitHubTokenProvider;
private readonly IAzureDevOpsTokenProvider _azdoTokenProvider;
private readonly ISourceMappingParser _sourceMappingParser;
private readonly IServiceProvider _serviceProvider;

public RemoteFactory(
BuildAssetRegistryContext context,
Expand All @@ -35,25 +34,24 @@ public RemoteFactory(
OperationManager operations,
IProcessManager processManager,
ILoggerFactory loggerFactory,
ISourceMappingParser sourceMappingParser)
IServiceProvider serviceProvider)
{
_operations = operations;
_processManager = processManager;
_loggerFactory = loggerFactory;
_versionDetailsParser = versionDetailsParser;
_context = context;
_gitHubTokenProvider = gitHubTokenProvider;
_azdoTokenProvider = azdoTokenProvider;
_cache = memoryCache;
_sourceMappingParser = sourceMappingParser;
_serviceProvider = serviceProvider;
}

public async Task<IRemote> CreateRemoteAsync(string repoUrl)
{
using (_operations.BeginOperation($"Getting remote for repo {repoUrl}."))
{
IRemoteGitRepo remoteGitClient = await GetRemoteGitClient(repoUrl);
return new Remote(remoteGitClient, _versionDetailsParser, _sourceMappingParser, _loggerFactory.CreateLogger<IRemote>());
return ActivatorUtilities.CreateInstance<Remote>(_serviceProvider, remoteGitClient);
}
}

Expand All @@ -62,7 +60,7 @@ public async Task<IDependencyFileManager> CreateDependencyFileManagerAsync(strin
using (_operations.BeginOperation($"Getting remote file manager for repo {repoUrl}."))
{
IRemoteGitRepo remoteGitClient = await GetRemoteGitClient(repoUrl);
return new DependencyFileManager(remoteGitClient, _versionDetailsParser, _loggerFactory.CreateLogger<IRemote>());
return ActivatorUtilities.CreateInstance<DependencyFileManager>(_serviceProvider, remoteGitClient);
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/Microsoft.DotNet.Darc/Darc/Helpers/RemoteFactory.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.DotNet.Darc.Options;
using Microsoft.DotNet.DarcLib;
using Microsoft.DotNet.DarcLib.Helpers;
using Microsoft.DotNet.DarcLib.VirtualMonoRepo;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Microsoft.DotNet.Darc.Helpers;
Expand All @@ -15,29 +16,28 @@ internal class RemoteFactory : IRemoteFactory
{
private readonly ILoggerFactory _loggerFactory;
private readonly ICommandLineOptions _options;
private readonly ISourceMappingParser _sourceMappingParser;
private readonly IServiceProvider _serviceProvider;

public RemoteFactory(
ILoggerFactory loggerFactory,
ICommandLineOptions options,
ISourceMappingParser sourceMappingParser)
IServiceProvider serviceProvider)
{
_loggerFactory = loggerFactory;
_options = options;
_sourceMappingParser = sourceMappingParser;
_serviceProvider = serviceProvider;
}

public Task<IRemote> CreateRemoteAsync(string repoUrl)
{
IRemoteGitRepo gitClient = CreateRemoteGitClient(_options, repoUrl);
return Task.FromResult<IRemote>(new Remote(gitClient, new VersionDetailsParser(), _sourceMappingParser, _loggerFactory.CreateLogger<IRemote>()));
return Task.FromResult<IRemote>(ActivatorUtilities.CreateInstance<Remote>(_serviceProvider, gitClient));
}

public Task<IDependencyFileManager> CreateDependencyFileManagerAsync(string repoUrl)
{
IRemoteGitRepo gitClient = CreateRemoteGitClient(_options, repoUrl);
var dfm = new DependencyFileManager(gitClient, new VersionDetailsParser(), _loggerFactory.CreateLogger<IDependencyFileManager>());
return Task.FromResult<IDependencyFileManager>(dfm);
return Task.FromResult<IDependencyFileManager>(ActivatorUtilities.CreateInstance<DependencyFileManager>(_serviceProvider, gitClient));
}

private IRemoteGitRepo CreateRemoteGitClient(ICommandLineOptions options, string repoUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,22 @@ internal class UpdateDependenciesOperation : Operation
private readonly IBarApiClient _barClient;
private readonly IRemoteFactory _remoteFactory;
private readonly IGitRepoFactory _gitRepoFactory;
private readonly ICoherencyUpdateResolver _coherencyUpdateResolver;

public UpdateDependenciesOperation(
UpdateDependenciesCommandLineOptions options,
IBarApiClient barClient,
IRemoteFactory remoteFactory,
IGitRepoFactory gitRepoFactory,
ICoherencyUpdateResolver coherencyUpdateResolver,
ILogger<UpdateDependenciesOperation> logger)
{
_options = options;
_logger = logger;
_barClient = barClient;
_remoteFactory = remoteFactory;
_gitRepoFactory = gitRepoFactory;
_coherencyUpdateResolver = coherencyUpdateResolver;
}

/// <summary>
Expand All @@ -50,8 +53,6 @@ public override async Task<int> ExecuteAsync()
{
try
{
var coherencyUpdateResolver = new CoherencyUpdateResolver(_barClient, _logger);

var local = new Local(_options.GetRemoteTokenProvider(), _logger);
List<DependencyDetail> dependenciesToUpdate = [];
bool someUpToDate = false;
Expand Down Expand Up @@ -113,7 +114,7 @@ public override async Task<int> ExecuteAsync()
Console.WriteLine($"Looking up build with BAR id {_options.BARBuildId}");
var specificBuild = await _barClient.GetBuildAsync(_options.BARBuildId);

int nonCoherencyResult = NonCoherencyUpdatesForBuild(specificBuild, coherencyUpdateResolver, currentDependencies, candidateDependenciesForUpdate, dependenciesToUpdate);
int nonCoherencyResult = NonCoherencyUpdatesForBuild(specificBuild, currentDependencies, candidateDependenciesForUpdate, dependenciesToUpdate);
if (nonCoherencyResult != Constants.SuccessCode)
{
_logger.LogError("Failed to update non-coherent parent tied dependencies.");
Expand Down Expand Up @@ -187,7 +188,7 @@ public override async Task<int> ExecuteAsync()
continue;
}

int nonCoherencyResult = NonCoherencyUpdatesForBuild(build, coherencyUpdateResolver, currentDependencies, candidateDependenciesForUpdate, dependenciesToUpdate);
int nonCoherencyResult = NonCoherencyUpdatesForBuild(build, currentDependencies, candidateDependenciesForUpdate, dependenciesToUpdate);
if (nonCoherencyResult != Constants.SuccessCode)
{
_logger.LogError("Failed to update non-coherent parent tied dependencies.");
Expand All @@ -196,7 +197,7 @@ public override async Task<int> ExecuteAsync()
}
}

int coherencyResult = await CoherencyUpdatesAsync(coherencyUpdateResolver, _remoteFactory, currentDependencies, dependenciesToUpdate)
int coherencyResult = await CoherencyUpdatesAsync(currentDependencies, dependenciesToUpdate)
.ConfigureAwait(false);
if (coherencyResult != Constants.SuccessCode)
{
Expand Down Expand Up @@ -250,9 +251,8 @@ public override async Task<int> ExecuteAsync()
}
}

private static int NonCoherencyUpdatesForBuild(
private int NonCoherencyUpdatesForBuild(
Build build,
ICoherencyUpdateResolver updateResolver,
List<DependencyDetail> currentDependencies,
List<DependencyDetail> candidateDependenciesForUpdate,
List<DependencyDetail> dependenciesToUpdate)
Expand All @@ -265,7 +265,7 @@ private static int NonCoherencyUpdatesForBuild(
});

// Now determine what needs to be updated.
List<DependencyUpdate> updates = updateResolver.GetRequiredNonCoherencyUpdates(
List<DependencyUpdate> updates = _coherencyUpdateResolver.GetRequiredNonCoherencyUpdates(
build.GetRepository(),
build.Commit,
assetData,
Expand All @@ -292,8 +292,6 @@ private static int NonCoherencyUpdatesForBuild(
}

private async Task<int> CoherencyUpdatesAsync(
ICoherencyUpdateResolver updateResolver,
IRemoteFactory remoteFactory,
List<DependencyDetail> currentDependencies,
List<DependencyDetail> dependenciesToUpdate)
{
Expand All @@ -303,7 +301,7 @@ private async Task<int> CoherencyUpdatesAsync(
try
{
// Now run a coherency update based on the current set of dependencies updated from the previous pass.
coherencyUpdates = await updateResolver.GetRequiredCoherencyUpdatesAsync(currentDependencies, remoteFactory);
coherencyUpdates = await _coherencyUpdateResolver.GetRequiredCoherencyUpdatesAsync(currentDependencies);
}
catch (DarcCoherencyException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public virtual IServiceCollection RegisterServices(IServiceCollection services)
disableInteractiveAuth: IsCi,
BuildAssetRegistryBaseUri));
services.TryAddSingleton<IBasicBarClient>(sp => sp.GetRequiredService<IBarApiClient>());
services.TryAddTransient<ICoherencyUpdateResolver, CoherencyUpdateResolver>();
services.TryAddTransient<ILogger>(sp => sp.GetRequiredService<ILogger<Operation>>());
services.TryAddTransient<ITelemetryRecorder, NoTelemetryRecorder>();
services.TryAddTransient<IGitRepoFactory>(sp => ActivatorUtilities.CreateInstance<GitRepoFactory>(sp, Path.GetTempPath()));
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.DotNet.Darc/DarcLib/AzureDevOpsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ private string DisplayPolicy(MergePolicyEvaluationResult result)
return $"- ❓ **{result.Title}** - {result.Message}";
}

if (result.Status == MergePolicyEvaluationStatus.DecisiveSuccess)
if (result.Status == MergePolicyEvaluationStatus.DecisiveSuccess || result.Status == MergePolicyEvaluationStatus.TransientSuccess)
{
return $"- ✔️ **{result.MergePolicyDisplayName}** Succeeded"
+ (result.Title == null ? string.Empty: $" - {result.Title}");
Expand Down
47 changes: 30 additions & 17 deletions src/Microsoft.DotNet.Darc/DarcLib/CoherencyUpdateResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ namespace Microsoft.DotNet.DarcLib;
public class CoherencyUpdateResolver : ICoherencyUpdateResolver
{
private readonly IBasicBarClient _barClient;
private readonly IRemoteFactory _remoteFactory;
private readonly ILogger _logger;

public CoherencyUpdateResolver(
IBasicBarClient barClient,
IRemoteFactory remoteFactory,
ILogger logger)
{
_barClient = barClient;
_remoteFactory = remoteFactory;
_logger = logger;
}

public async Task<List<DependencyUpdate>> GetRequiredCoherencyUpdatesAsync(
IEnumerable<DependencyDetail> dependencies,
IRemoteFactory remoteFactory)
=> await GetRequiredStrictCoherencyUpdatesAsync(dependencies, remoteFactory);
public async Task<List<DependencyUpdate>> GetRequiredCoherencyUpdatesAsync(IEnumerable<DependencyDetail> dependencies)
=> await GetRequiredStrictCoherencyUpdatesAsync(dependencies);

public List<DependencyUpdate> GetRequiredNonCoherencyUpdates(
string sourceRepoUri,
Expand All @@ -38,18 +39,32 @@ public List<DependencyUpdate> GetRequiredNonCoherencyUpdates(
Dictionary<DependencyDetail, DependencyDetail> toUpdate = [];

// Walk the assets, finding the dependencies that don't have coherency markers.
// And are not a part of the same build.
// those must be updated in a second pass.
foreach (AssetData asset in assets)
{
DependencyDetail matchingDependencyByName =
dependencies.FirstOrDefault(d => d.Name.Equals(asset.Name, StringComparison.OrdinalIgnoreCase) &&
string.IsNullOrEmpty(d.CoherentParentDependencyName));
dependencies.FirstOrDefault(d => d.Name.Equals(asset.Name, StringComparison.OrdinalIgnoreCase));

if (matchingDependencyByName == null)
{
continue;
}

// If the dependency has a coherent parent, and the parent is among the build assets (in case of VMR builds)
// we still want to update the dependency.
if (!string.IsNullOrEmpty(matchingDependencyByName.CoherentParentDependencyName))
{
if (!assets.Any(a => a.Name == matchingDependencyByName.CoherentParentDependencyName))
{
continue;
}
if (dependencies.FirstOrDefault(d => d.Name == matchingDependencyByName.CoherentParentDependencyName)?.Pinned ?? false)
{
continue;
}
}

// If the dependency is pinned, don't touch it.
if (matchingDependencyByName.Pinned)
{
Expand Down Expand Up @@ -97,7 +112,6 @@ public List<DependencyUpdate> GetRequiredNonCoherencyUpdates(
/// Get updates required by coherency constraints using the "strict" algorithm
/// </summary>
/// <param name="dependencies">Current set of dependencies.</param>
/// <param name="remoteFactory">Remote factory for remote queries.</param>
/// <returns>Dependencies with updates.</returns>
/// <remarks>
/// 'Strict' coherency is a version of coherency that does not **require** any build information,
Expand All @@ -119,9 +133,7 @@ public List<DependencyUpdate> GetRequiredNonCoherencyUpdates(
/// but this is fairly minimal and generally covered by the need to have dependencies explicit in the
/// version details files anyway.
/// </remarks>
private async Task<List<DependencyUpdate>> GetRequiredStrictCoherencyUpdatesAsync(
IEnumerable<DependencyDetail> dependencies,
IRemoteFactory remoteFactory)
private async Task<List<DependencyUpdate>> GetRequiredStrictCoherencyUpdatesAsync(IEnumerable<DependencyDetail> dependencies)
{
List<DependencyUpdate> toUpdate = [];
IEnumerable<DependencyDetail> leavesOfCoherencyTrees = CalculateLeavesOfCoherencyTrees(dependencies);
Expand Down Expand Up @@ -189,7 +201,7 @@ private async Task<List<DependencyUpdate>> GetRequiredStrictCoherencyUpdatesAsyn
if (!dependenciesCache.TryGetValue(parentCoherentDependencyCacheKey,
out IEnumerable<DependencyDetail> coherentParentsDependencies))
{
IRemote remoteClient = await remoteFactory.CreateRemoteAsync(parentCoherentDependency.RepoUri);
IRemote remoteClient = await _remoteFactory.CreateRemoteAsync(parentCoherentDependency.RepoUri);
coherentParentsDependencies = await remoteClient.GetDependenciesAsync(
parentCoherentDependency.RepoUri,
parentCoherentDependency.Commit);
Expand Down Expand Up @@ -235,7 +247,7 @@ private async Task<List<DependencyUpdate>> GetRequiredStrictCoherencyUpdatesAsyn
_logger.LogInformation($"Dependency {dependencyToUpdate.Name} will be updated to " +
$"{cpdDependency.Version} from {cpdDependency.RepoUri}@{cpdDependency.Commit}.");

Asset coherentAsset = await DisambiguateAssetsAsync(remoteFactory, buildCache, nugetConfigCache,
Asset coherentAsset = await DisambiguateAssetsAsync(buildCache, nugetConfigCache,
parentCoherentDependency, cpdDependency);

var updatedDependency = new DependencyDetail(dependencyToUpdate)
Expand Down Expand Up @@ -314,15 +326,16 @@ private static IEnumerable<DependencyDetail> CalculateLeavesOfCoherencyTrees(IEn
/// Disambiguate a set of potential assets based the nuget config
/// file in a repo. The asset's locations are returned if a match is found.
/// </summary>
/// <param name="remoteFactory">Remote factory for looking up the nuget config.</param>
/// <param name="buildCache">Cache of builds</param>
/// <param name="nugetConfigCache">Cache of nuget config files</param>
/// <param name="parentCoherentDependency">Parent dependency of <paramref name="cpdDependency"/></param>
/// <param name="cpdDependency">Dependency to disambiguate on.</param>
/// <returns>Asset if a match to nuget.config is found. Asset from newest build is returned </returns>
private async Task<Asset> DisambiguateAssetsAsync(IRemoteFactory remoteFactory,
Dictionary<string, List<Build>> buildCache, Dictionary<string, IEnumerable<string>> nugetConfigCache,
DependencyDetail parentCoherentDependency, DependencyDetail cpdDependency)
private async Task<Asset> DisambiguateAssetsAsync(
Dictionary<string, List<Build>> buildCache,
Dictionary<string, IEnumerable<string>> nugetConfigCache,
DependencyDetail parentCoherentDependency,
DependencyDetail cpdDependency)
{
var parentCoherentDependencyCacheKey = $"{parentCoherentDependency.RepoUri}@{parentCoherentDependency.Commit}";

Expand Down Expand Up @@ -389,7 +402,7 @@ private async Task<Asset> DisambiguateAssetsAsync(IRemoteFactory remoteFactory,
// coherent asset itself.
if (!nugetConfigCache.TryGetValue(parentCoherentDependencyCacheKey, out IEnumerable<string> nugetFeeds))
{
IRemote remoteClient = await remoteFactory.CreateRemoteAsync(parentCoherentDependency.RepoUri);
IRemote remoteClient = await _remoteFactory.CreateRemoteAsync(parentCoherentDependency.RepoUri);
nugetFeeds = await remoteClient.GetPackageSourcesAsync(parentCoherentDependency.RepoUri, parentCoherentDependency.Commit);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.DotNet.Darc/DarcLib/GitHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ private static void UpdateCheckRun(NewCheckRun newCheckRun, MergePolicyEvaluatio
{
newCheckRun.Status = CheckStatus.InProgress;
}
else if (result.Status == MergePolicyEvaluationStatus.DecisiveSuccess)
else if (result.Status == MergePolicyEvaluationStatus.DecisiveSuccess || result.Status == MergePolicyEvaluationStatus.TransientSuccess)
{
newCheckRun.Conclusion = "success";
newCheckRun.CompletedAt = DateTime.Now;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ public interface ICoherencyUpdateResolver
/// Get updates required by coherency constraints.
/// </summary>
/// <param name="dependencies">Current set of dependencies.</param>
/// <param name="remoteFactory">Remote factory for remote queries.</param>
/// <returns>List of dependency updates.</returns>
Task<List<DependencyUpdate>> GetRequiredCoherencyUpdatesAsync(
IEnumerable<DependencyDetail> dependencies,
IRemoteFactory remoteFactory);
Task<List<DependencyUpdate>> GetRequiredCoherencyUpdatesAsync(IEnumerable<DependencyDetail> dependencies);

/// <summary>
/// Given a current set of dependencies, determine what non-coherency updates
Expand Down
Loading