diff --git a/_repository_controller_8cs_source.html b/_repository_controller_8cs_source.html index 2f7a4c253a..95bc48e526 100644 --- a/_repository_controller_8cs_source.html +++ b/_repository_controller_8cs_source.html @@ -762,175 +762,198 @@ $(function() {
742  foreach (var I in search)
743  {
744  revInfoWereLookingFor = dbPull
-
745  .Where(x => model.NewTestMerges.Any(z =>
-
746  x.PrimaryTestMerge.Number == z.Number
-
747  && x.PrimaryTestMerge.PullRequestRevision.StartsWith(z.PullRequestRevision, StringComparison.Ordinal)
-
748  && (x.PrimaryTestMerge.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))
-
749  && x.ActiveTestMerges.Select(y => y.TestMerge).All(y => appliedTestMergeIds.Contains(y.Id)))
-
750  .FirstOrDefault();
-
751 
-
752  if (revInfoWereLookingFor != null)
-
753  {
-
754  lastGoodRevInfo = revInfoWereLookingFor;
-
755  appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id);
-
756  search.Remove(I);
-
757  break;
-
758  }
-
759  }
-
760  }
-
761  while (revInfoWereLookingFor != null && search.Count > 0);
+
745  .Where(testRevInfo =>
+
746  {
+
747  var testMergeMatch = model.NewTestMerges.Any(testTestMerge =>
+
748  {
+
749  var numberMatch = testRevInfo.PrimaryTestMerge.Number == testTestMerge.Number;
+
750  if (!numberMatch)
+
751  return false;
+
752 
+
753  var shaMatch = testRevInfo.PrimaryTestMerge.PullRequestRevision.StartsWith(
+
754  testTestMerge.PullRequestRevision,
+
755  StringComparison.Ordinal);
+
756  if (!shaMatch)
+
757  return false;
+
758 
+
759  var commentMatch = testRevInfo.PrimaryTestMerge.Comment == testTestMerge.Comment;
+
760  return commentMatch;
+
761  });
762 
-
763  revInfoWereLookingFor = lastGoodRevInfo;
-
764  needToApplyRemainingPrs = search.Count != 0;
-
765  if (needToApplyRemainingPrs)
-
766  model.NewTestMerges = search;
-
767  }
-
768  else if (revInfoWereLookingFor != null)
-
769  needToApplyRemainingPrs = false;
-
770  }
-
771  }
-
772 
-
773  if (revInfoWereLookingFor != null)
-
774  {
-
775  // goteem
-
776  Logger.LogDebug("Reusing existing SHA {0}...", revInfoWereLookingFor.CommitSha);
-
777  await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter(), cancellationToken).ConfigureAwait(false);
-
778  lastRevisionInfo = revInfoWereLookingFor;
-
779  }
-
780 
-
781  if (needToApplyRemainingPrs)
-
782  {
-
783  foreach (var I in model.NewTestMerges)
-
784  {
-
785  Octokit.PullRequest pr = null;
-
786  string errorMessage = null;
-
787 
-
788  if (lastRevisionInfo.ActiveTestMerges.Any(x => x.TestMerge.Number == I.Number))
-
789  throw new JobException(ErrorCode.RepoDuplicateTestMerge);
-
790 
-
791  Exception exception = null;
-
792  try
-
793  {
-
794  // load from cache if possible
-
795  if (prMap == null || !prMap.TryGetValue(I.Number, out pr))
-
796  pr = await gitHubClient
-
797  .PullRequest
-
798  .Get(repoOwner, repoName, I.Number)
-
799  .WithToken(ct)
-
800  .ConfigureAwait(false);
-
801  }
-
802  catch (Octokit.RateLimitExceededException ex)
-
803  {
-
804  // you look at your anonymous access and sigh
-
805  errorMessage = "REMOTE API ERROR: RATE LIMITED";
-
806  exception = ex;
-
807  }
-
808  catch (Octokit.AuthorizationException ex)
-
809  {
-
810  errorMessage = "REMOTE API ERROR: BAD CREDENTIALS";
-
811  exception = ex;
-
812  }
-
813  catch (Octokit.NotFoundException ex)
-
814  {
-
815  // you look at your shithub and sigh
-
816  errorMessage = "REMOTE API ERROR: PULL REQUEST NOT FOUND";
-
817  exception = ex;
-
818  }
-
819 
-
820  if (exception != null)
-
821  Logger.LogWarning(exception, "Error retrieving pull request metadata!");
-
822 
-
823  // we want to take the earliest truth possible to prevent RCEs, if this fails AddTestMerge will set it
-
824  if (I.PullRequestRevision == null && pr != null)
-
825  I.PullRequestRevision = pr.Head.Sha;
-
826 
-
827  var mergeResult = await repo.AddTestMerge(
-
828  I,
-
829  committerName,
-
830  currentModel.CommitterEmail,
-
831  currentModel.AccessUser,
-
832  currentModel.AccessToken,
-
833  NextProgressReporter(),
-
834  ct).ConfigureAwait(false);
-
835 
-
836  if (!mergeResult.HasValue)
-
837  throw new JobException(
-
838  ErrorCode.RepoTestMergeConflict,
-
839  new JobException(
-
840  $"Merge of PR #{I.Number} at {I.PullRequestRevision.Substring(0, 7)} conflicted!"));
-
841 
-
842  ++doneSteps;
-
843 
-
844  // MergedBy will be set later
-
845  var tm = new Models.TestMerge
-
846  {
-
847  Author = pr?.User.Login ?? errorMessage,
-
848  BodyAtMerge = pr?.Body ?? errorMessage ?? String.Empty,
-
849  MergedAt = DateTimeOffset.Now,
-
850  TitleAtMerge = pr?.Title ?? errorMessage ?? String.Empty,
-
851  Comment = I.Comment,
-
852  Number = I.Number,
-
853  PullRequestRevision = I.PullRequestRevision,
-
854  Url = pr?.HtmlUrl ?? errorMessage
-
855  };
-
856 
-
857  await UpdateRevInfo(tm).ConfigureAwait(false);
-
858  }
-
859  }
-
860  }
-
861 
-
862  var currentHead = repo.Head;
-
863  if (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))
-
864  {
-
865  await repo.Sychronize(currentModel.AccessUser, currentModel.AccessToken, currentModel.CommitterName, currentModel.CommitterEmail, NextProgressReporter(), false, ct).ConfigureAwait(false);
-
866  await UpdateRevInfo().ConfigureAwait(false);
-
867  }
-
868 
-
869  return null;
-
870  }
-
871  catch
-
872  {
-
873  doneSteps = 0;
-
874  numSteps = 2;
-
875 
-
876  // Forget what we've done and abort
-
877  // DCTx2: Cancellation token is for job, operations should always run
-
878  await repo.CheckoutObject(startReference ?? startSha, NextProgressReporter(), default).ConfigureAwait(false);
-
879  if (startReference != null && repo.Head != startSha)
-
880  await repo.ResetToSha(startSha, NextProgressReporter(), default).ConfigureAwait(false);
-
881  else
-
882  progressReporter(100);
-
883  throw;
-
884  }
-
885  }
-
886 
-
887  var job = new Models.Job
-
888  {
-
889  Description = description,
-
890  StartedBy = AuthenticationContext.User,
-
891  Instance = Instance,
-
892  CancelRightsType = RightsType.Repository,
-
893  CancelRight = (ulong)RepositoryRights.CancelPendingChanges,
-
894  };
-
895 
-
896  // Time to access git, do it in a job
-
897  await jobManager.RegisterOperation(
-
898  job,
-
899  (core, databaseContextFactory, paramJob, progressReporter, ct) =>
-
900  UpdateCallbackThatDesperatelyNeedsRefactoring(
-
901  core,
-
902  databaseContextFactory,
-
903  progressReporter,
-
904  ct),
-
905  cancellationToken)
-
906  .ConfigureAwait(false);
-
907 
-
908  api.ActiveJob = job.ToApi();
-
909  return Accepted(api);
-
910  }
-
911  #pragma warning restore CA1502, CA1505
-
912  }
-
913 }
+
763  if (!testMergeMatch)
+
764  return false;
+
765 
+
766  var previousTestMergesMatch = testRevInfo
+
767  .ActiveTestMerges
+
768  .Select(previousRevInfoTestMerge => previousRevInfoTestMerge.TestMerge)
+
769  .All(previousTestMerge => appliedTestMergeIds.Contains(previousTestMerge.Id));
+
770 
+
771  return previousTestMergesMatch;
+
772  })
+
773  .FirstOrDefault();
+
774 
+
775  if (revInfoWereLookingFor != null)
+
776  {
+
777  lastGoodRevInfo = revInfoWereLookingFor;
+
778  appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id);
+
779  search.Remove(I);
+
780  break;
+
781  }
+
782  }
+
783  }
+
784  while (revInfoWereLookingFor != null && search.Count > 0);
+
785 
+
786  revInfoWereLookingFor = lastGoodRevInfo;
+
787  needToApplyRemainingPrs = search.Count != 0;
+
788  if (needToApplyRemainingPrs)
+
789  model.NewTestMerges = search;
+
790  }
+
791  else if (revInfoWereLookingFor != null)
+
792  needToApplyRemainingPrs = false;
+
793  }
+
794  }
+
795 
+
796  if (revInfoWereLookingFor != null)
+
797  {
+
798  // goteem
+
799  Logger.LogDebug("Reusing existing SHA {0}...", revInfoWereLookingFor.CommitSha);
+
800  await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter(), cancellationToken).ConfigureAwait(false);
+
801  lastRevisionInfo = revInfoWereLookingFor;
+
802  }
+
803 
+
804  if (needToApplyRemainingPrs)
+
805  {
+
806  foreach (var I in model.NewTestMerges)
+
807  {
+
808  Octokit.PullRequest pr = null;
+
809  string errorMessage = null;
+
810 
+
811  if (lastRevisionInfo.ActiveTestMerges.Any(x => x.TestMerge.Number == I.Number))
+
812  throw new JobException(ErrorCode.RepoDuplicateTestMerge);
+
813 
+
814  Exception exception = null;
+
815  try
+
816  {
+
817  // load from cache if possible
+
818  if (prMap == null || !prMap.TryGetValue(I.Number, out pr))
+
819  pr = await gitHubClient
+
820  .PullRequest
+
821  .Get(repoOwner, repoName, I.Number)
+
822  .WithToken(ct)
+
823  .ConfigureAwait(false);
+
824  }
+
825  catch (Octokit.RateLimitExceededException ex)
+
826  {
+
827  // you look at your anonymous access and sigh
+
828  errorMessage = "REMOTE API ERROR: RATE LIMITED";
+
829  exception = ex;
+
830  }
+
831  catch (Octokit.AuthorizationException ex)
+
832  {
+
833  errorMessage = "REMOTE API ERROR: BAD CREDENTIALS";
+
834  exception = ex;
+
835  }
+
836  catch (Octokit.NotFoundException ex)
+
837  {
+
838  // you look at your shithub and sigh
+
839  errorMessage = "REMOTE API ERROR: PULL REQUEST NOT FOUND";
+
840  exception = ex;
+
841  }
+
842 
+
843  if (exception != null)
+
844  Logger.LogWarning(exception, "Error retrieving pull request metadata!");
+
845 
+
846  // we want to take the earliest truth possible to prevent RCEs, if this fails AddTestMerge will set it
+
847  if (I.PullRequestRevision == null && pr != null)
+
848  I.PullRequestRevision = pr.Head.Sha;
+
849 
+
850  var mergeResult = await repo.AddTestMerge(
+
851  I,
+
852  committerName,
+
853  currentModel.CommitterEmail,
+
854  currentModel.AccessUser,
+
855  currentModel.AccessToken,
+
856  NextProgressReporter(),
+
857  ct).ConfigureAwait(false);
+
858 
+
859  if (!mergeResult.HasValue)
+
860  throw new JobException(
+
861  ErrorCode.RepoTestMergeConflict,
+
862  new JobException(
+
863  $"Merge of PR #{I.Number} at {I.PullRequestRevision.Substring(0, 7)} conflicted!"));
+
864 
+
865  ++doneSteps;
+
866 
+
867  // MergedBy will be set later
+
868  var tm = new Models.TestMerge
+
869  {
+
870  Author = pr?.User.Login ?? errorMessage,
+
871  BodyAtMerge = pr?.Body ?? errorMessage ?? String.Empty,
+
872  MergedAt = DateTimeOffset.Now,
+
873  TitleAtMerge = pr?.Title ?? errorMessage ?? String.Empty,
+
874  Comment = I.Comment,
+
875  Number = I.Number,
+
876  PullRequestRevision = I.PullRequestRevision,
+
877  Url = pr?.HtmlUrl ?? errorMessage
+
878  };
+
879 
+
880  await UpdateRevInfo(tm).ConfigureAwait(false);
+
881  }
+
882  }
+
883  }
+
884 
+
885  var currentHead = repo.Head;
+
886  if (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))
+
887  {
+
888  await repo.Sychronize(currentModel.AccessUser, currentModel.AccessToken, currentModel.CommitterName, currentModel.CommitterEmail, NextProgressReporter(), false, ct).ConfigureAwait(false);
+
889  await UpdateRevInfo().ConfigureAwait(false);
+
890  }
+
891 
+
892  return null;
+
893  }
+
894  catch
+
895  {
+
896  doneSteps = 0;
+
897  numSteps = 2;
+
898 
+
899  // Forget what we've done and abort
+
900  // DCTx2: Cancellation token is for job, operations should always run
+
901  await repo.CheckoutObject(startReference ?? startSha, NextProgressReporter(), default).ConfigureAwait(false);
+
902  if (startReference != null && repo.Head != startSha)
+
903  await repo.ResetToSha(startSha, NextProgressReporter(), default).ConfigureAwait(false);
+
904  else
+
905  progressReporter(100);
+
906  throw;
+
907  }
+
908  }
+
909 
+
910  var job = new Models.Job
+
911  {
+
912  Description = description,
+
913  StartedBy = AuthenticationContext.User,
+
914  Instance = Instance,
+
915  CancelRightsType = RightsType.Repository,
+
916  CancelRight = (ulong)RepositoryRights.CancelPendingChanges,
+
917  };
+
918 
+
919  // Time to access git, do it in a job
+
920  await jobManager.RegisterOperation(
+
921  job,
+
922  (core, databaseContextFactory, paramJob, progressReporter, ct) =>
+
923  UpdateCallbackThatDesperatelyNeedsRefactoring(
+
924  core,
+
925  databaseContextFactory,
+
926  progressReporter,
+
927  ct),
+
928  cancellationToken)
+
929  .ConfigureAwait(false);
+
930 
+
931  api.ActiveJob = job.ToApi();
+
932  return Accepted(api);
+
933  }
+
934  #pragma warning restore CA1502, CA1505
+
935  }
+
936 }
Tgstation.Server.Host.Controllers.InstanceRequiredController.instanceManager
readonly IInstanceManager instanceManager
The IInstanceManager for the InstanceRequiredController.
Definition: InstanceRequiredController.cs:22
Tgstation.Server.Api.Models.Repository
Represents a git repository
Definition: Repository.cs:10
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_controllers_1_1_repository_controller.html b/class_tgstation_1_1_server_1_1_host_1_1_controllers_1_1_repository_controller.html index 6f6d1887e5..bbcc87750e 100644 --- a/class_tgstation_1_1_server_1_1_host_1_1_controllers_1_1_repository_controller.html +++ b/class_tgstation_1_1_server_1_1_host_1_1_controllers_1_1_repository_controller.html @@ -1261,172 +1261,195 @@ Here is the call graph for this function:
742  foreach (var I in search)
743  {
744  revInfoWereLookingFor = dbPull
-
745  .Where(x => model.NewTestMerges.Any(z =>
-
746  x.PrimaryTestMerge.Number == z.Number
-
747  && x.PrimaryTestMerge.PullRequestRevision.StartsWith(z.PullRequestRevision, StringComparison.Ordinal)
-
748  && (x.PrimaryTestMerge.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))
-
749  && x.ActiveTestMerges.Select(y => y.TestMerge).All(y => appliedTestMergeIds.Contains(y.Id)))
-
750  .FirstOrDefault();
-
751 
-
752  if (revInfoWereLookingFor != null)
-
753  {
-
754  lastGoodRevInfo = revInfoWereLookingFor;
-
755  appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id);
-
756  search.Remove(I);
-
757  break;
-
758  }
-
759  }
-
760  }
-
761  while (revInfoWereLookingFor != null && search.Count > 0);
+
745  .Where(testRevInfo =>
+
746  {
+
747  var testMergeMatch = model.NewTestMerges.Any(testTestMerge =>
+
748  {
+
749  var numberMatch = testRevInfo.PrimaryTestMerge.Number == testTestMerge.Number;
+
750  if (!numberMatch)
+
751  return false;
+
752 
+
753  var shaMatch = testRevInfo.PrimaryTestMerge.PullRequestRevision.StartsWith(
+
754  testTestMerge.PullRequestRevision,
+
755  StringComparison.Ordinal);
+
756  if (!shaMatch)
+
757  return false;
+
758 
+
759  var commentMatch = testRevInfo.PrimaryTestMerge.Comment == testTestMerge.Comment;
+
760  return commentMatch;
+
761  });
762 
-
763  revInfoWereLookingFor = lastGoodRevInfo;
-
764  needToApplyRemainingPrs = search.Count != 0;
-
765  if (needToApplyRemainingPrs)
-
766  model.NewTestMerges = search;
-
767  }
-
768  else if (revInfoWereLookingFor != null)
-
769  needToApplyRemainingPrs = false;
-
770  }
-
771  }
-
772 
-
773  if (revInfoWereLookingFor != null)
-
774  {
-
775  // goteem
-
776  Logger.LogDebug("Reusing existing SHA {0}...", revInfoWereLookingFor.CommitSha);
-
777  await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter(), cancellationToken).ConfigureAwait(false);
-
778  lastRevisionInfo = revInfoWereLookingFor;
-
779  }
-
780 
-
781  if (needToApplyRemainingPrs)
-
782  {
-
783  foreach (var I in model.NewTestMerges)
-
784  {
-
785  Octokit.PullRequest pr = null;
-
786  string errorMessage = null;
-
787 
-
788  if (lastRevisionInfo.ActiveTestMerges.Any(x => x.TestMerge.Number == I.Number))
-
789  throw new JobException(ErrorCode.RepoDuplicateTestMerge);
-
790 
-
791  Exception exception = null;
-
792  try
-
793  {
-
794  // load from cache if possible
-
795  if (prMap == null || !prMap.TryGetValue(I.Number, out pr))
-
796  pr = await gitHubClient
-
797  .PullRequest
-
798  .Get(repoOwner, repoName, I.Number)
-
799  .WithToken(ct)
-
800  .ConfigureAwait(false);
-
801  }
-
802  catch (Octokit.RateLimitExceededException ex)
-
803  {
-
804  // you look at your anonymous access and sigh
-
805  errorMessage = "REMOTE API ERROR: RATE LIMITED";
-
806  exception = ex;
-
807  }
-
808  catch (Octokit.AuthorizationException ex)
-
809  {
-
810  errorMessage = "REMOTE API ERROR: BAD CREDENTIALS";
-
811  exception = ex;
-
812  }
-
813  catch (Octokit.NotFoundException ex)
-
814  {
-
815  // you look at your shithub and sigh
-
816  errorMessage = "REMOTE API ERROR: PULL REQUEST NOT FOUND";
-
817  exception = ex;
-
818  }
-
819 
-
820  if (exception != null)
-
821  Logger.LogWarning(exception, "Error retrieving pull request metadata!");
-
822 
-
823  // we want to take the earliest truth possible to prevent RCEs, if this fails AddTestMerge will set it
-
824  if (I.PullRequestRevision == null && pr != null)
-
825  I.PullRequestRevision = pr.Head.Sha;
-
826 
-
827  var mergeResult = await repo.AddTestMerge(
-
828  I,
-
829  committerName,
-
830  currentModel.CommitterEmail,
-
831  currentModel.AccessUser,
-
832  currentModel.AccessToken,
-
833  NextProgressReporter(),
-
834  ct).ConfigureAwait(false);
-
835 
-
836  if (!mergeResult.HasValue)
-
837  throw new JobException(
-
838  ErrorCode.RepoTestMergeConflict,
-
839  new JobException(
-
840  $"Merge of PR #{I.Number} at {I.PullRequestRevision.Substring(0, 7)} conflicted!"));
-
841 
-
842  ++doneSteps;
-
843 
-
844  // MergedBy will be set later
-
845  var tm = new Models.TestMerge
-
846  {
-
847  Author = pr?.User.Login ?? errorMessage,
-
848  BodyAtMerge = pr?.Body ?? errorMessage ?? String.Empty,
-
849  MergedAt = DateTimeOffset.Now,
-
850  TitleAtMerge = pr?.Title ?? errorMessage ?? String.Empty,
-
851  Comment = I.Comment,
-
852  Number = I.Number,
-
853  PullRequestRevision = I.PullRequestRevision,
-
854  Url = pr?.HtmlUrl ?? errorMessage
-
855  };
-
856 
-
857  await UpdateRevInfo(tm).ConfigureAwait(false);
-
858  }
-
859  }
-
860  }
-
861 
-
862  var currentHead = repo.Head;
-
863  if (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))
-
864  {
-
865  await repo.Sychronize(currentModel.AccessUser, currentModel.AccessToken, currentModel.CommitterName, currentModel.CommitterEmail, NextProgressReporter(), false, ct).ConfigureAwait(false);
-
866  await UpdateRevInfo().ConfigureAwait(false);
-
867  }
-
868 
-
869  return null;
-
870  }
-
871  catch
-
872  {
-
873  doneSteps = 0;
-
874  numSteps = 2;
-
875 
-
876  // Forget what we've done and abort
-
877  // DCTx2: Cancellation token is for job, operations should always run
-
878  await repo.CheckoutObject(startReference ?? startSha, NextProgressReporter(), default).ConfigureAwait(false);
-
879  if (startReference != null && repo.Head != startSha)
-
880  await repo.ResetToSha(startSha, NextProgressReporter(), default).ConfigureAwait(false);
-
881  else
-
882  progressReporter(100);
-
883  throw;
-
884  }
-
885  }
-
886 
-
887  var job = new Models.Job
-
888  {
-
889  Description = description,
-
890  StartedBy = AuthenticationContext.User,
-
891  Instance = Instance,
-
892  CancelRightsType = RightsType.Repository,
-
893  CancelRight = (ulong)RepositoryRights.CancelPendingChanges,
-
894  };
-
895 
-
896  // Time to access git, do it in a job
-
897  await jobManager.RegisterOperation(
-
898  job,
-
899  (core, databaseContextFactory, paramJob, progressReporter, ct) =>
-
900  UpdateCallbackThatDesperatelyNeedsRefactoring(
-
901  core,
-
902  databaseContextFactory,
-
903  progressReporter,
-
904  ct),
-
905  cancellationToken)
-
906  .ConfigureAwait(false);
-
907 
-
908  api.ActiveJob = job.ToApi();
-
909  return Accepted(api);
-
910  }
+
763  if (!testMergeMatch)
+
764  return false;
+
765 
+
766  var previousTestMergesMatch = testRevInfo
+
767  .ActiveTestMerges
+
768  .Select(previousRevInfoTestMerge => previousRevInfoTestMerge.TestMerge)
+
769  .All(previousTestMerge => appliedTestMergeIds.Contains(previousTestMerge.Id));
+
770 
+
771  return previousTestMergesMatch;
+
772  })
+
773  .FirstOrDefault();
+
774 
+
775  if (revInfoWereLookingFor != null)
+
776  {
+
777  lastGoodRevInfo = revInfoWereLookingFor;
+
778  appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id);
+
779  search.Remove(I);
+
780  break;
+
781  }
+
782  }
+
783  }
+
784  while (revInfoWereLookingFor != null && search.Count > 0);
+
785 
+
786  revInfoWereLookingFor = lastGoodRevInfo;
+
787  needToApplyRemainingPrs = search.Count != 0;
+
788  if (needToApplyRemainingPrs)
+
789  model.NewTestMerges = search;
+
790  }
+
791  else if (revInfoWereLookingFor != null)
+
792  needToApplyRemainingPrs = false;
+
793  }
+
794  }
+
795 
+
796  if (revInfoWereLookingFor != null)
+
797  {
+
798  // goteem
+
799  Logger.LogDebug("Reusing existing SHA {0}...", revInfoWereLookingFor.CommitSha);
+
800  await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter(), cancellationToken).ConfigureAwait(false);
+
801  lastRevisionInfo = revInfoWereLookingFor;
+
802  }
+
803 
+
804  if (needToApplyRemainingPrs)
+
805  {
+
806  foreach (var I in model.NewTestMerges)
+
807  {
+
808  Octokit.PullRequest pr = null;
+
809  string errorMessage = null;
+
810 
+
811  if (lastRevisionInfo.ActiveTestMerges.Any(x => x.TestMerge.Number == I.Number))
+
812  throw new JobException(ErrorCode.RepoDuplicateTestMerge);
+
813 
+
814  Exception exception = null;
+
815  try
+
816  {
+
817  // load from cache if possible
+
818  if (prMap == null || !prMap.TryGetValue(I.Number, out pr))
+
819  pr = await gitHubClient
+
820  .PullRequest
+
821  .Get(repoOwner, repoName, I.Number)
+
822  .WithToken(ct)
+
823  .ConfigureAwait(false);
+
824  }
+
825  catch (Octokit.RateLimitExceededException ex)
+
826  {
+
827  // you look at your anonymous access and sigh
+
828  errorMessage = "REMOTE API ERROR: RATE LIMITED";
+
829  exception = ex;
+
830  }
+
831  catch (Octokit.AuthorizationException ex)
+
832  {
+
833  errorMessage = "REMOTE API ERROR: BAD CREDENTIALS";
+
834  exception = ex;
+
835  }
+
836  catch (Octokit.NotFoundException ex)
+
837  {
+
838  // you look at your shithub and sigh
+
839  errorMessage = "REMOTE API ERROR: PULL REQUEST NOT FOUND";
+
840  exception = ex;
+
841  }
+
842 
+
843  if (exception != null)
+
844  Logger.LogWarning(exception, "Error retrieving pull request metadata!");
+
845 
+
846  // we want to take the earliest truth possible to prevent RCEs, if this fails AddTestMerge will set it
+
847  if (I.PullRequestRevision == null && pr != null)
+
848  I.PullRequestRevision = pr.Head.Sha;
+
849 
+
850  var mergeResult = await repo.AddTestMerge(
+
851  I,
+
852  committerName,
+
853  currentModel.CommitterEmail,
+
854  currentModel.AccessUser,
+
855  currentModel.AccessToken,
+
856  NextProgressReporter(),
+
857  ct).ConfigureAwait(false);
+
858 
+
859  if (!mergeResult.HasValue)
+
860  throw new JobException(
+
861  ErrorCode.RepoTestMergeConflict,
+
862  new JobException(
+
863  $"Merge of PR #{I.Number} at {I.PullRequestRevision.Substring(0, 7)} conflicted!"));
+
864 
+
865  ++doneSteps;
+
866 
+
867  // MergedBy will be set later
+
868  var tm = new Models.TestMerge
+
869  {
+
870  Author = pr?.User.Login ?? errorMessage,
+
871  BodyAtMerge = pr?.Body ?? errorMessage ?? String.Empty,
+
872  MergedAt = DateTimeOffset.Now,
+
873  TitleAtMerge = pr?.Title ?? errorMessage ?? String.Empty,
+
874  Comment = I.Comment,
+
875  Number = I.Number,
+
876  PullRequestRevision = I.PullRequestRevision,
+
877  Url = pr?.HtmlUrl ?? errorMessage
+
878  };
+
879 
+
880  await UpdateRevInfo(tm).ConfigureAwait(false);
+
881  }
+
882  }
+
883  }
+
884 
+
885  var currentHead = repo.Head;
+
886  if (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))
+
887  {
+
888  await repo.Sychronize(currentModel.AccessUser, currentModel.AccessToken, currentModel.CommitterName, currentModel.CommitterEmail, NextProgressReporter(), false, ct).ConfigureAwait(false);
+
889  await UpdateRevInfo().ConfigureAwait(false);
+
890  }
+
891 
+
892  return null;
+
893  }
+
894  catch
+
895  {
+
896  doneSteps = 0;
+
897  numSteps = 2;
+
898 
+
899  // Forget what we've done and abort
+
900  // DCTx2: Cancellation token is for job, operations should always run
+
901  await repo.CheckoutObject(startReference ?? startSha, NextProgressReporter(), default).ConfigureAwait(false);
+
902  if (startReference != null && repo.Head != startSha)
+
903  await repo.ResetToSha(startSha, NextProgressReporter(), default).ConfigureAwait(false);
+
904  else
+
905  progressReporter(100);
+
906  throw;
+
907  }
+
908  }
+
909 
+
910  var job = new Models.Job
+
911  {
+
912  Description = description,
+
913  StartedBy = AuthenticationContext.User,
+
914  Instance = Instance,
+
915  CancelRightsType = RightsType.Repository,
+
916  CancelRight = (ulong)RepositoryRights.CancelPendingChanges,
+
917  };
+
918 
+
919  // Time to access git, do it in a job
+
920  await jobManager.RegisterOperation(
+
921  job,
+
922  (core, databaseContextFactory, paramJob, progressReporter, ct) =>
+
923  UpdateCallbackThatDesperatelyNeedsRefactoring(
+
924  core,
+
925  databaseContextFactory,
+
926  progressReporter,
+
927  ct),
+
928  cancellationToken)
+
929  .ConfigureAwait(false);
+
930 
+
931  api.ActiveJob = job.ToApi();
+
932  return Accepted(api);
+
933  }

References Tgstation.Server.Host.Core.IGitHubClientFactory.CreateClient(), Tgstation.Server.Host.Controllers.RepositoryController.generalConfiguration, Tgstation.Server.Host.Security.AuthenticationContext.GetRight(), Tgstation.Server.Host.Configuration.GeneralConfiguration.GitHubAccessToken, Tgstation.Server.Host.Controllers.RepositoryController.gitHubClientFactory, Tgstation.Server.Host.Controllers.ApiController.Gone(), Tgstation.Server.Api.Models.EntityId.Id, Tgstation.Server.Api.Models.Internal.User.Id, Tgstation.Server.Host.Controllers.ApiController.Instance, Tgstation.Server.Host.Controllers.RepositoryController.jobManager, Tgstation.Server.Host.Controllers.RepositoryController.LoadRevisionInformation(), Tgstation.Server.Host.Controllers.ApiController.Logger, Tgstation.Server.Api.Models.Internal.User.Name, Tgstation.Server.Host.Controllers.RepositoryController.PopulateApi(), Tgstation.Server.Host.Jobs.IJobManager.RegisterOperation(), Tgstation.Server.Host.Components.IInstanceCore.RepositoryManager, Tgstation.Server.Host.Database.DatabaseContext.RepositorySettings, Tgstation.Server.Host.Database.DatabaseContext.Save(), Tgstation.Server.Host.Database.IDatabaseContextFactory.UseContext(), Tgstation.Server.Host.Security.AuthenticationContext.User, and Tgstation.Server.Host.Controllers.InstanceRequiredController.WithComponentInstance().