Skip to content

Commit 02870a1

Browse files
authored
feat: add GitHub Actions workflow and auto code format (#1)
1 parent f1abdf9 commit 02870a1

29 files changed

Lines changed: 2380 additions & 1682 deletions

.github/workflows/ci.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
push:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
concurrency:
11+
cancel-in-progress: true
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
14+
jobs:
15+
ci:
16+
name: CI (Python ${{ matrix.python-version }})
17+
if: ${{ !cancelled() && !failure() }}
18+
runs-on: ubuntu-latest
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
python-version: ["3.10", "3.11"]
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Set up Python ${{ matrix.python-version }}
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: ${{ matrix.python-version }}
33+
cache: 'pip'
34+
cache-dependency-path: requirements.txt
35+
36+
- name: Show environment
37+
run: env | sort
38+
39+
- name: Upgrade pip tooling
40+
run: |
41+
python -m pip install --upgrade pip setuptools wheel
42+
43+
- name: Install dependencies
44+
run: |
45+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
46+
47+
- name: Sanity build (byte-compile sources)
48+
run: |
49+
python -m compileall -q src || (echo "Byte-compilation failed" && exit 1)
50+
51+
- name: Verify dependency resolution
52+
run: |
53+
python -m pip check || true
54+
55+
dependabot:
56+
name: Dependabot validation
57+
if: ${{ github.actor == 'dependabot[bot]' && startsWith(github.head_ref, 'dependabot/pip/') }}
58+
permissions:
59+
contents: write
60+
runs-on: ubuntu-latest
61+
steps:
62+
- name: Checkout PR branch
63+
uses: actions/checkout@v4
64+
with:
65+
fetch-depth: 0
66+
ref: ${{ github.head_ref }}
67+
68+
- name: Set up Git
69+
run: |
70+
git config --global user.name github-actions
71+
git config --global user.email github-actions@github.com
72+
73+
- name: Validate requirements on Python 3.10 and 3.11
74+
run: |
75+
set -euo pipefail
76+
for PYV in 3.10 3.11; do
77+
echo "Setting up Python ${PYV}..."
78+
echo "python-version: ${PYV}" >> $GITHUB_OUTPUT
79+
echo "Installing with Python ${PYV}..."
80+
pyenv global ${PYV} || true
81+
python -V
82+
python -m pip install --upgrade pip setuptools wheel
83+
if [ -f requirements.txt ]; then
84+
pip install -r requirements.txt
85+
pip check || true
86+
fi
87+
done
88+
89+
- name: Push changes if applicable
90+
run: |
91+
if [[ -n $(git status --porcelain) ]]; then
92+
git commit -a -m "build: Apply automated updates for dependabot."
93+
git push
94+
fi
95+
96+

Makefile

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
.PHONY: clean deepclean install dev constraints black isort mypy ruff toml-sort lint pre-commit \
2+
auto-black auto-isort auto-toml-sort auto-lint \
3+
test-run test-run-offline test test-offline \
4+
build upload docs-autobuild changelog docs-gen docs-mypy docs-coverage docs
5+
6+
SHELL := /bin/bash
7+
8+
########################################################################################
9+
# Variables
10+
########################################################################################
11+
12+
# Use pipenv when not in CI and available
13+
PIPRUN := $(shell [ "$$CI" != "true" ] && command -v pipenv > /dev/null 2>&1 && echo "pipenv run")
14+
15+
# Python version (major.minor)
16+
PYTHON_VERSION := $(shell echo $${PYTHON_VERSION:-$$(python -V 2>&1 | cut -d ' ' -f 2)} | cut -d '.' -f 1,2)
17+
18+
# Constraints file by Python version
19+
CONSTRAINTS_DIR := constraints
20+
CONSTRAINTS_FILE := $(CONSTRAINTS_DIR)/$(PYTHON_VERSION).txt
21+
22+
# Public docs dir (compatible with ReadTheDocs)
23+
PUBLIC_DIR := $(shell [ "$$READTHEDOCS" = "True" ] && echo "$$READTHEDOCS_OUTPUT/html" || echo "public")
24+
25+
# Changelog (optional)
26+
CHANGELOG_URL := $(shell echo $${CI_PAGES_URL:-https://example.com/yourproject}/_sources/changelog.md.txt)
27+
CHANGELOG_PATH := docs/changelog.md
28+
29+
########################################################################################
30+
# Development Environment Management
31+
########################################################################################
32+
33+
clean:
34+
-rm -rf \
35+
$(PUBLIC_DIR) \
36+
.coverage \
37+
.mypy_cache \
38+
.pytest_cache \
39+
.ruff_cache \
40+
Pipfile* \
41+
coverage.xml \
42+
dist \
43+
release-notes.md
44+
find . -name '*.egg-info' -print0 | xargs -0 rm -rf
45+
find . -name '*.pyc' -print0 | xargs -0 rm -f
46+
find . -name '*.swp' -print0 | xargs -0 rm -f
47+
find . -name '.DS_Store' -print0 | xargs -0 rm -f
48+
find . -name '__pycache__' -print0 | xargs -0 rm -rf
49+
50+
deepclean: clean
51+
if command -v pre-commit > /dev/null 2>&1; then pre-commit uninstall --hook-type pre-push; fi
52+
if command -v pipenv >/dev/null 2>&1 && pipenv --venv >/dev/null 2>&1; then pipenv --rm; fi
53+
54+
# Editable install (if this is a package). For this repo we default to requirements.txt
55+
install:
56+
@if [ -f setup.py ] || [ -f pyproject.toml ]; then \
57+
$(PIPRUN) pip install -e . -c $(CONSTRAINTS_FILE) || $(PIPRUN) pip install -e . ; \
58+
else \
59+
$(PIPRUN) pip install -r requirements.txt ; \
60+
fi
61+
62+
# Developer setup: project deps + common dev tooling
63+
dev:
64+
@if [ -f requirements.txt ]; then $(PIPRUN) pip install -r requirements.txt ; fi
65+
# Common dev tools (safe if already installed)
66+
$(PIPRUN) pip install -U \
67+
black isort ruff mypy \
68+
pytest coverage build twine \
69+
sphinx sphinx-autobuild git-changelog toml-sort
70+
@if [ "$(CI)" != "true" ] && command -v pre-commit > /dev/null 2>&1; then pre-commit install --hook-type pre-push; fi
71+
72+
# Generate constraints for current Python version
73+
constraints: deepclean
74+
@mkdir -p $(CONSTRAINTS_DIR)
75+
@if [ -f setup.py ] || [ -f pyproject.toml ]; then \
76+
$(PIPRUN) --python $(PYTHON_VERSION) pip install --upgrade -e . ; \
77+
fi
78+
@if [ -f requirements.txt ]; then $(PIPRUN) pip install -r requirements.txt ; fi
79+
$(PIPRUN) pip freeze --exclude-editable > $(CONSTRAINTS_FILE)
80+
81+
########################################################################################
82+
# Lint and pre-commit
83+
########################################################################################
84+
85+
black:
86+
@command -v black >/dev/null 2>&1 || { echo "black not installed. Run 'make dev' first."; exit 1; }
87+
$(PIPRUN) python -m black --check --diff . -l 120
88+
89+
isort:
90+
@command -v isort >/dev/null 2>&1 || { echo "isort not installed. Run 'make dev' first."; exit 1; }
91+
$(PIPRUN) python -m isort --check .
92+
93+
mypy:
94+
@command -v mypy >/dev/null 2>&1 || { echo "mypy not installed. Run 'make dev' first."; exit 1; }
95+
# Narrow the scope if needed
96+
$(PIPRUN) python -m mypy src || true
97+
98+
ruff:
99+
@command -v ruff >/dev/null 2>&1 || { echo "ruff not installed. Run 'make dev' first."; exit 1; }
100+
$(PIPRUN) ruff check src || true
101+
102+
toml-sort:
103+
@command -v toml-sort >/dev/null 2>&1 || { echo "toml-sort not installed. Run 'make dev' first."; exit 1; }
104+
$(PIPRUN) toml-sort --check pyproject.toml || true
105+
106+
# Prioritize isort before black to avoid style conflicts
107+
lint: mypy ruff isort black toml-sort
108+
109+
pre-commit:
110+
pre-commit run --all-files
111+
112+
########################################################################################
113+
# Auto Lint
114+
########################################################################################
115+
116+
auto-black:
117+
@command -v black >/dev/null 2>&1 || { echo "black not installed. Run 'make dev' first."; exit 1; }
118+
$(PIPRUN) python -m black . -l 120
119+
120+
auto-isort:
121+
@command -v isort >/dev/null 2>&1 || { echo "isort not installed. Run 'make dev' first."; exit 1; }
122+
$(PIPRUN) python -m isort .
123+
124+
auto-toml-sort:
125+
@command -v toml-sort >/dev/null 2>&1 || { echo "toml-sort not installed. Run 'make dev' first."; exit 1; }
126+
$(PIPRUN) toml-sort --in-place pyproject.toml >/dev/null 2>&1 || true
127+
128+
auto-lint: auto-isort auto-black auto-toml-sort
129+
130+
########################################################################################
131+
# Test
132+
########################################################################################
133+
134+
test-run:
135+
@command -v coverage >/dev/null 2>&1 || { echo "coverage not installed. Run 'make dev' first."; exit 1; }
136+
@if command -v pytest >/dev/null 2>&1; then \
137+
$(PIPRUN) python -m coverage erase; \
138+
$(PIPRUN) python -m coverage run --concurrency=multiprocessing -m pytest || true; \
139+
$(PIPRUN) python -m coverage combine; \
140+
else \
141+
echo "pytest not installed or no tests; skipping test-run."; \
142+
fi
143+
144+
test-run-offline:
145+
@command -v coverage >/dev/null 2>&1 || { echo "coverage not installed. Run 'make dev' first."; exit 1; }
146+
@if command -v pytest >/dev/null 2>&1; then \
147+
$(PIPRUN) python -m coverage erase; \
148+
$(PIPRUN) python -m coverage run --concurrency=multiprocessing -m pytest -m "offline" || true; \
149+
$(PIPRUN) python -m coverage combine; \
150+
else \
151+
echo "pytest not installed or no tests; skipping test-run-offline."; \
152+
fi
153+
154+
test: test-run
155+
$(PIPRUN) python -m coverage report --fail-under 20 || true
156+
$(PIPRUN) python -m coverage xml --fail-under 20 || true
157+
158+
test-offline: test-run-offline
159+
$(PIPRUN) python -m coverage report --fail-under 20 || true
160+
$(PIPRUN) python -m coverage xml --fail-under 20 || true
161+
162+
########################################################################################
163+
# Package
164+
########################################################################################
165+
166+
build:
167+
@command -v python >/dev/null 2>&1 || { echo "python not found"; exit 1; }
168+
$(PIPRUN) python -m build
169+
170+
upload:
171+
$(PIPRUN) python -m twine upload dist/*
172+
173+
########################################################################################
174+
# Documentation (optional, only if docs/ exists)
175+
########################################################################################
176+
177+
docs-autobuild:
178+
@if [ -d docs ]; then \
179+
$(PIPRUN) python -m sphinx_autobuild docs $(PUBLIC_DIR); \
180+
else \
181+
echo "No docs directory; skipping docs-autobuild."; \
182+
fi
183+
184+
changelog:
185+
@if wget -q --spider $(CHANGELOG_URL); then \
186+
echo "Existing Changelog found at '$(CHANGELOG_URL)', download for incremental generation."; \
187+
wget -q -O $(CHANGELOG_PATH) $(CHANGELOG_URL); \
188+
fi
189+
@command -v git-changelog >/dev/null 2>&1 || { echo "git-changelog not installed. Run 'make dev' first."; exit 1; }
190+
$(PIPRUN) LATEST_TAG=$$(git tag --sort=-creatordate | head -n 1); \
191+
git-changelog --bump $$LATEST_TAG -Tio docs/changelog.md -c conventional -s build,chore,ci,deps,doc,docs,feat,fix,perf,ref,refactor,revert,style,test,tests || true
192+
193+
release-notes:
194+
@command -v git-changelog >/dev/null 2>&1 || { echo "git-changelog not installed. Run 'make dev' first."; exit 1; }
195+
@$(PIPRUN) git-changelog --input $(CHANGELOG_PATH) --release-notes || true
196+
197+
docs-gen:
198+
@if [ -d docs ]; then \
199+
$(PIPRUN) python -m sphinx.cmd.build -W docs $(PUBLIC_DIR); \
200+
else \
201+
echo "No docs directory; skipping docs-gen."; \
202+
fi
203+
204+
docs-mypy: docs-gen
205+
@if [ -d docs ]; then \
206+
$(PIPRUN) python -m mypy src --html-report $(PUBLIC_DIR)/reports/mypy || true; \
207+
else \
208+
echo "No docs directory; skipping docs-mypy."; \
209+
fi
210+
211+
docs-coverage: test-run docs-gen
212+
@if [ -d docs ]; then \
213+
$(PIPRUN) python -m coverage html -d $(PUBLIC_DIR)/reports/coverage --fail-under 20 || true; \
214+
else \
215+
echo "No docs directory; skipping docs-coverage."; \
216+
fi
217+
218+
docs: changelog docs-gen docs-mypy docs-coverage
219+
220+
########################################################################################
221+
# End
222+
########################################################################################
223+
224+

pyproject.toml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
[build-system]
2+
requires = ["hatchling>=1.24.2"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "debate"
7+
version = "0.0.0"
8+
description = "Debate project"
9+
readme = "README.md"
10+
requires-python = ">=3.10"
11+
license = {text = "MIT"}
12+
authors = [{name = "LeiLi Lab"}]
13+
dependencies = []
14+
15+
[tool.black]
16+
line-length = 120
17+
target-version = ["py310", "py311"]
18+
19+
[tool.coverage.report]
20+
exclude_lines = [
21+
"if __name__ == \"__main__\":"
22+
]
23+
24+
[tool.coverage.run]
25+
source = ["src"]
26+
branch = true
27+
28+
[tool.isort]
29+
profile = "black"
30+
line_length = 120
31+
skip = ["dataset"]
32+
33+
[tool.mypy]
34+
python_version = "3.10"
35+
ignore_missing_imports = true
36+
warn_unused_ignores = true
37+
warn_redundant_casts = true
38+
warn_unreachable = true
39+
strict_optional = false
40+
show_error_codes = true
41+
pretty = true
42+
files = ["src"]
43+
44+
[tool.pytest.ini_options]
45+
addopts = "-ra"
46+
testpaths = ["tests", "test"]
47+
48+
[tool.ruff]
49+
line-length = 120
50+
target-version = "py310"
51+
src = ["src"]
52+
53+
[tool.ruff.lint]
54+
select = ["E", "F", "W"]
55+
ignore = []

0 commit comments

Comments
 (0)