Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

various amendments #21

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cbee59c
Feat: rework GitHub workflows
dornech Dec 22, 2024
709b655
Feat: add config files for linting of commit messages
dornech Dec 22, 2024
a84383e
Feat: add config file for generate-changelog
dornech Dec 22, 2024
81c989d
Feat: adjust pre-commit.yaml for linting commit-msg and version update
dornech Dec 22, 2024
a2b6e2e
Fix: correct build.yaml
dornech Dec 22, 2024
7e26c6e
Fix: amend .gitignore for ruff cache
dornech Dec 22, 2024
834b155
Feat: include hatch-vcs-footgun-example in __init__.py
dornech Dec 22, 2024
fd0418b
Feat: various changes to pyproject.toml to include additional features
dornech Dec 22, 2024
e24f745
Update README.md
dornech Dec 22, 2024
3cae85e
feat: code blocks in mkdocs.yaml
dornech Dec 22, 2024
f2f65b6
feat: add. settings pymdownx.highlight
dornech Dec 22, 2024
7c5e882
fix: escaping of variable in .changelog-config.yml
dornech Dec 23, 2024
f45280a
fix: escaping of variable in .changelog-config.yml /2.
dornech Dec 23, 2024
d5ff3a1
fix: escaping of semantic-release config in pyproject.toml
dornech Dec 23, 2024
10ae8ff
fix: correct build.yml (incorrect escaping)
dornech Dec 23, 2024
60a35d3
fix: correct build.yml (incorrect escaping) /2.
dornech Dec 23, 2024
4b816fb
fix: correct build.yml (incorrect escaping) /3.
dornech Dec 23, 2024
2807155
fix: correct pyproject.toml (incomplete escaping)
dornech Dec 23, 2024
3f45e9f
fix: editing ...
dornech Dec 23, 2024
4698acf
feat: add basic Cruft config (template update helper)
dornech Dec 25, 2024
42c03b1
fix: clean __init__.py to avoid Hatch dependency
dornech Dec 25, 2024
67a7df1
feat: make gitlint optional via cookiecutter variable
dornech Dec 25, 2024
1826263
feat: make gitlint optional via cookiecutter variable /2.
dornech Dec 25, 2024
0f0908e
feat: make gitlint optional via cookiecutter variable /2.
dornech Dec 25, 2024
2ddb160
fix: postgen_project.py hook for optional .gitlint
dornech Dec 25, 2024
f3e85af
fix: postgen_project.py hook for optional .gitlint /2.
dornech Dec 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ The Hatchlor integrates the following features:
* [EditorConfig]: maintain consistent coding styles for multiple developers,
* [src-layout]: the actual Python package is kept under a `src` folder avoiding many common errors.

Please note additional integrations and following amendments:

* [semantic-release]: local prepare of a commit: create changelog and commit with a version tag
* [bump-my-version] and [generate-changelog]: alternative to [semantic-release]
* [gitlint]: include linting of commit messages
* [GitHub Actions]: reworked workflows - dump context, add test publishing on TestPy, switch to new PyPi mechanism

The amendments support a local development and commit process while "outsourcing" testing for different OS
and with different Python versions to GitHub.
The local committing includes preparation of a changelog. It is based on semantic-versioning.
Commit-messages are linted to enforce commit messages according to conventional commits format as
basis for a proper and automatically generated changelog.

The template includes a `skeleton.py` with a simple function `fib` that calculates the Fibonacci numbers
as demonstration. This is tested with `tests/test_skeleton.py` to demonstrate the corresponding features
from above. As an additional tidbit, `skeleton.py` also features [Typer] to show how `fib` can be
Expand Down
4 changes: 3 additions & 1 deletion cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"project_repo": "https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }}",
"pypi_username": "{{ cookiecutter.github_username }}",
"lock_file_support": false,
"gitlint_commitmsg_linter": true,
"__prompts__": {
"full_name": "Provide your [bold yellow]full name[/]",
"email": "Provide your [bold yellow]email[/]",
Expand All @@ -23,6 +24,7 @@
"open_source_license": "Provide the [bold yellow]license[/] of this project",
"pypi_username": "Optionally, provide a [bold yellow]PyPI user name[/]",
"github_username": "Optionally, provide a [bold yellow]Github user name[/]",
"lock_file_support": "Activate support for lock files?"
"lock_file_support": "Activate support for lock files?",
"gitlint_commitmsg_linter": "Include gitlint commit message linter?"
}
}
6 changes: 6 additions & 0 deletions hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import subprocess
import os


if not {{cookiecutter.gitlint_commitmsg_linter}}:
if os.path.exists(".gitlint"):
os.remove(".gitlint")

try:
subprocess.call(['git', 'init', '--initial-branch', 'main'])
Expand Down
123 changes: 123 additions & 0 deletions {{cookiecutter.project_slug}}/.changelog-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# For more configuration information, please see https://callowayproject.github.io/generate-changelog/

# User variables for reference in other parts of the configuration.
variables:
changelog_filename: CHANGELOG.md

# Pipeline to find the most recent tag for incremental changelog generation.
# Leave empty to always start at first commit.
starting_tag_pipeline:
- action: ReadFile
kwargs:
filename: '{% raw %}{{ changelog_filename }}{% endraw %}'
- action: FirstRegExMatch
kwargs:
pattern: (?im)^## (?P<rev>\d+\.\d+(?:\.\d+)?)\s+\(\d+-\d{2}-\d{2}\)$
named_subgroup: rev

# Used as the version title of the changes since the last valid tag.
unreleased_label: Unreleased

# Process the commit's first line for use in the changelog.
summary_pipeline:
- action: strip_spaces
- action: Strip
comment: Get rid of any periods so we don't get double periods
kwargs:
chars: .
- action: SetDefault
args:
- no commit message
- action: capitalize
- action: append_dot

# Process the commit's body for use in the changelog.
body_pipeline:
- action: ParseTrailers
comment: Parse the trailers into metadata.
kwargs:
commit_metadata: save_commit_metadata

# Process and store the full or partial changelog.
output_pipeline:
- action: IncrementalFileInsert
kwargs:
filename: '{% raw %}{{ changelog_filename }}{% endraw %}'
last_heading_pattern: (?im)^## \d+\.\d+(?:\.\d+)?\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)$

# Group the commits within a version by these commit attributes.
group_by:
- metadata.category

# Only tags matching this regular expression are used for the changelog.
# tag_pattern: ^[0-9]+\.[0-9]+(?:\.[0-9]+)?$
# tag_pattern: ^v[0-9]+\.[0-9]+(?:\.[0-9]+)?$
# Version tags RegEx from https://regex101.com/r/vkijKf/1/ preceeded by v
tag_pattern: ^(v0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$

# Tells ``git-log`` whether to include merge commits in the log.
include_merges: true

# Ignore commits whose summary line matches any of these regular expression patterns.
ignore_patterns:
- '[@!]minor'
- '[@!]cosmetic'
- '[@!]refactor'
- '[@!]wip'
- ^$
- ^Merge branch
- ^Merge pull
- ^[0-9]+\.[0-9]+(?:\.[0-9]+)?(?:\.)? # release commit for semantic-release

# Set the commit's category metadata to the first classifier that returns ``True``.
commit_classifiers:
- action: SummaryRegexMatch
category: New Features
kwargs:
pattern: (?i)^(?:new|add)[^\n]*$
- action: SummaryRegexMatch
category: Updates
kwargs:
pattern: (?i)^(?:update|change|rename|remove|delete|improve|refactor|chg|modif)[^\n]*$
- action: SummaryRegexMatch
category: Fixes
kwargs:
pattern: (?i)^(?:fix)[^\n]*$
- action:
category: Other

# Tokens in git commit trailers that indicate authorship.
valid_author_tokens:
- author
- based-on-a-patch-by
- based-on-patch-by
- co-authored-by
- co-committed-by
- contributions-by
- from
- helped-by
- improved-by
- original-patch-by

# Rules applied to commits to determine the type of release to suggest.
release_hint_rules:
- match_result: dev
branch: ^((?!master|main).)*$
- match_result: patch
grouping: Other
branch: master|main
- match_result: patch
grouping: Fixes
branch: master|main
- match_result: minor
grouping: Updates
branch: master|main
- match_result: minor
grouping: New
branch: master|main
- match_result: minor
grouping: New Features
branch: master|main
- match_result: major
grouping: Breaking Changes
branch: master|main
136 changes: 106 additions & 30 deletions {{cookiecutter.project_slug}}/.github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,75 +1,151 @@
name: Build
name: Build and Release Package

on: [push, pull_request]

jobs:
test:

runs-on: {% raw %}${{ matrix.os }}{% endraw %}
dump-context:
runs-on: ubuntu-latest
steps:
- name: Dump context "GitHub"
env:
GITHUB_CONTEXT: {% raw %}${{ toJson(github) }}{% endraw %}
run: echo "$GITHUB_CONTEXT"

build-test:
strategy:
matrix:
os: [ubuntu-latest]
python_version: ['{{ cookiecutter.target_python_version }}']

os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: {% raw %}${{ matrix.os }}{% endraw %}
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
- name: Check out the repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: {% raw %}${{ matrix.python_version }}{% endraw %}
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install hatch pre-commit
pip install hatch pre-commit coverage
hatch env create
- name: Lint and typecheck
run: |
hatch run lint:all
- name: Run Tests
- name: Run Tests with coverage analysis
run: |
hatch run test:pytest
hatch test --cover
- uses: codecov/codecov-action@v4
with:
token: {% raw %}${{ secrets.CODECOV_TOKEN }}{% endraw %}
fail_ci_if_error: true
verbose: true

release:
build-distribution:
runs-on: ubuntu-latest
environment: release
needs: test
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
id-token: write

needs: build-test
steps:
- uses: actions/checkout@v4
- name: Set up Python {% raw %}${{ matrix.python_version }}{% endraw %}
- name: Check out the repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '{{ cookiecutter.target_python_version }}'
python-version: '3.x'
- name: Install dependencies
shell: bash
run: |
python -m pip install --upgrade pip
pip install hatch pre-commit
- name: Build
- name: Build with Hatch
run: |
hatch build
- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/

publish-testpypi:
runs-on: ubuntu-latest
needs: build-distribution
environment:
name: pypi-test
url: https://testpypi.org/project/p/{% raw %}${{ github.event.repository.name }}{% endraw %}
permissions:
id-token: write
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish 📦 to Test PyPI
if: startsWith(github.ref, 'refs/heads/main')
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip_existing: true
user: __token__
password: {% raw %}${{ secrets.TEST_PYPI_SECRECT }}{% endraw %}
packages-dir: dist/
repository-url: https://test.pypi.org/legacy/
verbose: true
# skip-existing: true
# user: __token__
# password: {% raw %}${{ secrets.TEST_PYPI_SECRECT }}{% endraw %}

publish-pypi:
runs-on: ubuntu-latest
needs: [ build-distribution, publish-testpypi ]
environment:
name: pypi
url: https://pypi.org/project/p/{% raw %}${{ github.event.repository.name }}{% endraw %}
permissions:
id-token: write
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish 📦 to PyPI
if: startsWith(github.ref, 'refs/heads/main')
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: {% raw %}${{ secrets.PYPI_SECRECT }}{% endraw %}
packages-dir: dist/
# repository-url = "https://upload.pypi.org/legacy/"
verbose: true
# user: __token__
# password: {% raw %}${{ secrets.PYPI_SECRECT }}{% endraw %}

github-release:
runs-on: ubuntu-latest
needs: publish-pypi
permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
id-token: write # IMPORTANT: mandatory for sigstore
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Sign the Python 🐍 distribution 📦 with Sigstore
uses: sigstore/[email protected]
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Create GitHub Release
env:
GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %}
run: >-
gh release create
'{% raw %}${{ github.ref_name }}{% endraw %}'
--repo '{% raw %}${{ github.repository }}{% endraw %}'
--notes ""
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
'{% raw %}${{ github.ref_name }}{% endraw %}' dist/**
--repo '{% raw %}${{ github.repository }}{% endraw %}'
Loading