diff --git a/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs b/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs index e6b77d3fae..96a1bd3fa2 100644 --- a/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs +++ b/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs @@ -111,7 +111,7 @@ public IObservable GetAllForRepository(string owner, string name, A Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); Ensure.ArgumentNotNull(options, nameof(options)); - return _connection.GetAndFlattenAllPages(ApiUrls.PullRequests(owner, name), options); + return _connection.GetAndFlattenAllPages(ApiUrls.PullRequests(owner, name), null, AcceptHeaders.DraftPullRequestApiPreview, options); } /// @@ -126,7 +126,7 @@ public IObservable GetAllForRepository(long repositoryId, ApiOption { Ensure.ArgumentNotNull(options, nameof(options)); - return _connection.GetAndFlattenAllPages(ApiUrls.PullRequests(repositoryId), options); + return _connection.GetAndFlattenAllPages(ApiUrls.PullRequests(repositoryId), null, AcceptHeaders.DraftPullRequestApiPreview, options); } /// @@ -180,7 +180,7 @@ public IObservable GetAllForRepository(string owner, string name, P Ensure.ArgumentNotNull(options, nameof(options)); return _connection.GetAndFlattenAllPages(ApiUrls.PullRequests(owner, name), - request.ToParametersDictionary(), options); + request.ToParametersDictionary(), AcceptHeaders.DraftPullRequestApiPreview, options); } /// @@ -198,7 +198,7 @@ public IObservable GetAllForRepository(long repositoryId, PullReque Ensure.ArgumentNotNull(options, nameof(options)); return _connection.GetAndFlattenAllPages(ApiUrls.PullRequests(repositoryId), - request.ToParametersDictionary(), options); + request.ToParametersDictionary(), AcceptHeaders.DraftPullRequestApiPreview, options); } /// diff --git a/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs b/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs index b8a18936c1..046c9734dc 100644 --- a/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs @@ -38,6 +38,17 @@ public async Task CanCreate() Assert.Equal("a pull request", result.Title); } + [IntegrationTest] + public async Task CanCreateDraft() + { + await CreateTheWorld(); + + var newPullRequest = new NewPullRequest("a draft pull request", branchName, "master") { Draft = true }; + var result = await _fixture.Create(Helper.UserName, _context.RepositoryName, newPullRequest); + Assert.Equal("a draft pull request", result.Title); + Assert.True(result.Draft); + } + [IntegrationTest] public async Task CanCreateWithRepositoryId() { @@ -48,6 +59,17 @@ public async Task CanCreateWithRepositoryId() Assert.Equal("a pull request", result.Title); } + [IntegrationTest] + public async Task CanCreateDraftWithRepositoryId() + { + await CreateTheWorld(); + + var newPullRequest = new NewPullRequest("a draft pull request", branchName, "master") { Draft = true }; + var result = await _fixture.Create(_context.Repository.Id, newPullRequest); + Assert.Equal("a draft pull request", result.Title); + Assert.True(result.Draft); + } + [IntegrationTest] public async Task CanGetForRepository() { @@ -63,6 +85,22 @@ public async Task CanGetForRepository() Assert.True(pullRequests[0].Id > 0); } + [IntegrationTest] + public async Task CanGetDraftForRepository() + { + await CreateTheWorld(); + + var newPullRequest = new NewPullRequest("a draft pull request", branchName, "master") { Draft = true }; + var result = await _fixture.Create(Helper.UserName, _context.RepositoryName, newPullRequest); + + var pullRequests = await _fixture.GetAllForRepository(Helper.UserName, _context.RepositoryName); + + Assert.Equal(1, pullRequests.Count); + Assert.Equal(result.Title, pullRequests[0].Title); + Assert.Equal(result.Draft, pullRequests[0].Draft); + Assert.True(pullRequests[0].Id > 0); + } + [IntegrationTest] public async Task CanGetForRepositoryWithRepositoryId() { @@ -77,6 +115,22 @@ public async Task CanGetForRepositoryWithRepositoryId() Assert.Equal(result.Title, pullRequests[0].Title); } + [IntegrationTest] + public async Task CanGetDraftForRepositoryWithRepositoryId() + { + await CreateTheWorld(); + + var newPullRequest = new NewPullRequest("a draft pull request", branchName, "master") { Draft = true }; + var result = await _fixture.Create(_context.Repository.Id, newPullRequest); + + var pullRequests = await _fixture.GetAllForRepository(_context.Repository.Id); + + Assert.Equal(1, pullRequests.Count); + Assert.Equal(result.Title, pullRequests[0].Title); + Assert.Equal(result.Draft, pullRequests[0].Draft); + Assert.True(pullRequests[0].Id > 0); + } + [IntegrationTest] public async Task CanGetWithAssigneesForRepository() { diff --git a/Octokit.Tests/Clients/PullRequestsClientTests.cs b/Octokit.Tests/Clients/PullRequestsClientTests.cs index f30d2e89ca..fe0a411905 100644 --- a/Octokit.Tests/Clients/PullRequestsClientTests.cs +++ b/Octokit.Tests/Clients/PullRequestsClientTests.cs @@ -18,7 +18,7 @@ public async Task RequestsCorrectUrl() await client.Get("fake", "repo", 42); - connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls/42")); + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls/42"), Arg.Any>(), "application/vnd.github.shadow-cat-preview+json"); } [Fact] @@ -29,7 +29,7 @@ public async Task RequestsCorrectUrlWithRepositoryId() await client.Get(1, 42); - connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/pulls/42")); + connection.Received().Get(Arg.Is(u => u.ToString() == "repositories/1/pulls/42"), Arg.Any>(), "application/vnd.github.shadow-cat-preview+json"); } [Fact] @@ -56,7 +56,7 @@ public async Task RequestsCorrectUrl() await client.GetAllForRepository("fake", "repo"); connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls"), - Arg.Any>(), Args.ApiOptions); + Arg.Any>(), "application/vnd.github.shadow-cat-preview+json", Args.ApiOptions); } [Fact] @@ -68,7 +68,7 @@ public async Task RequestsCorrectUrlWithRepositoryId() await client.GetAllForRepository(1); connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/pulls"), - Arg.Any>(), Args.ApiOptions); + Arg.Any>(), "application/vnd.github.shadow-cat-preview+json", Args.ApiOptions); } [Fact] @@ -87,7 +87,7 @@ public async Task RequestsCorrectUrlWithApiOptions() await client.GetAllForRepository("fake", "repo", options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls"), - Arg.Any>(), options); + Arg.Any>(), "application/vnd.github.shadow-cat-preview+json", options); } [Fact] @@ -106,7 +106,7 @@ public async Task RequestsCorrectUrlWithApiOptionsWithRepositoryId() await client.GetAllForRepository(1, options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/pulls"), - Arg.Any>(), options); + Arg.Any>(), "application/vnd.github.shadow-cat-preview+json", options); } [Fact] @@ -123,7 +123,7 @@ public async Task SendsAppropriateParameters() && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), Args.ApiOptions); + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json", Args.ApiOptions); } [Fact] @@ -140,7 +140,7 @@ public async Task SendsAppropriateParametersWithRepositoryId() && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), Args.ApiOptions); + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json", Args.ApiOptions); } [Fact] @@ -164,7 +164,7 @@ public async Task SendsAppropriateParametersWithApiOptions() && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), options); + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json", options); } [Fact] @@ -188,7 +188,7 @@ public async Task SendsAppropriateParametersWithApiOptionsWithRepositoryId() && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), options); + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json", options); } [Fact] @@ -243,7 +243,7 @@ public async Task PostsToCorrectUrl() await client.Create("fake", "repo", newPullRequest); connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls"), - newPullRequest); + newPullRequest, "application/vnd.github.shadow-cat-preview+json"); } [Fact] @@ -256,7 +256,7 @@ public async Task PostsToCorrectUrlWithRepositoryId() await client.Create(1, newPullRequest); connection.Received().Post(Arg.Is(u => u.ToString() == "repositories/1/pulls"), - newPullRequest); + newPullRequest, "application/vnd.github.shadow-cat-preview+json"); } [Fact] @@ -288,7 +288,7 @@ public async Task PostsToCorrectUrl() await client.Update("fake", "repo", 42, pullRequestUpdate); connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls/42"), - pullRequestUpdate); + pullRequestUpdate, "application/vnd.github.shadow-cat-preview+json"); } [Fact] @@ -301,7 +301,7 @@ public async Task PostsToCorrectUrlWithRepositoryId() await client.Update(1, 42, pullRequestUpdate); connection.Received().Patch(Arg.Is(u => u.ToString() == "repositories/1/pulls/42"), - pullRequestUpdate); + pullRequestUpdate, "application/vnd.github.shadow-cat-preview+json"); } [Fact] diff --git a/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs b/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs index b76e89bdf2..4109c2d1ff 100644 --- a/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs @@ -209,11 +209,11 @@ public async Task ReturnsEveryPageOfPullRequests() } ); var gitHubClient = Substitute.For(); - gitHubClient.Connection.Get>(firstPageUrl, Args.EmptyDictionary, null) + gitHubClient.Connection.Get>(firstPageUrl, Args.EmptyDictionary, "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => firstPageResponse)); - gitHubClient.Connection.Get>(secondPageUrl, Args.EmptyDictionary, null) + gitHubClient.Connection.Get>(secondPageUrl, Args.EmptyDictionary, "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => secondPageResponse)); - gitHubClient.Connection.Get>(thirdPageUrl, Args.EmptyDictionary, null) + gitHubClient.Connection.Get>(thirdPageUrl, Args.EmptyDictionary, "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => lastPageResponse)); var client = new ObservablePullRequestsClient(gitHubClient); @@ -262,11 +262,11 @@ public async Task ReturnsEveryPageOfPullRequestsWithRepositoryId() } ); var gitHubClient = Substitute.For(); - gitHubClient.Connection.Get>(firstPageUrl, Args.EmptyDictionary, null) + gitHubClient.Connection.Get>(firstPageUrl, Args.EmptyDictionary, "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => firstPageResponse)); - gitHubClient.Connection.Get>(secondPageUrl, Args.EmptyDictionary, null) + gitHubClient.Connection.Get>(secondPageUrl, Args.EmptyDictionary, "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => secondPageResponse)); - gitHubClient.Connection.Get>(thirdPageUrl, Args.EmptyDictionary, null) + gitHubClient.Connection.Get>(thirdPageUrl, Args.EmptyDictionary, "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => lastPageResponse)); var client = new ObservablePullRequestsClient(gitHubClient); @@ -321,21 +321,21 @@ public async Task SendsAppropriateParametersMulti() && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), Arg.Any()) + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => firstPageResponse)); gitHubClient.Connection.Get>(secondPageUrl, Arg.Is>(d => d.Count == 5 && d["head"] == "user:ref-name" && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), null) + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => secondPageResponse)); gitHubClient.Connection.Get>(thirdPageUrl, Arg.Is>(d => d.Count == 5 && d["head"] == "user:ref-name" && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), null) + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => lastPageResponse)); var client = new ObservablePullRequestsClient(gitHubClient); @@ -390,21 +390,21 @@ public async Task SendsAppropriateParametersMultiWithRepositoryId() && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), Arg.Any()) + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => firstPageResponse)); gitHubClient.Connection.Get>(secondPageUrl, Arg.Is>(d => d.Count == 5 && d["head"] == "user:ref-name" && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), null) + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => secondPageResponse)); gitHubClient.Connection.Get>(thirdPageUrl, Arg.Is>(d => d.Count == 5 && d["head"] == "user:ref-name" && d["state"] == "open" && d["base"] == "fake_base_branch" && d["sort"] == "created" - && d["direction"] == "desc"), null) + && d["direction"] == "desc"), "application/vnd.github.shadow-cat-preview+json") .Returns(Task.Factory.StartNew>>(() => lastPageResponse)); var client = new ObservablePullRequestsClient(gitHubClient); diff --git a/Octokit/Clients/PullRequestsClient.cs b/Octokit/Clients/PullRequestsClient.cs index 844dd8f337..8a75157f32 100644 --- a/Octokit/Clients/PullRequestsClient.cs +++ b/Octokit/Clients/PullRequestsClient.cs @@ -46,7 +46,7 @@ public Task Get(string owner, string name, int number) Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); - return ApiConnection.Get(ApiUrls.PullRequest(owner, name, number)); + return ApiConnection.Get(ApiUrls.PullRequest(owner, name, number), null,AcceptHeaders.DraftPullRequestApiPreview); } /// @@ -57,7 +57,7 @@ public Task Get(string owner, string name, int number) /// public Task Get(long repositoryId, int number) { - return ApiConnection.Get(ApiUrls.PullRequest(repositoryId, number)); + return ApiConnection.Get(ApiUrls.PullRequest(repositoryId, number), null, AcceptHeaders.DraftPullRequestApiPreview); } /// @@ -172,7 +172,7 @@ public Task> GetAllForRepository(string owner, string Ensure.ArgumentNotNull(options, nameof(options)); return ApiConnection.GetAll(ApiUrls.PullRequests(owner, name), - request.ToParametersDictionary(), options); + request.ToParametersDictionary(), AcceptHeaders.DraftPullRequestApiPreview, options); } /// @@ -190,7 +190,7 @@ public Task> GetAllForRepository(long repositoryId, P Ensure.ArgumentNotNull(options, nameof(options)); return ApiConnection.GetAll(ApiUrls.PullRequests(repositoryId), - request.ToParametersDictionary(), options); + request.ToParametersDictionary(), AcceptHeaders.DraftPullRequestApiPreview, options); } /// @@ -206,7 +206,7 @@ public Task Create(string owner, string name, NewPullRequest newPul Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); Ensure.ArgumentNotNull(newPullRequest, nameof(newPullRequest)); - return ApiConnection.Post(ApiUrls.PullRequests(owner, name), newPullRequest); + return ApiConnection.Post(ApiUrls.PullRequests(owner, name), newPullRequest, AcceptHeaders.DraftPullRequestApiPreview); } /// @@ -219,7 +219,7 @@ public Task Create(long repositoryId, NewPullRequest newPullRequest { Ensure.ArgumentNotNull(newPullRequest, nameof(newPullRequest)); - return ApiConnection.Post(ApiUrls.PullRequests(repositoryId), newPullRequest); + return ApiConnection.Post(ApiUrls.PullRequests(repositoryId), newPullRequest, AcceptHeaders.DraftPullRequestApiPreview); } /// @@ -237,7 +237,7 @@ public Task Update(string owner, string name, int number, PullReque Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); Ensure.ArgumentNotNull(pullRequestUpdate, nameof(pullRequestUpdate)); - return ApiConnection.Patch(ApiUrls.PullRequest(owner, name, number), pullRequestUpdate); + return ApiConnection.Patch(ApiUrls.PullRequest(owner, name, number), pullRequestUpdate, AcceptHeaders.DraftPullRequestApiPreview); } /// @@ -252,7 +252,7 @@ public Task Update(long repositoryId, int number, PullRequestUpdate { Ensure.ArgumentNotNull(pullRequestUpdate, nameof(pullRequestUpdate)); - return ApiConnection.Patch(ApiUrls.PullRequest(repositoryId, number), pullRequestUpdate); + return ApiConnection.Patch(ApiUrls.PullRequest(repositoryId, number), pullRequestUpdate, AcceptHeaders.DraftPullRequestApiPreview); } /// diff --git a/Octokit/Helpers/AcceptHeaders.cs b/Octokit/Helpers/AcceptHeaders.cs index 085ff4f3af..6c9de111ea 100644 --- a/Octokit/Helpers/AcceptHeaders.cs +++ b/Octokit/Helpers/AcceptHeaders.cs @@ -49,6 +49,8 @@ public static class AcceptHeaders public const string PullRequestReviewsApiPreview = "application/vnd.github.black-cat-preview+json"; + public const string DraftPullRequestApiPreview = "application/vnd.github.shadow-cat-preview+json"; + public const string ProjectsApiPreview = "application/vnd.github.inertia-preview+json"; public const string OrganizationMembershipPreview = "application/vnd.github.korra-preview+json"; diff --git a/Octokit/Models/Request/NewPullRequest.cs b/Octokit/Models/Request/NewPullRequest.cs index d383b227a7..d3e5de07bd 100644 --- a/Octokit/Models/Request/NewPullRequest.cs +++ b/Octokit/Models/Request/NewPullRequest.cs @@ -50,6 +50,11 @@ public NewPullRequest(string title, string head, string baseRef) /// Body of the pull request (optional) /// public string Body { get; set; } + + /// + /// Whether the pull request is in a draft state or not (optional) + /// + public bool? Draft { get; set; } internal string DebuggerDisplay { diff --git a/Octokit/Models/Response/PullRequest.cs b/Octokit/Models/Response/PullRequest.cs index 6eeb01213b..05eaecb546 100644 --- a/Octokit/Models/Response/PullRequest.cs +++ b/Octokit/Models/Response/PullRequest.cs @@ -16,7 +16,7 @@ public PullRequest(int number) Number = number; } - public PullRequest(long id, string nodeId, string url, string htmlUrl, string diffUrl, string patchUrl, string issueUrl, string statusesUrl, int number, ItemState state, string title, string body, DateTimeOffset createdAt, DateTimeOffset updatedAt, DateTimeOffset? closedAt, DateTimeOffset? mergedAt, GitReference head, GitReference @base, User user, User assignee, IReadOnlyList assignees, bool? mergeable, MergeableState? mergeableState, User mergedBy, string mergeCommitSha, int comments, int commits, int additions, int deletions, int changedFiles, Milestone milestone, bool locked, bool? maintainerCanModify, IReadOnlyList requestedReviewers, IReadOnlyList public Milestone Milestone { get; protected set; } + /// + /// Whether or not the pull request is in a draft state, and cannot be merged. + /// + public bool Draft { get; protected set; } + /// /// Whether or not the pull request has been merged. ///