Skip to content

Commit 93696e5

Browse files
ci: add ci.yml
1 parent b8f3238 commit 93696e5

File tree

9 files changed

+386
-62
lines changed

9 files changed

+386
-62
lines changed

.github/workflows/ci.yml

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
name: CI
2+
3+
# Trigger CI on pushes to main and all pull requests
4+
# This ensures every code change is validated before merging
5+
on:
6+
push:
7+
branches:
8+
- main
9+
pull_request:
10+
# Run on all PRs regardless of target branch
11+
branches:
12+
- '**'
13+
14+
jobs:
15+
# Job 1: Lint and Format Check
16+
# Runs ruff to check code quality and formatting
17+
lint:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
23+
- name: Set up Python
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: '3.11'
27+
28+
- name: Install uv
29+
uses: astral-sh/setup-uv@v5
30+
with:
31+
version: "latest"
32+
33+
- name: Install dependencies
34+
# Install the package with uv in system mode
35+
# This installs ruff and other tools defined in dependencies
36+
run: uv pip install --system .
37+
38+
- name: Run ruff check
39+
run: ruff check --config ./afterpython/ruff.toml .
40+
41+
- name: Run ruff format check
42+
# --check flag ensures it only validates, doesn't reformat
43+
run: ruff format --check --config ./afterpython/ruff.toml .
44+
45+
# Job 2: Detect Test Strategy
46+
# Determines whether to use pixi or uv based on pixi.toml presence
47+
detect-test-strategy:
48+
runs-on: ubuntu-latest
49+
outputs:
50+
use_pixi: ${{ steps.check.outputs.use_pixi }}
51+
steps:
52+
- name: Checkout code
53+
uses: actions/checkout@v4
54+
55+
- name: Check for pixi.toml
56+
id: check
57+
run: |
58+
if [ -f "pixi.toml" ]; then
59+
echo "use_pixi=true" >> $GITHUB_OUTPUT
60+
else
61+
echo "use_pixi=false" >> $GITHUB_OUTPUT
62+
fi
63+
64+
# Job 3: Test Suite - UV Workflow
65+
# Traditional Python testing with uv for projects without pixi
66+
test-uv:
67+
needs: detect-test-strategy
68+
if: needs.detect-test-strategy.outputs.use_pixi == 'false'
69+
runs-on: ubuntu-latest
70+
strategy:
71+
matrix:
72+
# TODO: support python 3.14
73+
python-version: ['3.11', '3.12', '3.13']
74+
fail-fast: false
75+
76+
steps:
77+
- name: Checkout code
78+
uses: actions/checkout@v4
79+
80+
- name: Set up Python ${{ matrix.python-version }}
81+
uses: actions/setup-python@v5
82+
with:
83+
python-version: ${{ matrix.python-version }}
84+
85+
- name: Install uv
86+
uses: astral-sh/setup-uv@v5
87+
with:
88+
version: "latest"
89+
90+
- name: Install dependencies
91+
run: |
92+
# Install package, main dependencies, and test dependencies
93+
# If no [dependency-groups] test exists, only the package and main dependencies are installed
94+
uv pip install --system . --group test || uv pip install --system .
95+
96+
- name: Run tests with pytest
97+
# Run pytest with verbose output
98+
# Even without tests, pytest will exit successfully (0 tests collected)
99+
run: pytest -v
100+
101+
# Job 4: Test Suite - Pixi Workflow
102+
# Pixi-based testing for projects using pixi.toml
103+
test-pixi:
104+
needs: detect-test-strategy
105+
if: needs.detect-test-strategy.outputs.use_pixi == 'true'
106+
runs-on: ubuntu-latest
107+
strategy:
108+
matrix:
109+
# TODO: support python 3.14
110+
environment: ['py311', 'py312', 'py313']
111+
fail-fast: false
112+
113+
steps:
114+
- name: Checkout code
115+
uses: actions/checkout@v4
116+
117+
- name: Set up pixi
118+
uses: prefix-dev/setup-pixi@v0.9.3
119+
with:
120+
pixi-version: v0.59.0
121+
cache: true
122+
# Optional: Uncomment if you need prefix.dev authentication
123+
# auth-host: prefix.dev
124+
# auth-token: ${{ secrets.PREFIX_DEV_TOKEN }}
125+
126+
- name: Run tests with pixi
127+
# Runs test in specific Python environment (py311, py312, py313)
128+
# Assumes you have environments defined in pixi.toml with a "test" task
129+
# Example pixi.toml:
130+
# [environments]
131+
# py311 = ["py311", "test"]
132+
# [feature.test.tasks]
133+
# test = "pytest -v"
134+
run: pixi run -e ${{ matrix.environment }} test
135+
136+
# Job 5: Build Verification
137+
# Ensures the package can be built successfully
138+
build:
139+
runs-on: ubuntu-latest
140+
steps:
141+
- name: Checkout code
142+
uses: actions/checkout@v4
143+
144+
- name: Set up Python
145+
uses: actions/setup-python@v5
146+
with:
147+
python-version: '3.11'
148+
149+
- name: Install uv
150+
uses: astral-sh/setup-uv@v5
151+
with:
152+
version: "latest"
153+
154+
- name: Build package
155+
run: uv build
156+
157+
- name: List build artifacts
158+
# Show what was built (wheel + sdist)
159+
# Useful for debugging build issues
160+
run: ls -lh dist/
161+
162+
- name: Install built package
163+
# Test that the built wheel can be installed
164+
# This catches packaging issues like missing files
165+
run: uv pip install --system dist/*.whl
166+
167+
- name: Verify installation
168+
# Confirm the CLI entry point works
169+
# This ensures the package is usable after installation
170+
run: ap --help
171+
172+
# Job 6: Type Check
173+
# typecheck:

afterpython/cli/commands/init.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,22 @@ def init_website():
4747

4848

4949
@click.command()
50+
@click.option(
51+
"--yes",
52+
"-y",
53+
is_flag=True,
54+
help="Automatically answer yes to all prompts",
55+
)
5056
@click.pass_context
51-
def init(ctx):
57+
def init(ctx, yes):
5258
"""Initialize afterpython with MyST Markdown (by default) and project website template"""
5359
from afterpython.tools.pyproject import init_pyproject
5460
from afterpython.tools._afterpython import init_afterpython
5561
from afterpython.tools.myst import init_myst
5662
from afterpython.tools.pre_commit import init_pre_commit
5763
from afterpython.tools.commitizen import init_commitizen
5864
from afterpython.tools.github_actions import (
59-
init_release_workflow,
60-
init_deploy_workflow,
65+
create_workflow,
6166
)
6267

6368
paths = ctx.obj["paths"]
@@ -79,20 +84,21 @@ def init(ctx):
7984

8085
init_website()
8186

82-
if click.confirm(
87+
if yes or click.confirm(
8388
f"\nCreate .pre-commit-config.yaml in {afterpython_path}?", default=True
8489
):
8590
init_pre_commit()
8691

87-
if click.confirm(f"\nCreate ruff.toml in {afterpython_path}?", default=True):
92+
if yes or click.confirm(f"\nCreate ruff.toml in {afterpython_path}?", default=True):
8893
init_ruff_toml()
8994

90-
if click.confirm(
95+
if yes or click.confirm(
9196
f"\nCreate commitizen configuration (cz.toml) in {afterpython_path} "
9297
f"and release workflow in .github/workflows/release.yml?",
9398
default=True,
9499
):
95100
init_commitizen()
96-
init_release_workflow()
101+
create_workflow("release")
97102

98-
init_deploy_workflow()
103+
create_workflow("deploy")
104+
create_workflow("ci")

afterpython/doc/package_maintenance/ci_cd.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ Currently, `afterpython` only supports GitHub Actions for CI/CD pipelines.
66
## GitHub Actions
77
Inside `.github/workflows/`, you'll find the following workflows:
88

9-
### `release.yml`
9+
### `ci.yml`
10+
Runs linting and formatting with ruff, runs tests with pytest and builds the package and verifies it can be installed with `uv build`.
11+
12+
### `release.yml` (optional)
1013
Releases your package to [PyPI] and GitHub.
1114

15+
`release.yml` will NOT be created if `commitizen` is not initialized during `ap init`.
16+
1217
See [PyPI and GitHub Releases](./release_management.md#pypi-and-github-releases) for more details.
1318

1419
### `deploy.yml`

afterpython/doc/references/roadmap.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ This roadmap is tentative and subject to change
1010
- full-text search engine using pagefind
1111
- incremental build, only build changed content (for `ap dev`)
1212
- github dependabot
13+
- update the versions in github workflows (e.g. `ci.yml`, not `pyproject.toml` coz `pcu` handles it already)
1314
- integrate with `git-cliff` for changelog generation
1415
- integrate with `pixi`, supports `conda install`
1516
- supports docs built by different engines? e.g. Sphix, MkDocs
17+
- update `afterpython` itself using `ap update afterpython`
18+
- it merges the new defaults in a newer version of `afterpython` into your project
19+
- very difficult, need to create an interactive UX to show the diffs and let the user choose to merge or not
20+
- support python 3.14

0 commit comments

Comments
 (0)