Skip to content

Commit ac4fcb3

Browse files
authored
Merge pull request #4 from mxstack/hatchling
update build system and CI/CD
2 parents c207024 + ce14a90 commit ac4fcb3

File tree

9 files changed

+244
-55
lines changed

9 files changed

+244
-55
lines changed

.github/dependabot.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5+
6+
version: 2
7+
updates:
8+
# Enable version updates for GitHub Actions
9+
- package-ecosystem: "github-actions"
10+
# Workflow files stored in the default location of `.github/workflows`
11+
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
12+
directory: "/"
13+
schedule:
14+
interval: "weekly"

.github/workflows/lint.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Lint
2+
3+
on:
4+
push:
5+
workflow_call:
6+
workflow_dispatch:
7+
8+
jobs:
9+
lint:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v5
14+
15+
- name: Set up uv
16+
uses: astral-sh/setup-uv@v7
17+
with:
18+
enable-cache: true
19+
cache-dependency-glob: "pyproject.toml"
20+
21+
- name: Set up Python 3.10
22+
run: uv python install 3.10
23+
24+
- name: Install Project
25+
run: make install
26+
27+
- name: Run checks
28+
run: make check

.github/workflows/release.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
name: Build & upload PyPI package
3+
4+
on:
5+
push:
6+
branches: [main]
7+
tags: ["*"]
8+
release:
9+
types:
10+
- published
11+
workflow_dispatch:
12+
13+
jobs:
14+
tests:
15+
uses: "./.github/workflows/test.yml"
16+
lint:
17+
uses: "./.github/workflows/lint.yml"
18+
typecheck:
19+
uses: "./.github/workflows/typecheck.yml"
20+
21+
# Always build & lint package.
22+
build-package:
23+
name: Build & verify package
24+
needs:
25+
- lint
26+
- tests
27+
- typecheck
28+
runs-on: ubuntu-latest
29+
permissions:
30+
attestations: write
31+
id-token: write
32+
33+
steps:
34+
- uses: actions/checkout@v5
35+
with:
36+
fetch-depth: 0
37+
persist-credentials: false
38+
39+
- uses: hynek/build-and-inspect-python-package@v2
40+
with:
41+
attest-build-provenance-github: 'true'
42+
43+
# Upload to Test PyPI on every commit on main.
44+
release-test-pypi:
45+
name: Publish in-dev package to test.pypi.org
46+
environment: release-test-pypi
47+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
48+
runs-on: ubuntu-latest
49+
needs:
50+
- build-package
51+
permissions:
52+
id-token: write
53+
54+
steps:
55+
- name: Download packages built by build-and-inspect-python-package
56+
uses: actions/download-artifact@v6
57+
with:
58+
name: Packages
59+
path: dist
60+
61+
- name: Upload package to Test PyPI
62+
uses: pypa/gh-action-pypi-publish@release/v1
63+
with:
64+
repository-url: https://test.pypi.org/legacy/
65+
66+
# Upload to real PyPI on GitHub Releases.
67+
release-pypi:
68+
name: Publish released package to pypi.org
69+
environment: release-pypi
70+
if: github.event.action == 'published'
71+
runs-on: ubuntu-latest
72+
needs:
73+
- build-package
74+
permissions:
75+
id-token: write
76+
77+
steps:
78+
- name: Download packages built by build-and-inspect-python-package
79+
uses: actions/download-artifact@v6
80+
with:
81+
name: Packages
82+
path: dist
83+
84+
- name: Upload package to PyPI
85+
uses: pypa/gh-action-pypi-publish@release/v1
86+
docs:
87+
needs:
88+
- release-pypi
89+
uses: "./.github/workflows/docs.yml"

.github/workflows/test.yml

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,43 @@ name: Tests
22

33
on:
44
push:
5-
branches: [ main ]
6-
pull_request:
7-
branches: [ main ]
5+
workflow_call:
6+
workflow_dispatch:
87

98
jobs:
10-
test:
11-
runs-on: ubuntu-latest
9+
build:
1210
strategy:
13-
matrix:
14-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
1511
fail-fast: false
16-
12+
matrix:
13+
python-version:
14+
- "3.10"
15+
- "3.11"
16+
- "3.12"
17+
- "3.13"
18+
- "3.14"
19+
os:
20+
- ubuntu-latest
21+
- macos-latest
22+
- windows-latest
23+
runs-on: ${{ matrix.os }}
1724
steps:
18-
- uses: actions/checkout@v4
19-
20-
- name: Set up Python ${{ matrix.python-version }}
21-
uses: actions/setup-python@v5
25+
- uses: actions/checkout@v5
26+
- name: Set up uv
27+
uses: astral-sh/setup-uv@v7
2228
with:
23-
python-version: ${{ matrix.python-version }}
24-
allow-prereleases: true
25-
26-
- name: Install uv
27-
run: |
28-
curl -LsSf https://astral.sh/uv/install.sh | sh
29-
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
30-
31-
- name: Install dependencies
32-
run: |
33-
uv pip install --system -e ".[test]"
34-
uv pip install --system ruff isort
35-
36-
- name: Run ruff check
37-
run: ruff check src/
38-
39-
- name: Run isort check
40-
run: isort --check src/
41-
42-
- name: Run tests with coverage
43-
run: pytest --cov=mxrepo --cov-report=term-missing --cov-report=xml
44-
45-
- name: Upload coverage to Codecov
46-
uses: codecov/codecov-action@v4
47-
if: matrix.python-version == '3.13'
48-
with:
49-
file: ./coverage.xml
50-
fail_ci_if_error: false
51-
continue-on-error: true
29+
enable-cache: true
30+
cache-dependency-glob: "pyproject.toml"
31+
- name: Set up Python ${{ matrix.python-version }}
32+
run: uv python install ${{ matrix.python-version }}
33+
- name: Install Project (Windows)
34+
if: runner.os == 'Windows'
35+
run: make MAKESHELL='C:/Program Files/Git/usr/bin/bash' install
36+
- name: Install Project (Unix)
37+
if: runner.os != 'Windows'
38+
run: make install
39+
- name: Run Tests (Windows)
40+
if: runner.os == 'Windows'
41+
run: make MAKESHELL='C:/Program Files/Git/usr/bin/bash' test
42+
- name: Run Tests (Unix)
43+
if: runner.os != 'Windows'
44+
run: make test

.github/workflows/typecheck.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Type checks
2+
3+
on:
4+
push:
5+
workflow_call:
6+
workflow_dispatch:
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v5
14+
15+
- name: Set up uv
16+
uses: astral-sh/setup-uv@v7
17+
with:
18+
enable-cache: true
19+
cache-dependency-glob: "pyproject.toml"
20+
21+
- name: Set up Python 3.13
22+
run: uv python install 3.13
23+
24+
- name: Install Project
25+
run: make install
26+
27+
- name: Run Typechecks
28+
run: make typecheck

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
*.egg-info
21
__pycache__
2+
.claude
3+
.coverage
4+
*.egg-info
35
/.mxmake/
6+
/dist/
7+
/reports/
48
/requirements-mxdev.txt
59
/.claude/
610
CLAUDE.md

CHANGES.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3-
## 1.0 (unreleased)
3+
## 1.0.0
44

5+
- Added tests, CI workflows and hatchling/ trusted publishing
6+
[@jensens, 2025-11-03]
57
- Initial porting from https://github.com/rnixx/githelper
8+
[@rnix, 2025-03-03]

Makefile

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ INCLUDE_MAKEFILE?=include.mk
3939
# No default value.
4040
EXTRA_PATH?=
4141

42+
# Path to Python project relative to Makefile (repository root).
43+
# Leave empty if Python project is in the same directory as Makefile.
44+
# For monorepo setups, set to subdirectory name (e.g., `backend`).
45+
# Future-proofed for multi-language monorepos (e.g., PROJECT_PATH_NODEJS).
46+
# No default value.
47+
PROJECT_PATH_PYTHON?=
48+
4249
## core.mxenv
4350

4451
# Primary Python interpreter to use. It is used to create the
@@ -156,6 +163,9 @@ FORMAT_TARGETS?=
156163

157164
export PATH:=$(if $(EXTRA_PATH),$(EXTRA_PATH):,)$(PATH)
158165

166+
# Helper variable: adds trailing slash to PROJECT_PATH_PYTHON only if non-empty
167+
PYTHON_PROJECT_PREFIX=$(if $(PROJECT_PATH_PYTHON),$(PROJECT_PATH_PYTHON)/,)
168+
159169
# Defensive settings for make: https://tech.davis-hansson.com/p/make/
160170
SHELL:=bash
161171
.ONESHELL:
@@ -299,6 +309,11 @@ CLEAN_TARGETS+=mxenv-clean
299309
# ruff
300310
##############################################################################
301311

312+
# Adjust RUFF_SRC to respect PROJECT_PATH_PYTHON if still at default
313+
ifeq ($(RUFF_SRC),src)
314+
RUFF_SRC:=$(PYTHON_PROJECT_PREFIX)src
315+
endif
316+
302317
RUFF_TARGET:=$(SENTINEL_FOLDER)/ruff.sentinel
303318
$(RUFF_TARGET): $(MXENV_TARGET)
304319
@echo "Install Ruff"
@@ -334,6 +349,11 @@ CLEAN_TARGETS+=ruff-clean
334349
# isort
335350
##############################################################################
336351

352+
# Adjust ISORT_SRC to respect PROJECT_PATH_PYTHON if still at default
353+
ifeq ($(ISORT_SRC),src)
354+
ISORT_SRC:=$(PYTHON_PROJECT_PREFIX)src
355+
endif
356+
337357
ISORT_TARGET:=$(SENTINEL_FOLDER)/isort.sentinel
338358
$(ISORT_TARGET): $(MXENV_TARGET)
339359
@echo "Install isort"
@@ -391,7 +411,7 @@ else
391411
@echo "[settings]" > $(PROJECT_CONFIG)
392412
endif
393413

394-
LOCAL_PACKAGE_FILES:=$(wildcard pyproject.toml setup.cfg setup.py requirements.txt constraints.txt)
414+
LOCAL_PACKAGE_FILES:=$(wildcard $(PYTHON_PROJECT_PREFIX)pyproject.toml $(PYTHON_PROJECT_PREFIX)setup.cfg $(PYTHON_PROJECT_PREFIX)setup.py $(PYTHON_PROJECT_PREFIX)requirements.txt $(PYTHON_PROJECT_PREFIX)constraints.txt)
395415

396416
FILES_TARGET:=requirements-mxdev.txt
397417
$(FILES_TARGET): $(PROJECT_CONFIG) $(MXENV_TARGET) $(SOURCES_TARGET) $(LOCAL_PACKAGE_FILES)

pyproject.toml

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
[project]
22
name = "mxrepo"
33
description = "Helper script for working with multiple git repositories."
4-
version = "1.0.0.dev0"
54
keywords = ["development", "deployment", "git"]
65
authors = [
76
{name = "MX Stack Developers", email = "dev@bluedynamics.com" }
87
]
9-
requires-python = ">=3.9"
8+
requires-python = ">=3.10"
109
license = { text = "BSD 2-Clause License" }
1110
classifiers = [
1211
"Intended Audience :: Developers",
1312
"Topic :: Software Development :: Build Tools",
1413
"License :: OSI Approved :: BSD License",
1514
"Operating System :: OS Independent",
1615
"Programming Language :: Python",
17-
"Programming Language :: Python :: 3.9",
1816
"Programming Language :: Python :: 3.10",
1917
"Programming Language :: Python :: 3.11",
2018
"Programming Language :: Python :: 3.12",
2119
"Programming Language :: Python :: 3.13",
2220
"Programming Language :: Python :: 3.14",
2321
]
24-
dynamic = ["readme"]
22+
dynamic = ["version", "readme"]
2523

2624
[project.optional-dependencies]
2725
test = [
@@ -39,14 +37,26 @@ Source = "https://github.com/mxstack/mxrepo/tree/main"
3937
mxrepo = "mxrepo.main:main"
4038

4139
[build-system]
42-
requires = ["setuptools"]
43-
build-backend = "setuptools.build_meta"
40+
requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"]
41+
build-backend = "hatchling.build"
4442

45-
[tool.distutils.bdist_wheel]
46-
universal = true
43+
[tool.hatch.version]
44+
source = "vcs"
4745

48-
[tool.setuptools.dynamic]
49-
readme = {file = ["README.md", "CHANGES.md", "LICENSE.md"], content-type = "text/markdown"}
46+
[tool.hatch.metadata]
47+
allow-direct-references = true
48+
49+
[tool.hatch.metadata.hooks.fancy-pypi-readme]
50+
content-type = "text/markdown"
51+
52+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
53+
path = "README.md"
54+
55+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
56+
path = "CHANGES.md"
57+
58+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
59+
path = "LICENSE.md"
5060

5161
[tool.isort]
5262
profile = "black"
@@ -56,7 +66,7 @@ lines_after_imports = 2
5666

5767
[tool.mypy]
5868
ignore_missing_imports = true
59-
python_version = "3.9"
69+
python_version = "3.10"
6070

6171
[tool.ruff]
6272
line-length = 88

0 commit comments

Comments
 (0)