diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs index 4da69c51af..a7aca78c4b 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs @@ -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 { /// @@ -87,16 +85,18 @@ namespace Tgstation.Server.Host.Components.Repository IDatabaseContext databaseContext, ILogger logger, Models.Instance instance, - string lastOriginCommitSha, - Action revInfoSink, + string? lastOriginCommitSha, + Action? revInfoSink, CancellationToken cancellationToken) { var repoSha = repository.Head; IQueryable ApplyQuery(IQueryable 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 /// A representing the running operation. #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 dbPull = null; + List? 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(); - 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);