public GitHubPullDogRepositoryClient( IGitHubClient gitHubClient, GitReference gitReference) { this.gitHubClient = gitHubClient; this.gitReference = gitReference; }
internal string ZeroString() { switch (Type) { case GitUpdateReferenceType.Update: if (!GitReference.ValidName(Name, true)) { throw new InvalidOperationException($"'{Name}' is not a valid reference name"); } if (Target != null && OldTarget != null) { return($"update {Name}\0{Target}\0{OldTarget}\0"); } else if (Target != null) { return($"update {Name}\0{Target}\0\0"); } else if (SymbolicTarget != null) { if (!GitReference.ValidName(SymbolicTarget, true)) { throw new InvalidOperationException($"'{SymbolicTarget}' is not a valid reference name"); } return($"update {Name}\0{SymbolicTarget}\0"); } else { throw new InvalidOperationException(); } default: throw new NotImplementedException($"Update reference type {Type} not implemented yet"); } }
public async Task Given_Parameters_When_FindShaAsync_Invoked_Then_It_Should_Return_Property() { var sha = this._fixture.Create <string>(); var @ref = this._fixture.Create <string>(); var head = new GitReference().SetValue("Sha", sha).SetValue("Ref", @ref); var pr = new PullRequest().SetValue("Head", head); var prc = new Mock <IPullRequestsClient>(); prc.Setup(p => p.Get(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <int>())).ReturnsAsync(pr); var client = new Mock <IGitHubClient>(); client.SetupGet(p => p.PullRequest).Returns(prc.Object); var handler = new MessageHandler() .WithGitHubClient(client.Object); var options = new Options(); await handler.FindShaAsync(options).ConfigureAwait(false); handler.Sha.Should().BeEquivalentTo(pr.Head.Sha); handler.Ref.Should().BeEquivalentTo(pr.Head.Ref); }
public override async Task ExecuteAsync() { Uri imageInfoPathIdentifier = GitHelper.GetBlobUrl(Options.GitOptions); GitObject imageInfoGitObject = await GetUpdatedImageInfoGitObjectAsync(); if (imageInfoGitObject is null) { loggerService.WriteMessage($"No changes to the '{imageInfoPathIdentifier}' file were needed."); return; } loggerService.WriteMessage( $"The '{imageInfoPathIdentifier}' file has been updated with the following content:" + Environment.NewLine + imageInfoGitObject.Content + Environment.NewLine); if (!Options.IsDryRun) { using IGitHubClient gitHubClient = this.gitHubClientFactory.GetClient(Options.GitOptions.ToGitHubAuth(), Options.IsDryRun); await GitHelper.ExecuteGitOperationsWithRetryAsync(async() => { GitReference gitRef = await GitHelper.PushChangesAsync( gitHubClient, Options, "Merging image info updates from build.", branch => Task.FromResult <IEnumerable <GitObject> >(new GitObject[] { imageInfoGitObject })); Uri commitUrl = GitHelper.GetCommitUrl(Options.GitOptions, gitRef.Object.Sha); loggerService.WriteMessage($"The '{imageInfoPathIdentifier}' file was updated ({commitUrl})."); }); } }
protected internal override async ValueTask <GitReference?> ResolveAsync(GitReference gitReference) { string dir = gitReference.Name.Contains('/', StringComparison.Ordinal) ? GitDir : WorkTreeDir; string fileName = Path.Combine(dir, gitReference.Name); if (!File.Exists(fileName)) { return(null); } if (GitRepository.TryReadRefFile(fileName, null, out var body)) { if (body.StartsWith("ref: ", StringComparison.OrdinalIgnoreCase)) { body = body.Substring("ref: ".Length); var ob = await Repository.ReferenceRepository.GetAsync(body.Trim()).ConfigureAwait(false); if (ob is not null) { return(ob); } } else if (GitId.TryParse(body, out var id)) { return(new GitReference(Repository.ReferenceRepository, gitReference.Name, id)); } } return(gitReference); // Not symbolic, and exists. Or error and exists }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously public override async IAsyncEnumerable <GitReference> GetAll(HashSet <string> alreadyReturned) #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { string baseDir = Path.GetFullPath(GitDir); foreach (string file in Directory.EnumerateFiles(Path.Combine(baseDir, "refs"), "*", SearchOption.AllDirectories)) { if (file.Length > baseDir.Length + 1 && file[baseDir.Length] == Path.DirectorySeparatorChar) { string name = file.Substring(baseDir.Length + 1).Replace(Path.DirectorySeparatorChar, '/'); yield return(new GitReference(this, name, (GitId?)null)); } } foreach (string file in Directory.EnumerateFiles(GitDir)) { string name = Path.GetFileName(file); if (GitReference.AllUpper(name) && !alreadyReturned.Contains(name)) { yield return(new GitSymbolicReference(this, file.Substring(GitDir.Length + 1))); } } }
public override async Task ExecuteAsync() { _loggerService.WriteHeading("PUBLISHING MCR DOCS"); // Hookup a TraceListener in order to capture details from Microsoft.DotNet.VersionTools Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); IEnumerable <GitObject> gitObjects = GetUpdatedReadmes() .Concat(GetUpdatedTagsMetadata()); foreach (GitObject gitObject in gitObjects) { _loggerService.WriteMessage( $"Updated file '{gitObject.Path}' with contents:{Environment.NewLine}{gitObject.Content}{Environment.NewLine}"); } if (!Options.IsDryRun) { using IGitHubClient gitHubClient = _gitHubClientFactory.GetClient(Options.GitOptions.ToGitHubAuth(), Options.IsDryRun); await RetryHelper.GetWaitAndRetryPolicy <HttpRequestException>(_loggerService).ExecuteAsync(async() => { GitReference gitRef = await GitHelper.PushChangesAsync(gitHubClient, Options, $"Mirroring readmes", branch => { return(FilterUpdatedGitObjectsAsync(gitObjects, gitHubClient, branch)); }); if (gitRef != null) { _loggerService.WriteMessage(PipelineHelper.FormatOutputVariable("readmeCommitDigest", gitRef.Object.Sha)); } }); } }
public ValueTask <GitReference?> GetAsync(string name) { if (!GitReference.ValidName(name, true)) { throw new ArgumentOutOfRangeException(nameof(name), name, "Invalid Reference name"); } return(GetUnsafeAsync(name)); }
private Commit GetCommitFromGithubCommit(GitReference commit) { return(new Commit { //Author = commit.Author.Name, //Message = commit.Message, Revision = commit.Sha }); }
internal GitRevisionSet AddReference(GitReference gitReference) { if (gitReference?.Commit is GitCommit q) { return(AddCommit(q)); } return(this); }
internal GitReferenceChangeSet(GitRepository repository, GitReference reference) : base(repository) { _reference = reference; #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code Expression = Expression.Property(Expression.Property(Expression.Property(Expression.Constant(Repository), nameof(Repository.References)), "Item", Expression.Constant(_reference.Name)), nameof(GitReference.ReferenceChanges)); #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code }
private static string CreateLink(GitReference reference) { if (reference.Repository != null) { var baseHtml = reference.Repository.HtmlUrl + "/tree/" + reference.Ref; return(string.Format("<a href='{0}'>{1}</a>", baseHtml, reference.Label)); } return("<a href='#'>unknown repository</a>"); }
protected internal override async ValueTask <GitReference?> ResolveAsync(GitReference gitReference) { await Read().ConfigureAwait(false); if (_peelRefs !.TryGetValue(gitReference.Name, out var v)) { return(new GitReference(this, v.Name, v.Id).SetPeeled(v.Peeled)); } return(null); }
public override IAsyncEnumerable <GitReferenceChange>?GetChanges(GitReference reference) { string fileName = Path.Combine(GitDir, "logs", reference.Name); if (File.Exists(fileName)) { return(GetChangesFromRefLogFile(fileName)); } return(null); }
public MockPullRequest() { Title = "Title"; Body = @"# 1st head paragraph1 # 2nd head paragraph2 "; Base = new GitReference("", "BASE", "", "1212", null, null); Head = new GitReference("", "HEAD", "", "asdfasdf", null, null); }
private protected void ParseLineToPeel(BucketBytes line, ref GitRefPeel?last, int idLength) { if (char.IsLetterOrDigit((char)line[0]) && line.Length > idLength + 1) { if (GitId.TryParse(line.Slice(0, idLength), out var oid)) { string name = line.Slice(idLength + 1).Trim().ToUTF8String(); if (GitReference.ValidName(name, false)) { _peelRefs ![name] = last = new GitRefPeel {
protected internal override async ValueTask <GitReference?> ResolveAsync(GitReference gitReference) { foreach (var v in Sources) { var r = await v.ResolveAsync(gitReference).ConfigureAwait(false); if (r is not null) { return(r); } } return(null); }
public override IAsyncEnumerable <GitReferenceChange> GetChanges(GitReference reference) { foreach (var v in Sources) { var r = v.GetChanges(reference); if (r is not null) { return(r); } } return(AsyncEnumerable.Empty <GitReferenceChange>()); }
private static async Task CreatePullRequestAsync(GitHubClient client, GitRepo gitRepo, Config config) { GitHubProject project = new GitHubProject(gitRepo.Name, gitRepo.Owner); GitHubProject forkedProject = new GitHubProject(gitRepo.Name, Options.GitUser); GitHubBranch baseBranch = new GitHubBranch(gitRepo.Branch, project); GitHubBranch headBranch = new GitHubBranch( $"{gitRepo.Name}-{gitRepo.Branch}{config.WorkingBranchSuffix}", forkedProject); IEnumerable <GitObject> changes = await GetUpdatedFiles(config.SourcePath, client, baseBranch); if (!changes.Any()) { return; } GitReference currentRef = await client.GetReferenceAsync(project, $"heads/{baseBranch.Name}"); string parentSha = currentRef.Object.Sha; GitTree tree = await client.PostTreeAsync(forkedProject, parentSha, changes.ToArray()); GitCommit commit = await client.PostCommitAsync(forkedProject, config.CommitMessage, tree.Sha, new[] { parentSha }); string workingReference = $"heads/{headBranch.Name}"; if (await BranchExists(client, forkedProject, workingReference)) { await client.PatchReferenceAsync(forkedProject, workingReference, commit.Sha, force : true); } else { await client.PostReferenceAsync(forkedProject, workingReference, commit.Sha); } GitHubPullRequest pullRequestToUpdate = await client.SearchPullRequestsAsync( project, headBranch.Name, await client.GetMyAuthorIdAsync()); if (pullRequestToUpdate == null) { await client.PostGitHubPullRequestAsync( $"[{gitRepo.Branch}] {config.PullRequestTitle}", config.PullRequestDescription, headBranch, baseBranch, maintainersCanModify : true); } }
public override async Task ExecuteAsync() { Logger.WriteHeading("UPDATING VERSIONS"); // Hookup a TraceListener in order to capture details from Microsoft.DotNet.VersionTools Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); DockerHelper.PullBaseImages(Manifest, Options); GitHubAuth githubAuth = new GitHubAuth(Options.GitAuthToken, Options.GitUsername, Options.GitEmail); using (GitHubClient client = new GitHubClient(githubAuth)) { for (int i = 0; i < MaxTries; i++) { try { GitHubProject project = new GitHubProject(Options.GitRepo, Options.GitOwner); GitHubBranch branch = new GitHubBranch(Options.GitBranch, project); GitObject[] gitObjects = await GetUpdatedVerionInfo(client, branch); if (gitObjects.Any()) { string masterRef = $"heads/{Options.GitBranch}"; GitReference currentMaster = await client.GetReferenceAsync(project, masterRef); string masterSha = currentMaster.Object.Sha; GitTree tree = await client.PostTreeAsync(project, masterSha, gitObjects); string commitMessage = "Update Docker image digests"; GitCommit commit = await client.PostCommitAsync( project, commitMessage, tree.Sha, new[] { masterSha }); // Only fast-forward. Don't overwrite other changes: throw exception instead. await client.PatchReferenceAsync(project, masterRef, commit.Sha, force : false); } break; } catch (HttpRequestException ex) when(i < (MaxTries - 1)) { Logger.WriteMessage($"Encountered exception committing build-info update: {ex.Message}"); Logger.WriteMessage($"Trying again in {RetryMillisecondsDelay}ms. {MaxTries - i - 1} tries left."); await Task.Delay(RetryMillisecondsDelay); } } } }
public static async Task <GitReference> PushChangesAsync(IGitHubClient client, IGitOptionsHost options, string commitMessage, Func <GitHubBranch, Task <IEnumerable <GitObject> > > getChanges) { GitOptions gitOptions = options.GitOptions; GitHubProject project = new GitHubProject(gitOptions.Repo, gitOptions.Owner); GitHubBranch branch = new GitHubBranch(gitOptions.Branch, project); IEnumerable <GitObject> changes = await getChanges(branch); if (!changes.Any()) { return(null); } string masterRef = $"heads/{gitOptions.Branch}"; GitReference currentMaster = await client.GetReferenceAsync(project, masterRef); string masterSha = currentMaster.Object.Sha; if (!options.IsDryRun) { GitTree tree = await client.PostTreeAsync(project, masterSha, changes.ToArray()); GitCommit commit = await client.PostCommitAsync( project, commitMessage, tree.Sha, new[] { masterSha }); // Only fast-forward. Don't overwrite other changes: throw exception instead. return(await client.PatchReferenceAsync(project, masterRef, commit.Sha, force : false)); } else { Logger.WriteMessage($"The following files would have been updated at {gitOptions.Owner}/{gitOptions.Repo}/{gitOptions.Branch}:"); Logger.WriteMessage(); foreach (GitObject gitObject in changes) { Logger.WriteMessage($"{gitObject.Path}:"); Logger.WriteMessage(gitObject.Content); Logger.WriteMessage(); } return(null); } }
public async Task PushNewBuildAsync( BuildManifestLocation location, OrchestratedBuildModel build, IEnumerable <SupplementaryUploadRequest> supplementaryUploads, string message) { await Retry.RunAsync(async attempt => { GitReference remoteRef = await _github.GetReferenceAsync( location.GitHubProject, location.GitHubRef); string remoteCommit = remoteRef.Object.Sha; Trace.TraceInformation($"Creating update on remote commit: {remoteCommit}"); IEnumerable <SupplementaryUploadRequest> uploads = supplementaryUploads.NullAsEmpty() .Concat(new[] { new SupplementaryUploadRequest { Path = BuildManifestXmlName, Contents = build.ToXml().ToString() }, new SupplementaryUploadRequest { Path = SemaphoreModel.BuildSemaphorePath, Contents = new SemaphoreModel { BuildId = build.Identity.BuildId }.ToFileContent() } }) .ToArray(); return(await PushUploadsAsync(location, message, remoteCommit, uploads)); }); }
/// <summary> /// Initializes a new instance of the <see cref="GitHubCommit"/> class. /// </summary> /// <param name="branch">The branch with this commit.</param> /// <param name="source">The Octokit commit.</param> internal GitHubCommit(GitHubBranch branch, GitReference source) { Branch = branch; Source = source; }
/// <param name="updateLatestVersion">If true, updates Latest.txt with a prerelease moniker. If there isn't one, makes the file empty.</param> /// <param name="updateLatestPackageList">If true, updates Latest_Packages.txt.</param> /// <param name="updateLastBuildPackageList">If true, updates Last_Build_Packages.txt, and enables keeping old packages in Latest_Packages.txt.</param> public async Task UpdateBuildInfoAsync( IEnumerable <string> packagePaths, string versionsRepoPath, bool updateLatestPackageList = true, bool updateLatestVersion = true, bool updateLastBuildPackageList = true) { if (packagePaths == null) { throw new ArgumentNullException(nameof(packagePaths)); } if (versionsRepoPath == null) { throw new ArgumentNullException(nameof(versionsRepoPath)); } NupkgInfo[] packages = CreatePackageInfos(packagePaths).ToArray(); string prereleaseVersion = GetPrereleaseVersion(packages); Dictionary <string, string> packageDictionary = CreatePackageInfoDictionary(packages); using (GitHubClient client = new GitHubClient(_gitHubAuth)) { for (int i = 0; i < MaxTries; i++) { try { // Master commit to use as new commit's parent. string masterRef = "heads/master"; GitReference currentMaster = await client.GetReferenceAsync(_project, masterRef); string masterSha = currentMaster.Object.Sha; List <GitObject> objects = new List <GitObject>(); if (updateLastBuildPackageList) { objects.Add(new GitObject { Path = $"{versionsRepoPath}/{BuildInfo.LastBuildPackagesTxtFilename}", Type = GitObject.TypeBlob, Mode = GitObject.ModeFile, Content = CreatePackageListContent(packageDictionary) }); } if (updateLatestPackageList) { var allPackages = new Dictionary <string, string>(packageDictionary); if (updateLastBuildPackageList) { await AddExistingPackages( client, new GitHubBranch("master", _project), versionsRepoPath, allPackages); } objects.Add(new GitObject { Path = $"{versionsRepoPath}/{BuildInfo.LatestPackagesTxtFilename}", Type = GitObject.TypeBlob, Mode = GitObject.ModeFile, Content = CreatePackageListContent(allPackages) }); } if (updateLatestVersion) { objects.Add(new GitObject { Path = $"{versionsRepoPath}/{BuildInfo.LatestTxtFilename}", Type = GitObject.TypeBlob, Mode = GitObject.ModeFile, Content = prereleaseVersion }); } string message = $"Updating {versionsRepoPath}"; if (string.IsNullOrEmpty(prereleaseVersion)) { message += ". No prerelease versions published."; } else { message += $" for {prereleaseVersion}"; } GitTree tree = await client.PostTreeAsync(_project, masterSha, objects.ToArray()); GitCommit commit = await client.PostCommitAsync(_project, message, tree.Sha, new[] { masterSha }); // Only fast-forward. Don't overwrite other changes: throw exception instead. await client.PatchReferenceAsync(_project, masterRef, commit.Sha, force : false); Trace.TraceInformation($"Committed build-info update on attempt {i + 1}."); break; } catch (Exception ex) when(ex is HttpRequestException || ex is NotFastForwardUpdateException) { int nextTry = i + 1; if (nextTry < MaxTries) { Trace.TraceInformation($"Encountered exception committing build-info update: {ex.Message}"); Trace.TraceInformation($"Trying again in {RetryMillisecondsDelay}ms. {MaxTries - nextTry} tries left."); await Task.Delay(RetryMillisecondsDelay); } else { Trace.TraceInformation("Encountered exception committing build-info update."); throw; } } } } }
/// <param name="updateLatestVersion">If true, updates Latest.txt with a prerelease moniker. If there isn't one, makes the file empty.</param> /// <param name="updateLatestPackageList">If true, updates Latest_Packages.txt.</param> /// <param name="updateLastBuildPackageList">If true, updates Last_Build_Packages.txt, and enables keeping old packages in Latest_Packages.txt.</param> public async Task UpdateBuildInfoAsync( IEnumerable <string> packagePaths, string versionsRepoPath, bool updateLatestPackageList = true, bool updateLatestVersion = true, bool updateLastBuildPackageList = true) { if (packagePaths == null) { throw new ArgumentNullException(nameof(packagePaths)); } if (versionsRepoPath == null) { throw new ArgumentNullException(nameof(versionsRepoPath)); } NupkgInfo[] packages = CreatePackageInfos(packagePaths).ToArray(); string prereleaseVersion = packages .Select(t => t.Prerelease) .FirstOrDefault(prerelease => !string.IsNullOrEmpty(prerelease)) ?? "stable"; Dictionary <string, string> packageDictionary = CreatePackageInfoDictionary(packages); using (GitHubClient client = new GitHubClient(_gitHubAuth)) { for (int i = 0; i < MaxTries; i++) { try { // Master commit to use as new commit's parent. string masterRef = "heads/master"; GitReference currentMaster = await client.GetReferenceAsync(_project, masterRef); string masterSha = currentMaster.Object.Sha; List <GitObject> objects = new List <GitObject>(); if (updateLastBuildPackageList) { objects.Add(new GitObject { Path = $"{versionsRepoPath}/Last_Build_Packages.txt", Type = GitObject.TypeBlob, Mode = GitObject.ModeFile, Content = CreatePackageListContent(packageDictionary) }); } if (updateLatestPackageList) { string latestPackagesPath = $"{versionsRepoPath}/Latest_Packages.txt"; var allPackages = new Dictionary <string, string>(packageDictionary); if (updateLastBuildPackageList) { Dictionary <string, string> existingPackages = await GetPackagesAsync(client, latestPackagesPath); if (existingPackages == null) { Trace.TraceInformation( "No exising Latest_Packages file found; one will be " + $"created in '{versionsRepoPath}'"); } else { // Add each existing package if there isn't a new package with the same id. foreach (var package in existingPackages) { if (!allPackages.ContainsKey(package.Key)) { allPackages[package.Key] = package.Value; } } } } objects.Add(new GitObject { Path = latestPackagesPath, Type = GitObject.TypeBlob, Mode = GitObject.ModeFile, Content = CreatePackageListContent(allPackages) }); } if (updateLatestVersion) { objects.Add(new GitObject { Path = $"{versionsRepoPath}/Latest.txt", Type = GitObject.TypeBlob, Mode = GitObject.ModeFile, Content = prereleaseVersion }); } string message = $"Updating {versionsRepoPath}"; if (string.IsNullOrEmpty(prereleaseVersion)) { message += ". No prerelease versions published."; } else { message += $" for {prereleaseVersion}"; } GitTree tree = await client.PostTreeAsync(_project, masterSha, objects.ToArray()); GitCommit commit = await client.PostCommitAsync(_project, message, tree.Sha, new[] { masterSha }); // Only fast-forward. Don't overwrite other changes: throw exception instead. await client.PatchReferenceAsync(_project, masterRef, commit.Sha, force : false); Trace.TraceInformation($"Committed build-info update on attempt {i + 1}."); break; } catch (HttpRequestException ex) { int nextTry = i + 1; if (nextTry < MaxTries) { Trace.TraceInformation($"Encountered exception committing build-info update: {ex.Message}"); Trace.TraceInformation($"Trying again in {RetryMillisecondsDelay}ms. {MaxTries - nextTry} tries left."); await Task.Delay(RetryMillisecondsDelay); } else { Trace.TraceInformation("Encountered exception committing build-info update."); throw; } } } } }
public async Task PushChangeAsync(BuildManifestChange change) { await Retry.RunAsync(async attempt => { BuildManifestLocation location = change.Location; // Get the current commit. Use this throughout to ensure a clean transaction. GitReference remoteRef = await _github.GetReferenceAsync( location.GitHubProject, location.GitHubRef); string remoteCommit = remoteRef.Object.Sha; Trace.TraceInformation($"Creating update on remote commit: {remoteCommit}"); XElement remoteModelXml = await FetchModelXmlAsync( location.GitHubProject, remoteCommit, location.GitHubBasePath); OrchestratedBuildModel remoteModel = OrchestratedBuildModel.Parse(remoteModelXml); // This is a subsequent publish step: make sure a new build hasn't happened already. if (change.OrchestratedBuildId != remoteModel.Identity.BuildId) { throw new ManifestChangeOutOfDateException( change.OrchestratedBuildId, remoteModel.Identity.BuildId); } OrchestratedBuildModel modifiedModel = OrchestratedBuildModel.Parse(remoteModelXml); change.ApplyModelChanges(modifiedModel); if (modifiedModel.Identity.BuildId != change.OrchestratedBuildId) { throw new ArgumentException( "Change action shouldn't modify BuildId. Changed from " + $"'{change.OrchestratedBuildId}' to '{modifiedModel.Identity.BuildId}'.", nameof(change)); } XElement modifiedModelXml = modifiedModel.ToXml(); string[] changedSemaphorePaths = change.SemaphorePaths.ToArray(); // Check if any join groups are completed by this change. var joinCompleteCheckTasks = change.JoinSemaphoreGroups.NullAsEmpty() .Select(async g => new { Group = g, Joinable = await IsGroupJoinableAsync( location, remoteCommit, change.OrchestratedBuildId, changedSemaphorePaths, g) }); var completeJoinedSemaphores = (await Task.WhenAll(joinCompleteCheckTasks)) .Where(g => g.Joinable) .Select(g => g.Group.JoinSemaphorePath) .ToArray(); IEnumerable <SupplementaryUploadRequest> semaphoreUploads = completeJoinedSemaphores .Concat(changedSemaphorePaths) .Select(p => new SupplementaryUploadRequest { Path = p, Contents = new SemaphoreModel { BuildId = change.OrchestratedBuildId }.ToFileContent() }); IEnumerable <SupplementaryUploadRequest> uploads = semaphoreUploads.Concat(change.SupplementaryUploads.NullAsEmpty()); if (!XNode.DeepEquals(modifiedModelXml, remoteModelXml)) { uploads = uploads.Concat(new[] { new SupplementaryUploadRequest { Path = BuildManifestXmlName, Contents = modifiedModelXml.ToString() } }); } return(await PushUploadsAsync( location, change.CommitMessage, remoteCommit, uploads)); }); }
public void UseGitClient() { GitCommitArgs ga = new GitCommitArgs(); ga.Author.Name = "Tester"; ga.Author.EmailAddress = "*****@*****.**"; ga.Signature.Name = "Other"; ga.Signature.EmailAddress = "*****@*****.**"; // Use stable time and offset to always produce the same hash DateTime ct = new DateTime(2002, 01, 01, 0, 0, 0, DateTimeKind.Utc); ga.Author.When = ct; ga.Author.TimeOffsetInMinutes = 120; ga.Signature.When = ct; ga.Signature.TimeOffsetInMinutes = 120; string repoDir = GetTempPath(); string repo2Dir = GetTempPath(); GitId firstResult; GitId lastCommit; using (GitRepository repo = GitRepository.Create(repoDir)) using (GitClient git = new GitClient()) { string ignoreFile = Path.Combine(repoDir, ".gitignore"); string file = Path.Combine(repoDir, "newfile"); string subDir = Path.Combine(repoDir, "dir"); string fileInSubDir = Path.Combine(subDir, "file2"); string file3 = Path.Combine(repoDir, "other"); string file4 = Path.Combine(repoDir, "q.ignore"); File.WriteAllText(file, "Some body"); Directory.CreateDirectory(subDir); File.WriteAllText(fileInSubDir, "Some other body"); File.WriteAllText(file3, "file3"); File.WriteAllText(ignoreFile, "*.ignore\n"); File.WriteAllText(file4, "file4"); git.Add(ignoreFile); git.Add(file); git.Commit(repoDir, ga, out firstResult); git.Add(fileInSubDir); int ticked = 0; File.AppendAllText(file, "\nExtra Line"); GitStatusArgs gsa = new GitStatusArgs(); gsa.IncludeIgnored = true; gsa.IncludeUnmodified = true; Assert.That(git.Status(repoDir, gsa, delegate(object sender, GitStatusEventArgs e) { switch (e.RelativePath) { case "newfile": //Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.Added)); Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.Normal), "newfile index normal"); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.Normal), "newfile wc modified"); Assert.That(e.WorkingDirectoryModified); Assert.That(e.Ignored, Is.False); break; case "dir/file2": Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.New), "file2 index added"); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.Normal), "file2 wc normal"); Assert.That(e.Ignored, Is.False); break; case "other": Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.None)); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.New)); Assert.That(e.Ignored, Is.False); break; case ".gitignore": Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.Normal)); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.Normal)); Assert.That(e.Ignored, Is.False); break; case "q.ignore": // TODO: Make this ignored Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.None)); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.Normal)); Assert.That(e.Ignored, Is.True); break; default: Assert.Fail("Invalid node found: {0}", e.RelativePath); break; } Assert.That(e.FullPath, Is.EqualTo(Path.GetFullPath(Path.Combine(repoDir, e.RelativePath)))); ticked++; }), Is.True); Assert.That(ticked, Is.EqualTo(5), "Ticked"); ga.LogMessage = "Intermediate"; git.Commit(repoDir, ga); Assert.That(git.Delete(fileInSubDir)); Assert.That(git.Add(file)); GitId commit; ga.LogMessage = "A log message to remember"; // The passed path is currently just used to find the local repository lastCommit = new GitId("996cf198b49ed6fce3bcba232e2d88eb473560f9"); Assert.That(git.Commit(repoDir, ga, out commit)); Assert.That(commit, Is.EqualTo(lastCommit)); File.Move(file, file + ".a"); ticked = 0; gsa.IncludeIgnored = false; gsa.IncludeUnversioned = true; gsa.IncludeUnmodified = false; Assert.That(git.Status(repoDir, gsa, delegate(object sender, GitStatusEventArgs e) { switch (e.RelativePath) { /*case "dir": * Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.Normal), "dir index normal"); * Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.New), "dir wc normal"); * break;*/ case "newfile": Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.None), "newfile index normal"); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.Deleted), "newfile wc deleted"); break; case "newfile.a": Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.None), "newfile.a index normal"); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.New), "newfile.a wc new"); break; case "other": Assert.That(e.IndexStatus, Is.EqualTo(GitStatus.None), "other index normal"); Assert.That(e.WorkingDirectoryStatus, Is.EqualTo(GitStatus.New), "other wc normal"); break; default: Assert.Fail("Invalid node found: {0}", e.RelativePath); break; } Assert.That(e.FullPath, Is.EqualTo(Path.GetFullPath(Path.Combine(repoDir, e.RelativePath)))); ticked++; }), Is.True); Assert.That(ticked, Is.EqualTo(3)); GitCloneArgs gc = new GitCloneArgs(); gc.Synchronous = true; git.Clone(repoDir, repo2Dir, gc); GitCommit theCommit; Assert.That(repo.Lookup(commit, out theCommit)); Assert.That(repo.Branches.Create(theCommit, "vNext")); Assert.That(repo.Branches, Is.Not.Empty); } using (GitRepository repo1 = new GitRepository(repoDir)) using (GitRepository repo2 = new GitRepository(repo2Dir)) { GitReference head = repo1.HeadReference; Assert.That(head, Is.Not.Null, "Has head"); Assert.That(head.Name, Is.EqualTo("refs/heads/master")); //Assert.That(repo2.Head, Is.Not.Null); GitId headId; Assert.That(repo1.ResolveReference(repo1.HeadReference, out headId)); Assert.That(headId, Is.EqualTo(lastCommit)); GitCommit commit; Assert.That(repo1.Lookup(headId, out commit)); Assert.That(commit, Is.Not.Null, "Have a commit"); Assert.That(commit.Id, Is.EqualTo(lastCommit)); Assert.That(commit.Ancestors, Is.Not.Empty); Assert.That(commit.Ancestor, Is.Not.Null); Assert.That(commit.Ancestor.Ancestor, Is.Not.Null); Assert.That(commit.Ancestor.Ancestor.Ancestor, Is.Null); Assert.That(commit.Ancestor.Ancestor.Id, Is.EqualTo(firstResult)); Assert.That(commit.Author, Is.Not.Null); Assert.That(commit.Author.Name, Is.EqualTo("Tester")); Assert.That(commit.Author.EmailAddress, Is.EqualTo("*****@*****.**")); Assert.That(commit.Committer, Is.Not.Null); Assert.That(commit.Committer.Name, Is.EqualTo("Other")); Assert.That(commit.Committer.EmailAddress, Is.EqualTo("*****@*****.**")); Assert.That(commit.Committer.TimeOffsetInMinutes, Is.EqualTo(120), "Time offset"); // CEST dependent Assert.That(commit.Committer.When, Is.EqualTo(ct), "Exact time"); Assert.That(commit.LogMessage, Is.EqualTo("A log message to remember\n")); Assert.That(commit.Parents, Is.Not.Empty); Assert.That(commit.ParentIds, Is.Not.Empty); Assert.That(commit.Tree, Is.Not.Empty); Assert.That(commit.Tree.Count, Is.EqualTo(2)); Assert.That(commit.Ancestor.Tree.Count, Is.EqualTo(3)); Assert.That(commit.Ancestor.Ancestor.Tree.Count, Is.EqualTo(2)); Assert.That(commit.Tree.Id, Is.Not.EqualTo(commit.Ancestor.Tree.Id)); GitId id; Assert.That(repo1.LookupViaPrefix(commit.Id.ToString(), out id)); Assert.That(id, Is.EqualTo(commit.Id)); Assert.That(repo1.LookupViaPrefix(commit.Id.ToString().Substring(0, 10), out id)); Assert.That(id, Is.EqualTo(commit.Id)); Assert.That(commit.Peel <GitObject>().Id, Is.EqualTo(commit.Tree.Id)); Assert.That(commit.Peel <GitTree>(), Is.EqualTo(commit.Tree)); // Compares members Assert.That(commit.Tree.Peel <GitObject>(), Is.Null); GitTagArgs ta = new GitTagArgs(); ta.Signature.When = ct; ta.Signature.Name = "Me"; ta.Signature.EmailAddress = "[email protected]"; ta.LogMessage = "Some message"; ga.Author.TimeOffsetInMinutes = 120; Assert.That(commit.Tag("MyTag", ta, out id)); Assert.That(id, Is.EqualTo(new GitId("db31f8333fc64d7e7921ea91f6e007b755dcfcbb"))); GitTag tag; Assert.That(repo1.Lookup(id, out tag)); Assert.That(tag, Is.Not.Null); Assert.That(tag.Name, Is.EqualTo("MyTag")); Assert.That(tag.LogMessage, Is.EqualTo("Some message\n")); Assert.That(tag.Tagger.Name, Is.EqualTo("Me")); Assert.That(tag.Target.Id, Is.EqualTo(commit.Id)); Assert.That(tag.Peel <GitTree>(), Is.EqualTo(commit.Peel <GitTree>())); repo1.CheckOut(commit.Tree); //Console.WriteLine("1:"); //foreach (GitTreeEntry e in commit.Tree) //{ // Console.WriteLine(string.Format("{0}: {1} ({2})", e.Name, e.Kind, e.Children.Count)); //} //Console.WriteLine("2:"); //foreach (GitTreeEntry e in commit.Ancestor.Tree) //{ // Console.WriteLine(string.Format("{0}: {1} ({2})", e.Name, e.Kind, e.Children.Count)); //} //Console.WriteLine("3:"); //foreach (GitTreeEntry e in commit.Ancestor.Ancestor.Tree) //{ // Console.WriteLine(string.Format("{0}: {1} ({2})", e.Name, e.Kind, e.Children.Count)); //} //Console.WriteLine("-"); } }
public void PerformsCommitSerialization() { var tree = new GitReference { Sha = "tree-reference", Url = "tree-url" }; var parent1 = new GitReference { Sha = "parent1-reference", Url = "parent1-url" }; var parent2 = new GitReference { Sha = "parent2-reference", Url = "parent2-url" }; var author = new Signature { Name = "author-name", Email = "author-email", Date = new DateTime(2013, 10, 15, 13, 40, 14, DateTimeKind.Utc) }; var committer = new Signature { Name = "committer-name", Email = "committer-email", Date = new DateTime(2013, 06, 29, 10, 12, 50, DateTimeKind.Utc) }; var commit = new Commit { Sha = "commit-reference", Url = "commit-url", Message = "commit-message", Parents = new[] { parent1, parent2 }, Tree = tree, Author = author, Committer = committer, }; var json = new SimpleJsonSerializer().Serialize(commit); const string expectedResult = "{\"message\":\"commit-message\"," + "\"author\":{" + "\"name\":\"author-name\"," + "\"email\":\"author-email\"," + "\"date\":\"2013-10-15T13:40:14Z\"" + "}," + "\"committer\":{" + "\"name\":\"committer-name\"," + "\"email\":\"committer-email\"," + "\"date\":\"2013-06-29T10:12:50Z\"" + "}," + "\"tree\":{" + "\"url\":\"tree-url\"," + "\"sha\":\"tree-reference\"" + "}," + "\"parents\":[{" + "\"url\":\"parent1-url\"," + "\"sha\":\"parent1-reference\"" + "}," + "{" + "\"url\":\"parent2-url\"," + "\"sha\":\"parent2-reference\"" + "}]," + "\"url\":\"commit-url\"," + "\"sha\":\"commit-reference\"" + "}"; Assert.Equal(expectedResult, json); }
public virtual IAsyncEnumerable <GitReferenceChange>?GetChanges(GitReference reference) { return(default);
private async ValueTask CommitUpdateFileReferences() { foreach (var v in Updates.Where(x => x.Type == UpdateType.Verify)) { var r = await _referenceRepository.GetAsync(v.Name).ConfigureAwait(false); if (r is null || r.Id != v.Id) { throw new GitException($"Reference {v.Name} is not {v.Id}, but {r?.Id ?? Zero}"); } } Action?unlock = null; string?hookData = null; bool? logRefUpdates = null; try { foreach (var v in Updates.Select(x => x.Name).Distinct()) { var name = v; if (GitReference.AllUpper(name)) { var rf = await _referenceRepository.GetAsync(v).ConfigureAwait(false); if (rf is GitSymbolicReference sr) { rf = await sr.ResolveAsync().ConfigureAwait(false); name = (rf as GitSymbolicReference)?.ReferenceName ?? rf.Name ?? name; } } string path = Path.Combine(Repository.GitDirectory, name); Directory.CreateDirectory(Path.GetDirectoryName(path) !); string p = path + ".lock"; #pragma warning disable CA2000 // Dispose objects before losing scope var f = new FileStream(path + ".lock", FileMode.CreateNew); #pragma warning restore CA2000 // Dispose objects before losing scope unlock += () => { f.Close(); File.Delete(p); }; } bool allowContinue = true; if (!string.IsNullOrEmpty(GitConfiguration.GitProgramPath) && await Repository.Configuration.HookExistsAsync("reference-transaction").ConfigureAwait(false)) { StringBuilder sb = new StringBuilder(); foreach (var v in Updates) { GitReference?rf; // We might record 'HEAD' when we really update something like 'refs/heads/main' // This might need fixing when things are fixed in git itself switch (v.Type) { case UpdateType.Create: sb.Append(Zero); sb.Append(' '); sb.Append(v.Id); sb.Append(' '); sb.Append(v.Name); sb.Append('\n'); break; case UpdateType.Update: rf = await _referenceRepository.GetAsync(v.Name).ConfigureAwait(false); sb.Append(rf?.Id ?? Zero); sb.Append(' '); sb.Append(v.Id); sb.Append(' '); sb.Append(v.Name); sb.Append('\n'); break; case UpdateType.Delete: rf = await _referenceRepository.GetAsync(v.Name).ConfigureAwait(false); if (rf?.Id != null) { sb.Append(rf.Id); sb.Append(' '); sb.Append(Zero); sb.Append(' '); sb.Append(v.Name); sb.Append('\n'); } break; } } if (sb.Length > 0) { hookData = sb.ToString(); } if (hookData is not null) { var r = await Repository.RunHookErrAsync("reference-transaction", new[] { "prepared" }, stdinText : hookData, expectedResults : Array.Empty <int>()).ConfigureAwait(false); if (r.ExitCode != 0) { throw new GitException($"Git reference-transaction denied update: {r.OutputText} ({r.ErrorText})"); } } } if (allowContinue) { var signature = Repository.Configuration.Identity.AsRecord(); foreach (var v in Updates) { GitId? originalId = null; GitReference?rf = null; switch (v.Type) { case UpdateType.Create: using (var fs = new FileStream(Path.Combine(Repository.GitDirectory, v.TargetName), FileMode.CreateNew)) using (var sw = new StreamWriter(fs)) { await sw.WriteLineAsync(v.Id !.ToString()).ConfigureAwait(false); } break; case UpdateType.Update: rf = await _referenceRepository.GetAsync(v.Name).ConfigureAwait(false); if (rf is GitSymbolicReference sr) { rf = await sr.ResolveAsync().ConfigureAwait(false); v.TargetName = (rf as GitSymbolicReference)?.ReferenceName ?? rf.Name ?? v.Name; } originalId = rf?.Id; using (var fs = new FileStream(Path.Combine(Repository.GitDirectory, v.TargetName), FileMode.Create)) using (var sw = new StreamWriter(fs)) { fs.SetLength(0); await sw.WriteLineAsync(v.Id !.ToString()).ConfigureAwait(false); } break; case UpdateType.Delete: rf = await _referenceRepository.GetAsync(v.Name).ConfigureAwait(false); if (rf is GitSymbolicReference sr2) { rf = await sr2.ResolveAsync().ConfigureAwait(false); v.TargetName = rf.Name ?? v.Name; } originalId = rf?.Id; File.Delete(Path.Combine(Repository.GitDirectory, v.TargetName)); // If failed here, we need to cleanup packed references!! break; default: continue; } logRefUpdates ??= await Repository.Configuration.GetBoolAsync("core", "logallrefupdates").ConfigureAwait(false) ?? false; if (logRefUpdates == true && (GitReference.AllUpper(v.Name) || v.Name.StartsWith("refs/heads/", StringComparison.OrdinalIgnoreCase) || v.Name.StartsWith("refs/remotes/", StringComparison.OrdinalIgnoreCase) || v.Name.StartsWith("refs/notes/", StringComparison.OrdinalIgnoreCase))) { var log = new GitReferenceLogRecord { Original = originalId ?? Zero, Target = v.Id ?? Zero, Signature = signature, Reason = Reason }; await AppendLog(v.Name, log).ConfigureAwait(false); if (rf is not null && rf.Name != v.Name) { await AppendLog(rf.Name !, log).ConfigureAwait(false); } } } if (hookData is not null) { var hd = hookData; hookData = null; // Ignore errors await Repository.RunHookErrAsync("run", new[] { "committed" }, stdinText : hd, expectedResults : Array.Empty <int>()).ConfigureAwait(false); } } } catch when(hookData is not null) { // Ignore errors await Repository.RunHookErrAsync("run", new[] { "abort" }, stdinText : hookData, expectedResults : Array.Empty <int>()).ConfigureAwait(false); throw; } finally { unlock?.Invoke(); } }