Skip to content

Commit 95d9df6

Browse files
authored
github actions (#1)
1 parent a44b7ae commit 95d9df6

8 files changed

Lines changed: 196 additions & 4 deletions

File tree

.github/change_version.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env -S python3 -u
2+
3+
import argparse
4+
import re
5+
from pathlib import Path
6+
7+
# TODO: replace `example` with your package name
8+
VERSION_PY = Path(__file__).parent.parent / 'example' / '__init__.py'
9+
VERSION_RE = re.compile(r"__version__ = version = '(.*?)'")
10+
11+
12+
def main():
13+
p = argparse.ArgumentParser()
14+
p.add_argument('--set', type=str, metavar='VERSION', help='New version')
15+
args = p.parse_args()
16+
17+
data = VERSION_PY.read_text()
18+
version = VERSION_RE.findall(data)
19+
if not version:
20+
raise Exception('could not find version')
21+
version = version[0]
22+
print(f'Current version: {version}')
23+
24+
if args.set:
25+
VERSION_PY.write_text(VERSION_RE.sub(f"__version__ = version = '{args.set}'", data))
26+
print(f'New version: {args.set}')
27+
28+
29+
if __name__ == '__main__':
30+
main()

.github/workflows/publish-dev.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: 👷 publish dev
2+
3+
on:
4+
push:
5+
# TODO: choose your "feature branch" naming (or leave it like this)
6+
# or run this on every non-main branch, replacing the whole `branches` with
7+
# branches-ignore:
8+
# - main
9+
branches:
10+
- dev
11+
- dev/*
12+
- dev-*
13+
14+
jobs:
15+
test_and_publish:
16+
uses: ./.github/workflows/publish.yml
17+
with:
18+
version: '${{ github.run_number }}.0.0'
19+
repository: testpypi
20+
secrets:
21+
twine_username: ${{ secrets.TESTPYPI_USERNAME }}
22+
twine_password: ${{ secrets.TESTPYPI_TOKEN }}

.github/workflows/publish-main.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: 🚀 publish
2+
3+
on:
4+
push:
5+
tags:
6+
- '[0-9]+.[0-9]+.[0-9]+'
7+
8+
jobs:
9+
test_and_publish:
10+
uses: ./.github/workflows/publish.yml
11+
with:
12+
# so easy to forget bumping the version to match the tag, just override it!
13+
version: ${{ github.ref_name }}
14+
secrets:
15+
twine_username: ${{ secrets.PYPI_USERNAME }}
16+
twine_password: ${{ secrets.PYPI_TOKEN }}

.github/workflows/publish.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: publish
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
version:
7+
type: string
8+
required: true
9+
repository:
10+
type: string
11+
secrets:
12+
twine_username:
13+
required: true
14+
twine_password:
15+
required: true
16+
17+
run-name: publish to ${{ inputs.repository }}
18+
19+
jobs:
20+
test:
21+
uses: ./.github/workflows/test.yml
22+
23+
publish:
24+
name: publish to ${{ inputs.repository }}
25+
runs-on: ubuntu-latest
26+
needs: test
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
31+
- name: Set up Python
32+
uses: actions/setup-python@v5
33+
with:
34+
python-version: "3.10"
35+
36+
- name: Install dependencies
37+
run: |
38+
pip install pipenv
39+
pipenv requirements --dev > reqs.txt
40+
pip install -r reqs.txt
41+
- name: force right version
42+
run: |
43+
.github/change_version.py --set '${{ inputs.version }}'
44+
- name: Build
45+
run: pyproject-build
46+
- name: Publish
47+
env:
48+
TWINE_USERNAME: ${{ secrets.twine_username }}
49+
TWINE_PASSWORD: ${{ secrets.twine_password }}
50+
run: |
51+
pyproject-build
52+
twine upload --repository ${{ inputs.repository }} dist/*
53+
- name: highlight
54+
# TODO: update package name in summary text
55+
run: |
56+
INDEX=""
57+
if [ "${{ inputs.repository }}" != "pypi" ]; then
58+
INDEX=" -i ${{ inputs.repository }}"
59+
fi
60+
cat <<EOF >> ${GITHUB_STEP_SUMMARY}
61+
\`example\` uploaded to ${{ inputs.repository }}
62+
\`\`\`
63+
pip install${INDEX} example==${{ inputs.version }}
64+
\`\`\`
65+
EOF

.github/workflows/test.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: 🧪 tests
2+
3+
on:
4+
workflow_call:
5+
push:
6+
branches-ignore:
7+
# these are already tested by publish-dev
8+
- dev
9+
- dev/*
10+
- dev-*
11+
12+
jobs:
13+
tests:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: "3.10"
23+
24+
- name: Install dependencies
25+
run: |
26+
pip install pipenv
27+
pipenv requirements --dev > reqs.txt
28+
pip install -r reqs.txt
29+
30+
- name: Lint check
31+
id: lint-check
32+
# allow unit tests to run even if this fails
33+
continue-on-error: true
34+
run: |
35+
make lint-check
36+
37+
- name: Run unit tests
38+
run: |
39+
make test
40+
41+
- name: Final check
42+
if: ${{ steps.lint-check.outcome == 'failure' }}
43+
run: |
44+
echo Lint check failed, check its log
45+
exit 1

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ lint:
22
ruff format
33
ruff check --fix
44

5+
lint-check:
6+
ruff format --diff
7+
ruff check
8+
59
test:
610
python -m pytest --cov
711

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
# python package template
22

3+
[![ci](https://github.com/fopina/example/actions/workflows/publish-main.yml/badge.svg)](https://github.com/fopina/example/actions/workflows/publish-main.yml)
4+
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/fp-github-template-example.svg)](https://pypi.python.org/pypi/fp-github-template-example/)
5+
[![PyPI version](https://badge.fury.io/py/fp-github-template-example.svg)](https://badge.fury.io/py/fp-github-template-example)
6+
[![Very popular](https://img.shields.io/pypi/dm/fp-github-template-example)](https://pypistats.org/packages/fp-github-template-example)
7+
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
8+
39
## Content
410

511
* `pytest` for tests: `make test`
612
* `ruff` for linting/formatting: `make lint` (replaces both `black` and `isort`)
7-
* `.github` with actions ready to test PRs and publish releases
13+
* `.github` with actions ready to be used
14+
* [test](.github/workflows/test.yml) runs lint checks and unit tests
15+
* [publish-dev](.github/workflows/publish-dev.yml) publishes feature branches (`dev`/`dev-*`) to [testpypi](https://test.pypi.org)
16+
* [publish-main](.github/workflows/publish-main.yml) publishes semver tags to [pypi](https://pypi.org)
817

918
## New project checklist
1019

11-
* [ ] Replace `example` with *the* package
20+
* [ ] Replace folder `example` with the actual package
1221
* [ ] Replace `LICENSE` if MIT does not apply
1322
* [ ] Search the project for `# TODO` to find the (minimum list of) places that need to be changed.
1423
* [ ] Add PYPI credentials to secrets
15-
24+
* `PYPI_USERNAME` and `PYPI_TOKEN` to publish tags to pypi
25+
* `TESTPYPI_USERNAME` and `TESTPYPI_TOKEN` to publish dev branches to testpypi

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Homepage = "https://github.com/fopina/python-package-template"
1919

2020
[project.scripts]
2121
# TODO: remove this if package is not a CLI or update it if it is
22-
admindocs-cli = "example.__main__:cli"
22+
example-cli = "example.__main__:cli"
2323

2424
[tool.setuptools.packages.find]
2525
# TODO: replace example with your package name

0 commit comments

Comments
 (0)