Skip to content

Commit 060e2da

Browse files
blhsingclaude
andcommitted
ci: add GitHub Actions workflow
Adds .github/workflows/ci.yml with three jobs: - test: pytest matrix across Python 3.9-3.13 on Ubuntu, plus 3.13 on macOS and Windows. Installs the package with the test extras, configures a global git identity for the interop-test path that shells out to real git, runs the suite, and verifies both 'pygit' and 'git' entry points resolve to pythongit. - build: python -m build, twine check, and a smoke install of the wheel in a fresh venv. Uploads dist/ as a workflow artifact. - lint: bytecode-compiles every module and asserts >= 150 commands are registered. Also adds the CI status badge to the README. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent faf3dbc commit 060e2da

2 files changed

Lines changed: 145 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: ci-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
test:
19+
name: pytest (${{ matrix.os }} / py${{ matrix.python-version }})
20+
runs-on: ${{ matrix.os }}
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
# Full matrix on Linux; latest Python only on macOS and Windows to
25+
# keep run time reasonable while still catching platform regressions.
26+
include:
27+
- os: ubuntu-latest
28+
python-version: "3.9"
29+
- os: ubuntu-latest
30+
python-version: "3.10"
31+
- os: ubuntu-latest
32+
python-version: "3.11"
33+
- os: ubuntu-latest
34+
python-version: "3.12"
35+
- os: ubuntu-latest
36+
python-version: "3.13"
37+
- os: macos-latest
38+
python-version: "3.13"
39+
- os: windows-latest
40+
python-version: "3.13"
41+
42+
steps:
43+
- name: Checkout
44+
uses: actions/checkout@v4
45+
46+
- name: Set up Python ${{ matrix.python-version }}
47+
uses: actions/setup-python@v5
48+
with:
49+
python-version: ${{ matrix.python-version }}
50+
cache: pip
51+
52+
- name: Show git version (used by interop tests)
53+
shell: bash
54+
run: git --version
55+
56+
- name: Install package + test deps
57+
run: |
58+
python -m pip install --upgrade pip
59+
python -m pip install -e ".[test]"
60+
61+
- name: Configure global git identity (some tests shell out to real git)
62+
shell: bash
63+
run: |
64+
git config --global user.name "ci"
65+
git config --global user.email "ci@example.invalid"
66+
git config --global init.defaultBranch main
67+
68+
- name: Run pytest
69+
run: python -m pytest -v --color=yes
70+
71+
- name: Verify `pygit` entry point works
72+
shell: bash
73+
run: |
74+
pygit --version
75+
pygit help | head -5
76+
77+
- name: Verify `git` drop-in entry point resolves to pythongit
78+
shell: bash
79+
run: |
80+
# In the venv used by setup-python, our `git` shim lives in the
81+
# Scripts/bin dir. We invoke by absolute path so the system git on
82+
# PATH doesn't shadow it.
83+
if [[ "${{ runner.os }}" == "Windows" ]]; then
84+
"$(python -c 'import sys, os; print(os.path.join(os.path.dirname(sys.executable), "Scripts", "git.exe"))')" --version
85+
else
86+
"$(python -c 'import sys, os; print(os.path.join(os.path.dirname(sys.executable), "git"))')" --version
87+
fi
88+
89+
build:
90+
name: build wheel + sdist
91+
runs-on: ubuntu-latest
92+
steps:
93+
- uses: actions/checkout@v4
94+
95+
- uses: actions/setup-python@v5
96+
with:
97+
python-version: "3.13"
98+
cache: pip
99+
100+
- name: Install build tools
101+
run: python -m pip install --upgrade build twine
102+
103+
- name: Build
104+
run: python -m build
105+
106+
- name: twine check
107+
run: python -m twine check dist/*
108+
109+
- name: Smoke-install the built wheel
110+
run: |
111+
python -m venv /tmp/install-venv
112+
/tmp/install-venv/bin/pip install dist/*.whl
113+
/tmp/install-venv/bin/pygit --version
114+
/tmp/install-venv/bin/git --version
115+
116+
- name: Upload distribution artifacts
117+
uses: actions/upload-artifact@v4
118+
with:
119+
name: dist
120+
path: dist/
121+
if-no-files-found: error
122+
123+
lint:
124+
name: syntax + import sanity
125+
runs-on: ubuntu-latest
126+
steps:
127+
- uses: actions/checkout@v4
128+
129+
- uses: actions/setup-python@v5
130+
with:
131+
python-version: "3.13"
132+
133+
- name: Bytecode-compile every module
134+
run: python -m compileall -q pythongit tests
135+
136+
- name: Import smoke test
137+
run: |
138+
python -c "
139+
from pythongit import cli
140+
from pythongit.cli import _COMMANDS
141+
assert len(_COMMANDS) >= 150, f'expected >=150 commands, got {len(_COMMANDS)}'
142+
print(f'OK: {len(_COMMANDS)} commands registered')
143+
"

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# pythongit
22

3+
[![CI](https://github.com/blhsing/pythongit/actions/workflows/ci.yml/badge.svg)](https://github.com/blhsing/pythongit/actions/workflows/ci.yml)
4+
35
A pure-Python reimplementation of `git`. No external runtime dependencies — just
46
the Python standard library. All 141 of git's built-in subcommands are
57
implemented, the on-disk format is byte-for-byte compatible with real `git`,

0 commit comments

Comments
 (0)