diff --git a/Octokit.Reactive/Clients/IObservableReleasesClient.cs b/Octokit.Reactive/Clients/IObservableReleasesClient.cs index 7320f5addd..072aba0ff2 100644 --- a/Octokit.Reactive/Clients/IObservableReleasesClient.cs +++ b/Octokit.Reactive/Clients/IObservableReleasesClient.cs @@ -13,6 +13,29 @@ namespace Octokit.Reactive /// public interface IObservableReleasesClient { + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The repository's owner + /// The repository's name + /// The request for generating release notes + /// Thrown when a general API error occurs. + IObservable GenerateReleaseNotes(string owner, string name, GenerateReleaseNotesRequest data); + + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The Id of the repository + /// The request for generating release notes + /// Thrown when a general API error occurs. + IObservable GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data); + /// /// Gets all s for the specified repository. /// diff --git a/Octokit.Reactive/Clients/ObservableReleasesClient.cs b/Octokit.Reactive/Clients/ObservableReleasesClient.cs index 644269643b..dcab994bff 100644 --- a/Octokit.Reactive/Clients/ObservableReleasesClient.cs +++ b/Octokit.Reactive/Clients/ObservableReleasesClient.cs @@ -25,6 +25,41 @@ public ObservableReleasesClient(IGitHubClient client) _connection = client.Connection; } + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The repository's owner + /// The repository's name + /// The request for generating release notes + /// Thrown when a general API error occurs. + public IObservable GenerateReleaseNotes(string owner, string name, GenerateReleaseNotesRequest data) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(data, nameof(data)); + + return _client.GenerateReleaseNotes(owner, name, data).ToObservable(); + } + + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The Id of the repository + /// The request for generating release notes + /// Thrown when a general API error occurs. + public IObservable GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data) + { + Ensure.ArgumentNotNull(data, nameof(data)); + + return _client.GenerateReleaseNotes(repositoryId, data).ToObservable(); + } + /// /// Gets all s for the specified repository. /// diff --git a/Octokit.Tests/Clients/ReleasesClientTests.cs b/Octokit.Tests/Clients/ReleasesClientTests.cs index 742c8e8912..903d8115e9 100644 --- a/Octokit.Tests/Clients/ReleasesClientTests.cs +++ b/Octokit.Tests/Clients/ReleasesClientTests.cs @@ -20,6 +20,55 @@ public void EnsuresNonNullArguments() } } + public class TheGenerateReleaseNotesMethod + { + [Fact] + public async Task RequestsCorrectUrl() + { + var client = Substitute.For(); + var releasesClient = new ReleasesClient(client); + var data = new GenerateReleaseNotesRequest("fake-tag"); + + await releasesClient.GenerateReleaseNotes("fake", "repo", data); + + client.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/releases"), + data, + "application/vnd.github.v3"); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryId() + { + var client = Substitute.For(); + var releasesClient = new ReleasesClient(client); + var data = new GenerateReleaseNotesRequest("fake-tag"); + + await releasesClient.GenerateReleaseNotes(1, data); + + client.Received().Post(Arg.Is(u => u.ToString() == "repositories/1/releases"), + data, + "application/vnd.github.v3"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var releasesClient = new ReleasesClient(Substitute.For()); + Assert.Throws(() => new GenerateReleaseNotesRequest(null)); + + var data = new GenerateReleaseNotesRequest("fake-tag"); + + await Assert.ThrowsAsync(() => releasesClient.GenerateReleaseNotes(null, "name", data)); + await Assert.ThrowsAsync(() => releasesClient.GenerateReleaseNotes("owner", null, data)); + await Assert.ThrowsAsync(() => releasesClient.GenerateReleaseNotes("owner", "name", null)); + + await Assert.ThrowsAsync(() => releasesClient.GenerateReleaseNotes(1, null)); + + await Assert.ThrowsAsync(() => releasesClient.GenerateReleaseNotes("", "name", data)); + await Assert.ThrowsAsync(() => releasesClient.GenerateReleaseNotes("owner", "", data)); + } + } + public class TheGetAllMethod { [Fact] diff --git a/Octokit/Clients/IReleasesClient.cs b/Octokit/Clients/IReleasesClient.cs index d8ef30bb33..0af33be082 100644 --- a/Octokit/Clients/IReleasesClient.cs +++ b/Octokit/Clients/IReleasesClient.cs @@ -13,6 +13,29 @@ namespace Octokit /// public interface IReleasesClient { + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The repository's owner + /// The repository's name + /// The request for generating release notes + /// Thrown when a general API error occurs. + Task GenerateReleaseNotes(string owner, string name, GenerateReleaseNotesRequest data); + + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The Id of the repository + /// The request for generating release notes + /// Thrown when a general API error occurs. + Task GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data); + /// /// Gets all s for the specified repository. /// diff --git a/Octokit/Clients/ReleasesClient.cs b/Octokit/Clients/ReleasesClient.cs index dd1b360eb6..bc988dd876 100644 --- a/Octokit/Clients/ReleasesClient.cs +++ b/Octokit/Clients/ReleasesClient.cs @@ -20,6 +20,45 @@ public ReleasesClient(IApiConnection apiConnection) : base(apiConnection) { } + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The repository's owner + /// The repository's name + /// The request for generating release notes + /// Thrown when a general API error occurs. + [ManualRoute("GET", "/repos/{owner}/{repo}/releases")] + public Task GenerateReleaseNotes(string owner, string name, GenerateReleaseNotesRequest data) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); + Ensure.ArgumentNotNull(data, nameof(data)); + + var endpoint = ApiUrls.Releases(owner, name); + return ApiConnection.Post(endpoint, data, AcceptHeaders.StableVersion); + } + + /// + /// Generates a s for the specified repository with auto generated notes. + /// + /// + /// See the API documentation for more information. + /// + /// The Id of the repository + /// The request for generating release notes + /// Thrown when a general API error occurs. + [ManualRoute("GET", "/repos/{owner}/{repo}/releases")] + public Task GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data) + { + Ensure.ArgumentNotNull(data, nameof(data)); + + var endpoint = ApiUrls.Releases(repositoryId); + return ApiConnection.Post(endpoint, data, AcceptHeaders.StableVersion); + } + /// /// Gets all s for the specified repository. /// diff --git a/Octokit/Models/Request/GenerateReleaseNotesRequest.cs b/Octokit/Models/Request/GenerateReleaseNotesRequest.cs new file mode 100644 index 0000000000..f3aef13039 --- /dev/null +++ b/Octokit/Models/Request/GenerateReleaseNotesRequest.cs @@ -0,0 +1,66 @@ +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Used to generate release notes for a given tag. + /// + /// + /// API: https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class GenerateReleaseNotesRequest + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the tag to create in the repository for this release. + public GenerateReleaseNotesRequest(string tagName) + { + Ensure.ArgumentNotNullOrEmptyString(tagName, nameof(tagName)); + TagName = tagName; + } + + /// + /// Gets the name of the tag. + /// + /// + /// The name of the tag. + /// + public string TagName { get; private set; } + + /// + /// The name of the previous tag to use as the starting point for the release notes. + /// Use to manually specify the range for the set of changes considered as part this release. + /// + /// + /// The target commitish. + /// + public string TargetCommitish { get; set; } + + /// + /// Gets the name of the tag. + /// + /// + /// The name of the previous tag. + /// + public string PreviousTagName { get; set; } + + /// + /// Specifies a path to a file in the repository containing configuration settings used for generating the + /// release notes. If unspecified, the configuration file located in the repository at '.github/release.yml' or + /// '.github/release.yaml' will be used. If that is not present, the default configuration will be used. + /// + /// + /// The path to the configuration file. + /// + public string ConfigurationFilePath { get; set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "TagName: {0} PreviousTagName: {1}", TagName, PreviousTagName); } + } + + } +} diff --git a/Octokit/Models/Response/GeneratedReleaseNotes.cs b/Octokit/Models/Response/GeneratedReleaseNotes.cs new file mode 100644 index 0000000000..009e3dcf9a --- /dev/null +++ b/Octokit/Models/Response/GeneratedReleaseNotes.cs @@ -0,0 +1,47 @@ +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Used to retrieve generated release notes. + /// + /// + /// API: https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release + /// The generated release notes are not saved anywhere. + /// They are intended to be generated and used when creating a new release. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class GeneratedReleaseNotes + { + public GeneratedReleaseNotes() { } + + public GeneratedReleaseNotes(string name, string body) + { + Name = name; + Body = body; + } + + /// + /// Gets the name of the release. + /// + /// + /// The name of the relaese. + /// + public string Name { get; private set; } + + /// + /// Gets the body of the release. + /// + /// + /// The body of the release. + /// + public string Body { get; private set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Name: {0} Body: {1}", Name, Body); } + } + + } +} diff --git a/docs/releases.md b/docs/releases.md index 950c5b6ed0..3f9e9582c3 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -30,6 +30,19 @@ Console.WriteLine("Created release id {0}", result.Id); Note that the `Draft` flag is used to indicate when a release should be published to the world, whereas the `PreRelease` flag is used to indicate whether a release is unofficial or preview release. +#### Generate release notes + +Additionally, you can ask GitHub to generate a name and body before creating a new release. + +```csharp +var generationRequest = new GenerateReleaseNotesRequest("v2.0.0"); +var releaseNotes = await client.Repository.Release.GenerateReleaseNotes("octokit", "octokit.net", generationRequest); + +var newRelease = new NewRelease("v1.0.0"); +newRelease.Name = releaseNotes.Name; +newRelease.Body = releaseNotes.Body; +``` + ### Update Once the release is ready for the public, you can apply an update to the release: