public async void ShouldCheckoutBranchFromFork() { var gitClient = Substitute.For <IGitClient>(); var service = new PullRequestService( gitClient, MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo")); var pr = Substitute.For <IPullRequestModel>(); pr.Number.Returns(5); pr.Head.Returns(new GitReferenceModel("source", "owner:local", "123", "https://foo.bar/fork/repo.git")); await service.Checkout(localRepo, pr, "pr/5-fork-branch"); gitClient.Received().SetRemote(Arg.Any <IRepository>(), "fork", new Uri("https://foo.bar/fork/repo.git")).Forget(); gitClient.Received().Fetch(Arg.Any <IRepository>(), "fork").Forget(); gitClient.Received().Fetch(Arg.Any <IRepository>(), "fork", "source:pr/5-fork-branch").Forget(); gitClient.Received().Checkout(Arg.Any <IRepository>(), "pr/5-fork-branch").Forget(); gitClient.Received().SetTrackingBranch(Arg.Any <IRepository>(), "pr/5-fork-branch", "refs/remotes/fork/source").Forget(); gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.pr/5-fork-branch.ghfvs-pr", "5").Forget(); Assert.Equal(6, gitClient.ReceivedCalls().Count()); }
public void IsPullRequestMergedAsync_ShouldCallbackWithFalse_WhenResponseIsNotFound() { var mockResponse = new Mock <IGitHubResponse <object> >(MockBehavior.Strict); var mockClient = new Mock <IGitHubClient>(MockBehavior.Strict); mockResponse.Setup(r => r.ErrorException) .Returns(new Exception()); mockResponse.Setup(r => r.StatusCode) .Returns(HttpStatusCode.NotFound); mockClient.Setup(c => c.CallApiAsync <object>(It.IsAny <GitHubRequest>(), It.IsAny <Action <IGitHubResponse <object> > >(), It.IsAny <Action <GitHubException> >())) .Callback <GitHubRequest, Action <IGitHubResponse <object> >, Action <GitHubException> >((req, c, e) => { e(new GitHubException(mockResponse.Object, ErrorType.ResourceNotFound)); }) .Returns(TestHelpers.CreateTestHandle()); var pullReqSvc = new PullRequestService(mockClient.Object); var isMerged = true; pullReqSvc.IsPullRequestMergedAsync("akilb", "ngithub", 16, fl => isMerged = fl, e => { }); Assert.IsFalse(isMerged); }
public async Task ShouldCheckoutBranchFromFork() { var gitClient = MockGitClient(); var service = new PullRequestService( gitClient, MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo")); var pr = Substitute.For <IPullRequestModel>(); pr.Number.Returns(5); pr.Base.Returns(new GitReferenceModel("master", "owner:master", "123", "https://foo.bar/owner/repo.git")); pr.Head.Returns(new GitReferenceModel("prbranch", "fork:prbranch", "123", "https://foo.bar/fork/repo.git")); await service.Checkout(localRepo, pr, "pr/5-fork-branch"); gitClient.Received().SetRemote(Arg.Any <IRepository>(), "fork", new Uri("https://foo.bar/fork/repo.git")).Forget(); gitClient.Received().SetConfig(Arg.Any <IRepository>(), "remote.fork.created-by-ghfvs", "true").Forget(); gitClient.Received().Fetch(Arg.Any <IRepository>(), "fork").Forget(); gitClient.Received().Fetch(Arg.Any <IRepository>(), "fork", "prbranch:pr/5-fork-branch").Forget(); gitClient.Received().Checkout(Arg.Any <IRepository>(), "pr/5-fork-branch").Forget(); gitClient.Received().SetTrackingBranch(Arg.Any <IRepository>(), "pr/5-fork-branch", "refs/remotes/fork/prbranch").Forget(); gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.pr/5-fork-branch.ghfvs-pr-owner-number", "owner#5").Forget(); Assert.That(7, Is.EqualTo(gitClient.ReceivedCalls().Count())); }
public void IsPullRequestMergedAsync_ShouldCallbackWithError_WhenResponseIsSomeRandomError() { var mockResponse = new Mock <IGitHubResponse <object> >(MockBehavior.Strict); var mockClient = new Mock <IGitHubClient>(MockBehavior.Strict); mockResponse.Setup(r => r.ErrorException) .Returns(new Exception()); mockResponse.Setup(r => r.StatusCode) .Returns(HttpStatusCode.Forbidden); var expectedException = new GitHubException(mockResponse.Object, ErrorType.Unauthorized); mockClient.Setup(c => c.CallApiAsync <object>(It.IsAny <GitHubRequest>(), It.IsAny <Action <IGitHubResponse <object> > >(), It.IsAny <Action <GitHubException> >())) .Callback <GitHubRequest, Action <IGitHubResponse <object> >, Action <GitHubException> >((req, c, e) => { e(expectedException); }) .Returns(TestHelpers.CreateTestHandle()); var pullReqSvc = new PullRequestService(mockClient.Object); GitHubException actualException = null; pullReqSvc.IsPullRequestMergedAsync("akilb", "ngithub", 1, c => { }, e => actualException = e); Assert.AreSame(expectedException, actualException); }
static async Task <string> ExtractFile( string baseSha, object baseFileContent, string headSha, object headFileContent, string mergeBaseSha, object mergeBaseFileContent, string fileName, bool head, Encoding encoding, string repoDir = "repoDir", int pullNumber = 666, string baseRef = "baseRef", string headRef = "headRef") { var repositoryModel = Substitute.For <ILocalRepositoryModel>(); repositoryModel.LocalPath.Returns(repoDir); var pullRequest = Substitute.For <IPullRequestModel>(); pullRequest.Number.Returns(1); pullRequest.Base.Returns(new GitReferenceModel(baseRef, "label", baseSha, "uri")); pullRequest.Head.Returns(new GitReferenceModel("ref", "label", headSha, "uri")); var serviceProvider = Substitutes.ServiceProvider; var gitClient = MockGitClient(); var gitService = serviceProvider.GetGitService(); var service = new PullRequestService(gitClient, gitService, serviceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); gitClient.GetPullRequestMergeBase(Arg.Any <IRepository>(), Arg.Any <UriString>(), Arg.Any <UriString>(), baseSha, headSha, baseRef, headRef).ReturnsForAnyArgs(Task.FromResult(mergeBaseSha)); gitClient.ExtractFile(Arg.Any <IRepository>(), mergeBaseSha, fileName).Returns(GetFileTask(mergeBaseFileContent)); gitClient.ExtractFile(Arg.Any <IRepository>(), baseSha, fileName).Returns(GetFileTask(baseFileContent)); gitClient.ExtractFile(Arg.Any <IRepository>(), headSha, fileName).Returns(GetFileTask(headFileContent)); return(await service.ExtractFile(repositoryModel, pullRequest, fileName, head, encoding)); }
public async Task ShouldUseUniquelyNamedRemoteForFork() { var gitClient = MockGitClient(); var gitService = MockGitService(); var service = new PullRequestService( gitClient, gitService, Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo")); using (var repo = gitService.GetRepository(localRepo.CloneUrl)) { var remote = Substitute.For <Remote>(); var remoteCollection = Substitute.For <RemoteCollection>(); remoteCollection["fork"].Returns(remote); repo.Network.Remotes.Returns(remoteCollection); var pr = Substitute.For <IPullRequestModel>(); pr.Number.Returns(5); pr.Base.Returns(new GitReferenceModel("master", "owner:master", "123", "https://foo.bar/owner/repo.git")); pr.Head.Returns(new GitReferenceModel("prbranch", "fork:prbranch", "123", "https://foo.bar/fork/repo.git")); await service.Checkout(localRepo, pr, "pr/5-fork-branch"); gitClient.Received().SetRemote(Arg.Any <IRepository>(), "fork1", new Uri("https://foo.bar/fork/repo.git")).Forget(); gitClient.Received().SetConfig(Arg.Any <IRepository>(), "remote.fork1.created-by-ghfvs", "true").Forget(); } }
public async Task ReturnsErrorResultIfNoRepositoryFound() { var config = Options.Create( new WebConfiguration { PullRequestRepository = _pullRequestRepository }); var gitHubClientMock = new Mock <IGitHubClient>(); var gitHubClientFactoryMock = new Mock <IGitHubClientFactory>(); gitHubClientFactoryMock.Setup(x => x.CreateClient()) .Returns(gitHubClientMock.Object); gitHubClientMock.Setup(x => x.Repository.Get(It.IsAny <string>(), It.IsAny <string>())) .Throws <ApiException>(); var pullRequestService = new PullRequestService( config, Mock.Of <ISerializerFactory>(), gitHubClientFactoryMock.Object); var result = await pullRequestService.TryCreatePullRequestAsync( new Comment(string.Empty, string.Empty, string.Empty)) .ConfigureAwait(false); Assert.True(result.HasError); Assert.NotEmpty(result.Error); }
public async Task ShouldReturnMarkedBranchForPullRequestFromFork() { var repo = Substitute.For <IRepository>(); var config = Substitute.For <Configuration>(); var configEntry1 = Substitute.For <ConfigurationEntry <string> >(); configEntry1.Key.Returns("branch.pr/1-foo.ghfvs-pr"); configEntry1.Value.Returns("1"); var configEntry2 = Substitute.For <ConfigurationEntry <string> >(); configEntry2.Key.Returns("branch.pr/2-bar.ghfvs-pr"); configEntry2.Value.Returns("2"); config.GetEnumerator().Returns(new List <ConfigurationEntry <string> > { configEntry1, configEntry2, }.GetEnumerator()); repo.Config.Returns(config); var service = new PullRequestService( MockGitClient(), MockGitService(repo), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); var result = await service.GetLocalBranches(localRepo, CreatePullRequest(true)); Assert.Equal("pr/1-foo", result.Name); }
public async void ShouldCheckoutLocalBranch() { var gitClient = MockGitClient(); var service = new PullRequestService( gitClient, MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo")); var pr = Substitute.For <IPullRequestModel>(); pr.Number.Returns(5); pr.Base.Returns(new GitReferenceModel("master", "owner:master", "123", "https://foo.bar/owner/repo.git")); pr.Head.Returns(new GitReferenceModel("prbranch", "owner:prbranch", "123", "https://foo.bar/owner/repo")); await service.Checkout(localRepo, pr, "prbranch"); gitClient.Received().Fetch(Arg.Any <IRepository>(), "origin").Forget(); gitClient.Received().Checkout(Arg.Any <IRepository>(), "prbranch").Forget(); gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.prbranch.ghfvs-pr-owner-number", "owner#5").Forget(); Assert.Equal(4, gitClient.ReceivedCalls().Count()); }
public async Task CreatingPRs( string repoName, string sourceRepoOwner, string sourceBranchName, bool repoIsFork, bool sourceBranchIsTracking, string targetRepoOwner, string targetBranchName, string title, string body) { var remote = "origin"; var data = PrepareTestData(repoName, sourceRepoOwner, sourceBranchName, targetRepoOwner, targetBranchName, "origin", repoIsFork, sourceBranchIsTracking); var targetRepo = data.TargetRepo; var gitClient = data.GitClient; var l2repo = data.L2Repo; var activeRepo = data.ActiveRepo; var sourceBranch = data.SourceBranch; var targetBranch = data.TargetBranch; var ms = data.ModelService; var prservice = new PullRequestService(data.GitClient, data.GitService, data.ServiceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); prservice.GetPullRequestTemplate(data.ActiveRepo).Returns(Observable.Empty <string>()); var vm = new PullRequestCreationViewModel(data.RepositoryHost, data.ActiveRepo, prservice, data.NotificationService); vm.Initialize(); // the TargetBranch property gets set to whatever the repo default is (we assume master here), // so we only set it manually to emulate the user selecting a different target branch if (targetBranchName != "master") { vm.TargetBranch = new BranchModel(targetBranchName, targetRepo); } if (title != null) { vm.PRTitle = title; } // this is optional if (body != null) { vm.Description = body; } await vm.CreatePullRequest.ExecuteAsync(); var unused2 = gitClient.Received().Push(l2repo, sourceBranchName, remote); if (!sourceBranchIsTracking) { unused2 = gitClient.Received().SetTrackingBranch(l2repo, sourceBranchName, remote); } else { unused2 = gitClient.DidNotReceiveWithAnyArgs().SetTrackingBranch(Args.LibGit2Repo, Args.String, Args.String); } var unused = ms.Received().CreatePullRequest(activeRepo, targetRepo, sourceBranch, targetBranch, title ?? "Source branch", body ?? String.Empty); }
public void SetUp() { mockGitHubClient = new Mock <IGitHubClient>(); service = new PullRequestService() { GitHubClient = mockGitHubClient.Object }; }
public void TargetBranchDisplayNameIncludesRepoOwnerWhenFork() { var data = PrepareTestData("octokit.net", "shana", "master", "octokit", "master", "origin", true, true); var prservice = new PullRequestService(data.GitClient, data.GitService, data.ServiceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); prservice.GetPullRequestTemplate(data.ActiveRepo).Returns(Observable.Empty <string>()); var vm = new PullRequestCreationViewModel(data.RepositoryHost, data.ActiveRepo, prservice, data.NotificationService); Assert.Equal("octokit/master", vm.TargetBranch.DisplayName); }
public async Task TargetBranchDisplayNameIncludesRepoOwnerWhenForkAsync() { var data = PrepareTestData("octokit.net", "shana", "master", "octokit", "master", "origin", true, true); var prservice = new PullRequestService(data.GitClient, data.GitService, Substitute.For <IVSGitExt>(), Substitute.For <IGraphQLClientFactory>(), data.ServiceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); prservice.GetPullRequestTemplate(data.ActiveRepo).Returns(Observable.Empty <string>()); var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService); await vm.InitializeAsync(data.ActiveRepo, data.Connection); Assert.That("octokit/master", Is.EqualTo(vm.TargetBranch.DisplayName)); }
static PullRequestService CreatePullRequestService(Repository repo) { var repoDir = repo.Info.WorkingDirectory; var serviceProvider = Substitutes.ServiceProvider; var gitService = serviceProvider.GetGitService(); gitService.GetRepository(repoDir).Returns(repo); var service = new PullRequestService(Substitute.For <IGitClient>(), gitService, serviceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); return(service); }
public async Task ThrowsIfCommentIsNull() { var pullRequestService = new PullRequestService( Options.Create(new WebConfiguration()), Mock.Of <ISerializerFactory>(), Mock.Of <IGitHubClientFactory>()); await Assert.ThrowsAsync <ArgumentNullException>( () => pullRequestService.TryCreatePullRequestAsync(null !)) .ConfigureAwait(false); }
public async Task ShouldReturnCorrectDefaultLocalBranchName() { var service = new PullRequestService( Substitute.For <IGitClient>(), MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); var result = await service.GetDefaultLocalBranchName(localRepo, 123, "Pull requests can be \"named\" all sorts of thing's (sic)"); Assert.Equal("pr/123-pull-requests-can-be-named-all-sorts-of-thing-s-sic", result); }
public async Task DefaultLocalBranchNameShouldNotClashWithExistingBranchNames() { var service = new PullRequestService( Substitute.For <IGitClient>(), MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); var result = await service.GetDefaultLocalBranchName(localRepo, 123, "foo1"); Assert.Equal("pr/123-foo1-3", result); }
public async Task ShouldReturnCorrectDefaultLocalBranchNameForPullRequestsWithNonLatinChars() { var service = new PullRequestService( MockGitClient(), MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); var result = await service.GetDefaultLocalBranchName(localRepo, 123, "コードをレビューする準備ができたこと"); Assert.That("pr/123", Is.EqualTo(result)); }
public async Task ShouldRemoveUnusedRemote() { var gitClient = MockGitClient(); var gitService = MockGitService(); var service = new PullRequestService( gitClient, gitService, Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); localRepo.CloneUrl.Returns(new UriString("https://github.com/foo/bar")); using (var repo = gitService.GetRepository(localRepo.CloneUrl)) { var remote1 = Substitute.For <Remote>(); var remote2 = Substitute.For <Remote>(); var remote3 = Substitute.For <Remote>(); var remotes = new List <Remote> { remote1, remote2, remote3 }; var remoteCollection = Substitute.For <RemoteCollection>(); remote1.Name.Returns("remote1"); remote2.Name.Returns("remote2"); remote3.Name.Returns("remote3"); remoteCollection.GetEnumerator().Returns(_ => remotes.GetEnumerator()); repo.Network.Remotes.Returns(remoteCollection); var branch1 = Substitute.For <LibGit2Sharp.Branch>(); var branch2 = Substitute.For <LibGit2Sharp.Branch>(); var branches = new List <LibGit2Sharp.Branch> { branch1, branch2 }; var branchCollection = Substitute.For <BranchCollection>(); branch1.RemoteName.Returns("remote1"); branch2.RemoteName.Returns("remote1"); branchCollection.GetEnumerator().Returns(_ => branches.GetEnumerator()); repo.Branches.Returns(branchCollection); gitClient.GetConfig <bool>(Arg.Any <IRepository>(), "remote.remote1.created-by-ghfvs").Returns(Task.FromResult(true)); gitClient.GetConfig <bool>(Arg.Any <IRepository>(), "remote.remote2.created-by-ghfvs").Returns(Task.FromResult(true)); await service.RemoveUnusedRemotes(localRepo); remoteCollection.DidNotReceive().Remove("remote1"); remoteCollection.Received().Remove("remote2"); remoteCollection.DidNotReceive().Remove("remote3"); } }
public void CreatePullRequestAllArgsMandatory() { var serviceProvider = Substitutes.ServiceProvider; var gitService = serviceProvider.GetGitService(); var service = new PullRequestService( Substitute.For <IGitClient>(), serviceProvider.GetGitService(), Substitute.For <IVSGitExt>(), Substitute.For <IApiClientFactory>(), Substitute.For <IGraphQLClientFactory>(), serviceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); IModelService ms = null; LocalRepositoryModel sourceRepo = null; LocalRepositoryModel targetRepo = null; string title = null; string body = null; BranchModel source = null; BranchModel target = null; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); ms = Substitute.For <IModelService>(); Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); sourceRepo = new LocalRepositoryModel { Name = "name", CloneUrl = "http://github.com/github/stuff", LocalPath = "c:\\path" }; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); targetRepo = new LocalRepositoryModel { Name = "name", CloneUrl = "http://github.com/github/stuff", LocalPath = "c:\\path" }; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); title = "a title"; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); body = "a body"; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); source = new BranchModel("source", sourceRepo); Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); target = new BranchModel("target", targetRepo); var pr = service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body); Assert.NotNull(pr); }
public async Task ShouldReturnPullRequestBranchForPullRequestFromSameRepository() { var service = new PullRequestService( Substitute.For <IGitClient>(), MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); localRepo.CloneUrl.Returns(new UriString("https://github.com/foo/bar")); var result = await service.GetLocalBranches(localRepo, CreatePullRequest()); Assert.Equal("source", result.Name); }
public async void ShouldCheckoutExistingBranch() { var gitClient = Substitute.For <IGitClient>(); var service = new PullRequestService( gitClient, MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); var pr = Substitute.For <IPullRequestModel>(); await service.Checkout(localRepo, pr, "pr/123-foo1"); gitClient.Received().Checkout(Arg.Any <IRepository>(), "pr/123-foo1").Forget(); Assert.Equal(1, gitClient.ReceivedCalls().Count()); }
public async Task ReturnsEmptyResultIfSuccess() { var comment = new Comment("test-post-id", "This is a test message", "John Doe"); var config = Options.Create( new WebConfiguration { PullRequestRepository = _pullRequestRepository, Website = "http://www.example.com", FallbackCommitEmail = "*****@*****.**" }); var gitHubClientMock = new Mock <IGitHubClient>(); gitHubClientMock.Setup(x => x.Repository.Get(It.IsAny <string>(), It.IsAny <string>())) .ReturnsAsync(new Repository()); gitHubClientMock.Setup(x => x.Repository.Branch.Get(It.IsAny <long>(), It.IsAny <string>())) .ReturnsAsync(new Branch("TestBranch", new GitReference("nodeId", "url", "label", "ref", "sha", new User(), new Repository()), false)); gitHubClientMock.Setup(x => x.Git.Reference.Create(It.IsAny <long>(), It.IsAny <NewReference>())) .ReturnsAsync(new Reference("ref", "nodeId", "url", new TagObject())); gitHubClientMock.Setup(x => x.Repository.Content.CreateFile(It.IsAny <long>(), It.IsAny <string>(), It.IsAny <CreateFileRequest>())) .ReturnsAsync(new RepositoryContentChangeSet()); gitHubClientMock.Setup(x => x.Repository.PullRequest.Create(It.IsAny <long>(), It.IsAny <NewPullRequest>())) .ReturnsAsync(new PullRequest()); var gitHubClientFactoryMock = new Mock <IGitHubClientFactory>(); gitHubClientFactoryMock.Setup(x => x.CreateClient()) .Returns(gitHubClientMock.Object); var serializerMock = new Mock <ISerializer>(); serializerMock.Setup(x => x.Serialize(It.IsAny <object>())) .Returns(comment.Message); var serializerFactoryMock = new Mock <ISerializerFactory>(); serializerFactoryMock.Setup(x => x.BuildSerializer()).Returns(serializerMock.Object); var pullRequestService = new PullRequestService( config, serializerFactoryMock.Object, gitHubClientFactoryMock.Object); var result = await pullRequestService.TryCreatePullRequestAsync(comment).ConfigureAwait(false); Assert.False(result.HasError); }
public async Task ShouldCheckoutExistingBranch() { var gitClient = MockGitClient(); var service = new PullRequestService( gitClient, MockGitService(), Substitute.For <IOperatingSystem>(), Substitute.For <IUsageTracker>()); var localRepo = Substitute.For <ILocalRepositoryModel>(); var pr = Substitute.For <IPullRequestModel>(); pr.Number.Returns(4); pr.Base.Returns(new GitReferenceModel("master", "owner:master", "123", "https://foo.bar/owner/repo.git")); await service.Checkout(localRepo, pr, "pr/123-foo1"); gitClient.Received().Checkout(Arg.Any <IRepository>(), "pr/123-foo1").Forget(); gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.pr/123-foo1.ghfvs-pr-owner-number", "owner#4").Forget(); Assert.That(2, Is.EqualTo(gitClient.ReceivedCalls().Count())); }
public void CreatePullRequestAllArgsMandatory() { var serviceProvider = Substitutes.ServiceProvider; var gitService = serviceProvider.GetGitService(); var service = new PullRequestService(Substitute.For <IGitClient>(), serviceProvider.GetGitService(), serviceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); IModelService ms = null; ILocalRepositoryModel sourceRepo = null; ILocalRepositoryModel targetRepo = null; string title = null; string body = null; IBranch source = null; IBranch target = null; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); ms = Substitute.For <IModelService>(); Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); sourceRepo = new LocalRepositoryModel("name", new GitHub.Primitives.UriString("http://github.com/github/stuff"), "c:\\path", gitService); Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); targetRepo = new LocalRepositoryModel("name", new GitHub.Primitives.UriString("http://github.com/github/stuff"), "c:\\path", gitService); Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); title = "a title"; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); body = "a body"; Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); source = new BranchModel("source", sourceRepo); Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body)); target = new BranchModel("target", targetRepo); var pr = service.CreatePullRequest(ms, sourceRepo, targetRepo, source, target, title, body); Assert.NotNull(pr); }
public async Task CreatingPRsAsync( string repoName, string sourceRepoOwner, string sourceBranchName, bool repoIsFork, bool sourceBranchIsTracking, string targetRepoOwner, string targetBranchName, string title, string body) { var remote = "origin"; var data = PrepareTestData(repoName, sourceRepoOwner, sourceBranchName, targetRepoOwner, targetBranchName, "origin", repoIsFork, sourceBranchIsTracking); var targetRepo = data.TargetRepo; var gitClient = data.GitClient; var l2repo = data.L2Repo; var activeRepo = data.ActiveRepo; var sourceBranch = data.SourceBranch; var targetBranch = data.TargetBranch; var ms = data.ModelService; var prservice = new PullRequestService(data.GitClient, data.GitService, Substitute.For <IVSGitExt>(), Substitute.For <IGraphQLClientFactory>(), data.ServiceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>()); var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService, Substitute.For <IMessageDraftStore>(), data.GitService); await vm.InitializeAsync(data.ActiveRepo, data.Connection); // the TargetBranch property gets set to whatever the repo default is (we assume master here), // so we only set it manually to emulate the user selecting a different target branch if (targetBranchName != "master") { vm.TargetBranch = new BranchModel(targetBranchName, targetRepo); } if (title != null) { vm.PRTitle = title; } // this is optional if (body != null) { vm.Description = body; } ms.CreatePullRequest(activeRepo, targetRepo, sourceBranch, targetBranch, Arg.Any <string>(), Arg.Any <string>()) .Returns(x => { var pr = Substitute.For <IPullRequestModel>(); pr.Base.Returns(new GitReferenceModel("ref", "label", "sha", "https://clone.url")); return(Observable.Return(pr)); }); await vm.CreatePullRequest.Execute(); var unused2 = gitClient.Received().Push(l2repo, sourceBranchName, remote); if (!sourceBranchIsTracking) { unused2 = gitClient.Received().SetTrackingBranch(l2repo, sourceBranchName, remote); } else { unused2 = gitClient.DidNotReceiveWithAnyArgs().SetTrackingBranch(Args.LibGit2Repo, Args.String, Args.String); } var unused = ms.Received().CreatePullRequest(activeRepo, targetRepo, sourceBranch, targetBranch, title ?? "Source branch", body ?? String.Empty); }
public List <PullRequestsInPeriod> GetGroupedPullRequestData(DateTime fromDate, DateTime toDate, string repository = "Umbraco-CMS") { var pullRequestService = new PullRequestService(); var pullsNonHq = pullRequestService.GetPullsNonHq(repository); var mergedPullsInPeriod = pullsNonHq .Where(x => x.MergedAt != null && x.MergedAt > fromDate && x.MergedAt <= toDate) .OrderBy(x => x.MergedAt) .GroupBy(x => new { x.MergedAt.Value.Year, x.MergedAt.Value.Month }) .ToDictionary(x => x.Key, x => x.ToList()); var closedPullsInPeriod = pullsNonHq .Where(x => x.ClosedAt != null && x.ClosedAt > fromDate && x.ClosedAt <= toDate) .OrderBy(x => x.ClosedAt) .GroupBy(x => new { x.ClosedAt.Value.Year, x.ClosedAt.Value.Month }) .ToDictionary(x => x.Key, x => x.ToList()); var createdPullsInPeriod = pullsNonHq .Where(x => x.CreatedAt != null && x.CreatedAt > fromDate && x.CreatedAt <= toDate) .OrderBy(x => x.CreatedAt) .GroupBy(x => new { x.CreatedAt.Value.Year, x.CreatedAt.Value.Month }) .ToDictionary(x => x.Key, x => x.ToList()); var firstPrs = new List <FirstPullRequest>(); foreach (var pr in pullsNonHq) { if (pr.MergedAt != null && firstPrs.Any(x => x.Username == pr.User.Login) == false) { firstPrs.Add(new FirstPullRequest { Username = pr.User.Login, Year = pr.MergedAt.Value.Year, Month = pr.MergedAt.Value.Month }); } } var groupedPrs = new List <PullRequestsInPeriod>(); foreach (var prInPeriod in mergedPullsInPeriod) { var recentPrsMerged = 0; var totalMergeTimeInHours = 0; var totalMergedOnTime = 0; var totalMergedNotOnTime = 0; foreach (var pr in prInPeriod.Value) { var mergeTimeInHours = Convert.ToInt32(pr.MergedAt.Value.Subtract(pr.CreatedAt.Value).TotalHours); var mergeTimeInDays = Convert.ToInt32(pr.MergedAt.Value.Subtract(pr.CreatedAt.Value).TotalDays); if (pr.CreatedAt >= new DateTime(2018, 01, 01)) { recentPrsMerged = recentPrsMerged + 1; totalMergeTimeInHours = totalMergeTimeInHours + mergeTimeInHours; } if (mergeTimeInDays <= 30) { totalMergedOnTime = totalMergedOnTime + 1; } else { totalMergedNotOnTime = totalMergedNotOnTime + 1; } } var period = $"{prInPeriod.Key.Year}{prInPeriod.Key.Month:00}"; var mergedPrs = new PullRequestsInPeriod { MonthYear = period, NumberMerged = prInPeriod.Value.Count, }; var firstPrsUsernames = new List <string>(); foreach (var firstPr in firstPrs) { if (firstPr.Year == prInPeriod.Key.Year && firstPr.Month == prInPeriod.Key.Month) { firstPrsUsernames.Add(firstPr.Username); } } mergedPrs.NewContributors = firstPrsUsernames; mergedPrs.NumberOfNewContributors = firstPrsUsernames.Count; mergedPrs.NumberMergedInThirtyDays = totalMergedOnTime; mergedPrs.NumberNotMergedInThirtyDays = totalMergedNotOnTime; mergedPrs.NumberMergedRecent = recentPrsMerged; mergedPrs.TotalMergeTimeInHours = totalMergeTimeInHours; var averageMergeTime = 0; if (recentPrsMerged > 0) { averageMergeTime = Convert.ToInt32(mergedPrs.TotalMergeTimeInHours / recentPrsMerged); } mergedPrs.AveragePullRequestClosingTimeInHours = averageMergeTime; groupedPrs.Add(mergedPrs); } foreach (var prInPeriod in closedPullsInPeriod) { var period = $"{prInPeriod.Key.Year}{prInPeriod.Key.Month:00}"; var prs = new PullRequestsInPeriod(); if (groupedPrs.Any(x => x.MonthYear == period)) { prs = groupedPrs.First(x => x.MonthYear == period); } else { prs.MonthYear = period; } prs.NumberClosed = prInPeriod.Value.Count - prs.NumberMerged; } foreach (var prInPeriod in createdPullsInPeriod) { var period = $"{prInPeriod.Key.Year}{prInPeriod.Key.Month:00}"; var prs = new PullRequestsInPeriod(); if (groupedPrs.Any(x => x.MonthYear == period)) { prs = groupedPrs.First(x => x.MonthYear == period); } else { prs.MonthYear = period; } prs.NumberCreated = prInPeriod.Value.Count; } foreach (var pullRequestsInPeriod in groupedPrs) { var currentYear = int.Parse(pullRequestsInPeriod.MonthYear.Substring(0, 4)); var currentMonth = int.Parse(pullRequestsInPeriod.MonthYear.Substring(4)); var lastDayInMonth = DateTime.DaysInMonth(currentYear, currentMonth); var maxDateInPeriod = new DateTime(currentYear, currentMonth, lastDayInMonth, 23, 59, 59); var openPrsForPeriod = new List <GithubPullRequestModel>(); // if the PR was created in or before this period and is not closed or merged IN this period then it counts as open for this period var pullsCreatedBeforePeriod = pullsNonHq.Where(x => x.CreatedAt.Value <= maxDateInPeriod).OrderBy(x => x.CreatedAt); foreach (var pr in pullsCreatedBeforePeriod) { if (pr.ClosedAt == null) { openPrsForPeriod.Add(pr); } else // Was it closed (merged items also get set as closed) after the current period? Then it's stil open for this period. if (pr.ClosedAt != null && pr.ClosedAt > maxDateInPeriod) { openPrsForPeriod.Add(pr); } } pullRequestsInPeriod.TotalNumberOpen = openPrsForPeriod.Count; foreach (var githubPullRequestModel in openPrsForPeriod) { if (githubPullRequestModel.CreatedAt > DateTime.Parse("2018-05-25") && githubPullRequestModel.MergedAt == null || githubPullRequestModel.MergedAt == DateTime.MinValue) { pullRequestsInPeriod.TotalNumberOpenAfterCodeGarden18 = pullRequestsInPeriod.TotalNumberOpenAfterCodeGarden18 + 1; } } var activeContributors = new List <string>(); foreach (var pr in pullsNonHq) { var startDate = maxDateInPeriod.AddYears(-1).AddMonths(-1).AddDays(1); if (pr.CreatedAt <= maxDateInPeriod && pr.CreatedAt >= startDate) { if (activeContributors.Any(x => x == pr.User.Login) == false) { activeContributors.Add(pr.User.Login); } } } pullRequestsInPeriod.NumberOfActiveContributorsInPastYear = activeContributors.Count; pullRequestsInPeriod.TotalNumberOfContributors = firstPrs.Count; } groupedPrs = groupedPrs.OrderBy(x => x.MonthYear).ToList(); var firstPrDate = groupedPrs.First().MonthYear.DateFromMonthYear(); var lastPrDate = groupedPrs.Last().MonthYear.DateFromMonthYear(); var numberOfMonths = firstPrDate.MonthsBetween(lastPrDate); var periodRange = new List <string>(); var periodDate = firstPrDate; for (var i = 0; i < numberOfMonths; i++) { var period = $"{periodDate.Year}{periodDate.Month:00}"; periodRange.Add(period); periodDate = periodDate.AddMonths(1); } foreach (var period in periodRange) { if (groupedPrs.Any(x => x.MonthYear == period)) { continue; } var dateTime = period.DateFromMonthYear(); PullRequestsInPeriod previousPrStats = null; var previousMonth = dateTime.AddMonths(-1); if (previousMonth >= fromDate) { previousPrStats = GetPreviousPrStatsInPeriod(previousMonth, groupedPrs); } if (previousPrStats == null) { var groupName = $"{DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(dateTime.Month)} {dateTime.Year}"; groupedPrs.Add(new PullRequestsInPeriod { GroupName = groupName, MonthYear = period }); } else { var groupName = $"{DateTimeFormatInfo.CurrentInfo.GetAbbreviatedMonthName(dateTime.Month)} {dateTime.Year}"; groupedPrs.Add(new PullRequestsInPeriod { GroupName = groupName, MonthYear = period, NumberOfActiveContributorsInPastYear = previousPrStats.NumberOfActiveContributorsInPastYear, TotalNumberOfContributors = previousPrStats.TotalNumberOfContributors, TotalNumberOpen = previousPrStats.TotalNumberOpen, TotalNumberOpenAfterCodeGarden18 = previousPrStats.TotalNumberOpenAfterCodeGarden18 }); } } return(groupedPrs.OrderBy(x => x.MonthYear).ToList()); }
public DevOpsPrController(PullRequestService prService, SettingsConfiguration settings) { _prService = prService; _settingsConfiguration = settings; }
public async Task ActivateAsync_NotActivated_ShouldCreateServiceHooksAndConfiguration() { var collectionId = Guid.NewGuid().ToString(); var projectId = Guid.NewGuid().ToString(); var repositoryId = Guid.NewGuid().ToString(); var statusPolicyName = "test-status-policy"; var configuration = new AccountConfiguration { BaseUrl = "https://fabrikam.visualstudio.com/DefaultCollection", CollectionId = collectionId }; var serviceHookId1 = Guid.NewGuid(); var serviceHookId2 = Guid.NewGuid(); var serviceHookClientMock = new Mock <ServiceHooksPublisherHttpClient>(new object[] { new Uri("https://fabrikam.visualstudio.com/DefaultCollection"), (VssCredentials) new VssBasicCredential() }); serviceHookClientMock .SetupSequence(m => m.CreateSubscriptionAsync(It.IsAny <Subscription>(), It.IsAny <object>())) .ReturnsAsync(new Subscription { Id = serviceHookId1 }) .ReturnsAsync(new Subscription { Id = serviceHookId2 }); var configurationRepositoryMock = new Mock <IConfigurationRepository>(); configurationRepositoryMock .Setup(m => m.GetAsync(collectionId)) .ReturnsAsync(configuration); var connectionFactoryMock = new Mock <IVssConnectionFactory>(); connectionFactoryMock .Setup(m => m.CreateFactory(It.IsAny <Uri>(), It.IsAny <VssCredentials>())) .Returns(connectionFactoryMock.Object); connectionFactoryMock .Setup(m => m.GetClientAsync <ServiceHooksPublisherHttpClient>()) .ReturnsAsync(serviceHookClientMock.Object); var statusPoliciesMock = new Mock <IStatusPoliciesService>(); var pullRequestService = new PullRequestService( new Uri("https://aitpullrequests.azurewebsites.net/"), connectionFactoryMock.Object, statusPoliciesMock.Object, configurationRepositoryMock.Object); await pullRequestService.ActivateStatusPolicyAsync(collectionId, projectId, repositoryId, statusPolicyName); configurationRepositoryMock .Verify(m => m.GetAsync(collectionId), Times.Once); serviceHookClientMock .Verify(m => m.CreateSubscriptionAsync(It.IsAny <Subscription>(), It.IsAny <object>()), Times.Exactly(2)); configurationRepositoryMock .Verify(m => m.UpdateAsync( It.Is <AccountConfiguration>(c => c.GetServiceHookIds(projectId).First() == serviceHookId1.ToString() && c.GetServiceHookIds(projectId).Last() == serviceHookId2.ToString())), Times.Once); }
public async Task EvaluateAsync_WithDisabledPolicy_ShouldNotEvaluatePolicy() { var pullRequestUpdate = new PullRequestUpdate { Id = 5, CollectionId = Guid.NewGuid().ToString(), ProjectId = Guid.NewGuid().ToString(), RepositoryId = Guid.NewGuid().ToString() }; var accountConfiguration = new AccountConfiguration { CollectionId = pullRequestUpdate.CollectionId, BaseUrl = "https://fabrikam.visualstudio.com/DefaultCollection", PersonalAccessToken = "SECRET!!" }; var pullRequest = new GitPullRequest(); var gitClientMock = new Mock <GitHttpClient>(new object[] { new Uri("https://fabrikam.visualstudio.com/DefaultCollection"), (VssCredentials) new VssBasicCredential() }); gitClientMock.Setup(m => m.GetPullRequestAsync(It.IsAny <string>(), It.IsAny <int>(), It.IsAny <int?>(), It.IsAny <int?>(), It.IsAny <int?>(), It.IsAny <bool?>(), It.IsAny <bool?>(), It.IsAny <object>(), It.IsAny <CancellationToken>())) .ReturnsAsync(pullRequest); var connectionFactoryMock = new Mock <IVssConnectionFactory>(); connectionFactoryMock.Setup(m => m.CreateFactory(It.IsAny <Uri>(), It.IsAny <VssCredentials>())) .Returns(connectionFactoryMock.Object); connectionFactoryMock.Setup(m => m.GetClientAsync <GitHttpClient>()) .ReturnsAsync(gitClientMock.Object); var testPolicyMock = new Mock <StatusPolicy>(new object[] { connectionFactoryMock.Object }); testPolicyMock.Setup(m => m.EvaluateAsync(It.IsAny <GitPullRequest>())); const string policyName = "TestPolicy"; var statusPoliciesServiceMock = new Mock <IStatusPoliciesService>(); statusPoliciesServiceMock.Setup(m => m.GetPolicies()) .Returns(new string[] { policyName }); statusPoliciesServiceMock.Setup(m => m.GetPolicy(It.IsAny <IVssConnectionFactory>(), It.IsAny <string>())) .Returns(testPolicyMock.Object); var configurationRepositoryMock = new Mock <IConfigurationRepository>(); configurationRepositoryMock.Setup(m => m.GetAsync(It.IsAny <string>())) .ReturnsAsync(accountConfiguration); var pullRequestService = new PullRequestService( new Uri("https://aitpullrequests.azurewebsites.net/"), connectionFactoryMock.Object, statusPoliciesServiceMock.Object, configurationRepositoryMock.Object); await pullRequestService.EvaluateAsync(pullRequestUpdate); configurationRepositoryMock.Verify(m => m.GetAsync(pullRequestUpdate.CollectionId), Times.Once); connectionFactoryMock.Verify(m => m.CreateFactory(new Uri(accountConfiguration.BaseUrl), It.IsAny <VssCredentials>()), Times.Once); gitClientMock.Verify(m => m.GetPullRequestAsync(pullRequestUpdate.RepositoryId, pullRequestUpdate.Id, It.IsAny <int?>(), It.IsAny <int?>(), It.IsAny <int?>(), It.IsAny <bool?>(), It.IsAny <bool?>(), It.IsAny <object>(), It.IsAny <CancellationToken>()), Times.Once); statusPoliciesServiceMock.Verify(m => m.GetPolicies(), Times.Once); statusPoliciesServiceMock.Verify(m => m.GetPolicy(connectionFactoryMock.Object, policyName), Times.Never); testPolicyMock.Verify(m => m.EvaluateAsync(pullRequest), Times.Never); }