Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
# Workflow files stored in the default location of `.github/workflows`
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
directory: "/"
schedule:
interval: "weekly"
28 changes: 28 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Lint

on:
push:
workflow_call:
workflow_dispatch:

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: "pyproject.toml"

- name: Set up Python 3.10
run: uv python install 3.10

- name: Install Project
run: make install

- name: Run checks
run: make check
89 changes: 89 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
name: Build & upload PyPI package

on:
push:
branches: [main]
tags: ["*"]
release:
types:
- published
workflow_dispatch:

jobs:
tests:
uses: "./.github/workflows/test.yml"
lint:
uses: "./.github/workflows/lint.yml"
typecheck:
uses: "./.github/workflows/typecheck.yml"

# Always build & lint package.
build-package:
name: Build & verify package
needs:
- lint
- tests
- typecheck
runs-on: ubuntu-latest
permissions:
attestations: write
id-token: write

steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
persist-credentials: false

- uses: hynek/build-and-inspect-python-package@v2
with:
attest-build-provenance-github: 'true'

# Upload to Test PyPI on every commit on main.
release-test-pypi:
name: Publish in-dev package to test.pypi.org
environment: release-test-pypi
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
needs:
- build-package
permissions:
id-token: write

steps:
- name: Download packages built by build-and-inspect-python-package
uses: actions/download-artifact@v6
with:
name: Packages
path: dist

- name: Upload package to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/

# Upload to real PyPI on GitHub Releases.
release-pypi:
name: Publish released package to pypi.org
environment: release-pypi
if: github.event.action == 'published'
runs-on: ubuntu-latest
needs:
- build-package
permissions:
id-token: write

steps:
- name: Download packages built by build-and-inspect-python-package
uses: actions/download-artifact@v6
with:
name: Packages
path: dist

- name: Upload package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
docs:
needs:
- release-pypi
uses: "./.github/workflows/docs.yml"
75 changes: 34 additions & 41 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,43 @@ name: Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_call:
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest
build:
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
fail-fast: false

matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true

- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.cargo/bin" >> $GITHUB_PATH

- name: Install dependencies
run: |
uv pip install --system -e ".[test]"
uv pip install --system ruff isort

- name: Run ruff check
run: ruff check src/

- name: Run isort check
run: isort --check src/

- name: Run tests with coverage
run: pytest --cov=mxrepo --cov-report=term-missing --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.13'
with:
file: ./coverage.xml
fail_ci_if_error: false
continue-on-error: true
enable-cache: true
cache-dependency-glob: "pyproject.toml"
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install Project (Windows)
if: runner.os == 'Windows'
run: make MAKESHELL='C:/Program Files/Git/usr/bin/bash' install
- name: Install Project (Unix)
if: runner.os != 'Windows'
run: make install
- name: Run Tests (Windows)
if: runner.os == 'Windows'
run: make MAKESHELL='C:/Program Files/Git/usr/bin/bash' test
- name: Run Tests (Unix)
if: runner.os != 'Windows'
run: make test
28 changes: 28 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Type checks

on:
push:
workflow_call:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: "pyproject.toml"

- name: Set up Python 3.13
run: uv python install 3.13

- name: Install Project
run: make install

- name: Run Typechecks
run: make typecheck
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
*.egg-info
__pycache__
.claude
.coverage
*.egg-info
/.mxmake/
/dist/
/reports/
/requirements-mxdev.txt
/.claude/
CLAUDE.md
5 changes: 4 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 1.0 (unreleased)
## 1.0.0

- Added tests, CI workflows and hatchling/ trusted publishing
[@jensens, 2025-11-03]
- Initial porting from https://github.com/rnixx/githelper
[@rnix, 2025-03-03]
22 changes: 21 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ INCLUDE_MAKEFILE?=include.mk
# No default value.
EXTRA_PATH?=

# Path to Python project relative to Makefile (repository root).
# Leave empty if Python project is in the same directory as Makefile.
# For monorepo setups, set to subdirectory name (e.g., `backend`).
# Future-proofed for multi-language monorepos (e.g., PROJECT_PATH_NODEJS).
# No default value.
PROJECT_PATH_PYTHON?=

## core.mxenv

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

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

# Helper variable: adds trailing slash to PROJECT_PATH_PYTHON only if non-empty
PYTHON_PROJECT_PREFIX=$(if $(PROJECT_PATH_PYTHON),$(PROJECT_PATH_PYTHON)/,)

# Defensive settings for make: https://tech.davis-hansson.com/p/make/
SHELL:=bash
.ONESHELL:
Expand Down Expand Up @@ -299,6 +309,11 @@ CLEAN_TARGETS+=mxenv-clean
# ruff
##############################################################################

# Adjust RUFF_SRC to respect PROJECT_PATH_PYTHON if still at default
ifeq ($(RUFF_SRC),src)
RUFF_SRC:=$(PYTHON_PROJECT_PREFIX)src
endif

RUFF_TARGET:=$(SENTINEL_FOLDER)/ruff.sentinel
$(RUFF_TARGET): $(MXENV_TARGET)
@echo "Install Ruff"
Expand Down Expand Up @@ -334,6 +349,11 @@ CLEAN_TARGETS+=ruff-clean
# isort
##############################################################################

# Adjust ISORT_SRC to respect PROJECT_PATH_PYTHON if still at default
ifeq ($(ISORT_SRC),src)
ISORT_SRC:=$(PYTHON_PROJECT_PREFIX)src
endif

ISORT_TARGET:=$(SENTINEL_FOLDER)/isort.sentinel
$(ISORT_TARGET): $(MXENV_TARGET)
@echo "Install isort"
Expand Down Expand Up @@ -391,7 +411,7 @@ else
@echo "[settings]" > $(PROJECT_CONFIG)
endif

LOCAL_PACKAGE_FILES:=$(wildcard pyproject.toml setup.cfg setup.py requirements.txt constraints.txt)
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)

FILES_TARGET:=requirements-mxdev.txt
$(FILES_TARGET): $(PROJECT_CONFIG) $(MXENV_TARGET) $(SOURCES_TARGET) $(LOCAL_PACKAGE_FILES)
Expand Down
32 changes: 21 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
[project]
name = "mxrepo"
description = "Helper script for working with multiple git repositories."
version = "1.0.0.dev0"
keywords = ["development", "deployment", "git"]
authors = [
{name = "MX Stack Developers", email = "dev@bluedynamics.com" }
]
requires-python = ">=3.9"
requires-python = ">=3.10"
license = { text = "BSD 2-Clause License" }
classifiers = [
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
dynamic = ["readme"]
dynamic = ["version", "readme"]

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

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"]
build-backend = "hatchling.build"

[tool.distutils.bdist_wheel]
universal = true
[tool.hatch.version]
source = "vcs"

[tool.setuptools.dynamic]
readme = {file = ["README.md", "CHANGES.md", "LICENSE.md"], content-type = "text/markdown"}
[tool.hatch.metadata]
allow-direct-references = true

[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"

[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
path = "README.md"

[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
path = "CHANGES.md"

[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
path = "LICENSE.md"

[tool.isort]
profile = "black"
Expand All @@ -56,7 +66,7 @@ lines_after_imports = 2

[tool.mypy]
ignore_missing_imports = true
python_version = "3.9"
python_version = "3.10"

[tool.ruff]
line-length = 88
Expand Down