/// <summary> /// Creates a new commit. /// </summary> private async Task <Octokit.Commit> CreateCommitAsync( GitHubRepository repository, string commitMessage, IList <IArchiveFile> fileContents, Octokit.Commit parentCommit) { var newTreeResponse = await RetryGitHubOperationIfNeededAsync ( async() => await _client.Git.Tree.Create ( repository.Owner, repository.Name, await GetTreeToPushAsync ( repository, fileContents, parentCommit?.Tree?.Sha ) ) ); return(await RetryGitHubOperationIfNeededAsync ( () => _client.Git.Commit.Create ( repository.Owner, repository.Name, parentCommit != null ? new NewCommit(commitMessage, newTreeResponse.Sha, parentCommit.Sha) : new NewCommit(commitMessage, newTreeResponse.Sha) ) )); }
/// <summary> /// Adds a push webhook for the repository. /// </summary> public Task EnsurePushWebhookAsync(GitHubRepository repository, string url) { return(RetryGitHubOperationIfNeededAsync ( async() => { var webhooks = await _client.Repository.Hooks.GetAll ( repository.Owner, repository.Name ); if (!webhooks.Any(webhook => webhook.Config["url"] == url)) { await RetryGitHubOperationIfNeededAsync ( () => _client.Repository.Hooks.Create ( repository.Owner, repository.Name, new NewRepositoryHook ( "web", new Dictionary <string, string>() { { "url", url }, { "content_type", "json" }, { "secret", _webhookSecret.Value }, { "insecure_ssl", "0" } } ) { Active = true, Events = new[] { "push" } } ) ); webhooks = await _client.Repository.Hooks.GetAll ( repository.Owner, repository.Name ); if (!webhooks.Any(webhook => webhook.Config["url"] == url)) { throw new ApiException ( $"Webhook not found for repository {repository.Name}", HttpStatusCode.NotFound ); } } return true; } )); }
/// <summary> /// Overwrites an existing repository with an existing archive. /// All existing commits will be erased, and the repository will /// be populated with two commits. /// </summary> public async Task OverwriteRepositoryAsync( GitHubRepository repository, string commitMessage, IArchive contents, Func <IArchiveFile, bool> includeFile, Func <IArchiveFile, bool> includeInFirstCommit) { var firstBatch = contents.Files .Where(file => includeFile(file) && includeInFirstCommit(file)) .ToList(); Commit firstCommit = null; if (firstBatch.Count > 0) { firstCommit = await RetryGitHubOperationIfNeededAsync ( () => CreateCommitAsync ( repository, $"{commitMessage}: Part 1", firstBatch, parentCommit : null ) ); } var secondBatch = contents.Files .Where(file => includeFile(file) && !includeInFirstCommit(file)) .ToList(); var starterCommit = await RetryGitHubOperationIfNeededAsync ( () => CreateCommitAsync ( repository, firstCommit != null ? $"{commitMessage}: Part 2" : commitMessage, secondBatch, firstCommit ) ); await RetryGitHubOperationIfNeededAsync ( () => _client.Git.Reference.Update ( repository.Owner, repository.Name, "heads/master", new ReferenceUpdate(starterCommit.Sha, force: true) ) ); }
/// <summary> /// Returns a list of push events for the given project. /// </summary> private async Task<StudentRepoPushEvents> GetAllPushEventsAsync( ClassroomMembership student, GitHubRepository repository) { var pushEvents = await _repoClient.GetPushEventsAsync ( repository.Owner, repository.Name ); return new StudentRepoPushEvents(student, pushEvents); }
/// <summary> /// Creates a new project tree. /// </summary> private async Task <NewTree> GetTreeToPushAsync( GitHubRepository repository, IList <IArchiveFile> fileContents, string baseTreeSha) { NewTree newTree = new NewTree() { BaseTree = baseTreeSha }; foreach (var entry in fileContents) { var newTreeItem = new NewTreeItem() { Path = entry.FullPath, Mode = "100644" /*blob*/, Type = TreeType.Blob }; if (entry.Ascii) { newTreeItem.Content = entry.GetEncodedData(); } else { var blobRef = await RetryGitHubOperationIfNeededAsync ( () => _client.Git.Blob.Create ( repository.Owner, repository.Name, new NewBlob() { Encoding = EncodingType.Base64, Content = entry.GetEncodedData() } ) ); newTreeItem.Sha = blobRef.Sha; } newTree.Tree.Add(newTreeItem); } return(newTree); }
/// <summary> /// Ensures that the webhook is present for the repository. /// </summary> private async Task<bool> EnsureWebHookPresentAsync( GitHubRepository repo, string webhookUrl) { try { await _repoClient.EnsurePushWebhookAsync(repo, webhookUrl); return true; } catch (Exception ex) { _logger.LogError(0, ex, "Exception ensuring that webhook is present for {orgName}/{repoName}", repo.Owner, repo.Name); return false; } }
/// <summary> /// Sets up CreateRepositoryAsync. /// </summary> private static void SetupCreateRepositoryAsync( Mock<IGitHubRepositoryClient> repoClient) { var repo = new GitHubRepository(1, "GitHubUser", "Project1_LastNameFirstName"); repoClient .Setup(GetCreateRepositoryExpression()) .ReturnsAsync(repo); }
/// <summary> /// Sets up GetAllRepositoriesAsync. /// </summary> private static void SetupGetAllRepositoriesAsync( Mock<IGitHubRepositoryClient> repoClient, bool existingStudentRepo) { var repo = new GitHubRepository(1, "GitHubUser", "Project1_LastNameFirstName"); repoClient .Setup(rc => rc.GetAllRepositoriesAsync("Class1GitHubOrg")) .ReturnsAsync ( existingStudentRepo ? Collections.CreateList(repo) : new List<GitHubRepository>() ); }