Skip to content

Commit 34c7c82

Browse files
committed
ci: add GitHub Actions CI pipeline
- Validates code across Python 3.12/3.13 on Ubuntu and Windows - Runs: pip check, compileall, ruff lint, pytest import smoke tests - No live Copilot calls by default (contributor-friendly) - CI-SETUP.md documents philosophy and local validation
1 parent abc8ee7 commit 34c7c82

3 files changed

Lines changed: 146 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: ci-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
validate:
17+
name: Validate (${{ matrix.os }}, Python ${{ matrix.python-version }})
18+
runs-on: ${{ matrix.os }}
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
os: ["ubuntu-latest", "windows-latest"]
23+
python-version: ["3.12", "3.13"]
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Set up Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: ${{ matrix.python-version }}
33+
cache: pip
34+
35+
- name: Install dependencies
36+
run: |
37+
python -m pip install --upgrade pip
38+
python -m pip install -r requirements.txt
39+
python -m pip install pytest ruff
40+
41+
- name: Verify environment
42+
run: |
43+
python --version
44+
python -m pip --version
45+
python -m pip check
46+
47+
- name: Static checks (compile)
48+
run: |
49+
python -m compileall -q samples scripts
50+
51+
- name: Lint (ruff)
52+
run: |
53+
python -m ruff check .
54+
55+
- name: Tests
56+
run: |
57+
python -m pytest -q

CI-SETUP.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# CI Setup
2+
3+
This repo contains runnable Copilot SDK sample scripts. In CI, we **do not run** the scripts end-to-end because they require:
4+
5+
- GitHub Copilot CLI availability and authentication
6+
- Network access
7+
- Potentially premium model usage depending on your Copilot plan
8+
9+
Instead, CI validates that the repository stays healthy for contributors.
10+
11+
## What CI does
12+
13+
The workflow in [.github/workflows/ci.yml](.github/workflows/ci.yml) runs:
14+
15+
1. **Dependency install** (`pip install -r requirements.txt`)
16+
2. **Environment verification** (`pip check`)
17+
3. **Static compile check** (`python -m compileall samples`)
18+
4. **Import smoke tests** (imports each script under `samples/` to ensure there are no missing top-level dependencies)
19+
20+
## Local equivalent
21+
22+
From repo root:
23+
24+
- Create/activate a venv
25+
- `pip install -r requirements.txt`
26+
- `python -m compileall samples`
27+
- `pytest -q`
28+
29+
## Running samples for real
30+
31+
To run the samples end-to-end locally, you’ll need:
32+
33+
- Copilot CLI installed and authenticated (`copilot auth login`)
34+
- For the Playwright sample: `python -m playwright install chromium`
35+
36+
## Optional CI proof (E2E)
37+
38+
If you want CI to run real networked scenarios as proof, use the manual workflow in [.github/workflows/agent-scenarios.yml](.github/workflows/agent-scenarios.yml).
39+
40+
It supports two modes:
41+
42+
1) `provider=copilot` (unattended Copilot models)
43+
44+
The Copilot SDK client supports non-interactive auth via a GitHub token. Configure this repository secret:
45+
46+
- `COPILOT_GITHUB_TOKEN`
47+
48+
This should be a token that can authenticate as a user with access to Copilot models in your org/account (for example, a PAT/fine-grained token depending on your GitHub policies).
49+
50+
1) `provider=openai` (BYOK)
51+
52+
Configure this repository secret:
53+
54+
- `OPENAI_API_KEY`
55+
56+
Optional:
57+
58+
- `OPENAI_BASE_URL` (defaults to `https://api.openai.com/v1`)
59+
60+
The workflow uploads an `agent-scenarios.txt` transcript as an artifact.

tests/test_imports.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
import importlib.util
4+
from pathlib import Path
5+
6+
7+
def _import_module_from_path(py_file: Path) -> None:
8+
module_name = f"samples_{py_file.stem}"
9+
spec = importlib.util.spec_from_file_location(module_name, py_file)
10+
assert spec is not None
11+
assert spec.loader is not None
12+
module = importlib.util.module_from_spec(spec)
13+
spec.loader.exec_module(module)
14+
15+
16+
def test_samples_import_cleanly() -> None:
17+
"""Import each sample script to catch missing deps / syntax errors.
18+
19+
These scripts should be safe to import because they guard runtime work
20+
with `if __name__ == "__main__":`.
21+
"""
22+
repo_root = Path(__file__).resolve().parents[1]
23+
samples_dir = repo_root / "samples"
24+
25+
py_files = sorted(p for p in samples_dir.glob("*.py") if not p.name.startswith("_"))
26+
assert py_files, "No sample files found"
27+
28+
for py_file in py_files:
29+
_import_module_from_path(py_file)

0 commit comments

Comments
 (0)