2using System.Collections.Generic;
3using System.Globalization;
6using System.Threading.Tasks;
9using LibGit2Sharp.Handlers;
11using Microsoft.Extensions.Logging;
24#pragma warning disable CA1506
40 public const string OriginTrackingErrorTemplate =
"Unable to determine most recent origin commit of {sha}. Marking it as an origin commit. This may result in invalid git metadata until the next hard reset to an origin reference.";
151 ILogger<Repository>
logger,
157 this.commands =
commands ??
throw new ArgumentNullException(nameof(
commands));
162 ArgumentNullException.ThrowIfNull(gitRemoteFeaturesFactory);
165 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
172#pragma warning disable CA1506
175 string committerName,
176 string committerEmail,
179 bool updateSubmodules,
181 CancellationToken cancellationToken)
183 ArgumentNullException.ThrowIfNull(testMergeParameters);
184 ArgumentNullException.ThrowIfNull(committerName);
185 ArgumentNullException.ThrowIfNull(committerEmail);
186 ArgumentNullException.ThrowIfNull(progressReporter);
189 "Begin AddTestMerge: #{prNumber} at {targetSha} ({comment}) by <{committerName} ({committerEmail})>",
190 testMergeParameters.
Number,
197 throw new InvalidOperationException(
"Cannot test merge with an Unknown RemoteGitProvider!");
199 var commitMessage = String.Format(
200 CultureInfo.InvariantCulture,
201 "TGS Test Merge (PR {0}){1}{2}",
202 testMergeParameters.
Number,
203 testMergeParameters.
Comment !=
null
204 ? Environment.NewLine
206 testMergeParameters.Comment ?? String.Empty);
208 var testMergeBranchName = String.Format(CultureInfo.InvariantCulture,
"tm-{0}", testMergeParameters.
Number);
212 var refSpecList =
new List<string> { refSpec };
213 var logMessage = String.Format(CultureInfo.InvariantCulture,
"Test merge #{0}", testMergeParameters.
Number);
217 MergeResult? result =
null;
219 var progressFactor = 1.0 / (updateSubmodules ? 3 : 2);
221 var sig =
new Signature(
new Identity(committerName, committerEmail), DateTimeOffset.UtcNow);
222 List<string>? conflictedPaths =
null;
223 await Task.Factory.StartNew(
230 logger.LogTrace(
"Fetching refspec {refSpec}...", refSpec);
232 var remote =
libGitRepo.Network.Remotes.First();
233 using var fetchReporter = progressReporter.
CreateSection($
"Fetch {refSpec}", progressFactor);
238 new FetchOptions().Hydrate(
245 catch (UserCancelledException ex)
247 logger.LogTrace(ex,
"Suppressing fetch cancel exception");
249 catch (LibGit2SharpException ex)
254 cancellationToken.ThrowIfCancellationRequested();
258 cancellationToken.ThrowIfCancellationRequested();
260 var objectName = testMergeParameters.TargetCommitSha ?? localBranchName;
261 var gitObject =
libGitRepo.Lookup(objectName) ??
throw new JobException($
"Could not find object to merge: {objectName}");
263 testMergeParameters.TargetCommitSha = gitObject.Sha;
265 cancellationToken.ThrowIfCancellationRequested();
269 using var mergeReporter = progressReporter.
CreateSection($
"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor);
272 CommitOnSuccess = commitMessage == null,
273 FailOnConflict = false,
274 FastForwardStrategy = FastForwardStrategy.NoFastForward,
276 OnCheckoutProgress = CheckoutProgressHandler(mergeReporter),
284 cancellationToken.ThrowIfCancellationRequested();
286 if (result.Status == MergeStatus.Conflicts)
289 conflictedPaths =
new List<string>();
290 foreach (var file
in repoStatus)
291 if (file.State == FileStatus.Conflicted)
292 conflictedPaths.Add(file.FilePath);
294 var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha;
295 logger.LogDebug(
"Merge conflict, aborting and reverting to {revertTarget}", revertTo);
297 using var revertReporter = progressReporter.
CreateSection(
"Hard Reset to {revertTo}", 1.0);
298 RawCheckout(revertTo,
false, revertReporter, cancellationToken);
299 cancellationToken.ThrowIfCancellationRequested();
306 TaskScheduler.Current);
308 if (result!.Status == MergeStatus.Conflicts)
310 var arguments =
new List<string>
312 originalCommit.Tip.Sha,
318 arguments.AddRange(conflictedPaths!);
328 ConflictingFiles = conflictedPaths,
332 if (result.Status != MergeStatus.UpToDate)
334 logger.LogTrace(
"Committing merge: \"{commitMessage}\"...", commitMessage);
335 await Task.Factory.StartNew(
336 () =>
libGitRepo.Commit(commitMessage, sig, sig,
new CommitOptions
338 PrettifyMessage =
true,
342 TaskScheduler.Current);
344 if (updateSubmodules)
346 using var progressReporter2 = progressReporter.
CreateSection(
"Update Submodules", progressFactor);
360 testMergeParameters.Number.ToString(CultureInfo.InvariantCulture),
361 testMergeParameters.TargetCommitSha!,
362 testMergeParameters.Comment,
372#pragma warning restore CA1506
379 bool updateSubmodules,
380 bool moveCurrentReference,
382 CancellationToken cancellationToken)
384 ArgumentNullException.ThrowIfNull(committish);
386 logger.LogDebug(
"Checkout object: {committish}...", committish);
388 await Task.Factory.StartNew(
392 using var progressReporter3 = progressReporter.
CreateSection(
null, updateSubmodules ? 2.0 / 3 : 1.0);
395 moveCurrentReference,
401 TaskScheduler.Current);
403 if (updateSubmodules)
405 using var progressReporter2 = progressReporter.
CreateSection(
null, 1.0 / 3);
420 bool deploymentPipeline,
421 CancellationToken cancellationToken)
423 logger.LogDebug(
"Fetch origin...");
425 await Task.Factory.StartNew(
428 var remote =
libGitRepo.Network.Remotes.First();
431 using var subReporter = progressReporter.
CreateSection(
"Fetch Origin", 1.0);
432 var fetchOptions =
new FetchOptions
435 TagFetchMode = TagFetchMode.All,
446 .Select(x => x.Specification),
449 "Fetch origin commits");
451 catch (UserCancelledException)
453 cancellationToken.ThrowIfCancellationRequested();
455 catch (LibGit2SharpException ex)
462 TaskScheduler.Current);
470 bool updateSubmodules,
471 bool deploymentPipeline,
472 CancellationToken cancellationToken)
474 ArgumentNullException.ThrowIfNull(progressReporter);
477 logger.LogTrace(
"Reset to origin...");
479 await
eventConsumer.
HandleEvent(
EventType.RepoResetOrigin,
new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, deploymentPipeline, cancellationToken);
481 using (var progressReporter2 = progressReporter.
CreateSection(
null, updateSubmodules ? 2.0 / 3 : 1.0))
483 trackedBranch.Tip.Sha,
487 if (updateSubmodules)
489 using var progressReporter3 = progressReporter.
CreateSection(
null, 1.0 / 3);
503 ArgumentNullException.ThrowIfNull(sha);
504 ArgumentNullException.ThrowIfNull(progressReporter);
506 logger.LogDebug(
"Reset to sha: {sha}", sha[..7]);
509 cancellationToken.ThrowIfCancellationRequested();
511 var gitObject =
libGitRepo.Lookup(sha, ObjectType.Commit);
512 cancellationToken.ThrowIfCancellationRequested();
514 if (gitObject ==
null)
515 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Cannot reset to non-existent SHA: {0}", sha));
517 libGitRepo.Reset(ResetMode.Hard, gitObject.Peel<Commit>(),
new CheckoutOptions
519 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($
"Reset to {gitObject.Sha}", 1.0)),
524 TaskScheduler.Current);
527 public async ValueTask
CopyTo(
string path, CancellationToken cancellationToken)
529 ArgumentNullException.ThrowIfNull(path);
530 logger.LogTrace(
"Copying to {path}...", path);
532 new List<string> {
".git" },
538 return ValueTask.CompletedTask;
547 public Task<string>
GetOriginSha(CancellationToken cancellationToken) => Task.Factory.StartNew(
553 cancellationToken.ThrowIfCancellationRequested();
559 TaskScheduler.Current);
564 string committerName,
565 string committerEmail,
566 bool deploymentPipeline,
567 CancellationToken cancellationToken)
569 ArgumentNullException.ThrowIfNull(progressReporter);
571 MergeResult? result =
null;
572 Branch? trackedBranch =
null;
575 var oldTip = oldHead.Tip;
577 await Task.Factory.StartNew(
585 cancellationToken.ThrowIfCancellationRequested();
589 "Merge origin/{trackedBranch}: <{committerName} ({committerEmail})>",
590 trackedBranch.FriendlyName,
593 result =
libGitRepo.Merge(trackedBranch,
new Signature(committerName, committerEmail, DateTimeOffset.UtcNow),
new MergeOptions
595 CommitOnSuccess = true,
596 FailOnConflict = true,
597 FastForwardStrategy = FastForwardStrategy.Default,
599 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection(
"Merge Origin", 1.0)),
602 cancellationToken.ThrowIfCancellationRequested();
604 if (result.Status == MergeStatus.Conflicts)
606 logger.LogDebug(
"Merge conflict, aborting and reverting to {oldHeadFriendlyName}", oldHead.FriendlyName);
608 libGitRepo.Reset(ResetMode.Hard, oldTip,
new CheckoutOptions
610 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($
"Hard Reset to {oldHead.FriendlyName}", 1.0)),
612 cancellationToken.ThrowIfCancellationRequested();
619 TaskScheduler.Current);
621 if (result!.Status == MergeStatus.Conflicts)
628 trackedBranch!.Tip.Sha,
630 trackedBranch.FriendlyName,
637 return result.Status == MergeStatus.FastForward;
645 string committerName,
646 string committerEmail,
647 bool synchronizeTrackedBranch,
648 bool deploymentPipeline,
649 CancellationToken cancellationToken)
651 ArgumentNullException.ThrowIfNull(committerName);
652 ArgumentNullException.ThrowIfNull(committerEmail);
653 ArgumentNullException.ThrowIfNull(progressReporter);
655 if (username ==
null && password ==
null)
657 logger.LogTrace(
"Not synchronizing due to lack of credentials!");
661 logger.LogTrace(
"Begin Synchronize...");
663 ArgumentNullException.ThrowIfNull(username);
664 ArgumentNullException.ThrowIfNull(password);
666 var startHead = Head;
668 logger.LogTrace(
"Configuring <{committerName} ({committerEmail})> as author/committer", committerName, committerEmail);
669 await Task.Factory.StartNew(
672 libGitRepo.Config.Set(
"user.name", committerName);
673 cancellationToken.ThrowIfCancellationRequested();
674 libGitRepo.Config.Set(
"user.email", committerEmail);
678 TaskScheduler.Current);
680 cancellationToken.ThrowIfCancellationRequested();
683 await eventConsumer.HandleEvent(
687 ioManager.ResolvePath(),
694 logger.LogTrace(
"Resetting and cleaning untracked files...");
695 await Task.Factory.StartNew(
698 using var resetProgress = progressReporter.
CreateSection(
"Hard reset and remove untracked files", 0.1);
699 libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip,
new CheckoutOptions
701 OnCheckoutProgress = CheckoutProgressHandler(resetProgress),
703 cancellationToken.ThrowIfCancellationRequested();
704 libGitRepo.RemoveUntrackedFiles();
708 TaskScheduler.Current);
711 var remainingProgressFactor = 0.9;
712 if (!synchronizeTrackedBranch)
714 using var progressReporter2 = progressReporter.
CreateSection(
"Push to temporary branch", remainingProgressFactor);
715 await PushHeadToTemporaryBranch(
723 var sameHead = Head == startHead;
724 if (sameHead || !Tracking)
726 logger.LogTrace(
"Aborted synchronize due to {abortReason}!", sameHead ?
"lack of changes" :
"not being on tracked reference");
730 logger.LogInformation(
"Synchronizing with origin...");
732 return await Task.Factory.StartNew(
735 var remote = libGitRepo.Network.Remotes.First();
738 using var pushReporter = progressReporter.
CreateSection(
"Push to origin", remainingProgressFactor);
739 var (pushOptions, progressReporters) = GeneratePushOptions(
746 libGitRepo.Network.Push(
752 foreach (var progressReporter
in progressReporters)
753 progressReporter.Dispose();
758 catch (NonFastForwardException)
760 logger.LogInformation(
"Synchronize aborted, non-fast forward!");
763 catch (UserCancelledException e)
765 cancellationToken.ThrowIfCancellationRequested();
766 throw new InvalidOperationException(
"Caught UserCancelledException without cancellationToken triggering", e);
768 catch (LibGit2SharpException e)
770 logger.LogWarning(e,
"Unable to make synchronization push!");
776 TaskScheduler.Current);
780 public Task<bool>
IsSha(
string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
784 var gitObject = libGitRepo.Lookup(committish, ObjectType.Tag);
785 if (gitObject !=
null)
787 cancellationToken.ThrowIfCancellationRequested();
790 if (libGitRepo.Branches[committish] !=
null)
792 cancellationToken.ThrowIfCancellationRequested();
795 if (libGitRepo.Lookup<Commit>(committish) !=
null)
801 TaskScheduler.Current);
804 public Task<bool>
CommittishIsParent(
string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
807 var targetObject = libGitRepo.Lookup(committish);
808 if (targetObject ==
null)
810 logger.LogTrace(
"Committish {committish} not found in repository", committish);
814 if (targetObject is not Commit targetCommit)
816 if (targetObject is not TagAnnotation)
818 logger.LogTrace(
"Committish {committish} is a {type} and does not point to a commit!", committish, targetObject.GetType().Name);
822 targetCommit = targetObject.Peel<Commit>();
823 if (targetCommit ==
null)
826 "TagAnnotation {committish} was found but the commit associated with it could not be found in repository!",
832 cancellationToken.ThrowIfCancellationRequested();
834 logger.LogTrace(
"Testing if {committish} is a parent of {startSha}...", committish, startSha);
835 MergeResult mergeResult;
838 mergeResult = libGitRepo.Merge(
841 DefaultCommitterName,
842 DefaultCommitterEmail,
843 DateTimeOffset.UtcNow),
846 FastForwardStrategy = FastForwardStrategy.FastForwardOnly,
847 FailOnConflict =
true,
850 catch (NonFastForwardException ex)
852 logger.LogTrace(ex,
"{committish} is not a parent of {startSha}", committish, startSha);
856 if (mergeResult.Status == MergeStatus.UpToDate)
859 logger.LogTrace(
"{committish} is not a parent of {startSha} ({mergeStatus}). Moving back...", committish, startSha, mergeResult.Status);
864 CheckoutModifiers = CheckoutModifiers.Force,
872 TaskScheduler.Current);
878 CancellationToken cancellationToken) => gitRemoteFeatures.GetTestMerge(
884 public Task<DateTimeOffset>
TimestampCommit(
string sha, CancellationToken cancellationToken) => Task.Factory.StartNew(
887 ArgumentNullException.ThrowIfNull(sha);
889 var commit = libGitRepo.Lookup<Commit>(sha) ??
throw new JobException($
"Commit {sha} does not exist in the repository!");
890 return commit.Committer.When.ToUniversalTime();
894 TaskScheduler.Current);
899 logger.LogTrace(
"Disposing...");
900 libGitRepo.Dispose();
913 logger.LogTrace(
"Checkout: {committish}", committish);
915 var checkoutOptions =
new CheckoutOptions
917 CheckoutModifiers = CheckoutModifiers.Force,
920 var stage = $
"Checkout {committish}";
921 using var newProgressReporter = progressReporter.
CreateSection(stage, 1.0);
923 checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(newProgressReporter);
925 cancellationToken.ThrowIfCancellationRequested();
927 if (moveCurrentReference)
929 if (Reference == NoReference)
930 throw new InvalidOperationException(
"Cannot move current reference when not on reference!");
932 var gitObject = libGitRepo.Lookup(committish);
933 if (gitObject ==
null)
934 throw new JobException($
"Could not find committish: {committish}");
936 var commit = gitObject.Peel<Commit>();
938 cancellationToken.ThrowIfCancellationRequested();
940 libGitRepo.Reset(ResetMode.Hard, commit, checkoutOptions);
944 void RunCheckout() => commands.Checkout(
953 catch (NotFoundException)
956 var remoteName = $
"origin/{committish}";
957 var remoteBranch = libGitRepo.Branches.FirstOrDefault(
958 branch => branch.FriendlyName.Equals(remoteName, StringComparison.Ordinal));
959 cancellationToken.ThrowIfCancellationRequested();
961 if (remoteBranch ==
default)
964 logger.LogDebug(
"Creating local branch for {remoteBranchFriendlyName}...", remoteBranch.FriendlyName);
965 var branch = libGitRepo.CreateBranch(committish, remoteBranch.Tip);
967 libGitRepo.Branches.Update(branch, branchUpdate => branchUpdate.TrackedBranch = remoteBranch.CanonicalName);
969 cancellationToken.ThrowIfCancellationRequested();
975 cancellationToken.ThrowIfCancellationRequested();
977 libGitRepo.RemoveUntrackedFiles();
991 logger.LogInformation(
"Pushing changes to temporary remote branch...");
992 var branch = libGitRepo.CreateBranch(RemoteTemporaryBranchName);
995 cancellationToken.ThrowIfCancellationRequested();
996 var remote = libGitRepo.Network.Remotes.First();
999 var forcePushString = String.Format(CultureInfo.InvariantCulture,
"+{0}:{0}", branch.CanonicalName);
1001 using (var mainPushReporter = progressReporter.CreateSection(
null, 0.9))
1003 var (pushOptions, progressReporters) = GeneratePushOptions(
1011 libGitRepo.Network.Push(remote, forcePushString, pushOptions);
1015 foreach (var progressReporter
in progressReporters)
1016 progressReporter.Dispose();
1020 var removalString = String.Format(CultureInfo.InvariantCulture,
":{0}", branch.CanonicalName);
1021 using var forcePushReporter = progressReporter.CreateSection(
null, 0.1);
1022 var (forcePushOptions, forcePushReporters) = GeneratePushOptions(forcePushReporter, username, password, cancellationToken);
1025 libGitRepo.Network.Push(remote, removalString, forcePushOptions);
1029 foreach (var subForcePushReporter
in forcePushReporters)
1030 forcePushReporter.Dispose();
1033 catch (UserCancelledException)
1035 cancellationToken.ThrowIfCancellationRequested();
1037 catch (LibGit2SharpException e)
1039 logger.LogWarning(e,
"Unable to push to temporary branch!");
1044 libGitRepo.Branches.Remove(branch);
1049 TaskScheduler.Current);
1059 (PushOptions PushOptions, IEnumerable<JobProgressReporter> SubProgressReporters)
GeneratePushOptions(
JobProgressReporter progressReporter,
string username,
string password, CancellationToken cancellationToken)
1061 var packFileCountingReporter = progressReporter.
CreateSection(
null, 0.25);
1062 var packFileDeltafyingReporter = progressReporter.
CreateSection(
null, 0.25);
1063 var transferProgressReporter = progressReporter.
CreateSection(
null, 0.5);
1066 PushOptions:
new PushOptions
1068 OnPackBuilderProgress = (stage, current, total) =>
1070 if (total < current)
1073 var percentage = ((double)current) / total;
1074 (stage == PackBuilderStage.Counting ? packFileCountingReporter : packFileDeltafyingReporter).ReportProgress(percentage);
1075 return !cancellationToken.IsCancellationRequested;
1077 OnNegotiationCompletedBeforePush = (a) => !cancellationToken.IsCancellationRequested,
1078 OnPushTransferProgress = (a, sentBytes, totalBytes) =>
1080 packFileCountingReporter.ReportProgress((
double)sentBytes / totalBytes);
1081 return !cancellationToken.IsCancellationRequested;
1083 CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
1085 SubProgressReporters:
new List<JobProgressReporter>
1087 packFileCountingReporter,
1088 packFileDeltafyingReporter,
1089 transferProgressReporter,
1098 => ioManager.GetDirectoryName(libGitRepo
1101 .TrimEnd(ioManager.DirectorySeparatorChar)
1102 .TrimEnd(ioManager.AltDirectorySeparatorChar));
1117 bool deploymentPipeline,
1118 CancellationToken cancellationToken)
1120 logger.LogTrace(
"Updating submodules {withOrWithout} credentials...", username ==
null ?
"without" :
"with");
1122 async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository,
JobProgressReporter currentProgressReporter,
string parentGitDirectory)
1124 var submoduleCount = libGitRepo.Submodules.Count();
1125 if (submoduleCount == 0)
1127 logger.LogTrace(
"No submodules, skipping update");
1131 var factor = 1.0 / submoduleCount / 3;
1132 foreach (var submodule
in parentRepository.Submodules)
1134 logger.LogTrace(
"Entering submodule {name} ({path}) for recursive updates...", submodule.Name, submodule.Path);
1135 var submoduleUpdateOptions =
new SubmoduleUpdateOptions
1138 OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested,
1141 using var fetchReporter = currentProgressReporter.
CreateSection($
"Fetch submodule {submodule.Name}", factor);
1143 submoduleUpdateOptions.FetchOptions.Hydrate(
1146 credentialsProvider.GenerateCredentialsHandler(username, password),
1149 using var checkoutReporter = currentProgressReporter.
CreateSection($
"Checkout submodule {submodule.Name}", factor);
1150 submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(checkoutReporter);
1152 logger.LogDebug(
"Updating submodule {submoduleName}...", submodule.Name);
1153 Task RawSubModuleUpdate() => Task.Factory.StartNew(
1154 () => parentRepository.Submodules.Update(submodule.Name, submoduleUpdateOptions),
1157 TaskScheduler.Current);
1161 await RawSubModuleUpdate();
1163 catch (LibGit2SharpException ex) when (parentRepository == libGitRepo)
1168 credentialsProvider.CheckBadCredentialsException(ex);
1169 logger.LogWarning(ex,
"Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name);
1172 ioManager.DeleteDirectory($
".git/modules/{submodule.Path}", cancellationToken),
1173 ioManager.DeleteDirectory(submodule.Path, cancellationToken));
1175 logger.LogTrace(
"Second update attempt for submodule {submoduleName}...", submodule.Name);
1178 await RawSubModuleUpdate();
1180 catch (UserCancelledException)
1182 cancellationToken.ThrowIfCancellationRequested();
1184 catch (LibGit2SharpException ex2)
1186 credentialsProvider.CheckBadCredentialsException(ex2);
1187 logger.LogTrace(ex2,
"Retried update of submodule {submoduleName} failed!", submodule.Name);
1188 throw new AggregateException(ex, ex2);
1192 await eventConsumer.HandleEvent(
1194 new List<string> { submodule.Name },
1198 var submodulePath = ioManager.ResolvePath(
1199 ioManager.ConcatPath(
1203 using var submoduleRepo = await submoduleFactory.CreateFromPath(
1207 using var submoduleReporter = currentProgressReporter.
CreateSection($
"Entering submodule \"{submodule.Name}\"...", factor);
1208 await RecursiveUpdateSubmodules(
1215 return RecursiveUpdateSubmodules(libGitRepo, progressReporter, GetRepositoryPath());
1228 if (completedSteps == 0)
1230 else if (totalSteps < completedSteps || totalSteps == 0)
1234 percentage = ((double)completedSteps) / totalSteps;
1239 if (percentage ==
null)
1241 "Bad checkout progress values (Please tell Dominion)! Completeds: {completed}, Total: {total}",
1248#pragma warning restore CA1506
Represents configurable settings for a git repository.
Parameters for creating a TestMerge.
virtual ? string TargetCommitSha
The sha of the test merge revision to merge. If not specified, the latest commit from the source will...
string? Comment
Optional comment about the test.
int Number
The number of the test merge source.
string Reference
The current reference the IRepository HEAD is using. This can be a branch or tag.
readonly ILibGit2Commands commands
The ILibGit2Commands for the Repository.
const string OriginTrackingErrorTemplate
Template error message for when tracking of the most recent origin commit fails.
Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Requires the current HEAD to be a reference. Hard resets the reference to the given sha....
const string DefaultCommitterEmail
The default password for committers.
async ValueTask FetchOrigin(JobProgressReporter progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Fetch commits from the origin repository.A ValueTask representing the running operation.
async ValueTask CopyTo(string path, CancellationToken cancellationToken)
Copies the current working directory to a given path .A ValueTask representing the running operation.
async ValueTask< TestMergeResult > AddTestMerge(TestMergeParameters testMergeParameters, string committerName, string committerEmail, string? username, string? password, bool updateSubmodules, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Attempt to merge the revision specified by a given set of testMergeParameters into HEAD....
string Head
The SHA of the IRepository HEAD.
string? RemoteRepositoryName
If RemoteGitProvider is not RemoteGitProvider.Unknown this will be set with the name of the repositor...
bool Tracking
If Reference tracks an upstream branch.
const string RemoteTemporaryBranchName
The branch name used for publishing testmerge commits.
async ValueTask< bool > Synchronize(JobProgressReporter progressReporter, string? username, string? password, string committerName, string committerEmail, bool synchronizeTrackedBranch, bool deploymentPipeline, CancellationToken cancellationToken)
Runs the synchronize event script and attempts to push any changes made to the IRepository if on a tr...
Uri Origin
The current origin remote the IRepository is using.
async ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Checks out a given committish .A ValueTask representing the running operation.
readonly LibGit2Sharp.IRepository libGitRepo
The LibGit2Sharp.IRepository for the Repository.
Task PushHeadToTemporaryBranch(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Force push the current repository HEAD to RemoteTemporaryBranchName;.
readonly IGitRemoteFeatures gitRemoteFeatures
The IGitRemoteFeatures for the Repository.
ValueTask UpdateSubmodules(JobProgressReporter progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Recusively update all Submodules in the libGitRepo.
readonly ILibGit2RepositoryFactory submoduleFactory
The ILibGit2RepositoryFactory used for updating submodules.
async ValueTask< bool?> MergeOrigin(JobProgressReporter progressReporter, string committerName, string committerEmail, bool deploymentPipeline, CancellationToken cancellationToken)
Requires the current HEAD to be a tracked reference. Merges the reference to what it tracks on the or...
readonly ILogger< Repository > logger
The ILogger for the Repository.
override void DisposeImpl()
Implementation of Dispose run after reentrancy check.
string? RemoteRepositoryOwner
If RemoteGitProvider is not RemoteGitProvider.Unknown this will be set with the owner of the reposito...
readonly IIOManager ioManager
The IIOManager for the Repository.
ValueTask< Models.TestMerge > GetTestMerge(TestMergeParameters parameters, RepositorySettings repositorySettings, CancellationToken cancellationToken)
Retrieve the Models.TestMerge representation of given test merge parameters .A ValueTask<TResult> res...
readonly IPostWriteHandler postWriteHandler
The IPostWriteHandler for the Repository.
const string DefaultCommitterName
The default username for committers.
const string UnknownReference
Used when a reference cannot be determined.
Task< string > GetOriginSha(CancellationToken cancellationToken)
Get the tracked reference's current SHA.A Task<TResult> resulting in the tracked origin reference's S...
Task< bool > IsSha(string committish, CancellationToken cancellationToken)
Checks if a given committish is a sha.A Task<TResult> resulting in true if committish is a sha,...
Task< bool > CommittishIsParent(string committish, CancellationToken cancellationToken)
Check if a given committish is a parent of the current Head.A Task<TResult> resulting in true if com...
Repository(LibGit2Sharp.IRepository libGitRepo, ILibGit2Commands commands, IIOManager ioManager, IEventConsumer eventConsumer, ICredentialsProvider credentialsProvider, IPostWriteHandler postWriteHandler, IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, ILibGit2RepositoryFactory submoduleFactory, ILogger< Repository > logger, GeneralConfiguration generalConfiguration, Action disposeAction)
Initializes a new instance of the Repository class.
string GetRepositoryPath()
Gets the path of libGitRepo.
readonly IEventConsumer eventConsumer
The IEventConsumer for the Repository.
const string NoReference
The value of Reference when not on a reference.
CheckoutProgressHandler CheckoutProgressHandler(JobProgressReporter progressReporter)
Converts a given progressReporter to a LibGit2Sharp.Handlers.CheckoutProgressHandler.
void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Runs a blocking force checkout to committish .
readonly ICredentialsProvider credentialsProvider
The ICredentialsProvider for the Repository.
Task< DateTimeOffset > TimestampCommit(string sha, CancellationToken cancellationToken)
Gets the DateTimeOffset a given sha was created on.A Task<TResult> resulting in the DateTimeOffset t...
async ValueTask ResetToOrigin(JobProgressReporter progressReporter, string? username, string? password, bool updateSubmodules, bool deploymentPipeline, CancellationToken cancellationToken)
Requires the current HEAD to be a tracked reference. Hard resets the reference to what it tracks on t...
PushOptions IEnumerable< JobProgressReporter > SubProgressReporters GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for the Repository.
Represents the result of a repository test merge attempt.
MergeStatus Status
The resulting MergeStatus.
General configuration options.
IIOManager that resolves paths to Environment.CurrentDirectory.
const TaskCreationOptions BlockingTaskCreationOptions
The TaskCreationOptions used to spawn Tasks for potentially long running, blocking operations.
Operation exceptions thrown from the context of a Models.Job.
Progress reporter for a Job.
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
void ReportProgress(double? progress)
Report progress.
Runs a given disposeAction on Dispose.
readonly Action disposeAction
The Action to run on Dispose.
Consumes EventTypes and takes the appropriate actions.
ValueTask HandleEvent(EventType eventType, IEnumerable< string?> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
Handle a given eventType .
For generating CredentialsHandlers.
CredentialsHandler GenerateCredentialsHandler(string? username, string? password)
Generate a CredentialsHandler from a given username and password .
void CheckBadCredentialsException(LibGit2SharpException exception)
Rethrow the authentication failure message as a JobException if it is one.
Factory for creating IGitRemoteFeatures.
IGitRemoteFeatures CreateGitRemoteFeatures(IRepository repository)
Create the IGitRemoteFeatures for a given repository .
Provides features for remote git services.
string TestMergeLocalBranchNameFormatter
Get.
string TestMergeRefSpecFormatter
Gets a formatter string which creates the remote refspec for fetching the HEAD of passed in test merg...
For low level interactions with a LibGit2Sharp.IRepository.
void Fetch(LibGit2Sharp.IRepository repository, IEnumerable< string > refSpecs, Remote remote, FetchOptions fetchOptions, string logMessage)
Runs a blocking fetch operation on a given repository .
Factory for creating LibGit2Sharp.IRepositorys.
Represents an on-disk git repository.
string Head
The SHA of the IRepository HEAD.
Interface for using filesystems.
string ResolvePath()
Retrieve the full path of the current working directory.
ValueTask CopyDirectory(IEnumerable< string >? ignore, Func< string, string, ValueTask >? postCopyCallback, string src, string dest, int? taskThrottle, CancellationToken cancellationToken)
Copies a directory from src to dest .
Handles changing file modes/permissions after writing.
void HandleWrite(string filePath)
For handling system specific necessities after a write.
bool NeedsPostWrite(string sourceFilePath)
Check if a given sourceFilePath will need HandleWrite(string) called on a copy of it.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
RemoteGitProvider
Indicates the remote git host.
EventType
Types of events. Mirror in tgs.dm. Prefer last listed name for script.