WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 984a3da

Browse files
authored
Only look at NuGet when cleaning darc feeds (#4448)
<!-- 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 --> #4266 Discussed with Matt, we don't need to look at AzDo feeds anymore, everything that's released should be in NuGet
2 parents 9e64866 + 8403da2 commit 984a3da

File tree

6 files changed

+108
-235
lines changed

6 files changed

+108
-235
lines changed

src/ProductConstructionService/ProductConstructionService.FeedCleaner/FeedCleaner.cs

Lines changed: 47 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
using Microsoft.EntityFrameworkCore;
1111
using Microsoft.Extensions.Logging;
1212

13-
using PackagesInReleaseFeeds = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, System.Collections.Generic.HashSet<string>>>;
14-
1513
namespace ProductConstructionService.FeedCleaner;
1614

1715
public class FeedCleaner
@@ -24,15 +22,16 @@ public class FeedCleaner
2422
public FeedCleaner(
2523
IAzureDevOpsClient azureDevOpsClient,
2624
BuildAssetRegistryContext context,
25+
IHttpClientFactory httpClientFactory,
2726
ILogger<FeedCleaner> logger)
2827
{
2928
_azureDevOpsClient = azureDevOpsClient;
3029
_context = context;
3130
_logger = logger;
32-
_httpClient = new HttpClient(new HttpClientHandler() { CheckCertificateRevocationList = true });
31+
_httpClient = httpClientFactory.CreateClient();
3332
}
3433

35-
public async Task CleanFeedAsync(AzureDevOpsFeed feed, PackagesInReleaseFeeds packagesInReleaseFeeds)
34+
public async Task CleanFeedAsync(AzureDevOpsFeed feed)
3635
{
3736
try
3837
{
@@ -44,10 +43,10 @@ public async Task CleanFeedAsync(AzureDevOpsFeed feed, PackagesInReleaseFeeds pa
4443

4544
foreach (var package in packages)
4645
{
47-
HashSet<string> updatedVersions = await UpdateReleasedVersionsForPackageAsync(feed, package, packagesInReleaseFeeds);
46+
HashSet<Asset> updatedAssets = await UpdateReleasedVersionsForPackageAsync(feed, package);
4847

49-
await DeletePackageVersionsFromFeedAsync(feed, package.Name, updatedVersions);
50-
updatedCount += updatedVersions.Count;
48+
await DeletePackageVersionsFromFeedAsync(feed, updatedAssets);
49+
updatedCount += updatedAssets.Count;
5150
}
5251

5352
_logger.LogInformation("Feed {feed} cleaning finished with {count}/{totalCount} updated packages", feed.Name, updatedCount, packages.Count);
@@ -74,12 +73,11 @@ public async Task CleanFeedAsync(AzureDevOpsFeed feed, PackagesInReleaseFeeds pa
7473
/// <param name="package">Package to search for</param>
7574
/// <param name="dotnetFeedsPackageMapping">Mapping of packages and their versions in the release feeds</param>
7675
/// <returns>Collection of versions that were updated for the package</returns>
77-
private async Task<HashSet<string>> UpdateReleasedVersionsForPackageAsync(
76+
private async Task<HashSet<Asset>> UpdateReleasedVersionsForPackageAsync(
7877
AzureDevOpsFeed feed,
79-
AzureDevOpsPackage package,
80-
PackagesInReleaseFeeds dotnetFeedsPackageMapping)
78+
AzureDevOpsPackage package)
8179
{
82-
var releasedVersions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
80+
HashSet<Asset> releasedAssets = new();
8381

8482
foreach (var version in package.Versions)
8583
{
@@ -101,119 +99,97 @@ private async Task<HashSet<string>> UpdateReleasedVersionsForPackageAsync(
10199
continue;
102100
}
103101

104-
if (matchingAsset.Locations.Any(l => l.Location == FeedConstants.NuGetOrgLocation ||
105-
dotnetFeedsPackageMapping.Any(f => l.Location == f.Key)))
102+
if (matchingAsset.Locations.Any(l => l.Location == FeedConstants.NuGetOrgLocation))
106103
{
107104
_logger.LogInformation("Package {package}.{version} is already present in a public location.",
108105
package.Name,
109106
version.Version);
110-
releasedVersions.Add(version.Version);
107+
releasedAssets.Add(matchingAsset);
111108
continue;
112109
}
113110

114-
List<string> feedsWherePackageIsAvailable = GetReleaseFeedsWherePackageIsAvailable(
115-
package.Name,
116-
version.Version,
117-
dotnetFeedsPackageMapping);
118-
119111
try
120112
{
121-
if (await IsPackageAvailableInNugetOrgAsync(package.Name, version.Version))
113+
if (!await IsPackageAvailableInNugetOrgAsync(package.Name, version.Version))
122114
{
123-
feedsWherePackageIsAvailable.Add(FeedConstants.NuGetOrgLocation);
115+
_logger.LogInformation("Package {package}.{version} not found in any of the release feeds", package.Name, version);
116+
continue;
124117
}
125118
}
126119
catch (HttpRequestException e)
127120
{
128121
_logger.LogWarning(e, "Failed to determine if package {package}.{version} is present in NuGet.org",
129122
package.Name,
130123
version.Version);
131-
}
132-
133-
if (feedsWherePackageIsAvailable.Count <= 0)
134-
{
135-
_logger.LogInformation("Package {package}.{version} not found in any of the release feeds", package.Name, version);
136124
continue;
137125
}
138126

139-
releasedVersions.Add(version.Version);
140-
foreach (string feedToAdd in feedsWherePackageIsAvailable)
141-
{
142-
_logger.LogInformation("Found package {package}.{version} in {feed}, adding location to asset",
143-
package.Name,
144-
version.Version,
145-
feedToAdd);
127+
releasedAssets.Add(matchingAsset);
146128

147-
matchingAsset.Locations.Add(new AssetLocation()
148-
{
149-
Location = feedToAdd,
150-
Type = LocationType.NugetFeed
151-
});
129+
_logger.LogInformation("Found package {package}.{version} in {feed}, adding location to asset",
130+
package.Name,
131+
version.Version,
132+
FeedConstants.NuGetOrgLocation);
152133

153-
await _context.SaveChangesAsync();
154-
}
134+
matchingAsset.Locations.Add(new AssetLocation()
135+
{
136+
Location = FeedConstants.NuGetOrgLocation,
137+
Type = LocationType.NugetFeed
138+
});
139+
140+
await _context.SaveChangesAsync();
155141
}
156142

157-
return releasedVersions;
143+
return releasedAssets;
158144
}
159145

160146
/// <summary>
161147
/// Deletes a version of a package from an Azure DevOps feed
162148
/// </summary>
163149
/// <param name="feed">Feed to delete the package from</param>
164150
/// <param name="packageName">package to delete</param>
165-
/// <param name="versionsToDelete">Collection of versions to delete</param>
151+
/// <param name="assetsToDelete">Collection of versions to delete</param>
166152
private async Task DeletePackageVersionsFromFeedAsync(
167153
AzureDevOpsFeed feed,
168-
string packageName,
169-
HashSet<string> versionsToDelete)
154+
HashSet<Asset> assetsToDelete)
170155
{
171-
foreach (string version in versionsToDelete)
156+
foreach (Asset asset in assetsToDelete)
172157
{
173158
try
174159
{
175160
_logger.LogInformation("Deleting package {package}.{version} from feed {feed}",
176-
packageName, version, feed.Name);
161+
asset.Name, asset.Version, feed.Name);
177162

178163
await _azureDevOpsClient.DeleteNuGetPackageVersionFromFeedAsync(
179164
feed.Account,
180165
feed.Project?.Name,
181166
feed.Name,
182-
packageName,
183-
version);
167+
asset.Name,
168+
asset.Version);
169+
170+
var assetLocation = asset.Locations.FirstOrDefault(al => al.Location.Contains(feed.Name, StringComparison.OrdinalIgnoreCase));
171+
if (assetLocation != null)
172+
{
173+
asset.Locations.Remove(assetLocation);
174+
}
184175
}
185176
catch (HttpRequestException e)
186177
{
187178
_logger.LogError(e, "There was an error attempting to delete package {package}.{version} from the {feed} feed. Skipping...",
188-
packageName,
189-
version,
179+
asset.Name,
180+
asset.Version,
190181
feed.Name);
191182
}
192183
}
193-
}
194184

195-
/// <summary>
196-
/// Gets a list of feeds where a given package is available
197-
/// </summary>
198-
/// <param name="name">Package to search for</param>
199-
/// <param name="version">Version to search for</param>
200-
/// <param name="packageMappings">Feeds to search</param>
201-
/// <returns>List of feeds in the package mappings where the provided package and version are available</returns>
202-
private static List<string> GetReleaseFeedsWherePackageIsAvailable(
203-
string name,
204-
string version,
205-
PackagesInReleaseFeeds packageMappings)
206-
{
207-
List<string> feeds = [];
208-
foreach ((string feedName, Dictionary<string, HashSet<string>> packages) in packageMappings)
185+
try
209186
{
210-
if (packages.TryGetValue(name, out HashSet<string>? versions) && versions.Contains(version))
211-
{
212-
feeds.Add(feedName);
213-
}
187+
await _context.SaveChangesAsync();
188+
}
189+
catch (Exception e)
190+
{
191+
_logger.LogError(e, "Failed to remove location {feed} from Assets in BAR", feed.Name);
214192
}
215-
216-
return feeds;
217193
}
218194

219195
/// <summary>

src/ProductConstructionService/ProductConstructionService.FeedCleaner/FeedCleanerConfiguration.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ public static void ConfigureFeedCleaner(this IHostApplicationBuilder builder, IT
3434
builder.Services.AddTransient<IAzureDevOpsClient, AzureDevOpsClient>();
3535
builder.Services.AddTransient<ILogger>(sp => sp.GetRequiredService<ILogger<FeedCleanerJob>>());
3636
builder.Services.AddTransient<IProcessManager>(sp => ActivatorUtilities.CreateInstance<ProcessManager>(sp, "git"));
37+
builder.Services.AddHttpClient().ConfigureHttpClientDefaults(builder =>
38+
{
39+
builder.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
40+
{
41+
CheckCertificateRevocationList = true,
42+
});
43+
});
3744

3845
builder.Services.AddTransient<FeedCleanerJob>();
3946
builder.Services.AddTransient<FeedCleaner>();

src/ProductConstructionService/ProductConstructionService.FeedCleaner/FeedCleanerJob.cs

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
using Microsoft.Extensions.Logging;
1111
using Microsoft.Extensions.Options;
1212

13-
using PackagesInReleaseFeeds = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, System.Collections.Generic.HashSet<string>>>;
14-
1513
namespace ProductConstructionService.FeedCleaner;
1614

1715
public class FeedCleanerJob
@@ -43,15 +41,6 @@ public async Task CleanManagedFeedsAsync()
4341
return;
4442
}
4543

46-
_logger.LogInformation("Loading packages in release feeds...");
47-
48-
PackagesInReleaseFeeds packagesInReleaseFeeds = await GetPackagesForReleaseFeedsAsync();
49-
50-
_logger.LogInformation("Loaded {versionCount} versions of {packageCount} packages from {feedCount} feeds",
51-
packagesInReleaseFeeds.Sum(feed => feed.Value.Sum(package => package.Value.Count)),
52-
packagesInReleaseFeeds.Sum(feed => feed.Value.Keys.Count),
53-
packagesInReleaseFeeds.Keys.Count);
54-
5544
foreach (var azdoAccount in Options.AzdoAccounts)
5645
{
5746
_logger.LogInformation("Processing feeds for {account}...", azdoAccount);
@@ -93,7 +82,7 @@ await Parallel.ForEachAsync(
9382
try
9483
{
9584
cancellationToken.ThrowIfCancellationRequested();
96-
await feedCleaner.CleanFeedAsync(feed, packagesInReleaseFeeds);
85+
await feedCleaner.CleanFeedAsync(feed);
9786
}
9887
catch (Exception e)
9988
{
@@ -111,55 +100,4 @@ await Parallel.ForEachAsync(
111100
azdoAccount);
112101
}
113102
}
114-
115-
/// <summary>
116-
/// Get a mapping of feed -> (package, versions) for the release feeds so it
117-
/// can be easily queried whether a version of a package is in a feed.
118-
/// </summary>
119-
/// <returns>Mapping of packages to versions for the release feeds.</returns>
120-
private async Task<PackagesInReleaseFeeds> GetPackagesForReleaseFeedsAsync()
121-
{
122-
var packagesWithVersionsInReleaseFeeds = new PackagesInReleaseFeeds();
123-
IEnumerable<ReleasePackageFeed> dotnetManagedFeeds = Options.ReleasePackageFeeds;
124-
foreach ((string account, string project, string feedName) in dotnetManagedFeeds)
125-
{
126-
string readableFeedURL = ComputeAzureArtifactsNuGetFeedUrl(feedName, account, project);
127-
128-
packagesWithVersionsInReleaseFeeds[readableFeedURL] = await GetPackageVersionsForFeedAsync(account, project, feedName);
129-
}
130-
return packagesWithVersionsInReleaseFeeds;
131-
}
132-
133-
/// <summary>
134-
/// Construct a nuget feed URL for an Azure DevOps Artifact feed
135-
/// </summary>
136-
/// <param name="feedName">Name of the feed</param>
137-
/// <param name="account">Azure DevOps Account where the feed is hosted</param>
138-
/// <param name="project">Optional project for the feed.</param>
139-
/// <returns>Url of the form https://pkgs.dev.azure.com/account/project/_packaging/feedName/nuget/v3/index.json </returns>
140-
private static string ComputeAzureArtifactsNuGetFeedUrl(string feedName, string account, string project = "")
141-
{
142-
string projectSection = string.IsNullOrEmpty(project) ? "" : $"{project}/";
143-
return $"https://pkgs.dev.azure.com/{account}/{projectSection}_packaging/{feedName}/nuget/v3/index.json";
144-
}
145-
146-
/// <summary>
147-
/// Gets a Mapping of package -> versions for an Azure DevOps feed.
148-
/// </summary>
149-
/// <param name="azdoClient">Azure DevOps client.</param>
150-
/// <param name="account">Azure DevOps account.</param>
151-
/// <param name="project">Azure DevOps project the feed is hosted in.</param>
152-
/// <param name="feedName">Name of the feed</param>
153-
/// <returns>Dictionary where the key is the package name, and the value is a HashSet of the versions of the package in the feed</returns>
154-
private async Task<Dictionary<string, HashSet<string>>> GetPackageVersionsForFeedAsync(string account, string project, string feedName)
155-
{
156-
var packagesWithVersions = new Dictionary<string, HashSet<string>>();
157-
List<AzureDevOpsPackage> packagesInFeed = await _azureDevOpsClient.GetPackagesForFeedAsync(account, project, feedName);
158-
foreach (AzureDevOpsPackage package in packagesInFeed)
159-
{
160-
packagesWithVersions.Add(package.Name, new HashSet<string>(StringComparer.OrdinalIgnoreCase));
161-
packagesWithVersions[package.Name].UnionWith(package.Versions?.Where(v => !v.IsDeleted).Select(v => v.Version) ?? []);
162-
}
163-
return packagesWithVersions;
164-
}
165103
}

src/ProductConstructionService/ProductConstructionService.FeedCleaner/FeedCleanerOptions.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,5 @@ public class FeedCleanerOptions
77
{
88
public required bool Enabled { get; set; }
99

10-
public required List<ReleasePackageFeed> ReleasePackageFeeds { get; set; }
11-
1210
public required List<string> AzdoAccounts { get; set; }
1311
}
14-
15-
public record ReleasePackageFeed(string Account, string Project, string Name);

src/ProductConstructionService/ProductConstructionService.FeedCleaner/appsettings.json

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,6 @@
77
}
88
},
99
"FeedCleaner": {
10-
"Enabled": false,
11-
"ReleasePackageFeeds": [
12-
{
13-
"Account": "dnceng",
14-
"Project": "public",
15-
"Name": "dotnet3"
16-
},
17-
{
18-
"Account": "dnceng",
19-
"Project": "public",
20-
"Name": "dotnet3.1"
21-
},
22-
{
23-
"Account": "dnceng",
24-
"Project": "public",
25-
"Name": "dotnet5"
26-
},
27-
{
28-
"Account": "dnceng",
29-
"Project": "public",
30-
"Name": "dotnet-tools"
31-
}
32-
]
10+
"Enabled": false
3311
}
3412
}

0 commit comments

Comments
 (0)