Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Releases]Added support for generating release notes #2563

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Octokit.Reactive/Clients/IObservableReleasesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,29 @@ namespace Octokit.Reactive
/// </remarks>
public interface IObservableReleasesClient
{
/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The repository's owner</param>
/// <param name="name">The repository's name</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<GeneratedReleaseNotes> GenerateReleaseNotes(string owner, string name, GenerateReleaseNotesRequest data);

/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<GeneratedReleaseNotes> GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data);

/// <summary>
/// Gets all <see cref="Release"/>s for the specified repository.
/// </summary>
Expand Down
35 changes: 35 additions & 0 deletions Octokit.Reactive/Clients/ObservableReleasesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,41 @@ public ObservableReleasesClient(IGitHubClient client)
_connection = client.Connection;
}

/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The repository's owner</param>
/// <param name="name">The repository's name</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<GeneratedReleaseNotes> 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();
}

/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<GeneratedReleaseNotes> GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data)
{
Ensure.ArgumentNotNull(data, nameof(data));

return _client.GenerateReleaseNotes(repositoryId, data).ToObservable();
}

/// <summary>
/// Gets all <see cref="Release"/>s for the specified repository.
/// </summary>
Expand Down
49 changes: 49 additions & 0 deletions Octokit.Tests/Clients/ReleasesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,55 @@ public void EnsuresNonNullArguments()
}
}

public class TheGenerateReleaseNotesMethod
{
[Fact]
public async Task RequestsCorrectUrl()
{
var client = Substitute.For<IApiConnection>();
var releasesClient = new ReleasesClient(client);
var data = new GenerateReleaseNotesRequest("fake-tag");

await releasesClient.GenerateReleaseNotes("fake", "repo", data);

client.Received().Post<GeneratedReleaseNotes>(Arg.Is<Uri>(u => u.ToString() == "repos/fake/repo/releases"),
data,
"application/vnd.github.v3");
}

[Fact]
public async Task RequestsCorrectUrlWithRepositoryId()
{
var client = Substitute.For<IApiConnection>();
var releasesClient = new ReleasesClient(client);
var data = new GenerateReleaseNotesRequest("fake-tag");

await releasesClient.GenerateReleaseNotes(1, data);

client.Received().Post<GeneratedReleaseNotes>(Arg.Is<Uri>(u => u.ToString() == "repositories/1/releases"),
data,
"application/vnd.github.v3");
}

[Fact]
public async Task EnsuresNonNullArguments()
{
var releasesClient = new ReleasesClient(Substitute.For<IApiConnection>());
Assert.Throws<ArgumentNullException>(() => new GenerateReleaseNotesRequest(null));

var data = new GenerateReleaseNotesRequest("fake-tag");

await Assert.ThrowsAsync<ArgumentNullException>(() => releasesClient.GenerateReleaseNotes(null, "name", data));
await Assert.ThrowsAsync<ArgumentNullException>(() => releasesClient.GenerateReleaseNotes("owner", null, data));
await Assert.ThrowsAsync<ArgumentNullException>(() => releasesClient.GenerateReleaseNotes("owner", "name", null));

await Assert.ThrowsAsync<ArgumentNullException>(() => releasesClient.GenerateReleaseNotes(1, null));

await Assert.ThrowsAsync<ArgumentException>(() => releasesClient.GenerateReleaseNotes("", "name", data));
await Assert.ThrowsAsync<ArgumentException>(() => releasesClient.GenerateReleaseNotes("owner", "", data));
}
}

public class TheGetAllMethod
{
[Fact]
Expand Down
23 changes: 23 additions & 0 deletions Octokit/Clients/IReleasesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,29 @@ namespace Octokit
/// </remarks>
public interface IReleasesClient
{
/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The repository's owner</param>
/// <param name="name">The repository's name</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task<GeneratedReleaseNotes> GenerateReleaseNotes(string owner, string name, GenerateReleaseNotesRequest data);

/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task<GeneratedReleaseNotes> GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data);

/// <summary>
/// Gets all <see cref="Release"/>s for the specified repository.
/// </summary>
Expand Down
39 changes: 39 additions & 0 deletions Octokit/Clients/ReleasesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,45 @@ public ReleasesClient(IApiConnection apiConnection) : base(apiConnection)
{
}

/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The repository's owner</param>
/// <param name="name">The repository's name</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "/repos/{owner}/{repo}/releases")]
public Task<GeneratedReleaseNotes> 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<GeneratedReleaseNotes>(endpoint, data, AcceptHeaders.StableVersion);
}

/// <summary>
/// Generates a <see cref="GeneratedReleaseNotes"/>s for the specified repository with auto generated notes.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release">API documentation</a> for more information.
/// </remarks>
/// <param name="repositoryId">The Id of the repository</param>
/// <param name="data">The request for generating release notes</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "/repos/{owner}/{repo}/releases")]
public Task<GeneratedReleaseNotes> GenerateReleaseNotes(long repositoryId, GenerateReleaseNotesRequest data)
{
Ensure.ArgumentNotNull(data, nameof(data));

var endpoint = ApiUrls.Releases(repositoryId);
return ApiConnection.Post<GeneratedReleaseNotes>(endpoint, data, AcceptHeaders.StableVersion);
}

/// <summary>
/// Gets all <see cref="Release"/>s for the specified repository.
/// </summary>
Expand Down
66 changes: 66 additions & 0 deletions Octokit/Models/Request/GenerateReleaseNotesRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Diagnostics;
using System.Globalization;

namespace Octokit
{
/// <summary>
/// Used to generate release notes for a given tag.
/// </summary>
/// <remarks>
/// API: https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release
/// </remarks>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class GenerateReleaseNotesRequest
{
/// <summary>
/// Initializes a new instance of the <see cref="GenerateReleaseNotesRequest"/> class.
/// </summary>
/// <param name="tagName">Name of the tag to create in the repository for this release.</param>
public GenerateReleaseNotesRequest(string tagName)
{
Ensure.ArgumentNotNullOrEmptyString(tagName, nameof(tagName));
TagName = tagName;
}

/// <summary>
/// Gets the name of the tag.
/// </summary>
/// <value>
/// The name of the tag.
/// </value>
public string TagName { get; private set; }

/// <summary>
/// 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.
/// </summary>
/// <value>
/// The target commitish.
/// </value>
public string TargetCommitish { get; set; }

/// <summary>
/// Gets the name of the tag.
/// </summary>
/// <value>
/// The name of the previous tag.
/// </value>
public string PreviousTagName { get; set; }

/// <summary>
/// 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.
/// </summary>
/// <value>
/// The path to the configuration file.
/// </value>
public string ConfigurationFilePath { get; set; }

internal string DebuggerDisplay
{
get { return string.Format(CultureInfo.InvariantCulture, "TagName: {0} PreviousTagName: {1}", TagName, PreviousTagName); }
}

}
}
47 changes: 47 additions & 0 deletions Octokit/Models/Response/GeneratedReleaseNotes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Diagnostics;
using System.Globalization;

namespace Octokit
{
/// <summary>
/// Used to retrieve generated release notes.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class GeneratedReleaseNotes
{
public GeneratedReleaseNotes() { }

public GeneratedReleaseNotes(string name, string body)
{
Name = name;
Body = body;
}

/// <summary>
/// Gets the name of the release.
/// </summary>
/// <value>
/// The name of the relaese.
/// </value>
public string Name { get; private set; }

/// <summary>
/// Gets the body of the release.
/// </summary>
/// <value>
/// The body of the release.
/// </value>
public string Body { get; private set; }

internal string DebuggerDisplay
{
get { return string.Format(CultureInfo.InvariantCulture, "Name: {0} Body: {1}", Name, Body); }
}

}
}
13 changes: 13 additions & 0 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down