2using System.Collections.Generic;
3using System.Globalization;
6using System.Threading.Tasks;
9using LibGit2Sharp.Handlers;
11using Microsoft.Extensions.Logging;
12using Microsoft.Extensions.Options;
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.";
138 var packFileCountingReporter = progressReporter.
CreateSection(
null, 0.25);
139 var packFileDeltafyingReporter = progressReporter.
CreateSection(
null, 0.25);
140 var transferProgressReporter = progressReporter.
CreateSection(
null, 0.5);
145 OnPackBuilderProgress = (stage, current, total) =>
150 var percentage = ((double)current) / total;
151 (stage == PackBuilderStage.Counting ? packFileCountingReporter : packFileDeltafyingReporter).ReportProgress(percentage);
152 return !cancellationToken.IsCancellationRequested;
154 OnNegotiationCompletedBeforePush = (a) => !cancellationToken.IsCancellationRequested,
155 OnPushTransferProgress = (a, sentBytes, totalBytes) =>
157 packFileCountingReporter.ReportProgress((
double)sentBytes / totalBytes);
158 return !cancellationToken.IsCancellationRequested;
160 CredentialsProvider = credentialsHandler,
162 SubProgressReporters:
new List<JobProgressReporter>
164 packFileCountingReporter,
165 packFileDeltafyingReporter,
166 transferProgressReporter,
194 ILogger<Repository>
logger,
199 this.commands =
commands ??
throw new ArgumentNullException(nameof(
commands));
204 ArgumentNullException.ThrowIfNull(gitRemoteFeaturesFactory);
207 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
213#pragma warning disable CA1506
216 string committerName,
217 string committerEmail,
220 bool updateSubmodules,
222 CancellationToken cancellationToken)
224 ArgumentNullException.ThrowIfNull(testMergeParameters);
225 ArgumentNullException.ThrowIfNull(committerName);
226 ArgumentNullException.ThrowIfNull(committerEmail);
227 ArgumentNullException.ThrowIfNull(progressReporter);
230 "Begin AddTestMerge: #{prNumber} at {targetSha} ({comment}) by <{committerName} ({committerEmail})>",
231 testMergeParameters.
Number,
238 throw new InvalidOperationException(
"Cannot test merge with an Unknown RemoteGitProvider!");
240 var commitMessage = String.Format(
241 CultureInfo.InvariantCulture,
242 "TGS Test Merge (PR {0}){1}{2}",
243 testMergeParameters.
Number,
244 testMergeParameters.
Comment !=
null
245 ? Environment.NewLine
247 testMergeParameters.Comment ?? String.Empty);
249 var testMergeBranchName = String.Format(CultureInfo.InvariantCulture,
"tm-{0}", testMergeParameters.
Number);
253 var refSpecList =
new List<string> { refSpec };
254 var logMessage = String.Format(CultureInfo.InvariantCulture,
"Test merge #{0}", testMergeParameters.
Number);
258 MergeResult? result =
null;
260 var progressFactor = 1.0 / (updateSubmodules ? 3 : 2);
262 var sig =
new Signature(
new Identity(committerName, committerEmail), DateTimeOffset.UtcNow);
263 List<string>? conflictedPaths =
null;
266 await Task.Factory.StartNew(
273 logger.LogTrace(
"Fetching refspec {refSpec}...", refSpec);
275 var remote =
libGitRepo.Network.Remotes.First();
276 using var fetchReporter = progressReporter.
CreateSection($
"Fetch {refSpec}", progressFactor);
281 new FetchOptions().Hydrate(
288 catch (UserCancelledException ex)
290 logger.LogTrace(ex,
"Suppressing fetch cancel exception");
292 catch (LibGit2SharpException ex)
297 cancellationToken.ThrowIfCancellationRequested();
301 cancellationToken.ThrowIfCancellationRequested();
303 var objectName = testMergeParameters.TargetCommitSha ?? localBranchName;
304 var gitObject =
libGitRepo.Lookup(objectName) ??
throw new JobException($
"Could not find object to merge: {objectName}");
306 testMergeParameters.TargetCommitSha = gitObject.Sha;
308 cancellationToken.ThrowIfCancellationRequested();
312 using var mergeReporter = progressReporter.
CreateSection($
"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor);
315 CommitOnSuccess = commitMessage == null,
316 FailOnConflict = false,
317 FastForwardStrategy = FastForwardStrategy.NoFastForward,
319 OnCheckoutProgress = CheckoutProgressHandler(mergeReporter),
327 cancellationToken.ThrowIfCancellationRequested();
329 if (result.Status == MergeStatus.Conflicts)
332 conflictedPaths =
new List<string>();
333 foreach (var file
in repoStatus)
334 if (file.State == FileStatus.Conflicted)
335 conflictedPaths.Add(file.FilePath);
337 var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha;
338 logger.LogDebug(
"Merge conflict, aborting and reverting to {revertTarget}", revertTo);
340 using var revertReporter = progressReporter.
CreateSection(
"Hard Reset to {revertTo}", 1.0);
341 RawCheckout(revertTo,
false, revertReporter, cancellationToken);
342 cancellationToken.ThrowIfCancellationRequested();
349 TaskScheduler.Current);
351 if (result!.Status == MergeStatus.Conflicts)
353 var arguments =
new List<string>
355 originalCommit.Tip.Sha,
361 arguments.AddRange(conflictedPaths!);
372 ConflictingFiles = conflictedPaths,
376 if (result.Status != MergeStatus.UpToDate)
378 logger.LogTrace(
"Committing merge: \"{commitMessage}\"...", commitMessage);
379 await Task.Factory.StartNew(
380 () =>
libGitRepo.Commit(commitMessage, sig, sig,
new CommitOptions
382 PrettifyMessage =
true,
386 TaskScheduler.Current);
388 if (updateSubmodules)
390 using var progressReporter2 = progressReporter.
CreateSection(
"Update Submodules", progressFactor);
404 testMergeParameters.Number.ToString(CultureInfo.InvariantCulture),
405 testMergeParameters.TargetCommitSha!,
406 testMergeParameters.Comment,
417#pragma warning restore CA1506
424 bool updateSubmodules,
425 bool moveCurrentReference,
427 CancellationToken cancellationToken)
429 ArgumentNullException.ThrowIfNull(committish);
431 logger.LogDebug(
"Checkout object: {committish}...", committish);
433 await Task.Factory.StartNew(
437 using var progressReporter3 = progressReporter.
CreateSection(
null, updateSubmodules ? 2.0 / 3 : 1.0);
440 moveCurrentReference,
446 TaskScheduler.Current);
448 if (updateSubmodules)
450 using var progressReporter2 = progressReporter.
CreateSection(
null, 1.0 / 3);
465 bool deploymentPipeline,
466 CancellationToken cancellationToken)
468 logger.LogDebug(
"Fetch origin...");
470 var parameters =
new List<string>();
472 if (username !=
null)
474 parameters.Add(username);
475 if (password !=
null)
478 if (transformedPassword !=
null)
479 parameters.Add(transformedPassword);
484 var credentialsHandler = await credentialsHandlerTask;
485 await Task.Factory.StartNew(
488 var remote =
libGitRepo.Network.Remotes.First();
491 using var subReporter = progressReporter.
CreateSection(
"Fetch Origin", 1.0);
492 var fetchOptions =
new FetchOptions
495 TagFetchMode = TagFetchMode.All,
506 .Select(x => x.Specification),
509 "Fetch origin commits");
511 catch (UserCancelledException)
513 cancellationToken.ThrowIfCancellationRequested();
515 catch (LibGit2SharpException ex)
522 TaskScheduler.Current);
530 bool updateSubmodules,
531 bool deploymentPipeline,
532 CancellationToken cancellationToken)
534 ArgumentNullException.ThrowIfNull(progressReporter);
537 logger.LogTrace(
"Reset to origin...");
539 await
eventConsumer.
HandleEvent(
EventType.RepoResetOrigin,
new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha },
false, deploymentPipeline, cancellationToken);
541 using (var progressReporter2 = progressReporter.
CreateSection(
null, updateSubmodules ? 2.0 / 3 : 1.0))
543 trackedBranch.Tip.Sha,
547 if (updateSubmodules)
549 using var progressReporter3 = progressReporter.
CreateSection(
null, 1.0 / 3);
563 ArgumentNullException.ThrowIfNull(sha);
564 ArgumentNullException.ThrowIfNull(progressReporter);
566 logger.LogDebug(
"Reset to sha: {sha}", sha[..7]);
569 cancellationToken.ThrowIfCancellationRequested();
572 cancellationToken.ThrowIfCancellationRequested();
574 if (gitObject ==
null)
575 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Cannot reset to non-existent SHA: {0}", sha));
577 libGitRepo.Reset(ResetMode.Hard, gitObject.Peel<Commit>(),
new CheckoutOptions
579 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($
"Reset to {gitObject.Sha}", 1.0)),
584 TaskScheduler.Current);
587 public async ValueTask
CopyTo(
string path, CancellationToken cancellationToken)
589 ArgumentNullException.ThrowIfNull(path);
590 logger.LogTrace(
"Copying to {path}...", path);
592 new List<string> {
".git" },
598 return ValueTask.CompletedTask;
607 public Task<string>
GetOriginSha(CancellationToken cancellationToken) => Task.Factory.StartNew(
613 cancellationToken.ThrowIfCancellationRequested();
619 TaskScheduler.Current);
624 string committerName,
625 string committerEmail,
626 bool deploymentPipeline,
627 CancellationToken cancellationToken)
629 ArgumentNullException.ThrowIfNull(progressReporter);
631 MergeResult? result =
null;
632 Branch? trackedBranch =
null;
635 var oldTip = oldHead.Tip;
637 await Task.Factory.StartNew(
645 cancellationToken.ThrowIfCancellationRequested();
649 "Merge origin/{trackedBranch}: <{committerName} ({committerEmail})>",
650 trackedBranch.FriendlyName,
653 result =
libGitRepo.Merge(trackedBranch,
new Signature(committerName, committerEmail, DateTimeOffset.UtcNow),
new MergeOptions
655 CommitOnSuccess = true,
656 FailOnConflict = true,
657 FastForwardStrategy = FastForwardStrategy.Default,
659 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection(
"Merge Origin", 1.0)),
662 cancellationToken.ThrowIfCancellationRequested();
664 if (result.Status == MergeStatus.Conflicts)
666 logger.LogDebug(
"Merge conflict, aborting and reverting to {oldHeadFriendlyName}", oldHead.FriendlyName);
668 libGitRepo.Reset(ResetMode.Hard, oldTip,
new CheckoutOptions
670 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($
"Hard Reset to {oldHead.FriendlyName}", 1.0)),
672 cancellationToken.ThrowIfCancellationRequested();
679 TaskScheduler.Current);
681 if (result!.Status == MergeStatus.Conflicts)
688 trackedBranch!.Tip.Sha,
690 trackedBranch.FriendlyName,
698 return result.Status == MergeStatus.FastForward;
706 string committerName,
707 string committerEmail,
708 bool synchronizeTrackedBranch,
709 bool deploymentPipeline,
710 CancellationToken cancellationToken)
712 ArgumentNullException.ThrowIfNull(committerName);
713 ArgumentNullException.ThrowIfNull(committerEmail);
714 ArgumentNullException.ThrowIfNull(progressReporter);
716 if (username ==
null && password ==
null)
718 logger.LogTrace(
"Not synchronizing due to lack of credentials!");
722 logger.LogTrace(
"Begin Synchronize...");
724 ArgumentNullException.ThrowIfNull(username);
725 ArgumentNullException.ThrowIfNull(password);
727 var startHead = Head;
729 logger.LogTrace(
"Configuring <{committerName} ({committerEmail})> as author/committer", committerName, committerEmail);
730 await Task.Factory.StartNew(
733 libGitRepo.Config.Set(
"user.name", committerName);
734 cancellationToken.ThrowIfCancellationRequested();
735 libGitRepo.Config.Set(
"user.email", committerEmail);
739 TaskScheduler.Current);
741 cancellationToken.ThrowIfCancellationRequested();
744 await eventConsumer.HandleEvent(
748 ioManager.ResolvePath(),
756 logger.LogTrace(
"Resetting and cleaning untracked files...");
757 await Task.Factory.StartNew(
760 using var resetProgress = progressReporter.
CreateSection(
"Hard reset and remove untracked files", 0.1);
761 libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip,
new CheckoutOptions
763 OnCheckoutProgress = CheckoutProgressHandler(resetProgress),
765 cancellationToken.ThrowIfCancellationRequested();
766 libGitRepo.RemoveUntrackedFiles();
770 TaskScheduler.Current);
773 var remainingProgressFactor = 0.9;
774 if (!synchronizeTrackedBranch)
776 using var progressReporter2 = progressReporter.
CreateSection(
"Push to temporary branch", remainingProgressFactor);
777 var credentialsHandler = await GenerateCredentialsHandler(username, password, cancellationToken);
778 await PushHeadToTemporaryBranch(
785 var sameHead = Head == startHead;
786 if (sameHead || !Tracking)
788 logger.LogTrace(
"Aborted synchronize due to {abortReason}!", sameHead ?
"lack of changes" :
"not being on tracked reference");
792 logger.LogInformation(
"Synchronizing with origin...");
793 using var pushReporter = progressReporter.
CreateSection(
"Push to origin", remainingProgressFactor);
794 var (pushOptions, progressReporters) = await GeneratePushOptions(
800 return await Task.Factory.StartNew(
803 var remote = libGitRepo.Network.Remotes.First();
808 libGitRepo.Network.Push(
814 foreach (var progressReporter
in progressReporters)
815 progressReporter.Dispose();
820 catch (NonFastForwardException)
822 logger.LogInformation(
"Synchronize aborted, non-fast forward!");
825 catch (UserCancelledException e)
827 cancellationToken.ThrowIfCancellationRequested();
828 throw new InvalidOperationException(
"Caught UserCancelledException without cancellationToken triggering", e);
830 catch (LibGit2SharpException e)
832 logger.LogWarning(e,
"Unable to make synchronization push!");
838 TaskScheduler.Current);
842 public Task<bool>
IsSha(
string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
846 var gitObject = libGitRepo.Lookup(committish,
ObjectType.Tag);
847 if (gitObject !=
null)
849 cancellationToken.ThrowIfCancellationRequested();
852 if (libGitRepo.Branches[committish] !=
null)
854 cancellationToken.ThrowIfCancellationRequested();
857 if (libGitRepo.Lookup<Commit>(committish) !=
null)
863 TaskScheduler.Current);
866 public Task<bool>
CommittishIsParent(
string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
869 var targetObject = libGitRepo.Lookup(committish);
870 if (targetObject ==
null)
872 logger.LogTrace(
"Committish {committish} not found in repository", committish);
876 if (targetObject is not Commit targetCommit)
878 if (targetObject is not TagAnnotation)
880 logger.LogTrace(
"Committish {committish} is a {type} and does not point to a commit!", committish, targetObject.GetType().Name);
884 targetCommit = targetObject.Peel<Commit>();
885 if (targetCommit ==
null)
888 "TagAnnotation {committish} was found but the commit associated with it could not be found in repository!",
894 cancellationToken.ThrowIfCancellationRequested();
896 logger.LogTrace(
"Testing if {committish} is a parent of {startSha}...", committish, startSha);
897 MergeResult mergeResult;
900 mergeResult = libGitRepo.Merge(
903 DefaultCommitterName,
904 DefaultCommitterEmail,
905 DateTimeOffset.UtcNow),
908 FastForwardStrategy = FastForwardStrategy.FastForwardOnly,
909 FailOnConflict =
true,
912 catch (NonFastForwardException ex)
914 logger.LogTrace(ex,
"{committish} is not a parent of {startSha}", committish, startSha);
918 if (mergeResult.Status == MergeStatus.UpToDate)
921 logger.LogTrace(
"{committish} is not a parent of {startSha} ({mergeStatus}). Moving back...", committish, startSha, mergeResult.Status);
926 CheckoutModifiers = CheckoutModifiers.Force,
934 TaskScheduler.Current);
940 CancellationToken cancellationToken) => gitRemoteFeatures.GetTestMerge(
946 public Task<DateTimeOffset>
TimestampCommit(
string sha, CancellationToken cancellationToken) => Task.Factory.StartNew(
949 ArgumentNullException.ThrowIfNull(sha);
951 var commit = libGitRepo.Lookup<Commit>(sha) ??
throw new JobException($
"Commit {sha} does not exist in the repository!");
952 return commit.Committer.When.ToUniversalTime();
956 TaskScheduler.Current);
961 logger.LogTrace(
"Disposing...");
962 libGitRepo.Dispose();
975 logger.LogTrace(
"Checkout: {committish}", committish);
977 var checkoutOptions =
new CheckoutOptions
979 CheckoutModifiers = CheckoutModifiers.Force,
982 var stage = $
"Checkout {committish}";
983 using var newProgressReporter = progressReporter.
CreateSection(stage, 1.0);
985 checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(newProgressReporter);
987 cancellationToken.ThrowIfCancellationRequested();
989 if (moveCurrentReference)
991 if (Reference == NoReference)
992 throw new InvalidOperationException(
"Cannot move current reference when not on reference!");
994 var gitObject = libGitRepo.Lookup(committish);
995 if (gitObject ==
null)
996 throw new JobException($
"Could not find committish: {committish}");
998 var commit = gitObject.Peel<Commit>();
1000 cancellationToken.ThrowIfCancellationRequested();
1002 libGitRepo.Reset(ResetMode.Hard, commit, checkoutOptions);
1006 void RunCheckout() => commands.Checkout(
1015 catch (NotFoundException)
1018 var remoteName = $
"origin/{committish}";
1019 var remoteBranch = libGitRepo.Branches.FirstOrDefault(
1020 branch => branch.FriendlyName.Equals(remoteName, StringComparison.Ordinal));
1021 cancellationToken.ThrowIfCancellationRequested();
1023 if (remoteBranch ==
default)
1026 logger.LogDebug(
"Creating local branch for {remoteBranchFriendlyName}...", remoteBranch.FriendlyName);
1027 var branch = libGitRepo.CreateBranch(committish, remoteBranch.Tip);
1029 libGitRepo.Branches.Update(branch, branchUpdate => branchUpdate.TrackedBranch = remoteBranch.CanonicalName);
1031 cancellationToken.ThrowIfCancellationRequested();
1037 cancellationToken.ThrowIfCancellationRequested();
1039 libGitRepo.RemoveUntrackedFiles();
1052 logger.LogInformation(
"Pushing changes to temporary remote branch...");
1053 var branch = libGitRepo.CreateBranch(RemoteTemporaryBranchName);
1056 cancellationToken.ThrowIfCancellationRequested();
1057 var remote = libGitRepo.Network.Remotes.First();
1060 var forcePushString = String.Format(CultureInfo.InvariantCulture,
"+{0}:{0}", branch.CanonicalName);
1062 using (var mainPushReporter = progressReporter.
CreateSection(
null, 0.9))
1064 var (pushOptions, progressReporters) = GeneratePushOptions(
1071 libGitRepo.Network.Push(remote, forcePushString, pushOptions);
1075 foreach (var progressReporter
in progressReporters)
1076 progressReporter.Dispose();
1080 var removalString = String.Format(CultureInfo.InvariantCulture,
":{0}", branch.CanonicalName);
1081 using var forcePushReporter = progressReporter.
CreateSection(
null, 0.1);
1082 var (forcePushOptions, forcePushReporters) = GeneratePushOptions(forcePushReporter, credentialsHandler, cancellationToken);
1085 libGitRepo.Network.Push(remote, removalString, forcePushOptions);
1089 foreach (var subForcePushReporter
in forcePushReporters)
1090 forcePushReporter.Dispose();
1093 catch (UserCancelledException)
1095 cancellationToken.ThrowIfCancellationRequested();
1097 catch (LibGit2SharpException e)
1099 logger.LogWarning(e,
"Unable to push to temporary branch!");
1104 libGitRepo.Branches.Remove(branch);
1109 TaskScheduler.Current);
1119 async ValueTask<(PushOptions PushOptions, IEnumerable<JobProgressReporter> SubProgressReporters)>
GeneratePushOptions(
JobProgressReporter progressReporter,
string username,
string password, CancellationToken cancellationToken)
1120 => GeneratePushOptions(
1122 await GenerateCredentialsHandler(username, password, cancellationToken),
1130 => ioManager.GetDirectoryName(libGitRepo
1133 .TrimEnd(ioManager.DirectorySeparatorChar)
1134 .TrimEnd(ioManager.AltDirectorySeparatorChar));
1149 bool deploymentPipeline,
1150 CancellationToken cancellationToken)
1152 logger.LogTrace(
"Updating submodules {withOrWithout} credentials...", username ==
null ?
"without" :
"with");
1154 async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository,
JobProgressReporter currentProgressReporter,
string parentGitDirectory)
1156 var submoduleCount = libGitRepo.Submodules.Count();
1157 if (submoduleCount == 0)
1159 logger.LogTrace(
"No submodules, skipping update");
1163 var factor = 1.0 / submoduleCount / 3;
1164 foreach (var submodule
in parentRepository.Submodules)
1166 logger.LogTrace(
"Entering submodule {name} ({path}) for recursive updates...", submodule.Name, submodule.Path);
1167 var submoduleUpdateOptions =
new SubmoduleUpdateOptions
1170 OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested,
1173 using var fetchReporter = currentProgressReporter.
CreateSection($
"Fetch submodule {submodule.Name}", factor);
1175 var credentialsHandler = await GenerateCredentialsHandler(username, password, cancellationToken);
1177 submoduleUpdateOptions.FetchOptions.Hydrate(
1183 using var checkoutReporter = currentProgressReporter.
CreateSection($
"Checkout submodule {submodule.Name}", factor);
1184 submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(checkoutReporter);
1186 logger.LogDebug(
"Updating submodule {submoduleName}...", submodule.Name);
1187 Task RawSubModuleUpdate() => Task.Factory.StartNew(
1188 () => parentRepository.Submodules.Update(submodule.Name, submoduleUpdateOptions),
1191 TaskScheduler.Current);
1195 await RawSubModuleUpdate();
1197 catch (LibGit2SharpException ex) when (parentRepository == libGitRepo)
1202 credentialsProvider.CheckBadCredentialsException(ex);
1203 logger.LogWarning(ex,
"Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name);
1206 ioManager.DeleteDirectory($
".git/modules/{submodule.Path}", cancellationToken),
1207 ioManager.DeleteDirectory(submodule.Path, cancellationToken));
1209 logger.LogTrace(
"Second update attempt for submodule {submoduleName}...", submodule.Name);
1212 await RawSubModuleUpdate();
1214 catch (UserCancelledException)
1216 cancellationToken.ThrowIfCancellationRequested();
1218 catch (LibGit2SharpException ex2)
1220 credentialsProvider.CheckBadCredentialsException(ex2);
1221 logger.LogTrace(ex2,
"Retried update of submodule {submoduleName} failed!", submodule.Name);
1222 throw new AggregateException(ex, ex2);
1226 await eventConsumer.HandleEvent(
1228 new List<string> { submodule.Name },
1233 var submodulePath = ioManager.ResolvePath(
1234 ioManager.ConcatPath(
1238 using var submoduleRepo = await submoduleFactory.CreateFromPath(
1242 using var submoduleReporter = currentProgressReporter.
CreateSection($
"Entering submodule \"{submodule.Name}\"...", factor);
1243 await RecursiveUpdateSubmodules(
1250 return RecursiveUpdateSubmodules(libGitRepo, progressReporter, GetRepositoryPath());
1261 => credentialsProvider.GenerateCredentialsHandler(gitRemoteFeatures, username, password, cancellationToken);
1273 if (completedSteps == 0)
1275 else if (totalSteps < completedSteps || totalSteps == 0)
1279 percentage = ((double)completedSteps) / totalSteps;
1284 if (percentage ==
null)
1286 "Bad checkout progress values (Please tell Dominion)! Completeds: {completed}, Total: {total}",
1293#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.
Task PushHeadToTemporaryBranch(CredentialsHandler credentialsHandler, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Force push the current repository HEAD to RemoteTemporaryBranchName;.
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.
readonly IOptionsMonitor< GeneralConfiguration > generalConfigurationOptions
The IOptionsMonitor<TOptions> of GeneralConfiguration for the Repository.
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.
ValueTask< CredentialsHandler > GenerateCredentialsHandler(string? username, string? password, CancellationToken cancellationToken)
Generate a CredentialsHandler from a given username and password .
async ValueTask CopyTo(string path, CancellationToken cancellationToken)
Copies the current working directory to a given path .A ValueTask representing the running operation.
Repository(LibGit2Sharp.IRepository libGitRepo, ILibGit2Commands commands, IIOManager ioManager, IEventConsumer eventConsumer, ICredentialsProvider credentialsProvider, IPostWriteHandler postWriteHandler, IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, ILibGit2RepositoryFactory submoduleFactory, IOptionsMonitor< GeneralConfiguration > generalConfigurationOptions, ILogger< Repository > logger, Action disposeAction)
Initializes a new instance of the Repository class.
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.
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.
async ValueTask<(PushOptions PushOptions, IEnumerable< JobProgressReporter > SubProgressReporters)> GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
Generate a standard set of PushOptions.
static PushOptions PushOptions
Generate a standard set of PushOptions.
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,...
static PushOptions IEnumerable< JobProgressReporter > SubProgressReporters GeneratePushOptions(JobProgressReporter progressReporter, CredentialsHandler credentialsHandler, CancellationToken cancellationToken)
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...
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...
Represents the result of a repository test merge attempt.
MergeStatus Status
The resulting MergeStatus.
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 sensitiveParameters, bool deploymentPipeline, CancellationToken cancellationToken)
Handle a given eventType .
For generating CredentialsHandlers.
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.
ValueTask< string?> TransformRepositoryPassword(string? rawPassword, CancellationToken cancellationToken)
Transform a service's rawPassword into a password usable by git.
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.