mirror of
https://github.com/actions/runner.git
synced 2025-12-12 15:13:30 +00:00
Run service: send more stuff as part of job completed (#2423)
* send more stuff as part of job completed * feedback * set only once * feedback * feedback * fix test * feedback * nit: spacing * nit: line Co-authored-by: Tingluo Huang <tingluohuang@github.com> --------- Co-authored-by: Tingluo Huang <tingluohuang@github.com>
This commit is contained in:
committed by
GitHub
parent
9a228e52e9
commit
67356a3305
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.Actions.RunService.WebApi;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
@@ -16,7 +18,7 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
Task<AgentJobRequestMessage> GetJobMessageAsync(string id, CancellationToken token);
|
Task<AgentJobRequestMessage> GetJobMessageAsync(string id, CancellationToken token);
|
||||||
|
|
||||||
Task CompleteJobAsync(Guid planId, Guid jobId, CancellationToken token);
|
Task CompleteJobAsync(Guid planId, Guid jobId, TaskResult result, Dictionary<String, VariableValue> outputs, IList<StepResult> stepResults, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RunServer : RunnerService, IRunServer
|
public sealed class RunServer : RunnerService, IRunServer
|
||||||
@@ -56,11 +58,11 @@ namespace GitHub.Runner.Common
|
|||||||
return jobMessage;
|
return jobMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task CompleteJobAsync(Guid planId, Guid jobId, CancellationToken cancellationToken)
|
public Task CompleteJobAsync(Guid planId, Guid jobId, TaskResult result, Dictionary<String, VariableValue> outputs, IList<StepResult> stepResults, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
return RetryRequest(
|
return RetryRequest(
|
||||||
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, cancellationToken), cancellationToken);
|
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, cancellationToken), cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.Actions.RunService.WebApi;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
@@ -437,6 +438,17 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
PublishStepTelemetry();
|
PublishStepTelemetry();
|
||||||
|
|
||||||
|
var stepResult = new StepResult();
|
||||||
|
stepResult.ExternalID = _record.Id;
|
||||||
|
stepResult.Conclusion = _record.Result ?? TaskResult.Succeeded;
|
||||||
|
stepResult.Status = _record.State;
|
||||||
|
stepResult.Number = _record.Order;
|
||||||
|
stepResult.Name = _record.Name;
|
||||||
|
stepResult.StartedAt = _record.StartTime;
|
||||||
|
stepResult.CompletedAt = _record.FinishTime;
|
||||||
|
|
||||||
|
Global.StepsResult.Add(stepResult);
|
||||||
|
|
||||||
if (Root != this)
|
if (Root != this)
|
||||||
{
|
{
|
||||||
// only dispose TokenSource for step level ExecutionContext
|
// only dispose TokenSource for step level ExecutionContext
|
||||||
@@ -710,6 +722,9 @@ namespace GitHub.Runner.Worker
|
|||||||
// ActionsStepTelemetry for entire job
|
// ActionsStepTelemetry for entire job
|
||||||
Global.StepsTelemetry = new List<ActionsStepTelemetry>();
|
Global.StepsTelemetry = new List<ActionsStepTelemetry>();
|
||||||
|
|
||||||
|
// Steps results for entire job
|
||||||
|
Global.StepsResult = new List<StepResult>();
|
||||||
|
|
||||||
// Job Outputs
|
// Job Outputs
|
||||||
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using GitHub.Actions.RunService.WebApi;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
@@ -16,6 +17,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public IList<String> FileTable { get; set; }
|
public IList<String> FileTable { get; set; }
|
||||||
public IDictionary<String, IDictionary<String, String>> JobDefaults { get; set; }
|
public IDictionary<String, IDictionary<String, String>> JobDefaults { get; set; }
|
||||||
public List<ActionsStepTelemetry> StepsTelemetry { get; set; }
|
public List<ActionsStepTelemetry> StepsTelemetry { get; set; }
|
||||||
|
public List<StepResult> StepsResult { get; set; }
|
||||||
public List<JobTelemetry> JobTelemetry { get; set; }
|
public List<JobTelemetry> JobTelemetry { get; set; }
|
||||||
public TaskOrchestrationPlanReference Plan { get; set; }
|
public TaskOrchestrationPlanReference Plan { get; set; }
|
||||||
public List<string> PrependPath { get; set; }
|
public List<string> PrependPath { get; set; }
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, default);
|
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, default);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
13
src/Sdk/RSWebApi/Contracts/AcquireJobRequest.cs
Normal file
13
src/Sdk/RSWebApi/Contracts/AcquireJobRequest.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
|
namespace GitHub.Actions.RunService.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public class AcquireJobRequest
|
||||||
|
{
|
||||||
|
[DataMember(Name = "streamId", EmitDefaultValue = false)]
|
||||||
|
public string StreamID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Sdk/RSWebApi/Contracts/CompleteJobRequest.cs
Normal file
26
src/Sdk/RSWebApi/Contracts/CompleteJobRequest.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
|
namespace GitHub.Actions.RunService.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public class CompleteJobRequest
|
||||||
|
{
|
||||||
|
[DataMember(Name = "planId", EmitDefaultValue = false)]
|
||||||
|
public Guid PlanID { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "jobId", EmitDefaultValue = false)]
|
||||||
|
public Guid JobID { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "conclusion")]
|
||||||
|
public TaskResult Conclusion { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "outputs", EmitDefaultValue = false)]
|
||||||
|
public Dictionary<string, VariableValue> Outputs { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "stepResults", EmitDefaultValue = false)]
|
||||||
|
public IList<StepResult> StepResults { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/Sdk/RSWebApi/Contracts/StepResult.cs
Normal file
38
src/Sdk/RSWebApi/Contracts/StepResult.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
|
namespace GitHub.Actions.RunService.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public class StepResult
|
||||||
|
{
|
||||||
|
[DataMember(Name = "external_id", EmitDefaultValue = false)]
|
||||||
|
public Guid ExternalID { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "number", EmitDefaultValue = false)]
|
||||||
|
public int? Number { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "name", EmitDefaultValue = false)]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "status")]
|
||||||
|
public TimelineRecordState? Status { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "conclusion")]
|
||||||
|
public TaskResult? Conclusion { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "started_at", EmitDefaultValue = false)]
|
||||||
|
public DateTime? StartedAt { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "completed_at", EmitDefaultValue = false)]
|
||||||
|
public DateTime? CompletedAt { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "completed_log_url", EmitDefaultValue = false)]
|
||||||
|
public string CompletedLogURL { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "completed_log_lines", EmitDefaultValue = false)]
|
||||||
|
public long? CompletedLogLines { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.Pipelines;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.OAuth;
|
using GitHub.Services.OAuth;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using Sdk.WebApi.WebApi;
|
using Sdk.WebApi.WebApi;
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.WebApi
|
namespace GitHub.Actions.RunService.WebApi
|
||||||
{
|
{
|
||||||
[ResourceArea(TaskResourceIds.AreaId)]
|
|
||||||
public class RunServiceHttpClient : RawHttpClientBase
|
public class RunServiceHttpClient : RawHttpClientBase
|
||||||
{
|
{
|
||||||
public RunServiceHttpClient(
|
public RunServiceHttpClient(
|
||||||
@@ -52,21 +54,21 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Pipelines.AgentJobRequestMessage> GetJobMessageAsync(
|
public Task<AgentJobRequestMessage> GetJobMessageAsync(
|
||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
string messageId,
|
string messageId,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
HttpMethod httpMethod = new HttpMethod("POST");
|
HttpMethod httpMethod = new HttpMethod("POST");
|
||||||
var payload = new {
|
var payload = new AcquireJobRequest
|
||||||
|
{
|
||||||
StreamID = messageId
|
StreamID = messageId
|
||||||
};
|
};
|
||||||
|
|
||||||
requestUri = new Uri(requestUri, "acquirejob");
|
requestUri = new Uri(requestUri, "acquirejob");
|
||||||
|
|
||||||
var payloadJson = JsonUtility.ToString(payload);
|
var requestContent = new ObjectContent<AcquireJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
|
||||||
var requestContent = new StringContent(payloadJson, System.Text.Encoding.UTF8, "application/json");
|
return SendAsync<AgentJobRequestMessage>(
|
||||||
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
|
||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri: requestUri,
|
requestUri: requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
@@ -77,18 +79,24 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
Guid planId,
|
Guid planId,
|
||||||
Guid jobId,
|
Guid jobId,
|
||||||
|
TaskResult result,
|
||||||
|
Dictionary<String, VariableValue> outputs,
|
||||||
|
IList<StepResult> stepResults,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
HttpMethod httpMethod = new HttpMethod("POST");
|
HttpMethod httpMethod = new HttpMethod("POST");
|
||||||
var payload = new {
|
var payload = new CompleteJobRequest()
|
||||||
PlanId = planId,
|
{
|
||||||
JobId = jobId
|
PlanID = planId,
|
||||||
|
JobID = jobId,
|
||||||
|
Conclusion = result,
|
||||||
|
Outputs = outputs,
|
||||||
|
StepResults = stepResults
|
||||||
};
|
};
|
||||||
|
|
||||||
requestUri = new Uri(requestUri, "completejob");
|
requestUri = new Uri(requestUri, "completejob");
|
||||||
|
|
||||||
var payloadJson = JsonUtility.ToString(payload);
|
var requestContent = new ObjectContent<CompleteJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
|
||||||
var requestContent = new StringContent(payloadJson, System.Text.Encoding.UTF8, "application/json");
|
|
||||||
return SendAsync(
|
return SendAsync(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri,
|
requestUri,
|
||||||
@@ -711,6 +711,63 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void PublishStepResult_EmbeddedStep()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange: Create a job request message.
|
||||||
|
TaskOrchestrationPlanReference plan = new();
|
||||||
|
TimelineReference timeline = new();
|
||||||
|
Guid jobId = Guid.NewGuid();
|
||||||
|
string jobName = "some job name";
|
||||||
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
||||||
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
|
{
|
||||||
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
Id = "github",
|
||||||
|
Version = "sha1"
|
||||||
|
});
|
||||||
|
jobRequest.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
|
||||||
|
// Arrange: Setup the paging logger.
|
||||||
|
var pagingLogger = new Mock<IPagingLogger>();
|
||||||
|
var pagingLogger2 = new Mock<IPagingLogger>();
|
||||||
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
|
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||||
|
|
||||||
|
hc.EnqueueInstance(pagingLogger.Object);
|
||||||
|
hc.EnqueueInstance(pagingLogger2.Object);
|
||||||
|
hc.SetSingleton(jobServerQueue.Object);
|
||||||
|
|
||||||
|
var ec = new Runner.Worker.ExecutionContext();
|
||||||
|
ec.Initialize(hc);
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
ec.Start();
|
||||||
|
|
||||||
|
var embeddedStep = ec.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, ActionRunStage.Main, isEmbedded: true);
|
||||||
|
embeddedStep.Start();
|
||||||
|
|
||||||
|
embeddedStep.StepTelemetry.Type = "node16";
|
||||||
|
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
||||||
|
embeddedStep.StepTelemetry.Ref = "v2";
|
||||||
|
|
||||||
|
embeddedStep.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
||||||
|
embeddedStep.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
||||||
|
embeddedStep.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice" });
|
||||||
|
|
||||||
|
ec.Complete();
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.Equal(1, ec.Global.StepsResult.Count);
|
||||||
|
Assert.Equal(TaskResult.Succeeded, ec.Global.StepsResult.Single().Conclusion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
||||||
{
|
{
|
||||||
var hc = new TestHostContext(this, testName);
|
var hc = new TestHostContext(this, testName);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using GitHub.Actions.RunService.WebApi;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.Actions.RunService.WebApi;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
|
|||||||
Reference in New Issue
Block a user