mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-23 13:07:07 +01:00
Nullify RepositoryUpdateService
This commit is contained in:
@@ -15,8 +15,6 @@ using Tgstation.Server.Host.Database;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
/// <summary>
|
||||
@@ -87,16 +85,18 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
IDatabaseContext databaseContext,
|
||||
ILogger logger,
|
||||
Models.Instance instance,
|
||||
string lastOriginCommitSha,
|
||||
Action<Models.RevisionInformation> revInfoSink,
|
||||
string? lastOriginCommitSha,
|
||||
Action<Models.RevisionInformation>? revInfoSink,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var repoSha = repository.Head;
|
||||
|
||||
IQueryable<Models.RevisionInformation> ApplyQuery(IQueryable<Models.RevisionInformation> query) => query
|
||||
.Where(x => x.CommitSha == repoSha && x.Instance.Id == instance.Id)
|
||||
.Where(x => x.CommitSha == repoSha && x.InstanceId == instance.Id)
|
||||
.Include(x => x.CompileJobs)
|
||||
.Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).ThenInclude(x => x.MergedBy);
|
||||
.Include(x => x.ActiveTestMerges!)
|
||||
.ThenInclude(x => x.TestMerge)
|
||||
.ThenInclude(x => x.MergedBy);
|
||||
|
||||
var revisionInfo = await ApplyQuery(databaseContext.RevisionInformations).FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
revisionInfo = databaseContext
|
||||
.RevisionInformations
|
||||
.Local
|
||||
.Where(x => x.CommitSha == repoSha && x.Instance.Id == instance.Id)
|
||||
.Where(x => x.CommitSha == repoSha && x.InstanceId == instance.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
var needsDbUpdate = revisionInfo == default;
|
||||
@@ -125,7 +125,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
databaseContext.RevisionInformations.Add(revisionInfo);
|
||||
}
|
||||
|
||||
revisionInfo.OriginCommitSha ??= lastOriginCommitSha;
|
||||
revisionInfo!.OriginCommitSha ??= lastOriginCommitSha;
|
||||
if (revisionInfo.OriginCommitSha == null)
|
||||
{
|
||||
revisionInfo.OriginCommitSha = repoSha;
|
||||
@@ -147,13 +147,15 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
#pragma warning disable CA1502, CA1506 // TODO: Decomplexify
|
||||
public async ValueTask RepositoryUpdateJob(
|
||||
IInstanceCore instance,
|
||||
IInstanceCore? instance,
|
||||
IDatabaseContextFactory databaseContextFactory,
|
||||
Job job,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
#pragma warning restore CA1502, CA1506
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(instance);
|
||||
|
||||
_ = job; // shuts up an IDE warning
|
||||
|
||||
var repoManager = instance.RepositoryManager;
|
||||
@@ -162,23 +164,23 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
var startReference = repo.Reference;
|
||||
var startSha = repo.Head;
|
||||
string postUpdateSha = null;
|
||||
string? postUpdateSha = null;
|
||||
|
||||
var newTestMerges = model.NewTestMerges != null && model.NewTestMerges.Count > 0;
|
||||
|
||||
if (newTestMerges && repo.RemoteGitProvider == RemoteGitProvider.Unknown)
|
||||
throw new JobException(ErrorCode.RepoUnsupportedTestMergeRemote);
|
||||
|
||||
var committerName = currentModel.ShowTestMergeCommitters.Value
|
||||
var committerName = (currentModel.ShowTestMergeCommitters!.Value
|
||||
? initiatingUser.Name
|
||||
: currentModel.CommitterName;
|
||||
: currentModel.CommitterName)!;
|
||||
|
||||
var hardResettingToOriginReference = model.UpdateFromOrigin == true && model.Reference != null;
|
||||
|
||||
var numSteps = (model.NewTestMerges?.Count ?? 0) + (model.UpdateFromOrigin == true ? 1 : 0) + (!modelHasShaOrReference ? 2 : (hardResettingToOriginReference ? 3 : 1));
|
||||
var progressFactor = 1.0 / numSteps;
|
||||
|
||||
JobProgressReporter NextProgressReporter(string stage)
|
||||
JobProgressReporter NextProgressReporter(string? stage)
|
||||
{
|
||||
return progressReporter.CreateSection(stage, progressFactor);
|
||||
}
|
||||
@@ -186,19 +188,19 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
progressReporter.ReportProgress(0);
|
||||
|
||||
// get a base line for where we are
|
||||
Models.RevisionInformation lastRevisionInfo = null;
|
||||
Models.RevisionInformation? lastRevisionInfo = null;
|
||||
|
||||
var attachedInstance = new Models.Instance
|
||||
{
|
||||
Id = instanceId,
|
||||
};
|
||||
|
||||
ValueTask CallLoadRevInfo(Models.TestMerge testMergeToAdd = null, string lastOriginCommitSha = null) => databaseContextFactory
|
||||
ValueTask CallLoadRevInfo(Models.TestMerge? testMergeToAdd = null, string? lastOriginCommitSha = null) => databaseContextFactory
|
||||
.UseContext(
|
||||
async databaseContext =>
|
||||
{
|
||||
databaseContext.Instances.Attach(attachedInstance);
|
||||
var previousRevInfo = lastRevisionInfo;
|
||||
var previousRevInfo = lastRevisionInfo!;
|
||||
var needsUpdate = await LoadRevisionInformation(
|
||||
repo,
|
||||
databaseContext,
|
||||
@@ -225,10 +227,11 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
testMergeToAdd.MergedBy = mergedBy;
|
||||
testMergeToAdd.MergedAt = DateTimeOffset.UtcNow;
|
||||
|
||||
foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges)
|
||||
lastRevisionInfo.ActiveTestMerges.Add(activeTestMerge);
|
||||
var activeTestMerges = lastRevisionInfo!.ActiveTestMerges!;
|
||||
foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges!)
|
||||
activeTestMerges.Add(activeTestMerge);
|
||||
|
||||
lastRevisionInfo.ActiveTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo));
|
||||
activeTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo));
|
||||
lastRevisionInfo.PrimaryTestMerge = testMergeToAdd;
|
||||
|
||||
needsUpdate = true;
|
||||
@@ -241,7 +244,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
await CallLoadRevInfo();
|
||||
|
||||
// apply new rev info, tracking applied test merges
|
||||
ValueTask UpdateRevInfo(Models.TestMerge testMergeToAdd = null) => CallLoadRevInfo(testMergeToAdd, lastRevisionInfo.OriginCommitSha);
|
||||
ValueTask UpdateRevInfo(Models.TestMerge? testMergeToAdd = null) => CallLoadRevInfo(testMergeToAdd, lastRevisionInfo!.OriginCommitSha);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -262,12 +265,12 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var fastForward = await repo.MergeOrigin(
|
||||
NextProgressReporter("Merge Origin"),
|
||||
committerName,
|
||||
currentModel.CommitterEmail,
|
||||
currentModel.CommitterEmail!,
|
||||
false,
|
||||
cancellationToken);
|
||||
if (!fastForward.HasValue)
|
||||
throw new JobException(ErrorCode.RepoMergeConflict);
|
||||
lastRevisionInfo.OriginCommitSha = await repo.GetOriginSha(cancellationToken);
|
||||
lastRevisionInfo!.OriginCommitSha = await repo.GetOriginSha(cancellationToken);
|
||||
await UpdateRevInfo();
|
||||
if (fastForward.Value)
|
||||
{
|
||||
@@ -275,8 +278,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
NextProgressReporter("Sychronize"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName,
|
||||
currentModel.CommitterEmail,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
true,
|
||||
false,
|
||||
cancellationToken);
|
||||
@@ -287,7 +290,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}
|
||||
}
|
||||
|
||||
var updateSubmodules = currentModel.UpdateSubmodules.Value;
|
||||
var updateSubmodules = currentModel.UpdateSubmodules!.Value;
|
||||
|
||||
// checkout/hard reset
|
||||
if (modelHasShaOrReference)
|
||||
@@ -301,7 +304,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
if (validCheckoutSha || validCheckoutReference)
|
||||
{
|
||||
var committish = model.CheckoutSha ?? model.Reference;
|
||||
var committish = model.CheckoutSha ?? model.Reference!;
|
||||
var isSha = await repo.IsSha(committish, cancellationToken);
|
||||
|
||||
if ((isSha && model.Reference != null) || (!isSha && model.CheckoutSha != null))
|
||||
@@ -334,8 +337,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
NextProgressReporter("Synchronize"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName,
|
||||
currentModel.CommitterEmail,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
true,
|
||||
false,
|
||||
cancellationToken);
|
||||
@@ -343,7 +346,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
// repo head is on origin so force this
|
||||
// will update the db if necessary
|
||||
lastRevisionInfo.OriginCommitSha = repo.Head;
|
||||
lastRevisionInfo!.OriginCommitSha = repo.Head;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,19 +357,20 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
throw new JobException(ErrorCode.RepoTestMergeInvalidRemote);
|
||||
|
||||
// bit of sanitization
|
||||
foreach (var newTestMergeWithoutTargetCommitSha in model.NewTestMerges.Where(x => String.IsNullOrWhiteSpace(x.TargetCommitSha)))
|
||||
var newTestMergeModels = model.NewTestMerges!;
|
||||
foreach (var newTestMergeWithoutTargetCommitSha in newTestMergeModels.Where(x => String.IsNullOrWhiteSpace(x.TargetCommitSha)))
|
||||
newTestMergeWithoutTargetCommitSha.TargetCommitSha = null;
|
||||
|
||||
var repoOwner = repo.RemoteRepositoryOwner;
|
||||
var repoName = repo.RemoteRepositoryName;
|
||||
|
||||
// optimization: if we've already merged these exact same commits in this fashion before, just find the rev info for it and check it out
|
||||
Models.RevisionInformation revInfoWereLookingFor = null;
|
||||
Models.RevisionInformation? revInfoWereLookingFor = null;
|
||||
bool needToApplyRemainingPrs = true;
|
||||
if (lastRevisionInfo.OriginCommitSha == lastRevisionInfo.CommitSha)
|
||||
if (lastRevisionInfo!.OriginCommitSha == lastRevisionInfo.CommitSha)
|
||||
{
|
||||
bool cantSearch = false;
|
||||
foreach (var newTestMerge in model.NewTestMerges)
|
||||
foreach (var newTestMerge in newTestMergeModels)
|
||||
{
|
||||
if (newTestMerge.TargetCommitSha != null)
|
||||
#pragma warning disable CA1308 // Normalize strings to uppercase
|
||||
@@ -390,56 +394,58 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
if (!cantSearch)
|
||||
{
|
||||
List<Models.RevisionInformation> dbPull = null;
|
||||
List<Models.RevisionInformation>? dbPull = null;
|
||||
|
||||
await databaseContextFactory.UseContext(
|
||||
async databaseContext =>
|
||||
dbPull = await databaseContext.RevisionInformations
|
||||
.AsQueryable()
|
||||
.Where(x => x.Instance.Id == instanceId
|
||||
&& x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
|
||||
&& x.ActiveTestMerges.Count <= model.NewTestMerges.Count
|
||||
&& x.ActiveTestMerges.Count > 0)
|
||||
.Include(x => x.ActiveTestMerges)
|
||||
.ThenInclude(x => x.TestMerge)
|
||||
.Where(x => x.InstanceId == instanceId
|
||||
&& x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
|
||||
&& x.ActiveTestMerges!.Count <= newTestMergeModels.Count
|
||||
&& x.ActiveTestMerges!.Count > 0)
|
||||
.Include(x => x.ActiveTestMerges!)
|
||||
.ThenInclude(x => x.TestMerge)
|
||||
.ToListAsync(cancellationToken));
|
||||
|
||||
// split here cause this bit has to be done locally
|
||||
revInfoWereLookingFor = dbPull
|
||||
.Where(x => x.ActiveTestMerges.Count == model.NewTestMerges.Count
|
||||
&& x.ActiveTestMerges.Select(y => y.TestMerge)
|
||||
.All(y => model.NewTestMerges.Any(z =>
|
||||
y.Number == z.Number
|
||||
&& y.TargetCommitSha.StartsWith(z.TargetCommitSha, StringComparison.Ordinal)
|
||||
&& (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))))
|
||||
revInfoWereLookingFor = dbPull!
|
||||
.Where(x => x.ActiveTestMerges!.Count == newTestMergeModels.Count
|
||||
&& x.ActiveTestMerges
|
||||
.Select(y => y.TestMerge)
|
||||
.All(y => newTestMergeModels
|
||||
.Any(z =>
|
||||
y.Number == z.Number
|
||||
&& y.TargetCommitSha!.StartsWith(z.TargetCommitSha!, StringComparison.Ordinal)
|
||||
&& (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (revInfoWereLookingFor == default && model.NewTestMerges.Count > 1)
|
||||
if (revInfoWereLookingFor == default && newTestMergeModels.Count > 1)
|
||||
{
|
||||
// okay try to add at least SOME prs we've seen before
|
||||
var listedNewTestMerges = model.NewTestMerges.ToList();
|
||||
var listedNewTestMerges = newTestMergeModels.ToList();
|
||||
|
||||
var appliedTestMergeIds = new List<long>();
|
||||
|
||||
Models.RevisionInformation lastGoodRevInfo = null;
|
||||
Models.RevisionInformation? lastGoodRevInfo = null;
|
||||
do
|
||||
{
|
||||
foreach (var newTestMergeParameters in listedNewTestMerges)
|
||||
{
|
||||
revInfoWereLookingFor = dbPull
|
||||
revInfoWereLookingFor = dbPull!
|
||||
.Where(testRevInfo =>
|
||||
{
|
||||
if (testRevInfo.PrimaryTestMerge == null)
|
||||
return false;
|
||||
|
||||
var testMergeMatch = model.NewTestMerges.Any(testTestMerge =>
|
||||
var testMergeMatch = newTestMergeModels.Any(testTestMerge =>
|
||||
{
|
||||
var numberMatch = testRevInfo.PrimaryTestMerge.Number == testTestMerge.Number;
|
||||
if (!numberMatch)
|
||||
return false;
|
||||
|
||||
var shaMatch = testRevInfo.PrimaryTestMerge.TargetCommitSha.StartsWith(
|
||||
testTestMerge.TargetCommitSha,
|
||||
var shaMatch = testRevInfo.PrimaryTestMerge.TargetCommitSha!.StartsWith(
|
||||
testTestMerge.TargetCommitSha!,
|
||||
StringComparison.Ordinal);
|
||||
if (!shaMatch)
|
||||
return false;
|
||||
@@ -452,7 +458,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
return false;
|
||||
|
||||
var previousTestMergesMatch = testRevInfo
|
||||
.ActiveTestMerges
|
||||
.ActiveTestMerges!
|
||||
.Select(previousRevInfoTestMerge => previousRevInfoTestMerge.TestMerge)
|
||||
.All(previousTestMerge => appliedTestMergeIds.Contains(previousTestMerge.Id));
|
||||
|
||||
@@ -463,7 +469,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if (revInfoWereLookingFor != null)
|
||||
{
|
||||
lastGoodRevInfo = revInfoWereLookingFor;
|
||||
appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id);
|
||||
appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge!.Id);
|
||||
listedNewTestMerges.Remove(newTestMergeParameters);
|
||||
break;
|
||||
}
|
||||
@@ -484,16 +490,17 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if (revInfoWereLookingFor != null)
|
||||
{
|
||||
// goteem
|
||||
logger.LogDebug("Reusing existing SHA {sha}...", revInfoWereLookingFor.CommitSha);
|
||||
await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter($"Reset to {revInfoWereLookingFor.CommitSha[..7]}"), cancellationToken);
|
||||
var commitSha = revInfoWereLookingFor.CommitSha!;
|
||||
logger.LogDebug("Reusing existing SHA {sha}...", commitSha);
|
||||
await repo.ResetToSha(commitSha, NextProgressReporter($"Reset to {commitSha[..7]}"), cancellationToken);
|
||||
lastRevisionInfo = revInfoWereLookingFor;
|
||||
}
|
||||
|
||||
if (needToApplyRemainingPrs)
|
||||
{
|
||||
foreach (var newTestMerge in model.NewTestMerges)
|
||||
foreach (var newTestMerge in newTestMergeModels)
|
||||
{
|
||||
if (lastRevisionInfo.ActiveTestMerges.Any(x => x.TestMerge.Number == newTestMerge.Number))
|
||||
if (lastRevisionInfo.ActiveTestMerges!.Any(x => x.TestMerge.Number == newTestMerge.Number))
|
||||
throw new JobException(ErrorCode.RepoDuplicateTestMerge);
|
||||
|
||||
var fullTestMergeTask = repo.GetTestMerge(newTestMerge, currentModel, cancellationToken);
|
||||
@@ -501,7 +508,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var mergeResult = await repo.AddTestMerge(
|
||||
newTestMerge,
|
||||
committerName,
|
||||
currentModel.CommitterEmail,
|
||||
currentModel.CommitterEmail!,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
@@ -512,7 +519,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
throw new JobException(
|
||||
ErrorCode.RepoTestMergeConflict,
|
||||
new JobException(
|
||||
$"Test Merge #{newTestMerge.Number} at {newTestMerge.TargetCommitSha[..7]} conflicted! Conflicting files:{Environment.NewLine}{String.Join(Environment.NewLine, mergeResult.ConflictingFiles.Select(file => $"\t- /{file}"))}"));
|
||||
$"Test Merge #{newTestMerge.Number} at {newTestMerge.TargetCommitSha![..7]} conflicted! Conflicting files:{Environment.NewLine}{String.Join(Environment.NewLine, mergeResult.ConflictingFiles!.Select(file => $"\t- /{file}"))}"));
|
||||
|
||||
Models.TestMerge fullTestMerge;
|
||||
try
|
||||
@@ -543,14 +550,14 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}
|
||||
|
||||
var currentHead = repo.Head;
|
||||
if (currentModel.PushTestMergeCommits.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead)))
|
||||
if (currentModel.PushTestMergeCommits!.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead)))
|
||||
{
|
||||
await repo.Synchronize(
|
||||
NextProgressReporter("Synchronize"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName,
|
||||
currentModel.CommitterEmail,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
false,
|
||||
false,
|
||||
cancellationToken);
|
||||
|
||||
Reference in New Issue
Block a user