2using System.Collections.Generic;
3using System.Globalization;
7using System.Threading.Tasks;
10using LibGit2Sharp.Handlers;
12using Microsoft.Extensions.Logging;
25#pragma warning disable CA1506
41 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.";
152 ILogger<Repository>
logger,
158 this.commands =
commands ??
throw new ArgumentNullException(nameof(
commands));
163 ArgumentNullException.ThrowIfNull(gitRemoteFeaturesFactory);
166 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
173#pragma warning disable CA1506
176 string committerName,
177 string committerEmail,
180 bool updateSubmodules,
182 CancellationToken cancellationToken)
184 ArgumentNullException.ThrowIfNull(testMergeParameters);
185 ArgumentNullException.ThrowIfNull(committerName);
186 ArgumentNullException.ThrowIfNull(committerEmail);
187 ArgumentNullException.ThrowIfNull(progressReporter);
190 "Begin AddTestMerge: #{prNumber} at {targetSha} ({comment}) by <{committerName} ({committerEmail})>",
191 testMergeParameters.
Number,
198 throw new InvalidOperationException(
"Cannot test merge with an Unknown RemoteGitProvider!");
200 var commitMessage = String.Format(
201 CultureInfo.InvariantCulture,
202 "TGS Test Merge (#{0}){1}{2}",
203 testMergeParameters.
Number,
204 testMergeParameters.
Comment !=
null
205 ? Environment.NewLine
207 testMergeParameters.Comment ?? String.Empty);
209 var testMergeBranchName = String.Format(CultureInfo.InvariantCulture,
"tm-{0}", testMergeParameters.
Number);
213 var refSpecList =
new List<string> { refSpec };
214 var logMessage = String.Format(CultureInfo.InvariantCulture,
"Test merge #{0}", testMergeParameters.
Number);
218 MergeResult? result =
null;
220 var progressFactor = 1.0 / (updateSubmodules ? 3 : 2);
222 var sig =
new Signature(
new Identity(committerName, committerEmail), DateTimeOffset.UtcNow);
223 List<string>? conflictedPaths =
null;
224 await Task.Factory.StartNew(
231 logger.LogTrace(
"Fetching refspec {refSpec}...", refSpec);
233 var remote =
libGitRepo.Network.Remotes.First();
234 using var fetchReporter = progressReporter.
CreateSection($
"Fetch {refSpec}", progressFactor);
239 new FetchOptions().Hydrate(
246 catch (UserCancelledException ex)
248 logger.LogTrace(ex,
"Suppressing fetch cancel exception");
250 catch (LibGit2SharpException ex)
255 cancellationToken.ThrowIfCancellationRequested();
259 cancellationToken.ThrowIfCancellationRequested();
261 var objectName = testMergeParameters.TargetCommitSha ?? localBranchName;
262 var gitObject =
libGitRepo.Lookup(objectName) ??
throw new JobException($
"Could not find object to merge: {objectName}");
264 testMergeParameters.TargetCommitSha = gitObject.Sha;
266 cancellationToken.ThrowIfCancellationRequested();
270 using var mergeReporter = progressReporter.
CreateSection($
"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor);
273 CommitOnSuccess = commitMessage == null,
274 FailOnConflict = false,
275 FastForwardStrategy = FastForwardStrategy.NoFastForward,
277 OnCheckoutProgress = CheckoutProgressHandler(mergeReporter),
285 cancellationToken.ThrowIfCancellationRequested();
287 if (result.Status == MergeStatus.Conflicts)
290 conflictedPaths =
new List<string>();
291 foreach (var file
in repoStatus)
292 if (file.State == FileStatus.Conflicted)
293 conflictedPaths.Add(file.FilePath);
295 var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha;
296 logger.LogDebug(
"Merge conflict, aborting and reverting to {revertTarget}", revertTo);
298 using var revertReporter = progressReporter.
CreateSection(
"Hard Reset to {revertTo}", 1.0);
299 RawCheckout(revertTo,
false, revertReporter, cancellationToken);
300 cancellationToken.ThrowIfCancellationRequested();
307 TaskScheduler.Current);
309 if (result!.Status == MergeStatus.Conflicts)
311 var arguments =
new List<string>
313 originalCommit.Tip.Sha,
319 arguments.AddRange(conflictedPaths!);
329 ConflictingFiles = conflictedPaths,
333 if (result.Status != MergeStatus.UpToDate)
335 logger.LogTrace(
"Committing merge: \"{commitMessage}\"...", commitMessage);
336 await Task.Factory.StartNew(
337 () =>
libGitRepo.Commit(commitMessage, sig, sig,
new CommitOptions
339 PrettifyMessage =
true,
343 TaskScheduler.Current);
345 if (updateSubmodules)
347 using var progressReporter2 = progressReporter.
CreateSection(
"Update Submodules", progressFactor);
361 testMergeParameters.Number.ToString(CultureInfo.InvariantCulture),
362 testMergeParameters.TargetCommitSha!,
363 testMergeParameters.Comment,
373#pragma warning restore CA1506
380 bool updateSubmodules,
381 bool moveCurrentReference,
383 CancellationToken cancellationToken)
385 ArgumentNullException.ThrowIfNull(committish);
387 logger.LogDebug(
"Checkout object: {committish}...", committish);
389 await Task.Factory.StartNew(
393 using var progressReporter3 = progressReporter.
CreateSection(
null, updateSubmodules ? 2.0 / 3 : 1.0);
396 moveCurrentReference,
402 TaskScheduler.Current);
404 if (updateSubmodules)
406 using var progressReporter2 = progressReporter.
CreateSection(
null, 1.0 / 3);
421 bool deploymentPipeline,
422 CancellationToken cancellationToken)
424 logger.LogDebug(
"Fetch origin...");
426 await Task.Factory.StartNew(
429 var remote =
libGitRepo.Network.Remotes.First();
432 using var subReporter = progressReporter.
CreateSection(
"Fetch Origin", 1.0);
433 var fetchOptions =
new FetchOptions
436 TagFetchMode = TagFetchMode.All,
447 .Select(x => x.Specification),
450 "Fetch origin commits");
452 catch (UserCancelledException)
454 cancellationToken.ThrowIfCancellationRequested();
456 catch (LibGit2SharpException ex)
463 TaskScheduler.Current);
471 bool updateSubmodules,
472 bool deploymentPipeline,
473 CancellationToken cancellationToken)
475 ArgumentNullException.ThrowIfNull(progressReporter);
478 logger.LogTrace(
"Reset to origin...");
480 await
eventConsumer.
HandleEvent(
EventType.RepoResetOrigin,
new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, deploymentPipeline, cancellationToken);
482 using (var progressReporter2 = progressReporter.
CreateSection(
null, updateSubmodules ? 2.0 / 3 : 1.0))
484 trackedBranch.Tip.Sha,
488 if (updateSubmodules)
490 using var progressReporter3 = progressReporter.
CreateSection(
null, 1.0 / 3);
504 ArgumentNullException.ThrowIfNull(sha);
505 ArgumentNullException.ThrowIfNull(progressReporter);
507 logger.LogDebug(
"Reset to sha: {sha}", sha[..7]);
510 cancellationToken.ThrowIfCancellationRequested();
512 var gitObject =
libGitRepo.Lookup(sha, ObjectType.Commit);
513 cancellationToken.ThrowIfCancellationRequested();
515 if (gitObject ==
null)
516 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Cannot reset to non-existent SHA: {0}", sha));
518 libGitRepo.Reset(ResetMode.Hard, gitObject.Peel<Commit>(),
new CheckoutOptions
520 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($
"Reset to {gitObject.Sha}", 1.0)),
525 TaskScheduler.Current);
528 public async ValueTask
CopyTo(
string path, CancellationToken cancellationToken)
530 ArgumentNullException.ThrowIfNull(path);
531 logger.LogTrace(
"Copying to {path}...", path);
533 new List<string> {
".git" },
539 return ValueTask.CompletedTask;
548 public Task<string>
GetOriginSha(CancellationToken cancellationToken) => Task.Factory.StartNew(
554 cancellationToken.ThrowIfCancellationRequested();
560 TaskScheduler.Current);
565 string committerName,
566 string committerEmail,
567 bool deploymentPipeline,
568 CancellationToken cancellationToken)
570 ArgumentNullException.ThrowIfNull(progressReporter);
572 MergeResult? result =
null;
573 Branch? trackedBranch =
null;
576 var oldTip = oldHead.Tip;
578 await Task.Factory.StartNew(
586 cancellationToken.ThrowIfCancellationRequested();
590 "Merge origin/{trackedBranch}: <{committerName} ({committerEmail})>",
591 trackedBranch.FriendlyName,
594 result =
libGitRepo.Merge(trackedBranch,
new Signature(committerName, committerEmail, DateTimeOffset.UtcNow),
new MergeOptions
596 CommitOnSuccess = true,
597 FailOnConflict = true,
598 FastForwardStrategy = FastForwardStrategy.Default,
600 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection(
"Merge Origin", 1.0)),
603 cancellationToken.ThrowIfCancellationRequested();
605 if (result.Status == MergeStatus.Conflicts)
607 logger.LogDebug(
"Merge conflict, aborting and reverting to {oldHeadFriendlyName}", oldHead.FriendlyName);
609 libGitRepo.Reset(ResetMode.Hard, oldTip,
new CheckoutOptions
611 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($
"Hard Reset to {oldHead.FriendlyName}", 1.0)),
613 cancellationToken.ThrowIfCancellationRequested();
620 TaskScheduler.Current);
622 if (result!.Status == MergeStatus.Conflicts)
629 trackedBranch!.Tip.Sha,
631 trackedBranch.FriendlyName,
638 return result.Status == MergeStatus.FastForward;
646 string committerName,
647 string committerEmail,
648 bool synchronizeTrackedBranch,
649 bool deploymentPipeline,
650 CancellationToken cancellationToken)
652 ArgumentNullException.ThrowIfNull(committerName);
653 ArgumentNullException.ThrowIfNull(committerEmail);
654 ArgumentNullException.ThrowIfNull(progressReporter);
656 if (username ==
null && password ==
null)
658 logger.LogTrace(
"Not synchronizing due to lack of credentials!");
662 logger.LogTrace(
"Begin Synchronize...");
664 ArgumentNullException.ThrowIfNull(username);
665 ArgumentNullException.ThrowIfNull(password);
667 var startHead = Head;
669 logger.LogTrace(
"Configuring <{committerName} ({committerEmail})> as author/committer", committerName, committerEmail);
670 await Task.Factory.StartNew(
673 libGitRepo.Config.Set(
"user.name", committerName);
674 cancellationToken.ThrowIfCancellationRequested();
675 libGitRepo.Config.Set(
"user.email", committerEmail);
679 TaskScheduler.Current);
681 cancellationToken.ThrowIfCancellationRequested();
684 await eventConsumer.HandleEvent(
688 ioManager.ResolvePath(),
695 logger.LogTrace(
"Resetting and cleaning untracked files...");
696 await Task.Factory.StartNew(
699 using var resetProgress = progressReporter.
CreateSection(
"Hard reset and remove untracked files", 0.1);
700 libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip,
new CheckoutOptions
702 OnCheckoutProgress = CheckoutProgressHandler(resetProgress),
704 cancellationToken.ThrowIfCancellationRequested();
705 libGitRepo.RemoveUntrackedFiles();
709 TaskScheduler.Current);
712 var remainingProgressFactor = 0.9;
713 if (!synchronizeTrackedBranch)
715 using var progressReporter2 = progressReporter.
CreateSection(
"Push to temporary branch", remainingProgressFactor);
716 await PushHeadToTemporaryBranch(
724 var sameHead = Head == startHead;
725 if (sameHead || !Tracking)
727 logger.LogTrace(
"Aborted synchronize due to {abortReason}!", sameHead ?
"lack of changes" :
"not being on tracked reference");
731 logger.LogInformation(
"Synchronizing with origin...");
733 return await Task.Factory.StartNew(
736 var remote = libGitRepo.Network.Remotes.First();
739 using var pushReporter = progressReporter.
CreateSection(
"Push to origin", remainingProgressFactor);
740 var (pushOptions, progressReporters) = GeneratePushOptions(
747 libGitRepo.Network.Push(
753 foreach (var progressReporter
in progressReporters)
754 progressReporter.Dispose();
759 catch (NonFastForwardException)
761 logger.LogInformation(
"Synchronize aborted, non-fast forward!");
764 catch (UserCancelledException e)
766 cancellationToken.ThrowIfCancellationRequested();
767 throw new InvalidOperationException(
"Caught UserCancelledException without cancellationToken triggering", e);
769 catch (LibGit2SharpException e)
771 logger.LogWarning(e,
"Unable to make synchronization push!");
777 TaskScheduler.Current);
781 public Task<bool>
IsSha(
string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
785 var gitObject = libGitRepo.Lookup(committish, ObjectType.Tag);
786 if (gitObject !=
null)
788 cancellationToken.ThrowIfCancellationRequested();
791 if (libGitRepo.Branches[committish] !=
null)
793 cancellationToken.ThrowIfCancellationRequested();
796 if (libGitRepo.Lookup<Commit>(committish) !=
null)
802 TaskScheduler.Current);
805 public Task<bool>
CommittishIsParent(
string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
808 var targetObject = libGitRepo.Lookup(committish);
809 if (targetObject ==
null)
811 logger.LogTrace(
"Committish {committish} not found in repository", committish);
815 if (targetObject is not Commit targetCommit)
817 if (targetObject is not TagAnnotation)
819 logger.LogTrace(
"Committish {committish} is a {type} and does not point to a commit!", committish, targetObject.GetType().Name);
823 targetCommit = targetObject.Peel<Commit>();
824 if (targetCommit ==
null)
827 "TagAnnotation {committish} was found but the commit associated with it could not be found in repository!",
833 cancellationToken.ThrowIfCancellationRequested();
835 logger.LogTrace(
"Testing if {committish} is a parent of {startSha}...", committish, startSha);
836 MergeResult mergeResult;
839 mergeResult = libGitRepo.Merge(
842 DefaultCommitterName,
843 DefaultCommitterEmail,
844 DateTimeOffset.UtcNow),
847 FastForwardStrategy = FastForwardStrategy.FastForwardOnly,
848 FailOnConflict =
true,
851 catch (NonFastForwardException ex)
853 logger.LogTrace(ex,
"{committish} is not a parent of {startSha}", committish, startSha);
857 if (mergeResult.Status == MergeStatus.UpToDate)
860 logger.LogTrace(
"{committish} is not a parent of {startSha} ({mergeStatus}). Moving back...", committish, startSha, mergeResult.Status);
865 CheckoutModifiers = CheckoutModifiers.Force,
873 TaskScheduler.Current);
879 CancellationToken cancellationToken) => gitRemoteFeatures.GetTestMerge(
885 public Task<DateTimeOffset>
TimestampCommit(
string sha, CancellationToken cancellationToken) => Task.Factory.StartNew(
888 ArgumentNullException.ThrowIfNull(sha);
890 var commit = libGitRepo.Lookup<Commit>(sha) ??
throw new JobException($
"Commit {sha} does not exist in the repository!");
891 return commit.Committer.When.ToUniversalTime();
895 TaskScheduler.Current);
900 logger.LogTrace(
"Disposing...");
901 libGitRepo.Dispose();
914 logger.LogTrace(
"Checkout: {committish}", committish);
916 var checkoutOptions =
new CheckoutOptions
918 CheckoutModifiers = CheckoutModifiers.Force,
921 var stage = $
"Checkout {committish}";
922 using var newProgressReporter = progressReporter.
CreateSection(stage, 1.0);
924 checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(newProgressReporter);
926 cancellationToken.ThrowIfCancellationRequested();
928 if (moveCurrentReference)
930 if (Reference == NoReference)
931 throw new InvalidOperationException(
"Cannot move current reference when not on reference!");
933 var gitObject = libGitRepo.Lookup(committish);
934 if (gitObject ==
null)
935 throw new JobException($
"Could not find committish: {committish}");
937 var commit = gitObject.Peel<Commit>();
939 cancellationToken.ThrowIfCancellationRequested();
941 libGitRepo.Reset(ResetMode.Hard, commit, checkoutOptions);
945 void RunCheckout() => commands.Checkout(
954 catch (NotFoundException)
957 var remoteName = $
"origin/{committish}";
958 var remoteBranch = libGitRepo.Branches.FirstOrDefault(
959 branch => branch.FriendlyName.Equals(remoteName, StringComparison.Ordinal));
960 cancellationToken.ThrowIfCancellationRequested();
962 if (remoteBranch ==
default)
965 logger.LogDebug(
"Creating local branch for {remoteBranchFriendlyName}...", remoteBranch.FriendlyName);
966 var branch = libGitRepo.CreateBranch(committish, remoteBranch.Tip);
968 libGitRepo.Branches.Update(branch, branchUpdate => branchUpdate.TrackedBranch = remoteBranch.CanonicalName);
970 cancellationToken.ThrowIfCancellationRequested();
976 cancellationToken.ThrowIfCancellationRequested();
978 libGitRepo.RemoveUntrackedFiles();
992 logger.LogInformation(
"Pushing changes to temporary remote branch...");
993 var branch = libGitRepo.CreateBranch(RemoteTemporaryBranchName);
996 cancellationToken.ThrowIfCancellationRequested();
997 var remote = libGitRepo.Network.Remotes.First();
1000 var forcePushString = String.Format(CultureInfo.InvariantCulture,
"+{0}:{0}", branch.CanonicalName);
1002 using (var mainPushReporter = progressReporter.CreateSection(
null, 0.9))
1004 var (pushOptions, progressReporters) = GeneratePushOptions(
1012 libGitRepo.Network.Push(remote, forcePushString, pushOptions);
1016 foreach (var progressReporter
in progressReporters)
1017 progressReporter.Dispose();
1021 var removalString = String.Format(CultureInfo.InvariantCulture,
":{0}", branch.CanonicalName);
1022 using var forcePushReporter = progressReporter.CreateSection(
null, 0.1);
1023 var (forcePushOptions, forcePushReporters) = GeneratePushOptions(forcePushReporter, username, password, cancellationToken);
1026 libGitRepo.Network.Push(remote, removalString, forcePushOptions);
1030 foreach (var subForcePushReporter
in forcePushReporters)
1031 forcePushReporter.Dispose();
1034 catch (UserCancelledException)
1036 cancellationToken.ThrowIfCancellationRequested();
1038 catch (LibGit2SharpException e)
1040 logger.LogWarning(e,
"Unable to push to temporary branch!");
1045 libGitRepo.Branches.Remove(branch);
1050 TaskScheduler.Current);
1060 (PushOptions PushOptions, IEnumerable<JobProgressReporter> SubProgressReporters)
GeneratePushOptions(
JobProgressReporter progressReporter,
string username,
string password, CancellationToken cancellationToken)
1062 var packFileCountingReporter = progressReporter.
CreateSection(
null, 0.25);
1063 var packFileDeltafyingReporter = progressReporter.
CreateSection(
null, 0.25);
1064 var transferProgressReporter = progressReporter.
CreateSection(
null, 0.5);
1067 PushOptions:
new PushOptions
1069 OnPackBuilderProgress = (stage, current, total) =>
1071 if (total < current)
1074 var percentage = ((double)current) / total;
1075 (stage == PackBuilderStage.Counting ? packFileCountingReporter : packFileDeltafyingReporter).ReportProgress(percentage);
1076 return !cancellationToken.IsCancellationRequested;
1078 OnNegotiationCompletedBeforePush = (a) => !cancellationToken.IsCancellationRequested,
1079 OnPushTransferProgress = (a, sentBytes, totalBytes) =>
1081 packFileCountingReporter.ReportProgress((
double)sentBytes / totalBytes);
1082 return !cancellationToken.IsCancellationRequested;
1084 CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
1086 SubProgressReporters:
new List<JobProgressReporter>
1088 packFileCountingReporter,
1089 packFileDeltafyingReporter,
1090 transferProgressReporter,
1099 => ioManager.GetDirectoryName(libGitRepo
1102 .TrimEnd(Path.DirectorySeparatorChar)
1103 .TrimEnd(Path.AltDirectorySeparatorChar));
1118 bool deploymentPipeline,
1119 CancellationToken cancellationToken)
1121 logger.LogTrace(
"Updating submodules {withOrWithout} credentials...", username ==
null ?
"without" :
"with");
1123 async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository,
JobProgressReporter currentProgressReporter,
string parentGitDirectory)
1125 var submoduleCount = libGitRepo.Submodules.Count();
1126 if (submoduleCount == 0)
1128 logger.LogTrace(
"No submodules, skipping update");
1132 var factor = 1.0 / submoduleCount / 3;
1133 foreach (var submodule
in parentRepository.Submodules)
1135 logger.LogTrace(
"Entering submodule {name} ({path}) for recursive updates...", submodule.Name, submodule.Path);
1136 var submoduleUpdateOptions =
new SubmoduleUpdateOptions
1139 OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested,
1142 using var fetchReporter = currentProgressReporter.
CreateSection($
"Fetch submodule {submodule.Name}", factor);
1144 submoduleUpdateOptions.FetchOptions.Hydrate(
1147 credentialsProvider.GenerateCredentialsHandler(username, password),
1150 using var checkoutReporter = currentProgressReporter.
CreateSection($
"Checkout submodule {submodule.Name}", factor);
1151 submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(checkoutReporter);
1153 logger.LogDebug(
"Updating submodule {submoduleName}...", submodule.Name);
1154 Task RawSubModuleUpdate() => Task.Factory.StartNew(
1155 () => parentRepository.Submodules.Update(submodule.Name, submoduleUpdateOptions),
1158 TaskScheduler.Current);
1162 await RawSubModuleUpdate();
1164 catch (LibGit2SharpException ex) when (parentRepository == libGitRepo)
1169 credentialsProvider.CheckBadCredentialsException(ex);
1170 logger.LogWarning(ex,
"Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name);
1173 ioManager.DeleteDirectory($
".git/modules/{submodule.Path}", cancellationToken),
1174 ioManager.DeleteDirectory(submodule.Path, cancellationToken));
1176 logger.LogTrace(
"Second update attempt for submodule {submoduleName}...", submodule.Name);
1179 await RawSubModuleUpdate();
1181 catch (UserCancelledException)
1183 cancellationToken.ThrowIfCancellationRequested();
1185 catch (LibGit2SharpException ex2)
1187 credentialsProvider.CheckBadCredentialsException(ex2);
1188 logger.LogTrace(ex2,
"Retried update of submodule {submoduleName} failed!", submodule.Name);
1189 throw new AggregateException(ex, ex2);
1193 await eventConsumer.HandleEvent(
1195 new List<string> { submodule.Name },
1199 var submodulePath = ioManager.ResolvePath(
1200 ioManager.ConcatPath(
1204 using var submoduleRepo = await submoduleFactory.CreateFromPath(
1208 using var submoduleReporter = currentProgressReporter.
CreateSection($
"Entering submodule \"{submodule.Name}\"...", factor);
1209 await RecursiveUpdateSubmodules(
1216 return RecursiveUpdateSubmodules(libGitRepo, progressReporter, GetRepositoryPath());
1229 if (completedSteps == 0)
1231 else if (totalSteps < completedSteps || totalSteps == 0)
1235 percentage = ((double)completedSteps) / totalSteps;
1240 if (percentage ==
null)
1242 "Bad checkout progress values (Please tell Dominion)! Completeds: {completed}, Total: {total}",
1249#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.