Repository navigation
220 lines (208 loc) · 8.37 KB
/
Copy pathci.yml
File metadata and controls
220 lines (208 loc) · 8.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# Continuous integration for the Didit Python SDK (docs/DESIGN.md section 11).
# Every third-party action is pinned by full commit SHA; Dependabot keeps the pins current.
name: CI
on:
push:
branches: [main]
pull_request:
# Manual runs also start the live smoke tests (job live-smoke) when the
# DIDIT_SANDBOX_API_KEY secret is set.
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
# Cancel superseded runs of a pull request; every push to main gets its own run.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
FORCE_COLOR: "1"
# Use uv.lock exactly as committed. The lint job checks that it matches pyproject.toml.
UV_FROZEN: "1"
defaults:
run:
shell: bash
jobs:
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up uv
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
- name: Check that uv.lock matches pyproject.toml
run: env -u UV_FROZEN uv lock --check
- name: Install dependencies
run: uv sync --frozen
- name: ruff check
run: uv run ruff check --output-format=github .
- name: ruff format --check
run: uv run ruff format --check .
typecheck:
name: Type check (mypy, pyright)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up uv
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
- name: Install dependencies
run: uv sync --frozen
- name: mypy --strict
run: uv run mypy
- name: pyright
run: uv run pyright
codegen:
name: Generated code is up to date
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up uv
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
- name: Install dependencies
run: uv sync --frozen
- name: Regenerate and compare with the committed code
# Fails when src/didit/types, src/didit/resources or tests/generated differ from
# what codegen/ produces from openapi/. Fix: uv run python codegen/generate.py
run: uv run python codegen/generate.py --check
test:
name: Test (Python ${{ matrix.python-version }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
include:
# Adds the coverage gate to the existing Linux 3.12 job.
- os: ubuntu-latest
python-version: "3.12"
coverage: true
- os: macos-latest
python-version: "3.12"
- os: windows-latest
python-version: "3.12"
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up uv and Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --frozen
- name: pytest
if: ${{ !matrix.coverage }}
run: uv run pytest -m "not live"
- name: pytest with the core coverage gate (90 %)
if: ${{ matrix.coverage }}
run: uv run pytest -m "not live" --cov --cov-report=term-missing --cov-fail-under=90
build:
name: Build and install the wheel
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up uv
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
- name: Build the sdist and the wheel
run: uv build
- name: Install the wheel into a fresh virtual environment
run: |
uv venv --python 3.12 "$RUNNER_TEMP/wheel-venv"
uv pip install --python "$RUNNER_TEMP/wheel-venv" dist/*.whl
- name: Import didit without the optional cryptography dependency
# Run outside the checkout so that the import resolves to the installed wheel.
working-directory: ${{ runner.temp }}
run: |
py="$RUNNER_TEMP/wheel-venv/bin/python"
if "$py" -c "import cryptography" 2>/dev/null; then
echo "::error::cryptography is installed without the auth extra; it must stay optional (didit-sdk[auth])."
exit 1
fi
"$py" -c "import didit; print(didit.__version__)"
secret-scan:
name: Secret scan (gitleaks, full history)
runs-on: ubuntu-latest
timeout-minutes: 10
env:
# The official gitleaks-action needs a paid licence for organisations, so the
# release binary is downloaded and verified against its published SHA-256.
GITLEAKS_VERSION: "8.30.1"
GITLEAKS_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
steps:
- name: Check out the repository with its full history
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Install gitleaks ${{ env.GITLEAKS_VERSION }}
run: |
archive="$RUNNER_TEMP/gitleaks.tar.gz"
curl -sSfL --retry 3 -o "$archive" \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
echo "${GITLEAKS_SHA256} ${archive}" | sha256sum --check --strict
tar -xzf "$archive" -C "$RUNNER_TEMP" gitleaks
"$RUNNER_TEMP/gitleaks" version
- name: Scan every commit
# `gitleaks git` is the current name of `gitleaks detect` (deprecated in 8.19).
run: '"$RUNNER_TEMP/gitleaks" git --config .gitleaks.toml --redact --verbose --no-banner .'
live-smoke:
name: Live smoke tests (sandbox)
# Never part of default CI (docs/DESIGN.md section 11): manual runs only, and only
# when the DIDIT_SANDBOX_API_KEY repository secret is set.
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check for the sandbox API key
id: key
env:
DIDIT_SANDBOX_API_KEY: ${{ secrets.DIDIT_SANDBOX_API_KEY }}
run: |
if [ -n "$DIDIT_SANDBOX_API_KEY" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
echo "::notice::DIDIT_SANDBOX_API_KEY is not set; the live smoke tests are skipped."
fi
- name: Check out the repository
if: steps.key.outputs.present == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up uv
if: steps.key.outputs.present == 'true'
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
- name: Install dependencies
if: steps.key.outputs.present == 'true'
run: uv sync --frozen
- name: pytest -m live
if: steps.key.outputs.present == 'true'
# The key reaches only this step, through the environment; it is never printed.
# Optional repository variables: DIDIT_SANDBOX_WORKFLOW_ID, DIDIT_SANDBOX_BASE_URL.
env:
DIDIT_SANDBOX_API_KEY: ${{ secrets.DIDIT_SANDBOX_API_KEY }}
DIDIT_SANDBOX_WORKFLOW_ID: ${{ vars.DIDIT_SANDBOX_WORKFLOW_ID }}
SANDBOX_BASE_URL: ${{ vars.DIDIT_SANDBOX_BASE_URL }}
run: |
if [ -n "$SANDBOX_BASE_URL" ]; then
export DIDIT_SANDBOX_BASE_URL="$SANDBOX_BASE_URL"
fi
uv run pytest -m live