Skip to content

Commit afa79da

Browse files
dkurepapremunCopilotondrejsmidadamzip
authored
[Production Rollout] Rollout 2025-07-09 (#5041)
<!-- Link the GitHub or AzDO issue this pull request is associated with. Please copy and paste the full URL rather than using the dotnet/arcade-services# syntax --> #5040 --------- Co-authored-by: Přemek Vysoký <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: premun <[email protected]> Co-authored-by: ondrejsmid <[email protected]> Co-authored-by: Adam <[email protected]>
2 parents 9d0b640 + 5d7a15f commit afa79da

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+510
-2422
lines changed

docs/Darc.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ use darc to achieve them, as well as a general reference guide to darc commands.
6565

6666
Darc also has a suite of new VMR commands. These all have the following format `darc vmr <command>`:
6767
- [initialize](#initialize) - Initializes new repo(s) that haven't been synchronized into the VMR yet.
68-
- [update](#update) - Updates given repo(s) in the VMR to match given refs.
6968
- [backflow](#backflow) - Flows source code from the current commit of a locally checked out VMR into a target local repository.
7069
- [cherry-pick](#cherry-pick) - Cherry-picks a single commit from a repository to/from the VMR.
7170
- [forwardflow](#forwardflow) - Flows source code from the current commit of a local repository into a local VMR.
7271
- [generate-tpn](#generate-tpn) - Generates a new THIRD-PARTY-NOTICES.txt.
7372
- [get-version](#get-version) - Gets the current version (a SHA) of a repository in the VMR.
7473
- [push](#push) - Pushes given VMR branch to a given remote.
74+
- [reset](#reset) - Resets the contents of a VMR mapping to match a specific commit SHA from the source repository.
7575
- [diff](#diff) - Diffs the VMR and the product repositories.
7676

7777
## Scenarios
@@ -2681,16 +2681,6 @@ Initializes new repo(s) that haven't been synchronized into the VMR yet. The new
26812681
darc vmr initialize -r --source-mappings <path to source mappings> arcade-services
26822682
```
26832683
2684-
### **`update`**
2685-
2686-
Updates given repo(s) in the VMR to match given refs. This command was primarely used in the dotnet/sdk pipelines to recursevly update the VMR with the latest commits.
2687-
The command shouldn't be used for local development, [backflow](#backflow) and [forwardflow](#forwardflow) commands are reccomended for this scenario
2688-
2689-
**Sample**
2690-
```
2691-
darc vmr update --recursive sdk:<sha>
2692-
```
2693-
26942684
### **`backflow`**
26952685
26962686
Flows source code from the current commit of a locally checked out VMR into a target local repository. Must be called from
@@ -2762,6 +2752,19 @@ Note: this command was used prior to onboarding repos onto flat flow to push new
27622752
darc vmr push --remote-url https://github.com/myfork/dotnet --branch main --skip-commit-verification
27632753
```
27642754
2755+
### **`reset`**
2756+
2757+
Resets the contents of a VMR mapping to match a specific commit SHA from the source repository, effectively restoring the mapping to a known good state. This command takes a single parameter in the format `[mapping]:[sha]`.
2758+
2759+
**Sample**
2760+
```
2761+
# Reset runtime mapping to specific commit
2762+
darc vmr reset runtime:abc123def456
2763+
# Invalid format - shows clear error
2764+
darc vmr reset invalid-format
2765+
# Output: fail: Invalid format. Expected [mapping]:[sha] but got: invalid-format
2766+
```
2767+
27652768
### **`diff`**
27662769
27672770
Diffs the VMR and the product repositories. Outputs the diff to stdout or saves it to a patch file (or multiple if patch > 1 GB), if --output-path is provided.

eng/enforce-issue.ps1

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,27 @@ elseif ($prDetail.title -match "\[automated\]") {
2424
exit 0
2525
}
2626

27-
# Look for https://github.com/dotnet/arcade-services/issues/3625
28-
$hasIssue = $prDetail.body -Match "github\.com/dotnet/(.+)/issues/(\d+)"
27+
28+
$issuePatterns = @{
29+
"GitHub Full Link" = "github\.com/dotnet/(.+)/issues/(\d+)" # Eg: https://github.com/dotnet/arcade-services/issues/3625
30+
"AzDO DevOps Link" = "dev\.azure\.com/(.+)/(.+)/_workitems" #Eg: https://dev.azure.com/dnceng/internal/_workitems/edit/45126
31+
"AzDO Visual Studio Link" = "(.+)\.visualstudio\.com/(.+)/_workitems"
32+
"GitHub Issue Shortcut" = "(?<!\w)#\d+\b" # Eg: #5374
33+
}
34+
35+
$hasIssue = $false
36+
37+
foreach ($name in $issuePatterns.Keys) {
38+
if ($prDetail.body -match $issuePatterns[$name]) {
39+
Write-Host "Found issue link matching pattern: $name"
40+
$hasIssue = $true
41+
break
42+
}
43+
}
44+
2945
if (-not $hasIssue) {
30-
# Or for https://dev.azure.com/dnceng/internal/_workitems/edit/45126
31-
$hasIssue = $prDetail.body -Match "dev\.azure\.com/(.+)/(.+)/_workitems"
32-
if (-not $hasIssue) {
33-
# Or for https://dev.azure.com/dnceng/internal/_workitems/edit/12345
34-
$hasIssue = $prDetail.body -Match "(.+)\.visualstudio\.com/(.+)/_workitems"
35-
if (-not $hasIssue) {
36-
Write-Host "##vso[task.LogIssue type=error;]Link to the corresponding GitHub/AzDO issue is missing in the PR description. Check failed."
37-
exit 1
38-
}
39-
}
46+
Write-Host "##vso[task.LogIssue type=error;]Link to the corresponding GitHub/AzDO issue is missing in the PR description. Check failed."
47+
exit 1
4048
}
4149

4250
exit 0

src/Microsoft.DotNet.Darc/Darc/Operations/VirtualMonoRepo/CodeFlowOperation.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ protected async Task FlowCodeLocallyAsync(
125125
excludedAssets: [],
126126
tmpTargetBranch,
127127
tmpHeadBranch,
128-
discardPatches: true,
129128
headBranchExisted: false,
130129
cancellationToken);
131130
}

src/Microsoft.DotNet.Darc/Darc/Operations/VirtualMonoRepo/InitializeOperation.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,12 @@ protected override async Task ExecuteInternalAsync(
3737
await _vmrInitializer.InitializeRepository(
3838
repoName,
3939
targetRevision,
40-
_options.Recursive,
4140
new NativePath(_options.SourceMappings),
4241
new CodeFlowParameters(
4342
additionalRemotes,
4443
_options.TpnTemplate,
4544
_options.GenerateCodeowners,
46-
_options.GenerateCredScanSuppressions,
47-
_options.DiscardPatches,
48-
ApplyAdditionalMappings: true),
49-
_options.EnableBuildLookUp,
45+
_options.GenerateCredScanSuppressions),
5046
cancellationToken);
5147
}
5248
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Collections.Immutable;
7+
using System.Linq;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using Microsoft.DotNet.Darc.Options.VirtualMonoRepo;
11+
using Microsoft.DotNet.DarcLib;
12+
using Microsoft.DotNet.DarcLib.Helpers;
13+
using Microsoft.DotNet.DarcLib.Models.VirtualMonoRepo;
14+
using Microsoft.DotNet.DarcLib.VirtualMonoRepo;
15+
using Microsoft.Extensions.Logging;
16+
17+
#nullable enable
18+
namespace Microsoft.DotNet.Darc.Operations.VirtualMonoRepo;
19+
20+
internal class ResetOperation : Operation
21+
{
22+
private readonly ResetCommandLineOptions _options;
23+
private readonly IVmrInfo _vmrInfo;
24+
private readonly IVmrUpdater _vmrUpdater;
25+
private readonly IVmrDependencyTracker _dependencyTracker;
26+
private readonly IProcessManager _processManager;
27+
private readonly ILogger<ResetOperation> _logger;
28+
29+
public ResetOperation(
30+
ResetCommandLineOptions options,
31+
IVmrInfo vmrInfo,
32+
IVmrUpdater vmrUpdater,
33+
IVmrDependencyTracker dependencyTracker,
34+
IProcessManager processManager,
35+
ILogger<ResetOperation> logger)
36+
{
37+
_options = options;
38+
_vmrInfo = vmrInfo;
39+
_vmrUpdater = vmrUpdater;
40+
_dependencyTracker = dependencyTracker;
41+
_processManager = processManager;
42+
_logger = logger;
43+
}
44+
45+
public override async Task<int> ExecuteAsync()
46+
{
47+
// Parse the mapping:sha parameter
48+
var parts = _options.Target.Split(':', 2);
49+
if (parts.Length != 2)
50+
{
51+
_logger.LogError("Invalid format. Expected [mapping]:[sha] but got: {input}", _options.Target);
52+
return Constants.ErrorCode;
53+
}
54+
55+
var mappingName = parts[0];
56+
var targetSha = parts[1];
57+
58+
if (string.IsNullOrWhiteSpace(mappingName) || string.IsNullOrWhiteSpace(targetSha))
59+
{
60+
_logger.LogError("Both mapping name and SHA must be provided. Got mapping: '{mapping}', SHA: '{sha}'",
61+
mappingName, targetSha);
62+
return Constants.ErrorCode;
63+
}
64+
65+
_logger.LogInformation("Resetting VMR mapping '{mapping}' to SHA '{sha}'", mappingName, targetSha);
66+
67+
_vmrInfo.VmrPath = new NativePath(_options.VmrPath);
68+
69+
// Validate that the mapping exists
70+
await _dependencyTracker.RefreshMetadata();
71+
72+
SourceMapping mapping;
73+
try
74+
{
75+
mapping = _dependencyTracker.GetMapping(mappingName);
76+
_logger.LogInformation("Found mapping '{mapping}' pointing to remote '{remote}'",
77+
mappingName, mapping.DefaultRemote);
78+
}
79+
catch (Exception ex)
80+
{
81+
_logger.LogError("Mapping '{mapping}' not found: {error}", mappingName, ex.Message);
82+
return Constants.ErrorCode;
83+
}
84+
85+
var currentVersion = _dependencyTracker.GetDependencyVersion(mapping);
86+
if (currentVersion == null)
87+
{
88+
_logger.LogError("Could not find current dependency version for mapping '{mapping}'", mappingName);
89+
return Constants.ErrorCode;
90+
}
91+
92+
// Additional remotes are in the form of [mapping name]:[remote URI]
93+
IReadOnlyCollection<AdditionalRemote> additionalRemotes = Array.Empty<AdditionalRemote>();
94+
if (_options.AdditionalRemotes != null)
95+
{
96+
additionalRemotes = _options.AdditionalRemotes
97+
.Select(a => a.Split(':', 2))
98+
.Select(parts => new AdditionalRemote(parts[0], parts[1]))
99+
.ToImmutableArray();
100+
}
101+
102+
// Perform the reset by updating to the target SHA
103+
// This will erase differences and repopulate content to match the target SHA
104+
var codeFlowParameters = new CodeFlowParameters(
105+
AdditionalRemotes: additionalRemotes,
106+
TpnTemplatePath: null,
107+
GenerateCodeOwners: false,
108+
GenerateCredScanSuppressions: false);
109+
110+
// We will remove everything not-cloaked and replace it with current contents of the source repo
111+
// When flowing to the VMR, we remove all files but the cloaked files
112+
List<string> removalFilters =
113+
[
114+
.. mapping.Include.Select(VmrPatchHandler.GetInclusionRule),
115+
.. mapping.Exclude.Select(VmrPatchHandler.GetExclusionRule)
116+
];
117+
118+
try
119+
{
120+
// Delete all uncloaked files in the mapping directory
121+
var targetDir = _vmrInfo.GetRepoSourcesPath(mapping);
122+
var result = await _processManager.Execute(
123+
_processManager.GitExecutable,
124+
["rm", "-r", "-q", "--", .. removalFilters],
125+
workingDir: targetDir);
126+
127+
result.ThrowIfFailed($"Failed to remove files in {targetDir}");
128+
129+
// Tell the VMR dependency tracker that the repository has been reset
130+
_dependencyTracker.UpdateDependencyVersion(new VmrDependencyUpdate(
131+
mapping,
132+
mapping.DefaultRemote,
133+
DarcLib.Constants.EmptyGitObject,
134+
Parent: null,
135+
OfficialBuildId: null,
136+
BarId: null));
137+
138+
await _vmrUpdater.UpdateRepository(
139+
mappingName,
140+
targetSha,
141+
codeFlowParameters,
142+
resetToRemoteWhenCloningRepo: false,
143+
CancellationToken.None);
144+
145+
_logger.LogInformation("Successfully reset {mapping} to {sha}", mappingName, targetSha);
146+
return Constants.SuccessCode;
147+
}
148+
catch (Exception ex)
149+
{
150+
_logger.LogError(ex, "An error occurred while resetting {mapping}", mappingName);
151+
return Constants.ErrorCode;
152+
}
153+
}
154+
}

src/Microsoft.DotNet.Darc/Darc/Operations/VirtualMonoRepo/UpdateOperation.cs

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Generic;
45
using CommandLine;
56
using Microsoft.DotNet.Darc.Operations.VirtualMonoRepo;
6-
using Microsoft.DotNet.DarcLib.Helpers;
77
using Microsoft.DotNet.DarcLib.VirtualMonoRepo;
88

99
namespace Microsoft.DotNet.Darc.Options.VirtualMonoRepo;
1010

1111
[Verb("initialize", HelpText = "Initializes new repo(s) that haven't been synchronized into the VMR yet.")]
12-
internal class InitializeCommandLineOptions : VmrSyncCommandLineOptions<InitializeOperation>
12+
internal class InitializeCommandLineOptions : VmrCommandLineOptions<InitializeOperation>, IBaseVmrCommandLineOptions
1313
{
14-
[Option('r', "recursive", Required = false, HelpText = $"Process also dependencies (from {VersionFiles.VersionDetailsXml}) recursively.")]
15-
public bool Recursive { get; set; } = false;
16-
1714
[Option("source-mappings", Required = true, HelpText = $"A path to the {VmrInfo.SourceMappingsFileName} file to be used for syncing.")]
1815
public string SourceMappings { get; set; }
1916

20-
[Option("enable-build-lookup", Required = false, HelpText = "Look up package versions and build number from BAR when populating version files.")]
21-
public bool EnableBuildLookUp { get; set; } = false;
17+
[Option("additional-remotes", Required = false, HelpText =
18+
"List of additional remote URIs to add to mappings in the format [mapping name]:[remote URI]. " +
19+
"Example: installer:https://github.com/myfork/installer sdk:/local/path/to/sdk")]
20+
[RedactFromLogging]
21+
public IEnumerable<string> AdditionalRemotes { get; set; }
22+
23+
[Value(0, Required = true, HelpText =
24+
"Repository names in the form of NAME or NAME:REVISION where REVISION is a commit SHA or other git reference (branch, tag). " +
25+
"Omitting REVISION will synchronize the repo to current HEAD.")]
26+
public IEnumerable<string> Repositories { get; set; }
27+
28+
[Option("tpn-template", Required = false, HelpText = "Path to a template for generating VMRs THIRD-PARTY-NOTICES file. Leave empty to skip generation.")]
29+
public string TpnTemplate { get; set; }
30+
31+
[Option("generate-codeowners", Required = false, HelpText = "Generate a common CODEOWNERS file for all repositories.")]
32+
public bool GenerateCodeowners { get; set; } = false;
33+
34+
[Option("generate-credscansuppressions", Required = false, HelpText = "Generate a common .config/CredScanSuppressions.json file for all repositories.")]
35+
public bool GenerateCredScanSuppressions { get; set; } = false;
2236
}

0 commit comments

Comments
 (0)