Skip to content

Commit b3dfa5c

Browse files
authored
ci: add release cycle workflows (#43)
* feat: introduce towncrier for changelogs (#41) * fix: misc docs fixes (#42) * fix(docs): actually add new files to index * fix(docs): fix installation instructions * feat(docs): watch changes to changelog or source files * fix(docs): properly resolve source code links * fix(docs): properly link to issues * ci: implement release cycle
1 parent a1fbf7f commit b3dfa5c

File tree

17 files changed

+1347
-26
lines changed

17 files changed

+1347
-26
lines changed

.github/workflows/changelog.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Adapted from https://github.com/DisnakeDev/disnake/blob/master/.github/workflows/changelog.yaml
2+
3+
name: changelog entry
4+
5+
on:
6+
pull_request:
7+
types: [opened, synchronize, labeled, unlabeled, reopened]
8+
branches:
9+
- master
10+
11+
permissions:
12+
contents: read
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
check-changelog-entry:
20+
name: Check for changelog entry
21+
runs-on: ubuntu-latest
22+
if: contains(github.event.pull_request.labels.*.name, 'skip news') != true
23+
24+
steps:
25+
- uses: actions/checkout@v4
26+
with:
27+
# towncrier needs a non-shallow clone
28+
fetch-depth: '0'
29+
30+
- name: Set up environment
31+
uses: ./.github/actions/setup-env
32+
with:
33+
python-version: '3.9'
34+
35+
- name: Install dependencies
36+
run: pdm install -dG changelog
37+
38+
- name: Check for presence of a Change Log fragment (only pull requests)
39+
# NOTE: The pull request' base branch needs to be fetched so towncrier
40+
# is able to compare the current branch with the base branch.
41+
run: |
42+
if ! pdm run towncrier check --compare-with origin/${BASE_BRANCH}; then
43+
echo "::error::Please see https://github.com/DisnakeCommunity/disnake-compass/blob/master/changelog/README.rst for details on how to create a changelog entry." >&2
44+
exit 1
45+
fi
46+
env:
47+
BASE_BRANCH: ${{ github.base_ref }}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Adapted from https://github.com/DisnakeDev/disnake/blob/master/.github/workflows/create-release-pr.yaml
2+
3+
name: Create Release PR
4+
5+
on:
6+
workflow_dispatch:
7+
inputs:
8+
version:
9+
description: "The new version number, e.g. `1.2.3`."
10+
type: string
11+
required: true
12+
13+
permissions: {}
14+
15+
jobs:
16+
create-release-pr:
17+
name: Create Release PR
18+
runs-on: ubuntu-latest
19+
20+
env:
21+
VERSION_INPUT: ${{ inputs.version }}
22+
23+
steps:
24+
# https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/making-authenticated-api-requests-with-a-github-app-in-a-github-actions-workflow
25+
- name: Generate app token
26+
id: generate_token
27+
uses: actions/create-github-app-token@f2acddfb5195534d487896a656232b016a682f3c # v1.9.0
28+
with:
29+
app-id: ${{ secrets.BOT_APP_ID }}
30+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
31+
32+
- uses: actions/checkout@v4
33+
with:
34+
token: ${{ steps.generate_token.outputs.token }}
35+
persist-credentials: false
36+
37+
- name: Set git name/email
38+
env:
39+
GIT_USER: ${{ vars.GIT_APP_USER_NAME }}
40+
GIT_EMAIL: ${{ vars.GIT_APP_USER_EMAIL }}
41+
run: |
42+
git config user.name "$GIT_USER"
43+
git config user.email "$GIT_EMAIL"
44+
45+
- name: Bootstrap disnake-compass
46+
uses: ./.github/actions/bootstrap
47+
with:
48+
python-version: '3.10'
49+
50+
- name: Update version
51+
run: |
52+
poetry run scripts/ci/versiontool.py --set "$VERSION_INPUT"
53+
git commit -a -m "chore: update version to $VERSION_INPUT"
54+
55+
- name: Build changelog
56+
run: |
57+
poetry run towncrier build --yes --version "$VERSION_INPUT"
58+
git commit -a -m "docs: build changelog"
59+
60+
- name: Create pull request
61+
uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e # v6.0.2
62+
with:
63+
token: ${{ steps.generate_token.outputs.token }}
64+
branch: auto/release-v${{ inputs.version }}
65+
delete-branch: true
66+
title: "chore(release): v${{ inputs.version }}"
67+
body: |
68+
Automated release PR, triggered by @${{ github.actor }} for ${{ github.sha }}.
69+
70+
### Tasks
71+
- [ ] Add changelogs from backports, if applicable.
72+
- [ ] Once merged, create + push a tag.
73+
74+
<sub>https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}</sub>
75+
labels: |
76+
t: release
77+
assignees: |
78+
${{ github.actor }}

.github/workflows/release.yml

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# Adapted from https://github.com/DisnakeDev/disnake/blob/master/.github/workflows/release.yaml
2+
3+
name: Release
4+
5+
on:
6+
push:
7+
tags:
8+
- "v[0-9]+.[0-9]+.[0-9]+"
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
# Builds sdist and wheel, runs `twine check`, and uploads artifacts.
15+
build:
16+
name: Build package
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Bootstrap disnake-compass
23+
uses: ./.github/actions/bootstrap
24+
with:
25+
python-version: '3.10'
26+
27+
- name: Build package
28+
run: |
29+
poetry build
30+
ls -la dist/
31+
32+
- name: Twine check
33+
run: poetry run twine check --strict dist/*
34+
35+
- name: Show metadata
36+
run: |
37+
mkdir out/
38+
tar -xf dist/*.tar.gz -C out/
39+
40+
echo -e "<details><summary>Metadata</summary>\n" >> $GITHUB_STEP_SUMMARY
41+
cat out/*/PKG-INFO | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY
42+
echo -e "\n</details>\n" >> $GITHUB_STEP_SUMMARY
43+
44+
- name: Upload artifact
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: dist
48+
path: dist/
49+
if-no-files-found: error
50+
51+
52+
# Ensures that git tag and built version match.
53+
validate-tag:
54+
name: Validate tag
55+
runs-on: ubuntu-latest
56+
needs:
57+
- build
58+
env:
59+
GIT_TAG: ${{ github.ref_name }}
60+
outputs:
61+
bump_dev: ${{ steps.check-dev.outputs.bump_dev }}
62+
63+
steps:
64+
- name: Download build artifact
65+
uses: actions/download-artifact@v4
66+
with:
67+
name: dist
68+
path: dist/
69+
70+
- name: Compare sdist version to git tag
71+
run: |
72+
mkdir out/
73+
tar -xf dist/*.tar.gz -C out/
74+
75+
SDIST_VERSION="$(grep "^Version:" out/*/PKG-INFO | cut -d' ' -f2-)"
76+
echo "git tag: $GIT_TAG"
77+
echo "sdist version: $SDIST_VERSION"
78+
79+
if [ "$GIT_TAG" != "v$SDIST_VERSION" ]; then
80+
echo "error: git tag does not match sdist version" >&2
81+
exit 1
82+
fi
83+
84+
- name: Determine if dev version PR is needed
85+
id: check-dev
86+
run: |
87+
BUMP_DEV=
88+
# if this is a new major/minor version, create a PR later
89+
if [[ "$GIT_TAG" =~ ^v[0-9]+\.[0-9]+\.0$ ]]; then
90+
BUMP_DEV=1
91+
fi
92+
echo "bump_dev=$BUMP_DEV" | tee -a $GITHUB_OUTPUT
93+
94+
95+
# Creates a draft release on GitHub, and uploads the artifacts there.
96+
release-github:
97+
name: Create GitHub draft release
98+
runs-on: ubuntu-latest
99+
needs:
100+
- build
101+
- validate-tag
102+
permissions:
103+
contents: write # required for creating releases
104+
105+
steps:
106+
- name: Download build artifact
107+
uses: actions/download-artifact@v4
108+
with:
109+
name: dist
110+
path: dist/
111+
112+
- name: Calculate versions
113+
id: versions
114+
env:
115+
GIT_TAG: ${{ github.ref_name }}
116+
run: |
117+
# v1.2.3 -> v1-2-3 (for changelog)
118+
echo "docs_version=${GIT_TAG//./-}" >> $GITHUB_OUTPUT
119+
120+
- name: Create Release
121+
uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v2.0.4
122+
with:
123+
files: dist/*
124+
draft: true
125+
body: |
126+
TBD.
127+
128+
**Changelog**: https://docs.disnake.dev/en/stable/whats_new.html#${{ steps.versions.outputs.docs_version }}
129+
**Git history**: https://github.com/${{ github.repository }}/compare/vTODO...${{ github.ref_name }}
130+
131+
132+
# Creates a PyPI release (using an environment which requires separate confirmation).
133+
release-pypi:
134+
name: Publish package to pypi.org
135+
environment:
136+
name: release-pypi
137+
url: https://pypi.org/project/disnake/
138+
runs-on: ubuntu-latest
139+
needs:
140+
- build
141+
- validate-tag
142+
permissions:
143+
id-token: write # this permission is mandatory for trusted publishing
144+
145+
steps:
146+
- name: Download build artifact
147+
uses: actions/download-artifact@v4
148+
with:
149+
name: dist
150+
path: dist/
151+
152+
- name: Upload to pypi
153+
uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450 # v1.8.14
154+
with:
155+
print-hash: true
156+
157+
158+
# Creates a PR to bump to an alpha version for development, if applicable.
159+
create-dev-version-pr:
160+
name: Create dev version bump PR
161+
runs-on: ubuntu-latest
162+
if: needs.validate-tag.outputs.bump_dev
163+
needs:
164+
- validate-tag
165+
- release-github
166+
- release-pypi
167+
168+
steps:
169+
# https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/making-authenticated-api-requests-with-a-github-app-in-a-github-actions-workflow
170+
- name: Generate app token
171+
id: generate_token
172+
uses: actions/create-github-app-token@f2acddfb5195534d487896a656232b016a682f3c # v1.9.0
173+
with:
174+
app-id: ${{ secrets.BOT_APP_ID }}
175+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
176+
177+
- uses: actions/checkout@v4
178+
with:
179+
token: ${{ steps.generate_token.outputs.token }}
180+
persist-credentials: false
181+
ref: master # the PR action wants a proper base branch
182+
183+
- name: Set git name/email
184+
env:
185+
GIT_USER: ${{ vars.GIT_APP_USER_NAME }}
186+
GIT_EMAIL: ${{ vars.GIT_APP_USER_EMAIL }}
187+
run: |
188+
git config user.name "$GIT_USER"
189+
git config user.email "$GIT_EMAIL"
190+
191+
- name: Update version to dev
192+
id: update-version
193+
run: |
194+
NEW_VERSION="$(python scripts/ci/versiontool.py --set dev)"
195+
git commit -a -m "chore: update version to v$NEW_VERSION"
196+
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
197+
198+
- name: Create pull request
199+
uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e # v6.0.2
200+
with:
201+
token: ${{ steps.generate_token.outputs.token }}
202+
branch: auto/dev-v${{ steps.update-version.outputs.new_version }}
203+
delete-branch: true
204+
base: master
205+
title: "chore: update version to v${{ steps.update-version.outputs.new_version }}"
206+
body: |
207+
Automated dev version PR.
208+
209+
<sub>https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}</sub>
210+
labels: |
211+
skip news

changelog/41.doc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Introduce towncrier for changelogs.

changelog/42.doc.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix source code links and installation instructions and some miscellaneous issues.

changelog/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
This directory contains "news fragments" which are short files that contain a small **ReST**-formatted
2+
text that will be added to the next changelog.
3+
4+
The changelog will be read by **users**, so this description should be aimed at users
5+
instead of describing internal changes which are only relevant to the developers.
6+
7+
Make sure to use full sentences in the **present tense** and use punctuation, examples:
8+
9+
- Improve Guild.create_text_channel by returning the channel type.
10+
11+
- Command syncing now uses logging instead of print.
12+
13+
Each file should use the following naming: ``<ISSUE>.<TYPE>.rst``, where
14+
``<ISSUE>`` is an issue number, and ``<TYPE>`` is one of:
15+
16+
* ``breaking``: a change which may break existing code, such as feature removal or behavior change.
17+
* ``deprecate``: feature deprecation.
18+
* ``feature``: new user facing features, support of new API features, and/or otherwise new behavior.
19+
* ``bugfix``: fixes a bug.
20+
* ``doc``: documentation improvement.
21+
* ``misc``: fixing a small typo or internal change that might be noteworthy.
22+
23+
So for example: ``123.feature.rst``, ``456.bugfix.rst``.
24+
25+
If your PR fixes an issue, use that number here. If there is no issue,
26+
then after you submit the PR and get the PR number you can add a
27+
changelog using that instead.
28+
29+
If there are multiple changes of the same type for the same issue, use the following naming for the conflicting changes:
30+
``<ISSUE>.<TYPE>.<COUNTER>.rst``
31+
32+
If you are not sure what issue type to use, don't hesitate to ask in your PR.
33+
34+
``towncrier`` preserves multiple paragraphs and formatting (code blocks, lists, and so on), but for entries
35+
other than ``features`` it is usually better to stick to a single paragraph to keep it concise.
36+
37+
You can also run ``poetry run task docs`` to build the documentation
38+
with the draft changelog (http://127.0.0.1:8009/whats_new.html) if you want to get a preview of how your change will look in the final release notes.
39+
40+
---
41+
42+
This file is adapted from [disnake's changelog documentation](https://github.com/DisnakeDev/disnake/blob/master/changelog/README.rst>).

0 commit comments

Comments
 (0)