-
-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🧪 Integrate changelog generation into CI/CD
This includes GitHub Actions CI/CD, tox and lockfiles.
- Loading branch information
Showing
21 changed files
with
389 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -142,6 +142,11 @@ jobs: | |
git-tag: ${{ steps.git-tag.outputs.tag }} | ||
sdist-artifact-name: ${{ steps.artifact-name.outputs.sdist }} | ||
wheel-artifact-name: ${{ steps.artifact-name.outputs.wheel }} | ||
changelog-patch-name: ${{ steps.changelog-patch-name.outputs.filename }} | ||
changelog-draft-name-md: >- | ||
${{ steps.changelog-draft-name.outputs.filename-base }}.md | ||
changelog-draft-name-rst: >- | ||
${{ steps.changelog-draft-name.outputs.filename-base }}.rst | ||
steps: | ||
- name: Switch to using Python 3.11 by default | ||
uses: actions/setup-python@v5 | ||
|
@@ -296,6 +301,10 @@ jobs: | |
mode=FILE_APPEND_MODE, | ||
) as outputs_file: | ||
print(f'dist-version={ver}', file=outputs_file) | ||
print( | ||
f'dist-version-for-filenames={ver.replace("+", "-")}', | ||
file=outputs_file, | ||
) | ||
- name: Set the target Git tag | ||
id: git-tag | ||
run: | | ||
|
@@ -342,6 +351,228 @@ jobs: | |
}}-py3-none-any.whl", | ||
file=outputs_file, | ||
) | ||
- name: Set the expected changelog patch filename | ||
id: changelog-patch-name | ||
run: | | ||
from os import environ | ||
from pathlib import Path | ||
FILE_APPEND_MODE = 'a' | ||
with Path(environ['GITHUB_OUTPUT']).open( | ||
mode=FILE_APPEND_MODE, | ||
) as outputs_file: | ||
print('filename=0001-Generate-a-changelog-entry-for-v${{ | ||
steps.request-check.outputs.release-requested == 'true' | ||
&& github.event.inputs.release-version | ||
|| steps.scm-version.outputs.dist-version-for-filenames | ||
}}.patch', file=outputs_file) | ||
- name: Set the expected changelog draft filename | ||
id: changelog-draft-name | ||
run: | | ||
from os import environ | ||
from pathlib import Path | ||
FILE_APPEND_MODE = 'a' | ||
with Path(environ['GITHUB_OUTPUT']).open( | ||
mode=FILE_APPEND_MODE, | ||
) as outputs_file: | ||
print('filename-base=change-notes-v${{ | ||
steps.request-check.outputs.release-requested == 'true' | ||
&& github.event.inputs.release-version | ||
|| steps.scm-version.outputs.dist-version-for-filenames | ||
}}', file=outputs_file) | ||
build-changelog: | ||
name: >- | ||
👷📝 ${{ needs.pre-setup.outputs.git-tag }} changelog | ||
[mode: ${{ | ||
fromJSON(needs.pre-setup.outputs.is-untagged-devel) | ||
&& 'nightly' || '' | ||
}}${{ | ||
fromJSON(needs.pre-setup.outputs.release-requested) | ||
&& 'release' || '' | ||
}}${{ | ||
( | ||
!fromJSON(needs.pre-setup.outputs.is-untagged-devel) | ||
&& !fromJSON(needs.pre-setup.outputs.release-requested) | ||
) && 'test' || '' | ||
}}] | ||
needs: | ||
- pre-setup | ||
runs-on: ubuntu-latest | ||
|
||
env: | ||
TOXENV: make-changelog | ||
|
||
steps: | ||
- name: Switch to using Python 3.11 | ||
uses: actions/[email protected] | ||
with: | ||
python-version: 3.11 | ||
|
||
- name: Grab the source from Git | ||
uses: actions/[email protected] | ||
with: | ||
fetch-depth: 1 # Enough for this job to generate the changelog | ||
ref: ${{ github.event.inputs.release-committish }} | ||
|
||
- name: >- | ||
Calculate Python interpreter version hash value | ||
for use in the cache key | ||
id: calc-cache-key-py | ||
run: | | ||
from hashlib import sha512 | ||
from os import environ | ||
from pathlib import Path | ||
from sys import version | ||
FILE_APPEND_MODE = 'a' | ||
hash = sha512(version.encode()).hexdigest() | ||
with Path(environ['GITHUB_OUTPUT']).open( | ||
mode=FILE_APPEND_MODE, | ||
) as outputs_file: | ||
print(f'py-hash-key={hash}', file=outputs_file) | ||
shell: python | ||
- name: Set up pip cache | ||
uses: actions/[email protected] | ||
with: | ||
path: >- | ||
${{ | ||
runner.os == 'Linux' | ||
&& '~/.cache/pip' | ||
|| '~/Library/Caches/pip' | ||
}} | ||
key: >- | ||
${{ runner.os }}-pip-${{ | ||
steps.calc-cache-key-py.outputs.py-hash-key }}-${{ | ||
needs.pre-setup.outputs.cache-key-files }} | ||
restore-keys: | | ||
${{ runner.os }}-pip-${{ | ||
steps.calc-cache-key-py.outputs.py-hash-key | ||
}}- | ||
${{ runner.os }}-pip- | ||
${{ runner.os }}- | ||
- name: Install tox | ||
run: >- | ||
python -m | ||
pip install | ||
--user | ||
'${{ env.TOX_VERSION }}' | ||
- name: Pre-populate the tox env | ||
run: >- | ||
python -m | ||
tox | ||
--parallel auto | ||
--parallel-live | ||
--skip-missing-interpreters false | ||
--notest | ||
- name: Drop Git tags from HEAD for non-tag-create events | ||
if: >- | ||
!fromJSON(needs.pre-setup.outputs.release-requested) | ||
run: >- | ||
git tag --points-at HEAD | ||
| | ||
xargs git tag --delete | ||
shell: bash | ||
|
||
- name: Setup git user as [bot] | ||
# Refs: | ||
# * https://github.community/t/github-actions-bot-email-address/17204/6 | ||
# * https://github.com/actions/checkout/issues/13#issuecomment-724415212 | ||
uses: fregante/[email protected] | ||
|
||
- name: Generate changelog draft to a temporary file | ||
run: >- | ||
2>/dev/null | ||
python -m | ||
tox | ||
--skip-missing-interpreters false | ||
--skip-pkg-install | ||
-- | ||
'${{ needs.pre-setup.outputs.dist-version }}' | ||
--draft | ||
| | ||
tee | ||
'${{ needs.pre-setup.outputs.changelog-draft-name-rst }}' | ||
shell: bash | ||
- name: Sanitize the markdown changelog version | ||
run: >- | ||
sed | ||
-i | ||
-e 's/:commit:`\([0-9a-f]\+\)`/${{ | ||
'' | ||
}}https:\/\/github.com\/cherrypy\/cheroot\/commit\/\1/g' | ||
-e 's/:gh:`\([-.a-zA-Z0-9]\+\)`/https:\/\/github.com\/\1/g' | ||
-e 's/:\(issue\|pr\):`\([0-9]\+\)`/#\2/g' | ||
-e 's/:user:`\([-.a-zA-Z0-9]\+\)`/@\1/g' | ||
'${{ needs.pre-setup.outputs.changelog-draft-name-rst }}' | ||
shell: bash | ||
- name: Install pandoc via apt | ||
run: sudo apt install -y pandoc | ||
- name: >- | ||
Convert ${{ needs.pre-setup.outputs.changelog-draft-name-rst }} | ||
into ${{ needs.pre-setup.outputs.changelog-draft-name-md }} | ||
with a native pandoc run | ||
run: >- | ||
pandoc | ||
--from=rst | ||
--to=gfm | ||
--output='${{ needs.pre-setup.outputs.changelog-draft-name-md }}' | ||
'${{ needs.pre-setup.outputs.changelog-draft-name-rst }}' | ||
- name: Render the changelog draft in the GitHub Job Summary | ||
run: | | ||
echo "# Changelog for ${{ | ||
needs.pre-setup.outputs.git-tag | ||
}}" >> "${GITHUB_STEP_SUMMARY}" | ||
echo >> "${GITHUB_STEP_SUMMARY}" | ||
echo >> "${GITHUB_STEP_SUMMARY}" | ||
cat '${{ | ||
needs.pre-setup.outputs.changelog-draft-name-md | ||
}}' >> "${GITHUB_STEP_SUMMARY}" | ||
shell: bash | ||
- name: Generate changelog update with tox and stage it in Git | ||
run: >- | ||
python -m | ||
tox | ||
--parallel auto | ||
--parallel-live | ||
--skip-missing-interpreters false | ||
--skip-pkg-install | ||
-- | ||
'${{ needs.pre-setup.outputs.dist-version }}' | ||
--yes | ||
- name: >- | ||
Commit the changelog updates for release | ||
${{ needs.pre-setup.outputs.git-tag }} in the local Git repo | ||
run: >- | ||
git commit -m | ||
'Generate a changelog entry for ${{ | ||
needs.pre-setup.outputs.git-tag | ||
}}' | ||
- name: Log the changelog commit | ||
run: git show --color | ||
- name: Create a changelog update patch from the last Git commit | ||
run: >- | ||
git format-patch | ||
--output='${{ needs.pre-setup.outputs.changelog-patch-name }}' | ||
-1 HEAD | ||
- name: Verify that expected patch got created | ||
run: ls -1 '${{ needs.pre-setup.outputs.changelog-patch-name }}' | ||
- name: Save the package bump patch as a GHA artifact | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: changelog | ||
path: | | ||
${{ needs.pre-setup.outputs.changelog-patch-name }} | ||
${{ needs.pre-setup.outputs.changelog-draft-name-md }} | ||
${{ needs.pre-setup.outputs.changelog-draft-name-rst }} | ||
build: | ||
name: >- | ||
|
@@ -359,6 +590,7 @@ jobs: | |
) && 'test' || '' | ||
}}] | ||
needs: | ||
- build-changelog | ||
- pre-setup # transitive, for accessing settings | ||
|
||
runs-on: ubuntu-latest | ||
|
@@ -1036,6 +1268,26 @@ jobs: | |
# * https://github.community/t/github-actions-bot-email-address/17204/6 | ||
# * https://github.com/actions/checkout/issues/13#issuecomment-724415212 | ||
uses: fregante/setup-git-user@v2 | ||
- name: Fetch the GHA artifact with the version patch | ||
if: steps.existing-remote-tag-check.outputs.already-exists != 'true' | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: changelog | ||
|
||
- name: Apply the changelog patch | ||
if: steps.existing-remote-tag-check.outputs.already-exists != 'true' | ||
run: git am '${{ needs.pre-setup.outputs.changelog-patch-name }}' | ||
shell: bash | ||
|
||
- name: >- | ||
Create a local 'release/${{ | ||
needs.pre-setup.outputs.dist-version | ||
}}' branch | ||
if: steps.existing-remote-tag-check.outputs.already-exists != 'true' | ||
run: >- | ||
git checkout -b 'release/${{ | ||
needs.pre-setup.outputs.dist-version | ||
}}' | ||
- name: >- | ||
Tag the release in the local Git repo | ||
|
@@ -1055,14 +1307,15 @@ jobs: | |
github.run_id | ||
}}' | ||
'${{ needs.pre-setup.outputs.git-tag }}' | ||
-- | ||
${{ github.event.inputs.release-committish }} | ||
- name: >- | ||
Push ${{ needs.pre-setup.outputs.git-tag }} tag corresponding | ||
to the just published release back to GitHub | ||
if: steps.existing-remote-tag-check.outputs.already-exists != 'true' | ||
run: >- | ||
git push --atomic origin '${{ needs.pre-setup.outputs.git-tag }}' | ||
git push --atomic origin | ||
'release/${{ needs.pre-setup.outputs.dist-version }}' | ||
'${{ needs.pre-setup.outputs.git-tag }}' | ||
publish-github-release: | ||
name: >- | ||
|
@@ -1083,6 +1336,35 @@ jobs: | |
with: | ||
name: ${{ env.dists-artifact-name }} | ||
path: dist/ | ||
- name: Fetch the GHA artifact with the version patch | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: changelog | ||
|
||
- name: Prepare the release notes file for the GitHub Releases | ||
run: | | ||
echo '## 📝 Release notes' | tee -a release-notes.md | ||
echo | tee -a release-notes.md | ||
echo | tee -a release-notes.md | ||
echo '📦 PyPI page: https://pypi.org/project/cheroot/${{ | ||
needs.pre-setup.outputs.dist-version | ||
}}' | tee -a release-notes.md | ||
echo | tee -a release-notes.md | ||
echo | tee -a release-notes.md | ||
echo '🔗 This release has been produced by ' \ | ||
'the following workflow run: ${{ | ||
github.server_url | ||
}}/${{ | ||
github.repository | ||
}}/actions/runs/${{ | ||
github.run_id | ||
}}' | tee -a release-notes.md | ||
echo | tee -a release-notes.md | ||
echo | tee -a release-notes.md | ||
cat '${{ | ||
needs.pre-setup.outputs.changelog-draft-name-md | ||
}}' | tee -a release-notes.md | ||
shell: bash | ||
|
||
- name: >- | ||
Publish a GitHub Release for | ||
|
@@ -1095,25 +1377,7 @@ jobs: | |
dist/${{ needs.pre-setup.outputs.sdist-artifact-name }} | ||
dist/${{ needs.pre-setup.outputs.wheel-artifact-name }} | ||
artifactContentType: raw # Because whl and tgz are of different types | ||
body: > | ||
# Release ${{ needs.pre-setup.outputs.git-tag }} | ||
This release is published to | ||
https://pypi.org/project/cheroot/${{ | ||
needs.pre-setup.outputs.dist-version | ||
}}. | ||
This release has been produced by the following workflow run: ${{ | ||
github.server_url | ||
}}/${{ | ||
github.repository | ||
}}/actions/runs/${{ | ||
github.run_id | ||
}}. | ||
# bodyFile: # FIXME: Use once Towncrier is integrated. | ||
commit: ${{ github.event.inputs.release-committish }} | ||
bodyFile: release-notes.md | ||
discussionCategory: Announcements | ||
draft: false | ||
name: ${{ needs.pre-setup.outputs.git-tag }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.