Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
68d4a5d
Add release notes template to main branch
mball-agathos Aug 19, 2024
1a6e8bc
add support for generate_release_notes
mball-agathos Aug 19, 2024
2f9d2a6
Merge branch 'PyGithub:main' into main
mball-agathos Aug 26, 2024
424eb89
Merge branch 'main' into issue_2794
mball-agathos Aug 26, 2024
e27a5ea
Merge branch 'PyGithub:main' into main
mball-agathos Feb 9, 2025
bfb8fa4
Merge remote-tracking branch 'origin/main' into issue_2794
mball-agathos Feb 9, 2025
4c5739a
Update github/Repository.py from reviewer suggestion
mball-agathos Feb 9, 2025
7684e44
Add description to test_release_notes.yml
mball-agathos Feb 9, 2025
a225374
rename jacquev6 to PyGithub
mball-agathos Feb 10, 2025
5a17934
Merge branch 'main' into issue_2794
EnricoMi Aug 13, 2025
88ea15d
Fix test replay data authentication
EnricoMi Aug 13, 2025
3167fd7
Add "make_latest" to test replay data required by main branch changes
EnricoMi Aug 13, 2025
5ca7320
Fix path to config file in test replay data
EnricoMi Aug 13, 2025
9ff1cca
Add OpenAPI schema
EnricoMi Aug 14, 2025
5f2b306
Run black to reformat files
mball-agathos Aug 14, 2025
2e685ce
Merge branch 'main' into issue_2794
EnricoMi Aug 25, 2025
1784f77
Merge branch 'PyGithub:main' into issue_2794
mball-agathos Aug 27, 2025
84257d7
Fix attribute ordering in GeneratedReleaseNotes.py
mball-agathos Aug 27, 2025
be2cc7e
Fix typo in _useAttributes method of GeneratedReleaseNotes
mball-agathos Aug 28, 2025
e9e068d
Fix assertions
EnricoMi Aug 28, 2025
7c65abf
Minor cleanup, no functional change
EnricoMi Aug 28, 2025
30b203c
Fix import and linting
EnricoMi Aug 28, 2025
78c2a2c
Fix schema annotation
EnricoMi Aug 28, 2025
c6b0835
Revert empty line before schema annotation
EnricoMi Aug 28, 2025
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
43 changes: 43 additions & 0 deletions github/GeneratedReleaseNotes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from __future__ import annotations

from typing import Any

from github.GithubObject import (
Attribute,
NonCompletableGithubObject,
NotSet,
)


class GeneratedReleaseNotes(NonCompletableGithubObject):
"""
This class represents the release notes generated by the release/generate-notes REST API endpoint.

The reference can be found here:
https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release

Comment thread
EnricoMi marked this conversation as resolved.
The OpenAPI schema can be found at
- /components/schemas/release-notes-content
Comment thread
EnricoMi marked this conversation as resolved.

"""

def _initAttributes(self) -> None:
self._body: Attribute[str] = NotSet
self._name: Attribute[str] = NotSet

def __repr__(self) -> str:
return self.get__repr__({"name": self._name.value, "body": self._body.value})

@property
def body(self) -> str:
return self._body.value

@property
def name(self) -> str:
return self._name.value

def _useAttributes(self, attributes: dict[str, Any]) -> None:
if "body" in attributes:
self._body = self._makeStringAttribute(attributes["body"])
if "name" in attributes:
self._name = self._makeStringAttribute(attributes["name"])
38 changes: 38 additions & 0 deletions github/Repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@
import github.WorkflowRun
from github import Consts
from github.Environment import Environment
from github.GeneratedReleaseNotes import GeneratedReleaseNotes
from github.GithubObject import (
Attribute,
CompletableGithubObject,
Expand Down Expand Up @@ -1549,6 +1550,43 @@ def create_git_release(
headers, data = self._requester.requestJsonAndCheck("POST", f"{self.url}/releases", input=post_parameters)
return github.GitRelease.GitRelease(self._requester, headers, data, completed=True)

def generate_release_notes(
self,
tag_name: str,
previous_tag_name: Opt[str] = NotSet,
target_commitish: Opt[str] = NotSet,
configuration_file_path: Opt[str] = NotSet,
) -> GeneratedReleaseNotes:
"""
:calls: `POST /repos/{owner}/{repo}/releases/generate-notes <https://docs.github.com/en/rest/releases/releases#generate-release-notes-content-for-a-release>`
:param tag_name: The tag name for the release. This can be an existing tag or a new one.
:param previous_tag_name: 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.
:param target_commitish: Specifies the commitish value that will be the target for the release's tag. Required if the supplied tag_name does not reference an existing tag. Ignored if the tag_name already exists.
:param configuration_file_path: 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.
:rytpe: :class:`GeneratedReleaseNotes`
"""
assert isinstance(tag_name, str), tag_name
assert isinstance(previous_tag_name, str) or is_optional(previous_tag_name, str), previous_tag_name
assert isinstance(target_commitish, str) or is_optional(target_commitish, str), target_commitish
assert isinstance(configuration_file_path, str) or is_optional(
configuration_file_path, str
), configuration_file_path

post_parameters = NotSet.remove_unset_items(
{
"tag_name": tag_name,
"previous_tag_name": previous_tag_name,
"target_commitish": target_commitish,
"configuration_file_path": configuration_file_path,
}
)

headers, data = self._requester.requestJsonAndCheck(
"POST", f"{self.url}/releases/generate-notes", input=post_parameters
)

return GeneratedReleaseNotes(self._requester, headers, data)

def create_git_tag(
self,
tag: str,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ quiet-level = 3
# https://github.com/codespell-project/codespell/issues/2839#issuecomment-1731601603
# also adding links until they ignored by its: nature
# https://github.com/codespell-project/codespell/issues/2243#issuecomment-1732019960
ignore-words-list = "bloaded,nto,pullrequest,pullrequests,thi,tim,wan,Wan,chang,chang,manuel"
ignore-words-list = "bloaded,nto,pullrequest,pullrequests,thi,tim,wan,Wan,chang,chang,manuel,commitish"

[tool.ruff]
line-length = 120
Expand Down
10 changes: 10 additions & 0 deletions tests/ReplayData/Repository.testGenerateReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
https
POST
api.github.com
None
/repos/PyGithub/PyGithub/releases/generate-notes
{'Authorization': 'token private_token_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
{"tag_name": "vX.Y.Z-by-PyGithub-acctest"}
200
[('Date', 'Sun, 18 Aug 2024 23:56:45 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"f05115701836368bcab805d829f1453234af1eea7b25bf97c3effa382838f562"'), ('X-OAuth-Scopes', 'repo'), ('X-Accepted-OAuth-Scopes', 'repo'), ('github-authentication-token-expiration', '2024-11-14 21:03:22 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4982'), ('X-RateLimit-Reset', '1724025644'), ('X-RateLimit-Used', '18'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('Transfer-Encoding', 'chunked'), ('X-GitHub-Request-Id', '86EA:313F29:56B6E84:A55D123:66C28A3C'), ('Server', 'github.com')]
{"name":"vX.Y.Z-by-PyGithub-acctest","body":"**Full Changelog**: https://github.com/PyGithub/PyGithub/commits/vX.Y.Z-by-PyGithub-acctest"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
https
POST
api.github.com
None
/repos/PyGithub/PyGithub/releases
{'Authorization': 'token private_token_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
{"tag_name": "vX.Y.Z-by-PyGithub-acctest-previous", "draft": false, "prerelease": false, "generate_release_notes": false, "name": "vX.Y.Z: PyGithub acctest", "body": "This release is created by PyGithub", "make_latest": "true"}
201
[('Date', 'Mon, 19 Aug 2024 00:34:07 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Content-Length', '1900'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With'), ('ETag', '"060006433f9b7748cbf7198d4f0d820482591704be702c1169dd21489da95c5d"'), ('X-OAuth-Scopes', 'repo'), ('X-Accepted-OAuth-Scopes', 'repo'), ('github-authentication-token-expiration', '2024-11-14 21:03:22 UTC'), ('Location', 'https://api.github.com/repos/PyGithub/PyGithub/releases/170779796'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4965'), ('X-RateLimit-Reset', '1724029435'), ('X-RateLimit-Used', '35'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('X-GitHub-Request-Id', 'D6C0:2B9908:1D4A719:37A4849:66C292FE'), ('Server', 'github.com')]
{"url":"https://api.github.com/repos/PyGithub/PyGithub/releases/170779796","assets_url":"https://api.github.com/repos/PyGithub/PyGithub/releases/170779796/assets","upload_url":"https://uploads.github.com/repos/PyGithub/PyGithub/releases/170779796/assets{?name,label}","html_url":"https://github.com/PyGithub/PyGithub/releases/tag/vX.Y.Z-by-PyGithub-acctest-previous","id":170779796,"author":{"login":"PyGithub","id":96152357,"node_id":"U_kgDOBbsrJQ","avatar_url":"https://avatars.githubusercontent.com/u/96152357?v=4","gravatar_id":"","url":"https://api.github.com/users/PyGithub","html_url":"https://github.com/PyGithub","followers_url":"https://api.github.com/users/PyGithub/followers","following_url":"https://api.github.com/users/PyGithub/following{/other_user}","gists_url":"https://api.github.com/users/PyGithub/gists{/gist_id}","starred_url":"https://api.github.com/users/PyGithub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PyGithub/subscriptions","organizations_url":"https://api.github.com/users/PyGithub/orgs","repos_url":"https://api.github.com/users/PyGithub/repos","events_url":"https://api.github.com/users/PyGithub/events{/privacy}","received_events_url":"https://api.github.com/users/PyGithub/received_events","type":"User","site_admin":false},"node_id":"RE_kwDOMlKsTM4KLeSU","tag_name":"vX.Y.Z-by-PyGithub-acctest-previous","target_commitish":"main","name":"vX.Y.Z: PyGithub acctest","draft":false,"prerelease":false,"created_at":"2024-08-19T00:25:59Z","published_at":"2024-08-19T00:34:06Z","assets":[],"tarball_url":"https://api.github.com/repos/PyGithub/PyGithub/tarball/vX.Y.Z-by-PyGithub-acctest-previous","zipball_url":"https://api.github.com/repos/PyGithub/PyGithub/zipball/vX.Y.Z-by-PyGithub-acctest-previous","body":"This release is created by PyGithub"}

https
POST
api.github.com
None
/repos/PyGithub/PyGithub/releases/generate-notes
{'Authorization': 'token private_token_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
{"tag_name": "vX.Y.Z-by-PyGithub-acctest", "previous_tag_name": "vX.Y.Z-by-PyGithub-acctest-previous", "target_commitish": "main", "configuration_file_path": "tests/test_release_notes.yml"}
200
[('Date', 'Mon, 19 Aug 2024 00:34:07 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"9cdecc62d8152adc4ab619d18dd9f194f4f76d5dba91ba53c92c9def3856f620"'), ('X-OAuth-Scopes', 'repo'), ('X-Accepted-OAuth-Scopes', 'repo'), ('github-authentication-token-expiration', '2024-11-14 21:03:22 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4964'), ('X-RateLimit-Reset', '1724029435'), ('X-RateLimit-Used', '36'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('Transfer-Encoding', 'chunked'), ('X-GitHub-Request-Id', 'D6C4:4388A:1BF3BE3:3510B09:66C292FF'), ('Server', 'github.com')]
{"name":"vX.Y.Z-by-PyGithub-acctest","body":"<!-- Release notes generated using configuration in tests/test_release_notes.yml at main -->\n\n\n\n**Full Changelog**: https://github.com/PyGithub/PyGithub/compare/vX.Y.Z-by-PyGithub-acctest-previous...vX.Y.Z-by-PyGithub-acctest"}
26 changes: 26 additions & 0 deletions tests/Repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,32 @@ def testCreateGitReleaseWithAllArguments(self):
tag = [tag for tag in self.repo.get_tags() if tag.name == "vX.Y.Z-by-PyGithub-acctest2"].pop()
self.assertEqual(tag.commit.sha, "da9a285fd8b782461e56cba39ae8d2fa41ca7cdc")

def testGenerateReleaseNotes(self):
notes = self.repo.generate_release_notes("vX.Y.Z-by-PyGithub-acctest")
self.assertEqual(notes.name, "vX.Y.Z-by-PyGithub-acctest")
self.assertEqual(
notes.body, "**Full Changelog**: https://github.com/PyGithub/PyGithub/commits/vX.Y.Z-by-PyGithub-acctest"
)
self.assertEqual(
repr(notes),
'GeneratedReleaseNotes(name="vX.Y.Z-by-PyGithub-acctest", body="**Full Changelog**: https://github.com/PyGithub/PyGithub/commits/vX.Y.Z-by-PyGithub-acctest")',
)

def testGenerateReleaseNotesWithAllArguments(self):
self.repo.create_git_release(
tag="vX.Y.Z-by-PyGithub-acctest-previous",
name="vX.Y.Z: PyGithub acctest",
message="This release is created by PyGithub",
)
notes = self.repo.generate_release_notes(
tag_name="vX.Y.Z-by-PyGithub-acctest",
previous_tag_name="vX.Y.Z-by-PyGithub-acctest-previous",
target_commitish="main",
configuration_file_path="tests/test_release_notes.yml",
)
self.assertEqual(notes.name, "vX.Y.Z-by-PyGithub-acctest")
self.assertIn("Release notes generated using configuration in tests/test_release_notes.yml at main", notes.body)

def testCreateGitTag(self):
tag = self.repo.create_git_tag(
"TaggedByPyGithub",
Expand Down
13 changes: 13 additions & 0 deletions tests/test_release_notes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This file is needed for generating release notes for the Repository::testGenerateReleaseNotesWithAllArguments test
# See https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes

# This is used to generate the ReplayData as used by Repository::testGenerateReleaseNotesWithAllArguments.
# If you need to regenerate this ReplayData files, you will need to copy this yaml file
# into the `.github` directory on the main branch of your forked repository.
# The GitHub API expects to see this file in the `.github` directory when generating release notes.

changelog:
categories:
- title: Features
labels:
- '*'
Loading