-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Use results for uploading step summaries #2301
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
Use results for uploading step summaries #2301
Conversation
yacaovsnc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
|
|
||
| namespace GitHub.Services.Results.Client | ||
| { | ||
| public class ResultsHttpClient : RawHttpClientBase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one thing to check if you plan to use ResultsHttpClient in production for customers, does the RawHttpClientBase support all the network settings for the runner, ex: proxy, SSL cert, etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for my education only, isn't the RawHttpClientBase the abstraction layer for proxy, SSL certs, retry and all other common http requirements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should, but I didn't review the initial PR and am not sure whether we implement all required pieces, it was added to testing RunService only in the dev environment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm that is a good question, I'm not familiar with what all the runner requires so I'm not sure if it supports that 🤔 I can look into it and make sure it at least satisfies our needs, though. Good call out!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yacaovsnc and I chatted and we are both thinking that we should push that effort into another issue, so we can work on incrementally getting this work in and tested. I'll make an issue for this so that we can track the effort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I can tell, RawHttpMessagehandler.cs handles timeouts, retries and has partial support for proxy - it doesn't apply proxy authentication.
It also doesn't support certs which is okay in Results case since we don't need to support self signed certificate yet.
I will try to add the proxy authentication support in the other issue created.
src/Runner.Common/Constants.cs
Outdated
| public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary"; | ||
| public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: {0}. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/."; | ||
| public static readonly string SummaryUploadError = "$GITHUB_STEP_SUMMARY upload aborted, an error occurred when uploading the summary. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary"; | ||
| public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/. Please update the following actions to use Node.js 16: {0}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you have a bad merge/rebase? the Node12DetectedAfterEndOfLife looks a little bit different.
src/Runner.Common/JobServer.cs
Outdated
| Trace.Info("Results client is not initialized. Skipping the step summary upload."); | ||
| return Task.CompletedTask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to skip or throw?
src/Runner.Common/JobServerQueue.cs
Outdated
| void Start(Pipelines.AgentJobRequestMessage jobRequest); | ||
| void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber = null); | ||
| void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource); | ||
| void QueueResultsSummaryUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, string stepId, bool deleteSource); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest renaming to QueueSummaryUpload.
src/Runner.Common/JobServerQueue.cs
Outdated
| private static readonly TimeSpan _delayForWebConsoleLineDequeue = TimeSpan.FromMilliseconds(500); | ||
| private static readonly TimeSpan _delayForTimelineUpdateDequeue = TimeSpan.FromMilliseconds(500); | ||
| private static readonly TimeSpan _delayForFileUploadDequeue = TimeSpan.FromMilliseconds(1000); | ||
| private static readonly TimeSpan _delayForResultsSummaryUploadDequeue = TimeSpan.FromMilliseconds(1000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rename everything in this file to not include Result, IJobServerQueue doesn't need to know it's uploading stuff to ResultService.
src/Runner.Common/JobServer.cs
Outdated
| Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken); | ||
| Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long? startLine, CancellationToken cancellationToken); | ||
| Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken); | ||
| Task CreateResultsStepSymmaryAsync(string planId, string jobId, string stepId, string file, CancellationToken cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Task CreateResultsStepSymmaryAsync(string planId, string jobId, string stepId, string file, CancellationToken cancellationToken); | |
| Task CreateStepSummaryAsync(string planId, string jobId, string stepId, string file, CancellationToken cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are creating a summary, and it happens to upload to the ResultService.
| _jobServer.InitializeWebsocketClient(serviceEndPoint); | ||
|
|
||
| // This code is usually wrapped by an instance of IExecutionContext which isn't available here. | ||
| jobRequest.Variables.TryGetValue("system.github.results_endpoint", out VariableValue resultsEndpointVariable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we use the SystemConnection to pass the URL? we have the same pattern for passing CacheServerUrl and GenerateIdTokenUrl from the service to the runner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference and the advantage of using SystemConnection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going to keep is as a variable for now. The SystemConnction has authorization parameters and for Results we are just sticking with the system access token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the auth in the SystemConnection is exactly the system access token.
the advantage is aline with the existing pattern, the SystemConnection was holding some connection info back to the service, I think the result service URL is just one of them.
src/Runner.Common/JobServerQueue.cs
Outdated
| try | ||
| { | ||
| Trace.Info($"Starting to upload summary file to results service {file.Type}, {file.Name}, {file.Path}"); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/Runner.Common/JobServerQueue.cs
Outdated
| Trace.Info($"Starting to upload summary file to results service {file.Type}, {file.Name}, {file.Path}"); | ||
|
|
||
|
|
||
| if (String.Equals(file.Type, ChecksAttachmentType.ResultsStepSummary, StringComparison.OrdinalIgnoreCase)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will there every be other types of files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not planned yet.
| TimelineId = timelineId, | ||
| TimelineRecordId = timelineRecordId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need these 2 fields? TimelineId and TimelineRecordId
|
|
||
| public static async Task<HttpResponseMessage> UploadFileAsync(string url, string blobStorageType, FileStream file, CancellationToken cancellationToken) { | ||
| // Upload the file to the url | ||
| var httpClient = new HttpClient(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we create a new HttpClient if we are using the RawHttpClientBase? should we use the RawHttpClientBase.SendAsync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the intention is this upload goes to Blob, not Results - that said, I think the Raw http client should still work.
| public static async Task<HttpResponseMessage> UploadFileAsync(string url, string blobStorageType, FileStream file, CancellationToken cancellationToken) { | ||
| // Upload the file to the url | ||
| var httpClient = new HttpClient(); | ||
| var request = new HttpRequestMessage(HttpMethod.Put, url) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also same about dispose.
|
|
||
| using (var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { | ||
| if (!response.IsSuccessStatusCode) { | ||
| throw new Exception($"Failed to upload file, status code: {response.StatusCode}, reason: {response.ReasonPhrase}, blobStorageType: {blobStorageType}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same about whether this will be on user's face.
| } | ||
| } | ||
|
|
||
| public static async Task<HttpResponseMessage> UploadFileAsync(string url, string blobStorageType, FileStream file, CancellationToken cancellationToken) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public or private?
| } | ||
|
|
||
| // Handle file upload for step summary | ||
| public async Task UploadStepSummaryAsync(string jobId, string planId, string stepId, string file, CancellationToken cancellationToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
order the parameters.
| var fileSize = new FileInfo(file).Length; | ||
| if (fileSize > uploadUrlResponse.soft_size_limit) | ||
| { | ||
| throw new Exception($"File size is larger than the upload url allows, file size: {fileSize}, upload url size: {uploadUrlResponse.soft_size_limit}, blobType: {uploadUrlResponse.blob_storage_type}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the user care about the storage type?
| await StepSummaryUploadCompleteAsync(jobId, planId, stepId, fileSize, cancellationToken); | ||
| } | ||
| catch (Exception ex) { | ||
| throw new Exception("Failed to upload step summary to results", ex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will this print out a nest error message with tons of stack about the inner exception?
Co-authored-by: Tingluo Huang <tingluohuang@github.com>
fhammerl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This reverts commit f41f5d2.
This reverts commit f41f5d2.
| public Guid TimelineId { get; set; } | ||
| public Guid TimelineRecordId { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't get why we need these fields.
await _jobServer.CreateStepSymmaryAsync(file.PlanId, file.JobId, file.StepId, file.Path, cancellationTokenSource.Token);
Do we only pass PlanId/JobId/StepId/Path to the _jobServer?
* Use results service for uploading step summaries * Use results summary over generic results naming convention * Apply suggestions from code review Co-authored-by: Tingluo Huang <tingluohuang@github.com> * Addressing feedback * Fix merge issue * Remove empty line * Update Results json objects to use snake case * Adding the reference Co-authored-by: Yang Cao <yacaovsnc@github.com> Co-authored-by: Tingluo Huang <tingluohuang@github.com>
* Use results service for uploading step summaries * Use results summary over generic results naming convention * Apply suggestions from code review Co-authored-by: Tingluo Huang <tingluohuang@github.com> * Addressing feedback * Fix merge issue * Remove empty line * Update Results json objects to use snake case * Adding the reference Co-authored-by: Yang Cao <yacaovsnc@github.com> Co-authored-by: Tingluo Huang <tingluohuang@github.com>
This PR introduces a new way to queue and upload step summaries.