diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 9d2285ddbf..81b8f26417 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "microsoft.dnceng.secretmanager": { - "version": "1.1.0-beta.24420.1", + "version": "1.1.0-beta.24460.1", "commands": [ "secret-manager" ] @@ -15,7 +15,7 @@ ] }, "microsoft.dnceng.configuration.bootstrap": { - "version": "1.1.0-beta.24420.1", + "version": "1.1.0-beta.24460.1", "commands": [ "bootstrap-dnceng-configuration" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 064556356b..2a0c7eb80e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -91,37 +91,37 @@ - + https://github.com/dotnet/arcade - 80264e60280e2815e7d65871081ccac04a32445c + 8c08d889b3c0b3f19398faceaccd74d0f184a3fb - + https://github.com/dotnet/arcade - 80264e60280e2815e7d65871081ccac04a32445c + 8c08d889b3c0b3f19398faceaccd74d0f184a3fb - + https://github.com/dotnet/arcade - 80264e60280e2815e7d65871081ccac04a32445c + 8c08d889b3c0b3f19398faceaccd74d0f184a3fb - + https://github.com/dotnet/arcade - 80264e60280e2815e7d65871081ccac04a32445c + 8c08d889b3c0b3f19398faceaccd74d0f184a3fb - + https://github.com/dotnet/arcade - 80264e60280e2815e7d65871081ccac04a32445c + 8c08d889b3c0b3f19398faceaccd74d0f184a3fb - + https://github.com/dotnet/arcade - 80264e60280e2815e7d65871081ccac04a32445c + 8c08d889b3c0b3f19398faceaccd74d0f184a3fb - + https://github.com/dotnet/dnceng - a0d339b12f248ca5b42d3a53a49c6b09ef1db579 + c74bfc3484389b8f365dcab61ecd63d506d3575a - + https://github.com/dotnet/dnceng - a0d339b12f248ca5b42d3a53a49c6b09ef1db579 + c74bfc3484389b8f365dcab61ecd63d506d3575a diff --git a/eng/Versions.props b/eng/Versions.props index 6b2f39315b..3db801c824 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -9,11 +9,11 @@ true 1.0.0-preview.1 - 8.0.0-beta.24426.2 - 8.0.0-beta.24426.2 - 8.0.0-beta.24426.2 - 8.0.0-beta.24426.2 - 8.0.0-beta.24426.2 + 8.0.0-beta.24463.3 + 8.0.0-beta.24463.3 + 8.0.0-beta.24463.3 + 8.0.0-beta.24463.3 + 8.0.0-beta.24463.3 17.4.1 1.1.0-beta.24376.1 1.1.0-beta.24376.1 @@ -37,8 +37,8 @@ 1.1.0-beta.24376.1 1.1.0-beta.24376.1 1.1.0-beta.24376.1 - 1.1.0-beta.24420.1 - 1.1.0-beta.24420.1 + 1.1.0-beta.24460.1 + 1.1.0-beta.24460.1 diff --git a/eng/deployment/product-construction-service-deploy.ps1 b/eng/deployment/product-construction-service-deploy.ps1 index 1c4ac33fbc..c152c04cd1 100644 --- a/eng/deployment/product-construction-service-deploy.ps1 +++ b/eng/deployment/product-construction-service-deploy.ps1 @@ -15,9 +15,9 @@ param( $containerapp = az containerapp show -g $resourceGroupName -n $containerappName | ConvertFrom-Json $pcsUrl = "https://$($containerapp.properties.configuration.ingress.fqdn)" -$pcsStatusUrl = $pcsUrl + "/status" -$pcsStopUrl = $pcsStatusUrl + "/stop" -$pcsStartUrl = $pcsStatusUrl + "/start" +$pcsStatusUrl = $pcsUrl + "/api/status" +$pcsStopUrl = $pcsStatusUrl + "/stop?api-version=2020-02-20" +$pcsStartUrl = $pcsStatusUrl + "/start?api-version=2020-02-20" $authenticationHeader = @{ "Authorization" = "Bearer $token" } diff --git a/global.json b/global.json index 6cb5cb8183..9c61800f19 100644 --- a/global.json +++ b/global.json @@ -15,6 +15,6 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24426.2" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24463.3" } } diff --git a/src/Microsoft.DotNet.Darc/DarcLib/GitHubClient.cs b/src/Microsoft.DotNet.Darc/DarcLib/GitHubClient.cs index 8e6f2c30fc..d8ada19fea 100644 --- a/src/Microsoft.DotNet.Darc/DarcLib/GitHubClient.cs +++ b/src/Microsoft.DotNet.Darc/DarcLib/GitHubClient.cs @@ -1015,7 +1015,7 @@ private async Task> GetChecksFromChecksApiAsync(string owner, strin CheckStatus.Queued or CheckStatus.InProgress => CheckState.Pending, CheckStatus.Completed => (run.Conclusion?.Value) switch { - CheckConclusion.Success => CheckState.Success, + CheckConclusion.Success or CheckConclusion.Skipped => CheckState.Success, CheckConclusion.ActionRequired or CheckConclusion.Cancelled or CheckConclusion.Failure or CheckConclusion.Neutral or CheckConclusion.TimedOut => CheckState.Failure, _ => CheckState.None, }, diff --git a/src/ProductConstructionService/ProductConstructionService.Api/Controllers/StatusController.cs b/src/ProductConstructionService/ProductConstructionService.Api/Controllers/StatusController.cs index 5b531a9ba6..8b989c9300 100644 --- a/src/ProductConstructionService/ProductConstructionService.Api/Controllers/StatusController.cs +++ b/src/ProductConstructionService/ProductConstructionService.Api/Controllers/StatusController.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.AspNetCore.ApiVersioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.OpenApi.Extensions; @@ -10,6 +11,7 @@ namespace ProductConstructionService.Api.Controllers; [Route("status")] +[ApiVersion("2020-02-20")] public class StatusController(WorkItemScopeManager workItemScopeManager) : ControllerBase { diff --git a/src/ProductConstructionService/ProductConstructionService.Client/Generated/ProductConstructionServiceApi.cs b/src/ProductConstructionService/ProductConstructionService.Client/Generated/ProductConstructionServiceApi.cs index 73f5d9ded6..f593a21f9a 100644 --- a/src/ProductConstructionService/ProductConstructionService.Client/Generated/ProductConstructionServiceApi.cs +++ b/src/ProductConstructionService/ProductConstructionService.Client/Generated/ProductConstructionServiceApi.cs @@ -35,6 +35,7 @@ public partial interface IProductConstructionServiceApi IChannels Channels { get; } IPipelines Pipelines { get; } IRepository Repository { get; } + IStatus Status { get; } ISubscriptions Subscriptions { get; } } @@ -129,6 +130,8 @@ public HttpPipeline Pipeline public IRepository Repository { get; } + public IStatus Status { get; } + public ISubscriptions Subscriptions { get; } @@ -149,6 +152,7 @@ public ProductConstructionServiceApi(ProductConstructionServiceApiOptions option Channels = new Channels(this); Pipelines = new Pipelines(this); Repository = new Repository(this); + Status = new Status(this); Subscriptions = new Subscriptions(this); SerializerSettings = new JsonSerializerSettings { diff --git a/src/ProductConstructionService/ProductConstructionService.Client/Generated/Status.cs b/src/ProductConstructionService/ProductConstructionService.Client/Generated/Status.cs new file mode 100644 index 0000000000..42d7a5fcfb --- /dev/null +++ b/src/ProductConstructionService/ProductConstructionService.Client/Generated/Status.cs @@ -0,0 +1,222 @@ +// 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; +using System.Threading.Tasks; +using Azure; +using Azure.Core; + + + +namespace ProductConstructionService.Client +{ + public partial interface IStatus + { + Task StopPcsWorkItemProcessorAsync( + CancellationToken cancellationToken = default + ); + + Task StartPcsWorkItemProcessorAsync( + CancellationToken cancellationToken = default + ); + + Task GetPcsWorkItemProcessorStatusAsync( + CancellationToken cancellationToken = default + ); + + } + + internal partial class Status : IServiceOperations, IStatus + { + public Status(ProductConstructionServiceApi client) + { + Client = client ?? throw new ArgumentNullException(nameof(client)); + } + + public ProductConstructionServiceApi Client { get; } + + partial void HandleFailedRequest(RestApiException ex); + + partial void HandleFailedStopPcsWorkItemProcessorRequest(RestApiException ex); + + public async Task StopPcsWorkItemProcessorAsync( + CancellationToken cancellationToken = default + ) + { + + const string apiVersion = "2020-02-20"; + + var _baseUri = Client.Options.BaseUri; + var _url = new RequestUriBuilder(); + _url.Reset(_baseUri); + _url.AppendPath( + "/api/status/stop", + false); + + _url.AppendQuery("api-version", Client.Serialize(apiVersion)); + + + using (var _req = Client.Pipeline.CreateRequest()) + { + _req.Uri = _url; + _req.Method = RequestMethod.Put; + + using (var _res = await Client.SendAsync(_req, cancellationToken).ConfigureAwait(false)) + { + if (_res.Status < 200 || _res.Status >= 300) + { + await OnStopPcsWorkItemProcessorFailed(_req, _res).ConfigureAwait(false); + } + + + return; + } + } + } + + internal async Task OnStopPcsWorkItemProcessorFailed(Request req, Response res) + { + string content = null; + if (res.ContentStream != null) + { + using (var reader = new StreamReader(res.ContentStream)) + { + content = await reader.ReadToEndAsync().ConfigureAwait(false); + } + } + + var ex = new RestApiException( + req, + res, + content, + Client.Deserialize(content) + ); + HandleFailedStopPcsWorkItemProcessorRequest(ex); + HandleFailedRequest(ex); + Client.OnFailedRequest(ex); + throw ex; + } + + partial void HandleFailedStartPcsWorkItemProcessorRequest(RestApiException ex); + + public async Task StartPcsWorkItemProcessorAsync( + CancellationToken cancellationToken = default + ) + { + + const string apiVersion = "2020-02-20"; + + var _baseUri = Client.Options.BaseUri; + var _url = new RequestUriBuilder(); + _url.Reset(_baseUri); + _url.AppendPath( + "/api/status/start", + false); + + _url.AppendQuery("api-version", Client.Serialize(apiVersion)); + + + using (var _req = Client.Pipeline.CreateRequest()) + { + _req.Uri = _url; + _req.Method = RequestMethod.Put; + + using (var _res = await Client.SendAsync(_req, cancellationToken).ConfigureAwait(false)) + { + if (_res.Status < 200 || _res.Status >= 300) + { + await OnStartPcsWorkItemProcessorFailed(_req, _res).ConfigureAwait(false); + } + + + return; + } + } + } + + internal async Task OnStartPcsWorkItemProcessorFailed(Request req, Response res) + { + string content = null; + if (res.ContentStream != null) + { + using (var reader = new StreamReader(res.ContentStream)) + { + content = await reader.ReadToEndAsync().ConfigureAwait(false); + } + } + + var ex = new RestApiException( + req, + res, + content, + Client.Deserialize(content) + ); + HandleFailedStartPcsWorkItemProcessorRequest(ex); + HandleFailedRequest(ex); + Client.OnFailedRequest(ex); + throw ex; + } + + partial void HandleFailedGetPcsWorkItemProcessorStatusRequest(RestApiException ex); + + public async Task GetPcsWorkItemProcessorStatusAsync( + CancellationToken cancellationToken = default + ) + { + + const string apiVersion = "2020-02-20"; + + var _baseUri = Client.Options.BaseUri; + var _url = new RequestUriBuilder(); + _url.Reset(_baseUri); + _url.AppendPath( + "/api/status", + false); + + _url.AppendQuery("api-version", Client.Serialize(apiVersion)); + + + using (var _req = Client.Pipeline.CreateRequest()) + { + _req.Uri = _url; + _req.Method = RequestMethod.Get; + + using (var _res = await Client.SendAsync(_req, cancellationToken).ConfigureAwait(false)) + { + if (_res.Status < 200 || _res.Status >= 300) + { + await OnGetPcsWorkItemProcessorStatusFailed(_req, _res).ConfigureAwait(false); + } + + + return; + } + } + } + + internal async Task OnGetPcsWorkItemProcessorStatusFailed(Request req, Response res) + { + string content = null; + if (res.ContentStream != null) + { + using (var reader = new StreamReader(res.ContentStream)) + { + content = await reader.ReadToEndAsync().ConfigureAwait(false); + } + } + + var ex = new RestApiException( + req, + res, + content, + Client.Deserialize(content) + ); + HandleFailedGetPcsWorkItemProcessorStatusRequest(ex); + HandleFailedRequest(ex); + Client.OnFailedRequest(ex); + throw ex; + } + } +} diff --git a/src/ProductConstructionService/ProductConstructionService.Common/MetricRecorder.cs b/src/ProductConstructionService/ProductConstructionService.Common/MetricRecorder.cs index 179c2211ab..28334df97b 100644 --- a/src/ProductConstructionService/ProductConstructionService.Common/MetricRecorder.cs +++ b/src/ProductConstructionService/ProductConstructionService.Common/MetricRecorder.cs @@ -8,7 +8,7 @@ namespace ProductConstructionService.Common; public interface IMetricRecorder { - void QueueMessageReceived(QueueMessage message, TimeSpan delay); + void QueueMessageReceived(QueueMessage message, int delayInSeconds); } public class MetricRecorder : IMetricRecorder @@ -24,9 +24,9 @@ public MetricRecorder(IMeterFactory meterFactory) _queueWaitTimeCounter = meter.CreateCounter(WaitTimeMetricName); } - public void QueueMessageReceived(QueueMessage message, TimeSpan delay) + public void QueueMessageReceived(QueueMessage message, int delayInSeconds) { - TimeSpan timeInQueue = DateTimeOffset.UtcNow - message.InsertedOn!.Value - delay; - _queueWaitTimeCounter.Add((int)timeInQueue.TotalSeconds); + TimeSpan timeInQueue = DateTimeOffset.UtcNow - message.InsertedOn!.Value; + _queueWaitTimeCounter.Add((int)timeInQueue.TotalSeconds - delayInSeconds); } } diff --git a/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItem.cs b/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItem.cs index 7c5b7cd9fd..becb8b2fc9 100644 --- a/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItem.cs +++ b/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItem.cs @@ -16,5 +16,5 @@ public abstract class WorkItem /// Period of time before the WorkItem becomes visible in the queue. /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault | JsonIgnoreCondition.WhenWritingNull)] - public TimeSpan? Delay { get; internal set; } + public int? Delay { get; internal set; } } diff --git a/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemConsumer.cs b/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemConsumer.cs index 76e80caf0e..2f791e9866 100644 --- a/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemConsumer.cs +++ b/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemConsumer.cs @@ -70,17 +70,14 @@ private async Task ReadAndProcessWorkItemAsync(QueueClient queueClient, WorkItem } string workItemType; - TimeSpan? delay; + int? delay; JsonNode node; try { node = JsonNode.Parse(message.Body)!; workItemType = node["type"]!.ToString(); - var d = node["delay"]?.GetValue(); - delay = d.HasValue - ? TimeSpan.FromSeconds(d.Value) - : null; + delay = node["delay"]?.GetValue(); } catch (Exception ex) { @@ -89,7 +86,7 @@ private async Task ReadAndProcessWorkItemAsync(QueueClient queueClient, WorkItem return; } - _metricRecorder.QueueMessageReceived(message, delay ?? default); + _metricRecorder.QueueMessageReceived(message, delay ?? 0); try { diff --git a/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemProducer.cs b/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemProducer.cs index 620db1d715..2f3a449839 100644 --- a/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemProducer.cs +++ b/src/ProductConstructionService/ProductConstructionService.WorkItems/WorkItemProducer.cs @@ -31,7 +31,7 @@ public async Task ProduceWorkItemAsync(T payload, TimeSpan delay = if (delay != default) { - payload.Delay = delay; + payload.Delay = (int)delay.TotalSeconds; } var json = JsonSerializer.Serialize(payload, WorkItemConfiguration.JsonSerializerOptions); diff --git a/test/ProductConstructionService.ScenarioTests/ScenarioTestBase.cs b/test/ProductConstructionService.ScenarioTests/ScenarioTestBase.cs index 0cbd2f579c..c0208da50f 100644 --- a/test/ProductConstructionService.ScenarioTests/ScenarioTestBase.cs +++ b/test/ProductConstructionService.ScenarioTests/ScenarioTestBase.cs @@ -55,7 +55,7 @@ public void SetTestParameters(TestParameters parameters) { Octokit.Repository repo = await GitHubApi.Repository.Get(_parameters.GitHubTestOrg, targetRepo); - var attempts = 20; + var attempts = 40; while (attempts-- > 0) { IReadOnlyList prs = await GitHubApi.PullRequest.GetAllForRepository(repo.Id, new Octokit.PullRequestRequest @@ -85,7 +85,7 @@ public void SetTestParameters(TestParameters parameters) throw new ScenarioTestException($"No pull request was created in {targetRepo} targeting {targetBranch}"); } - private async Task WaitForUpdatedPullRequestAsync(string targetRepo, string targetBranch, int attempts = 20) + private async Task WaitForUpdatedPullRequestAsync(string targetRepo, string targetBranch, int attempts = 40) { Octokit.Repository repo = await GitHubApi.Repository.Get(_parameters.GitHubTestOrg, targetRepo); Octokit.PullRequest pr = await WaitForPullRequestAsync(targetRepo, targetBranch); @@ -106,7 +106,7 @@ public void SetTestParameters(TestParameters parameters) throw new ScenarioTestException($"The created pull request for {targetRepo} targeting {targetBranch} was not updated with subsequent subscriptions after creation"); } - private async Task WaitForMergedPullRequestAsync(string targetRepo, string targetBranch, int attempts = 20) + private async Task WaitForMergedPullRequestAsync(string targetRepo, string targetBranch, int attempts = 40) { Octokit.Repository repo = await GitHubApi.Repository.Get(_parameters.GitHubTestOrg, targetRepo); Octokit.PullRequest pr = await WaitForPullRequestAsync(targetRepo, targetBranch); @@ -132,7 +132,7 @@ private async Task GetAzDoPullRequestIdAsync(string targetRepoName, string var searchBaseUrl = GetAzDoRepoUrl(targetRepoName); IEnumerable prs = new List(); - var attempts = 20; + var attempts = 40; while (attempts-- > 0) { try @@ -195,7 +195,7 @@ private async Task> GetAzDoPullRequestAsync(in throw new Exception($"{nameof(expectedPRTitle)} must be defined for AzDo PRs that require an update"); } - for (var tries = 20; tries > 0; tries--) + for (var tries = 40; tries > 0; tries--) { PullRequest pr = await AzDoClient.GetPullRequestAsync($"{apiBaseUrl}/pullRequests/{pullRequestId}"); var trimmedTitle = Regex.Replace(pr.Title, @"\s+", " "); @@ -891,7 +891,7 @@ protected async Task GetRepositoryPolicies(string repoUri, string branch return await RunDarcAsync("get-repository-policies", "--all", "--repo", repoUri, "--branch", branchName); } - protected async Task WaitForMergedPullRequestAsync(string targetRepo, string targetBranch, Octokit.PullRequest pr, Octokit.Repository repo, int attempts = 20) + protected async Task WaitForMergedPullRequestAsync(string targetRepo, string targetBranch, Octokit.PullRequest pr, Octokit.Repository repo, int attempts = 40) { while (attempts-- > 0) {