Skip to content

Commit

Permalink
🧪 Integrate changelog generation into CI/CD
Browse files Browse the repository at this point in the history
This includes GitHub Actions CI/CD, tox and lockfiles.
  • Loading branch information
webknjaz committed Apr 8, 2024
1 parent c0f1e41 commit ed4bc54
Show file tree
Hide file tree
Showing 21 changed files with 389 additions and 22 deletions.
308 changes: 286 additions & 22 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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: |
Expand Down Expand Up @@ -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
-qq
--
'${{ 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: >-
Expand All @@ -359,6 +590,7 @@ jobs:
) && 'test' || ''
}}]
needs:
- build-changelog
- pre-setup # transitive, for accessing settings

runs-on: ubuntu-latest
Expand Down Expand Up @@ -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
Expand All @@ -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: >-
Expand All @@ -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
Expand All @@ -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 }}
Expand Down
4 changes: 4 additions & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ conftest
conn
chunked
docstrings
downstreams
ef
environ
Faux
Expand All @@ -32,6 +33,7 @@ noqa
PIL
pipelining
positionally
pre
py
pytest
pythonic
Expand All @@ -49,11 +51,13 @@ stdout
subclasses
submodules
subpackages
symlinked
syscall
systemd
threadpool
Tidelift
TLS
Towncrier
tracebacks
tuple
tuples
Expand Down
Loading

0 comments on commit ed4bc54

Please sign in to comment.