Remove the job post complete step

This commit is contained in:
Jordan Brown
2020-05-06 16:31:39 -04:00
parent 99312a0977
commit cfdc190e5c
3 changed files with 128 additions and 132 deletions
@@ -261,84 +261,111 @@ namespace Tgstation.Server.Host.Components
compileJob.Job = job;
databaseContext.CompileJobs.Add(compileJob); // will be saved by job context
databaseContext.CompileJobs.Add(compileJob);
job.PostComplete = async postCompleteCancellationToken =>
// The difficulty with compile jobs is they have a two part commit
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
try
{
await compileJobConsumer.LoadCompileJob(compileJob, postCompleteCancellationToken).ConfigureAwait(false);
await eventConsumer.HandleEvent(EventType.DeploymentComplete, null, postCompleteCancellationToken).ConfigureAwait(false);
};
if (repositorySettings?.AccessToken != null)
await compileJobConsumer.LoadCompileJob(compileJob, cancellationToken).ConfigureAwait(false);
}
catch
{
// potential for commenting on a test merge change
var outgoingCompileJob = LatestCompileJob();
// So we need to un-commit the compile job if the above throws
databaseContext.CompileJobs.Remove(compileJob);
await databaseContext.Save(default).ConfigureAwait(false);
throw;
}
if (outgoingCompileJob != null && outgoingCompileJob.RevisionInformation.CommitSha != compileJob.RevisionInformation.CommitSha && repositorySettings.PostTestMergeComment.Value)
await eventConsumer.HandleEvent(EventType.DeploymentComplete, null, cancellationToken).ConfigureAwait(false);
await PostDeploymentComments(compileJob, repositorySettings, repoOwner, repoName).ConfigureAwait(false);
}
/// <summary>
/// Post deployment GitHub comments.
/// </summary>
/// <param name="compileJob">The deployed <see cref="CompileJob"/>.</param>
/// <param name="repositorySettings">The <see cref="RepositorySettings"/>.</param>
/// <param name="repoOwner">The GitHub repostiory owner.</param>
/// <param name="repoName">The GitHub repostiory name.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
async Task PostDeploymentComments(
CompileJob compileJob,
RepositorySettings repositorySettings,
string repoOwner,
string repoName)
{
if (repositorySettings?.AccessToken == null)
return;
// potential for commenting on a test merge change
var outgoingCompileJob = LatestCompileJob();
if (outgoingCompileJob == null || outgoingCompileJob.RevisionInformation.CommitSha == compileJob.RevisionInformation.CommitSha || !repositorySettings.PostTestMergeComment.Value)
return;
var gitHubClient = gitHubClientFactory.CreateClient(repositorySettings.AccessToken);
async Task CommentOnPR(int prNumber, string comment)
{
try
{
var gitHubClient = gitHubClientFactory.CreateClient(repositorySettings.AccessToken);
async Task CommentOnPR(int prNumber, string comment)
{
try
{
await gitHubClient.Issue.Comment.Create(repoOwner, repoName, prNumber, comment).ConfigureAwait(false);
}
catch (ApiException e)
{
logger.LogWarning("Error posting GitHub comment! Exception: {0}", e);
}
}
var tasks = new List<Task>();
string FormatTestMerge(TestMerge testMerge, bool updated) => String.Format(CultureInfo.InvariantCulture, "#### Test Merge {4}{0}{0}##### Server Instance{0}{5}{1}{0}{0}##### Revision{0}Origin: {6}{0}Pull Request: {2}{0}Server: {7}{3}",
Environment.NewLine,
repositorySettings.ShowTestMergeCommitters.Value ? String.Format(CultureInfo.InvariantCulture, "{0}{0}##### Merged By{0}{1}", Environment.NewLine, testMerge.MergedBy.Name) : String.Empty,
testMerge.PullRequestRevision,
testMerge.Comment != null ? String.Format(CultureInfo.InvariantCulture, "{0}{0}##### Comment{0}{1}", Environment.NewLine, testMerge.Comment) : String.Empty,
updated ? "Updated" : "Deployed",
metadata.Name,
compileJob.RevisionInformation.OriginCommitSha,
compileJob.RevisionInformation.CommitSha);
// added prs
foreach (var I in compileJob
.RevisionInformation
.ActiveTestMerges
.Select(x => x.TestMerge)
.Where(x => !outgoingCompileJob
.RevisionInformation
.ActiveTestMerges
.Any(y => y.TestMerge.Number == x.Number)))
tasks.Add(CommentOnPR(I.Number, FormatTestMerge(I, false)));
// removed prs
foreach (var I in outgoingCompileJob
.RevisionInformation
.ActiveTestMerges
.Select(x => x.TestMerge)
.Where(x => !compileJob
.RevisionInformation
.ActiveTestMerges
.Any(y => y.TestMerge.Number == x.Number)))
tasks.Add(CommentOnPR(I.Number, "#### Test Merge Removed"));
// updated prs
foreach (var I in compileJob
.RevisionInformation
.ActiveTestMerges
.Select(x => x.TestMerge)
.Where(x => outgoingCompileJob
.RevisionInformation
.ActiveTestMerges
.Any(y => y.TestMerge.Number == x.Number)))
tasks.Add(CommentOnPR(I.Number, FormatTestMerge(I, true)));
if (tasks.Any())
await Task.WhenAll(tasks).ConfigureAwait(false);
await gitHubClient.Issue.Comment.Create(repoOwner, repoName, prNumber, comment).ConfigureAwait(false);
}
catch (ApiException e)
{
logger.LogWarning("Error posting GitHub comment! Exception: {0}", e);
}
}
var tasks = new List<Task>();
string FormatTestMerge(TestMerge testMerge, bool updated) => String.Format(CultureInfo.InvariantCulture, "#### Test Merge {4}{0}{0}##### Server Instance{0}{5}{1}{0}{0}##### Revision{0}Origin: {6}{0}Pull Request: {2}{0}Server: {7}{3}",
Environment.NewLine,
repositorySettings.ShowTestMergeCommitters.Value ? String.Format(CultureInfo.InvariantCulture, "{0}{0}##### Merged By{0}{1}", Environment.NewLine, testMerge.MergedBy.Name) : String.Empty,
testMerge.PullRequestRevision,
testMerge.Comment != null ? String.Format(CultureInfo.InvariantCulture, "{0}{0}##### Comment{0}{1}", Environment.NewLine, testMerge.Comment) : String.Empty,
updated ? "Updated" : "Deployed",
metadata.Name,
compileJob.RevisionInformation.OriginCommitSha,
compileJob.RevisionInformation.CommitSha);
// added prs
foreach (var I in compileJob
.RevisionInformation
.ActiveTestMerges
.Select(x => x.TestMerge)
.Where(x => !outgoingCompileJob
.RevisionInformation
.ActiveTestMerges
.Any(y => y.TestMerge.Number == x.Number)))
tasks.Add(CommentOnPR(I.Number, FormatTestMerge(I, false)));
// removed prs
foreach (var I in outgoingCompileJob
.RevisionInformation
.ActiveTestMerges
.Select(x => x.TestMerge)
.Where(x => !compileJob
.RevisionInformation
.ActiveTestMerges
.Any(y => y.TestMerge.Number == x.Number)))
tasks.Add(CommentOnPR(I.Number, "#### Test Merge Removed"));
// updated prs
foreach (var I in compileJob
.RevisionInformation
.ActiveTestMerges
.Select(x => x.TestMerge)
.Where(x => outgoingCompileJob
.RevisionInformation
.ActiveTestMerges
.Any(y => y.TestMerge.Number == x.Number)))
tasks.Add(CommentOnPR(I.Number, FormatTestMerge(I, true)));
if (tasks.Any())
await Task.WhenAll(tasks).ConfigureAwait(false);
}
/// <summary>
+29 -49
View File
@@ -81,43 +81,8 @@ namespace Tgstation.Server.Host.Jobs
{
await databaseContextFactory.UseContext(async databaseContext =>
{
async Task HandleExceptions(Task task)
{
void LogRegularException() => logger.LogDebug("Job {0} exited with error! Exception: {1}", job.Id, job.ExceptionDetails);
try
{
await task.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
logger.LogDebug("Job {0} cancelled!", job.Id);
job.Cancelled = true;
}
catch (JobException e)
{
job.ErrorCode = e.ErrorCode;
job.ExceptionDetails = e.Message;
LogRegularException();
if (e.InnerException != null)
logger.LogDebug(
"Inner exception for job {0}: {1}",
job.Id,
e.InnerException is JobException
? e.InnerException.Message
: e.InnerException.ToString());
}
catch (Exception e)
{
job.ExceptionDetails = e.ToString();
LogRegularException();
}
finally
{
job.StoppedAt = DateTimeOffset.Now;
}
}
async Task RunJobInternal()
void LogRegularException() => logger.LogDebug("Job {0} exited with error! Exception: {1}", job.Id, job.ExceptionDetails);
try
{
var oldJob = job;
job = new Job { Id = oldJob.Id };
@@ -127,20 +92,35 @@ namespace Tgstation.Server.Host.Jobs
logger.LogDebug("Job {0} completed!", job.Id);
}
await HandleExceptions(RunJobInternal()).ConfigureAwait(false);
catch (OperationCanceledException)
{
logger.LogDebug("Job {0} cancelled!", job.Id);
job.Cancelled = true;
}
catch (JobException e)
{
job.ErrorCode = e.ErrorCode;
job.ExceptionDetails = e.Message;
LogRegularException();
if (e.InnerException != null)
logger.LogDebug(
"Inner exception for job {0}: {1}",
job.Id,
e.InnerException is JobException
? e.InnerException.Message
: e.InnerException.ToString());
}
catch (Exception e)
{
job.ExceptionDetails = e.ToString();
LogRegularException();
}
finally
{
job.StoppedAt = DateTimeOffset.Now;
}
await databaseContext.Save(default).ConfigureAwait(false);
bool JobErroredOrCancelled() => job.ExceptionDetails != null || job.Cancelled == true;
// ok so, now it's time for the post commit step if it exists
if (!JobErroredOrCancelled() && job.PostComplete != null)
{
await HandleExceptions(job.PostComplete(cancellationToken)).ConfigureAwait(false);
if (JobErroredOrCancelled())
await databaseContext.Save(default).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
finally
+1 -12
View File
@@ -1,8 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
{
@@ -26,13 +22,6 @@ namespace Tgstation.Server.Host.Models
[Required]
public Instance Instance { get; set; }
/// <summary>
/// A <see cref="Task"/> to run after the job completes. This will not affect the <see cref="Api.Models.Internal.Job.StoppedAt"/> time, unless it is cancelled or errors
/// </summary>
/// <remarks>This should only be used where there are database dependencies that also rely on the Job itself completing A.K.A. manually initiated <see cref="CompileJob"/>s</remarks>
[NotMapped]
public Func<CancellationToken, Task> PostComplete { get; set; }
/// <summary>
/// Convert the <see cref="Job"/> to it's API form
/// </summary>