Sphinx Github Changelog: Build a sphinx changelog from GitHub Releases
Sphinx-github-changelog is a Sphinx plugin that builds a changelog section based on a repository’s GitHub Releases content.
How ? (the short version)
In your Sphinx documentation conf.py:
extensions = [
..., # your other extensions
"sphinx_github_changelog",
]
In your documentation:
.. changelog::
:changelog-url: https://your-project.readthedocs.io/en/stable/#changelog
:github: https://github.com/you/your-project/releases/
:pypi: https://pypi.org/project/your-project/
or more minimally (but not necessarily recommended):
.. changelog::
See the end result for this project on ReadTheDocs.
Why ?
On the way to continuous delivery, it’s important to be able to release easily. One of the criteria for easy releases is that the release doesn’t require a commit and a Pull Request. Release Pull Requests usually include 2 parts:
Changing the version
Updating the changelog (if you keep a changelog, let’s assume you do)
Commitless releases need a way to store the version and the changelog, as close as possible to the code, but actually not in the code.
Setting aside the “version” question, sphinx-github-changelog aims at providing
a good way of managing the “changelog” part:
The best solution we’ve found so far for the changelog is to store it in the body of GitHub Releases. That’s very practical for maintainers, but it may not be the first place people will look for it. As far as we’ve seen, people expect the changelog to be:
in the repo, in
CHANGELOG.rst,in the built documentation.
Having the changelog in CHANGELOG.rst causes a few problems:
Either each PR adds its single line of changelog, but:
you’ll most probably run into countless merge conflicts,
the changelog won’t tell you which contribution was part of which release
This reduces the interest for the whole thing.
Or your changelog is edited at release time. Maybe you’re using towncrier for fragment-based changelog, but you’re not doing commitless releases anymore. You could imagine that the release commit is done by your CI, but this can quickly become annoying, especially if you require Pull Requests.
But there is another way. Instead of providing the changelog, the CHANGELOG.rst
file can hold a link to the changelog. This makes things much easier.
sphinx-github-changelog encourages you to do that.
Reference documentation
Automatic Configuration
The extension can automatically detect the GitHub repository URL from your git remotes in this order:
upstreamremoteoriginremote
The GitHub API base URL and GitHub root URL are derived from this URL.
If for any reason, you’d rather provide the repository explicitly (e.g. the doc
repo doesn’t match the repo you’re releasing from, or anything else), you can
define the :github: attribute to the directive. See directive for
details.
Authentication
The extension uses the GitHub Releases REST API to retrieve the changelog.
For public repositories, this can usually work without authentication, though it’s not
recommended as GitHub applies IP-based rate limits, so this may make your builds flaky.
Note that there will be automatic retries after HTTP 429 responses, controlled by the
sphinx_github_changelog_retries option (see below). For private repositories (or
when unauthenticated requests are rate limited), you need a GitHub API token.
Tokens can be read from (in this order):
sphinx_github_changelog_tokeninconf.py(please do NOT commit your secrets)SPHINX_GITHUB_CHANGELOG_TOKENenvironment variableGITHUB_TOKENenvironment variableYour
gitconfiguration, using git’s credential systemThe
ghcommand, using the auth token command
When using GitHub Actions, you can pass a token explicitly as an environment variable:
- name: Build documentation
run: make html
env:
SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ github.token }}
If you’re not in one of the cases above and your build environment cannot use
anonymous API access reliably (e.g. rate limits), you’ll need a personal access
token. If the repository is public, the token doesn’t need any special access
(you can uncheck everything). For private and internal repositories, the token
must have repo scope (classic tokens) or contents: read access
(fine-grained tokens).
Pass the token as the SPHINX_GITHUB_CHANGELOG_TOKEN (or GITHUB_TOKEN)
environment variable. You can also set the token as sphinx_github_changelog_token in
conf.py, but you should never commit secrets such as this.
Extension options (conf.py)
All options can also be set via environment variables of the same name in uppercase
(e.g. SPHINX_GITHUB_CHANGELOG_TOKEN).
Option |
Default |
Description |
|---|---|---|
|
|
GitHub API token. See above (please do NOT commit your secrets). |
|
|
Root URL to the repository. Usually detected automatically. |
|
|
Whether to include pre-releases in the changelog. Set to |
|
|
Number of retries after HTTP 429 responses from GitHub API. Will wait exponentially longer between each retry, starting at 5 second. |
Directive
.. changelog::
:changelog-url: https://your-project.readthedocs.io/en/stable/changelog.html
:github: https://github.com/you/your-project/releases/
:pypi: https://pypi.org/project/your-project/
Attributes
github(optional): URL to the releases page of the repository. If not provided, auto-detected from your git remote, as described above.changelog-url(optional): URL to the built version of your changelog.sphinx-github-changelogwill display a link to your built changelog if the GitHub token is not provided (hopefully, this does not happen in your built documentation)pypi(optional): URL to the PyPI page of the repository. This allows the changelog to display links to each PyPI release.
You’ll notice that each parameter here is not requested in the simplest form but as very specific URLs from which the program extracts the needed information. This is done on purpose. If people browse the unbuilt version of your documentation (e.g. on GitHub or PyPI directly), they’ll still be presented with links to the pages that contain the information they will need, instead of unhelping directives.
Changelog
This documentation itself is “drinking its own champagne”: it uses
sphinx-github-changelog. Here’s what it looks like.
2.3.0
Released on 2026-05-27 - GitHub - PyPI
What’s Changed
feat(api): switch changelog fetching to GitHub REST by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/211
Tip
With this release, we’re internally using the GitHub REST API instead of GraphQL, which means the token is not mandatory anymore (though it’s advised to avoid rate limiting)
Renovate minimum release age by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/210
Fail under 100% coverage by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/212
Skip no-commit-to-main on CI by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/213
feat: Exponential backoff on 429 by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/214
test(test): Add VCR tests by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/215
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/2.2.0…2.3.0
2.2.0
Released on 2026-05-24 - GitHub - PyPI
What’s Changed
fix: strip ‘v’ prefix from tags in titles, section IDs, and PyPI URLs by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/207
feat: add option to exclude pre-releases from changelog by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/208
fix: sort releases by publication date instead of creation date by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/209
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/2.1.1…2.2.0
2.1.1
Released on 2026-05-23 - GitHub - PyPI
What’s Changed
Bump idna from 3.13 to 3.15 by @dependabot[bot] in https://github.com/ewjoachim/sphinx-github-changelog/pull/202
Use correct environment when releasing by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/205
Lock file maintenance by @renovate[bot] in https://github.com/ewjoachim/sphinx-github-changelog/pull/201
Remove new package exclusion by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/206
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/2.1.0…2.1.1
2.1.0
Released on 2026-05-23 - GitHub - PyPI
What’s Changed
Update all dependencies by @renovate[bot] in https://github.com/ewjoachim/sphinx-github-changelog/pull/203
Refactor into separate modules, add
GITHUB_TOKENsupport, reach 100% test coverage by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/204
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/2.0.1…2.1.0
2.0.1
Released on 2026-05-16 - GitHub - PyPI
Internal changes
Fix coverage on main by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/197
Persist credentials: they’re used for comitting by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/198
Fix coverage badge by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/199
Exclude upgrades from changelog by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/200
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/2.0.0…2.0.1
2.0.0
Released on 2026-05-16 - GitHub - PyPI
Breaking changes
Dropped Python 3.9 and 3.10 support, added 3.14
Changed the way the lib works: instead of embedding HTML as a raw docutils node (which only works for HTML doc anyway), we now use
myst-parserto transform your release body Markdown into docutils nodes. The gaps in “what works vs what doesn’t” among all of the Markdown constructs might not be exactly the same between the 2 methods, so you’ll likely find that some parts that didn’t work before now do (e.g. admonitions) and it’s not impossible that we have regressions too. If you experience regressions, feel free to open a ticket, and it’s completely possible to stay on pre-2.0 for the time being.
What’s Changed
Add GitHub markdown alerts to Sphinx admonitions conversion by @ewjoachim and @ashnair1 (thank you) in https://github.com/ewjoachim/sphinx-github-changelog/pull/189
Upgrade and modernize lib boilerplate (basedpyright, prek, autofix.ci) by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/195
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.7.2…2.0.0
1.7.2
Released on 2026-03-23 - GitHub - PyPI
What’s Changed
Fix expiring image URLs in release descriptions by @ashnair1 in https://github.com/ewjoachim/sphinx-github-changelog/pull/184
New Contributors
@ashnair1 made their first contribution in https://github.com/ewjoachim/sphinx-github-changelog/pull/184
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.7.1…1.7.2
1.7.1
Released on 2025-05-11 - GitHub - PyPI
What’s Changed
Remove outdated paragraph in the README by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/158
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.7.0…1.7.1
1.7.0
Released on 2025-05-11 - GitHub - PyPI
What’s Changed
Specify Python versions in metadata. Drop python 3.8 by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/155
Fix github repo badge style by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/156
Update README.rst by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/157
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.6.2…1.7.0
1.6.2
Released on 2025-05-11 - GitHub - PyPI
What’s Changed
Licence, Renovate, Codeowner by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/151
Remove outdated script
publishby @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/153Add license file to metadata by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/154
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.6.1…1.6.2
1.6.1
Released on 2025-05-08 - GitHub - PyPI
What’s Changed
Fix release by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/150
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.6.0…1.6.1
1.6.0
Released on 2025-05-08 - GitHub - PyPI
What’s Changed
Modernize repository boilerplate by @ewjoachim in https://github.com/ewjoachim/sphinx-github-changelog/pull/149
Note: we removed the following top-level metadata attributes: __author__, __author_email__, __license__, __url__, __version__
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.5.0…1.6.0
1.5.0
Released on 2025-05-08 - GitHub - PyPI
What’s Changed
Bump setuptools from 68.0.0 to 70.0.0 by @dependabot in https://github.com/ewjoachim/sphinx-github-changelog/pull/136
[pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/ewjoachim/sphinx-github-changelog/pull/141
Configure extension automatically from git/gh by @lordmauve in https://github.com/ewjoachim/sphinx-github-changelog/pull/147
New Contributors
@lordmauve made their first contribution in https://github.com/ewjoachim/sphinx-github-changelog/pull/147
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.4.0…1.5.0
1.4.0
Released on 2024-08-09 - GitHub - PyPI
What’s Changed
Support self hosted git repo by @dzuev2 in https://github.com/ewjoachim/sphinx-github-changelog/pull/139
New Contributors
@dzuev2 made their first contribution in https://github.com/ewjoachim/sphinx-github-changelog/pull/139
Full Changelog: https://github.com/ewjoachim/sphinx-github-changelog/compare/1.3.0…1.4.0
1.3.0
Released on 2024-03-09 - GitHub - PyPI
Fix crashes (#124)
Bump jinja2 from 3.1.2 to 3.1.3 (#119)
[pre-commit.ci] pre-commit autoupdate (#118)
Bump urllib3 from 2.0.6 to 2.0.7 (#117)
Bump urllib3 from 2.0.4 to 2.0.6 (#115)
[pre-commit.ci] pre-commit autoupdate (#116)
remove line referencing tox in MANIFEST (#113)
Drop py3.7 and upgrade all deps (#112)
1.2.1
Released on 2023-02-15 - GitHub - PyPI
fix error message when PyPI url is incorrect (#105)
[pre-commit.ci] pre-commit autoupdate (#103, #102, #99, #97, #96, #95, #93, #92, #91, #90, #88, #86, #85, #84, #83, #82, #81, #80, #79, #78, #77, #76, #75, #74, #73, #69, #68, #67, #66, #65, #64, #63, #62, #61, #60, #59)
Bump certifi from 2022.6.15 to 2022.12.7 (#94)
Update .pre-commit-config.yaml (#72)
Kudos:
@bj00rn
1.2.0
Released on 2022-01-21 - GitHub - PyPI
Unpin deps (#58)
[pre-commit.ci] pre-commit autoupdate (#56)
[pre-commit.ci] pre-commit autoupdate (#55)
1.1.0
Released on 2022-01-03 - GitHub - PyPI
[pre-commit.ci] pre-commit autoupdate (#54, #52, #51, #50, #49, #48, #47, #46, #45, #44, #42, #41, #40, #39, #37, #36, #35, #34, #32, #28, #27, #26, #25, #24, #22, #21, #20)
Add support for Sphinx v4 (#53)
Replace codecov with coverage-comment (#43)
Fix CI python-version (#38)
Fix mypy (#31)
Delete unused requirements.txt (#23)
Kudos:
@mondeja
1.0.8
Released on 2021-04-17 - GitHub - PyPI
Miscellaneous
Badges (#19)
Kudos:
@ewjoachim
1.0.7
Released on 2021-04-17 - GitHub - PyPI
Bug Fixes
Readthedocs fail on warning (#18)
Kudos:
@ewjoachim
1.0.6
Released on 2021-04-17 - GitHub - PyPI
Miscellaneous
Iterate on CI again (#16)
ReadTheDocs (#17)
Kudos:
@ewjoachim
1.0.5
Released on 2021-04-17 - GitHub - PyPI
Bug Fixes
publish restores the file (#12)
Miscellaneous
iterate on CI (#14)
Improve cache & publish (#13)
pre-commit.ci is now responsible for the linting (#15)
Kudos:
@ewjoachim and @pre-commit-ci[bot]
1.0.4: Add missing dependency dunamai
Released on 2021-04-16 - GitHub - PyPI
Bug Fixes
Add dunamai (#11)
Kudos:
@ewjoachim
1.0.3: Redo boilerplate, fix crash when there are draft releases
Released on 2021-04-16 - GitHub - PyPI
Bug Fixes
Fixes #8 : node_for_release should not return [] (#9)
Miscellaneous
Redo Boilerplate (#10)
Adding “Framework :: Sphinx :: Extension” classifier (#7)
Kudos:
@jeriox
1.0.2: Fix for Release Drafts
Released on 2020-07-31 - GitHub - PyPI
Bug Fixes
Fix crash in case of draft release (#6)
Misc
Check lint in CI (#5)
1.0.1: Travis PyPI deployment
Released on 2020-07-27 - GitHub - PyPI
Add PyPI token to Travis (#4)
1.0.0: A fresh start
Released on 2020-07-27 - GitHub - PyPI
Features
Initial code (#2)
Bug Fixes
Main branch is actually called main (#3)
Test
The following text is just to test the changelog markup
Heading
emphasis / strong / strikethrough / sub / underlined
#336699 / @ewjoachim / https://github.com/ewjoachim/sphinx-github-changelog/labels/dependencies
Emojis:
👍 (UTF-8)
:thumbsup: (short code)
:shipit: :octocat: (GH specific)
Contribution guidelines for this project
List
Next item
Unordered
First
#1
Add delight to the experience when all tasks are complete :tada:
sub 1
Note
Highlights information that users should take into account, even when skimming.
Tip
Optional information to help a user be more successful.
Important
Crucial information necessary for users to succeed.
Warning
Critical content demanding immediate user attention due to potential risks.
Caution
Negative potential consequences of an action.
foo |
bar |
|---|---|
baz |
bim |
Foo
bar baz
def x():
pass
Details
Details
Let’s rename *our-new-project* to *our-old-project*.