Skip to content

Commit aefe5c6

Browse files
Merge pull request #37 from ipdata/auto-release
Release automatically when the version changes
2 parents 642fcc1 + 75dc563 commit aefe5c6

2 files changed

Lines changed: 66 additions & 2 deletions

File tree

‎.github/workflows/python-publish.yml‎

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,62 @@ jobs:
3131
run: |
3232
python -m pytest -m "not api"
3333
34+
release:
35+
name: Tag and create the GitHub release
36+
# Only pushes to the default branch can release; a version that is already tagged is left alone.
37+
if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
38+
needs: test
39+
runs-on: ubuntu-24.04
40+
permissions:
41+
contents: write
42+
concurrency:
43+
group: release
44+
cancel-in-progress: false
45+
outputs:
46+
tag: ${{ steps.version.outputs.tag }}
47+
created: ${{ steps.release.outputs.created }}
48+
steps:
49+
- uses: actions/checkout@v7
50+
- name: Read the version from setup.cfg
51+
id: version
52+
run: |
53+
tag="$(sed -nE 's/^version *= *([^[:space:]]+).*/\1/p' setup.cfg | head -1)"
54+
if [ -z "$tag" ]; then
55+
echo "::error file=setup.cfg::no version found in setup.cfg"
56+
exit 1
57+
fi
58+
echo "version $tag"
59+
echo "tag=$tag" >> "$GITHUB_OUTPUT"
60+
- name: Create the tag and the release unless the tag exists
61+
id: release
62+
env:
63+
GH_TOKEN: ${{ github.token }}
64+
TAG: ${{ steps.version.outputs.tag }}
65+
run: |
66+
status=0
67+
git ls-remote --exit-code --tags origin "refs/tags/$TAG" > /dev/null || status=$?
68+
case "$status" in
69+
0)
70+
echo "tag $TAG already exists, nothing to release"
71+
echo "created=false" >> "$GITHUB_OUTPUT"
72+
;;
73+
2)
74+
gh release create "$TAG" --target "$GITHUB_SHA" --title "$TAG" --generate-notes
75+
echo "created=true" >> "$GITHUB_OUTPUT"
76+
;;
77+
*)
78+
echo "::error::git ls-remote failed with exit code $status"
79+
exit "$status"
80+
;;
81+
esac
82+
3483
build-n-publish:
3584
name: Build and publish to PyPI
36-
if: github.event_name == 'push'
85+
needs: [test, release]
86+
# Runs for every push as before; the release job is skipped for tag pushes, hence the explicit result checks.
87+
if: >-
88+
!cancelled() && github.event_name == 'push' && needs.test.result == 'success'
89+
&& (needs.release.result == 'success' || needs.release.result == 'skipped')
3790
# kept on the same image as the test job
3891
runs-on: ubuntu-24.04
3992
steps:
@@ -60,7 +113,8 @@ jobs:
60113
build
61114
.
62115
- name: Publish to PyPI
63-
if: startsWith(github.ref, 'refs/tags')
116+
# a tag created by the release job in this run, or a tag pushed by hand
117+
if: needs.release.outputs.created == 'true' || startsWith(github.ref, 'refs/tags')
64118
uses: pypa/gh-action-pypi-publish@release/v1
65119
with:
66120
user: __token__

‎README.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Visit our [Documentation](https://docs.ipdata.co/) for more examples and tutoria
4949
- [Performance](#performance)
5050
- [Errors](#errors)
5151
- [Tests](#tests)
52+
- [Releasing](#releasing)
5253

5354
## Installation
5455

@@ -791,3 +792,12 @@ The tests marked `api` call the live API and need an `IPDATA_API_KEY` environmen
791792
```shell
792793
pytest -m "not api"
793794
```
795+
796+
## Releasing
797+
798+
Releases are cut by CI from the version in `setup.cfg`:
799+
800+
1. Bump `version` in `setup.cfg` in a pull request and merge it into `master`.
801+
2. CI runs the tests, tags the merge commit `x.y.z` (the version, with no `v` prefix), creates the GitHub release with generated notes and publishes the package to [PyPI](https://pypi.org/project/ipdata/).
802+
803+
A merge whose version is already tagged publishes nothing. Pushing a tag by hand still builds and publishes that tag as before.

0 commit comments

Comments
 (0)