Skip to content

Commit d90fc3c

Browse files
Use new HelixAPI /job/{job}/results endpoint (#15230)
Co-authored-by: Missy Messa <[email protected]>
1 parent d085db9 commit d90fc3c

File tree

12 files changed

+129
-50
lines changed

12 files changed

+129
-50
lines changed

src/Microsoft.DotNet.Helix/Client/CSharp/generated-code/Job.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public partial interface IJob
2020
Task<Models.JobCreationResult> NewAsync(
2121
Models.JobCreationRequest body,
2222
string idempotencyKey,
23+
bool? returnSas = default,
2324
CancellationToken cancellationToken = default
2425
);
2526

@@ -33,6 +34,11 @@ public partial interface IJob
3334
CancellationToken cancellationToken = default
3435
);
3536

37+
Task<Models.JobResultsUri> ResultsAsync(
38+
string job,
39+
CancellationToken cancellationToken = default
40+
);
41+
3642
Task<Models.JobPassFail> PassFailAsync(
3743
string job,
3844
CancellationToken cancellationToken = default
@@ -77,6 +83,7 @@ public Job(HelixApi client)
7783
public async Task<Models.JobCreationResult> NewAsync(
7884
Models.JobCreationRequest body,
7985
string idempotencyKey,
86+
bool? returnSas = default,
8087
CancellationToken cancellationToken = default
8188
)
8289
{
@@ -118,6 +125,11 @@ public Job(HelixApi client)
118125
_req.Headers.Add("Idempotency-Key", idempotencyKey);
119126
}
120127

128+
if (returnSas != default(bool?))
129+
{
130+
_req.Headers.Add("return-sas", returnSas.ToString());
131+
}
132+
121133
if (body != default(Models.JobCreationRequest))
122134
{
123135
_req.Content = RequestContent.Create(Encoding.UTF8.GetBytes(Client.Serialize(body)));
@@ -268,6 +280,81 @@ internal async Task OnListFailed(Request req, Response res)
268280
throw ex;
269281
}
270282

283+
partial void HandleFailedResultsRequest(RestApiException ex);
284+
285+
public async Task<Models.JobResultsUri> ResultsAsync(
286+
string job,
287+
CancellationToken cancellationToken = default
288+
)
289+
{
290+
291+
if (string.IsNullOrEmpty(job))
292+
{
293+
throw new ArgumentNullException(nameof(job));
294+
}
295+
296+
const string apiVersion = "2019-06-17";
297+
298+
var _baseUri = Client.Options.BaseUri;
299+
var _url = new RequestUriBuilder();
300+
_url.Reset(_baseUri);
301+
_url.AppendPath(
302+
"/api/jobs/{job}/results".Replace("{job}", Uri.EscapeDataString(Client.Serialize(job))),
303+
false);
304+
305+
_url.AppendQuery("api-version", Client.Serialize(apiVersion));
306+
307+
308+
using (var _req = Client.Pipeline.CreateRequest())
309+
{
310+
_req.Uri = _url;
311+
_req.Method = RequestMethod.Get;
312+
313+
using (var _res = await Client.SendAsync(_req, cancellationToken).ConfigureAwait(false))
314+
{
315+
if (_res.Status < 200 || _res.Status >= 300)
316+
{
317+
await OnResultsFailed(_req, _res).ConfigureAwait(false);
318+
}
319+
320+
if (_res.ContentStream == null)
321+
{
322+
await OnResultsFailed(_req, _res).ConfigureAwait(false);
323+
}
324+
325+
using (var _reader = new StreamReader(_res.ContentStream))
326+
{
327+
var _content = await _reader.ReadToEndAsync().ConfigureAwait(false);
328+
var _body = Client.Deserialize<Models.JobResultsUri>(_content);
329+
return _body;
330+
}
331+
}
332+
}
333+
}
334+
335+
internal async Task OnResultsFailed(Request req, Response res)
336+
{
337+
string content = null;
338+
if (res.ContentStream != null)
339+
{
340+
using (var reader = new StreamReader(res.ContentStream))
341+
{
342+
content = await reader.ReadToEndAsync().ConfigureAwait(false);
343+
}
344+
}
345+
346+
var ex = new RestApiException<Models.ApiError>(
347+
req,
348+
res,
349+
content,
350+
Client.Deserialize<Models.ApiError>(content)
351+
);
352+
HandleFailedResultsRequest(ex);
353+
HandleFailedRequest(ex);
354+
Client.OnFailedRequest(ex);
355+
throw ex;
356+
}
357+
271358
partial void HandleFailedPassFailRequest(RestApiException ex);
272359

273360
public async Task<Models.JobPassFail> PassFailAsync(

src/Microsoft.DotNet.Helix/Client/CSharp/generated-code/Models/JobCreationResult.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ public bool IsValid
4949
{
5050
return false;
5151
}
52-
if (string.IsNullOrEmpty(ResultsUriRSAS))
53-
{
54-
return false;
55-
}
5652
return true;
5753
}
5854
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.Immutable;
6+
using Newtonsoft.Json;
7+
8+
namespace Microsoft.DotNet.Helix.Client.Models
9+
{
10+
public partial class JobResultsUri
11+
{
12+
public JobResultsUri()
13+
{
14+
}
15+
16+
[JsonProperty("ResultsUri")]
17+
public string ResultsUri { get; set; }
18+
19+
[JsonProperty("ResultsUriRSAS")]
20+
public string ResultsUriRSAS { get; set; }
21+
}
22+
}

src/Microsoft.DotNet.Helix/JobSender/ISentJob.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,6 @@ public interface ISentJob
2323
/// </summary>
2424
string HelixCancellationToken { get; }
2525

26-
/// <summary>
27-
/// URI for blob storage container with the results.
28-
/// </summary>
29-
string ResultsContainerUri { get; }
30-
31-
/// <summary>
32-
/// Shared Access Signature for access to the container with results.
33-
/// Used for internal builds.
34-
/// </summary>
35-
string ResultsContainerReadSAS { get; }
36-
3726
/// <summary>
3827
/// Poll for the job to actually finish inside Helix.
3928
/// </summary>

src/Microsoft.DotNet.Helix/JobSender/JobDefinition.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,9 @@ public async Task<ISentJob> SendAsync(Action<string> log, CancellationToken canc
239239
}
240240

241241
string jobStartIdentifier = Guid.NewGuid().ToString("N");
242-
var newJob = await JobApi.NewAsync(creationRequest, jobStartIdentifier, cancellationToken).ConfigureAwait(false);
242+
var newJob = await JobApi.NewAsync(creationRequest, jobStartIdentifier, cancellationToken: cancellationToken).ConfigureAwait(false);
243243

244-
return new SentJob(JobApi, newJob, newJob.ResultsUri, newJob.ResultsUriRSAS);
244+
return new SentJob(JobApi, newJob);
245245
}
246246

247247
private void WarnForImpendingRemoval(Action<string> log, QueueInfo queueInfo)

src/Microsoft.DotNet.Helix/JobSender/SentJob.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,16 @@ namespace Microsoft.DotNet.Helix.Client
99
{
1010
internal class SentJob : ISentJob
1111
{
12-
public SentJob(IJob jobApi, JobCreationResult newJob, string resultsContainerUri, string resultsContainerReadSAS)
12+
public SentJob(IJob jobApi, JobCreationResult newJob)
1313
{
1414
JobApi = jobApi;
1515
CorrelationId = newJob.Name;
1616
HelixCancellationToken = newJob.CancellationToken;
17-
ResultsContainerUri = resultsContainerUri;
18-
ResultsContainerReadSAS = resultsContainerReadSAS;
1917
}
2018

2119
public IJob JobApi { get; }
2220
public string CorrelationId { get; }
2321
public string HelixCancellationToken { get; }
24-
public string ResultsContainerUri { get; }
25-
public string ResultsContainerReadSAS { get; }
2622

2723
public Task<JobPassFail> WaitAsync(int pollingIntervalMs = 10000, CancellationToken cancellationToken = default)
2824
{

src/Microsoft.DotNet.Helix/Sdk/DownloadFromResultsContainer.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ public class DownloadFromResultsContainer : HelixTask, ICancelableTask
2626
[Required]
2727
public ITaskItem[] MetadataToWrite { get; set; }
2828

29-
public string ResultsContainerReadSAS { get; set; }
30-
3129
private const string MetadataFile = "metadata.txt";
3230

3331
private readonly CancellationTokenSource _cancellationSource = new CancellationTokenSource();
@@ -74,6 +72,7 @@ private async Task DownloadFilesForWorkItem(ITaskItem workItem, string directory
7472

7573
// Use the Helix API to get the last possible iteration of the work item's execution
7674
var allAvailableFiles = await HelixApi.WorkItem.ListFilesAsync(workItemName, JobId, true, ct);
75+
var resultsUri = await HelixApi.Job.ResultsAsync(JobId, ct);
7776

7877
DirectoryInfo destinationDir = Directory.CreateDirectory(Path.Combine(directoryPath, workItemName));
7978
foreach (string file in filesToDownload)
@@ -109,14 +108,14 @@ private async Task DownloadFilesForWorkItem(ITaskItem workItem, string directory
109108
// If we have no read SAS token from the build, make a best-effort attempt using the URL from the Helix API.
110109
// For restricted queues, there will be no read SAS token available to use in the Helix API's result
111110
// (but hopefully the 'else' branch will be hit in this case)
112-
if (string.IsNullOrEmpty(ResultsContainerReadSAS))
111+
if (string.IsNullOrEmpty(resultsUri.ResultsUriRSAS))
113112
{
114113
blob = new BlobClient(new Uri(fileAvailableForDownload.Link), blobClientOptions);
115114
}
116115
else
117116
{
118117
var strippedFileUri = new Uri(fileAvailableForDownload.Link.Substring(0, fileAvailableForDownload.Link.LastIndexOf('?')));
119-
blob = new BlobClient(strippedFileUri, new AzureSasCredential(ResultsContainerReadSAS), blobClientOptions);
118+
blob = new BlobClient(strippedFileUri, new AzureSasCredential(resultsUri.ResultsUriRSAS), blobClientOptions);
120119
}
121120
await blob.DownloadToAsync(destinationFile);
122121
}

src/Microsoft.DotNet.Helix/Sdk/SendHelixJob.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,6 @@ public static class MetadataNames
7878
[Output]
7979
public string JobCancellationToken { get; set; }
8080

81-
/// <summary>
82-
/// When the task finishes, the results container uri should be available in case we want to download files.
83-
/// </summary>
84-
[Output]
85-
public string ResultsContainerUri { get; set; }
86-
87-
/// <summary>
88-
/// If the job is internal, we need to give the DownloadFromResultsContainer task the Write SAS to download files.
89-
/// </summary>
90-
[Output]
91-
public string ResultsContainerReadSAS { get; set; }
92-
9381
/// <summary>
9482
/// A collection of commands that will run for each work item before any work item commands.
9583
/// Use a semicolon to delimit these and escape semicolons by percent coding them ('%3B').
@@ -270,8 +258,6 @@ protected override async Task ExecuteCore(CancellationToken cancellationToken)
270258
ISentJob job = await def.SendAsync(msg => Log.LogMessageFromText(msg, MessageImportance.Normal), cancellationToken);
271259
JobCorrelationId = job.CorrelationId;
272260
JobCancellationToken = job.HelixCancellationToken;
273-
ResultsContainerUri = job.ResultsContainerUri;
274-
ResultsContainerReadSAS = job.ResultsContainerReadSAS;
275261
cancellationToken.ThrowIfCancellationRequested();
276262
}
277263

src/Microsoft.DotNet.Helix/Sdk/tools/Microsoft.DotNet.Helix.Sdk.MonoQueue.targets

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,11 @@
5959
HelixProperties="@(HelixProperties)">
6060
<Output TaskParameter="JobCorrelationId" PropertyName="HelixJobId"/>
6161
<Output TaskParameter="JobCancellationToken" PropertyName="HelixJobCancellationToken"/>
62-
<Output TaskParameter="ResultsContainerUri" PropertyName="HelixResultsContainer"/>
63-
<Output TaskParameter="ResultsContainerReadSAS" PropertyName="HelixResultsContainerReadSAS"/>
6462
</SendHelixJob>
6563
<ItemGroup>
6664
<SentJob Include="$(HelixJobId)">
6765
<WorkItemCount>@(HelixWorkItem->Count())</WorkItemCount>
6866
<HelixTargetQueue>$(HelixTargetQueue)</HelixTargetQueue>
69-
<ResultsContainerUri>$(HelixResultsContainer)</ResultsContainerUri>
70-
<ResultsContainerReadSAS>$(HelixResultsContainerReadSAS)</ResultsContainerReadSAS>
7167
<HelixJobCancellationToken>$(HelixJobCancellationToken)</HelixJobCancellationToken>
7268
</SentJob>
7369
</ItemGroup>

src/Microsoft.DotNet.Helix/Sdk/tools/download-results/DownloadFromResultsContainer.targets

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,13 @@
2121
<_shouldDownloadResults Condition="'@(_workItemsWithDownloadMetadata)' != '' AND '$(HelixResultsDestinationDir)' != ''">true</_shouldDownloadResults>
2222
</PropertyGroup>
2323

24-
<Warning Text="DownloadFromResultsContainer will be skipped for job %(SentJob.Identity) because results container uri is empty" Condition="'%(SentJob.ResultsContainerUri)' == '' AND $(_shouldDownloadResults)" />
25-
2624
<DownloadFromResultsContainer
27-
Condition="$(_shouldDownloadResults) AND '%(SentJob.ResultsContainerUri)' != ''"
25+
Condition="$(_shouldDownloadResults)"
2826
AccessToken="$(HelixAccessToken)"
2927
WorkItems="@(_workItemsWithDownloadMetadata)"
3028
OutputDirectory="$(HelixResultsDestinationDir)"
3129
MetadataToWrite="@(HelixDownloadResultsMetadata)"
32-
JobId="%(SentJob.Identity)"
33-
ResultsContainerReadSAS="%(SentJob.ResultsContainerReadSAS)" />
30+
JobId="%(SentJob.Identity)" />
3431
</Target>
3532

3633
</Project>

0 commit comments

Comments
 (0)