Skip to content

Commit f047be3

Browse files
committed
Speed up validation with path-aware jobs
1 parent 79fdf2d commit f047be3

3 files changed

Lines changed: 161 additions & 22 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55

66
permissions:
77
contents: read
8+
pull-requests: read
89

910
concurrency:
1011
group: ci-${{ github.workflow }}-${{ github.ref }}

.github/workflows/release.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ jobs:
5050
uses: actions/setup-python@v6
5151
with:
5252
python-version: ${{ env.PYTHON_VERSION }}
53-
cache: pip
5453

5554
- name: Cache uv
5655
uses: actions/cache@v5

.github/workflows/validate.yml

Lines changed: 160 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,86 @@ on:
1515

1616
permissions:
1717
contents: read
18+
pull-requests: read
1819

1920
defaults:
2021
run:
2122
shell: bash
2223

2324
jobs:
24-
package:
25-
name: Validate package
25+
changes:
26+
name: Detect changed paths
27+
runs-on: ubuntu-24.04
28+
outputs:
29+
github_actions: ${{ steps.changed_paths.outputs.github_actions }}
30+
markdown: ${{ steps.changed_paths.outputs.markdown }}
31+
python: ${{ steps.changed_paths.outputs.python }}
32+
package: ${{ steps.changed_paths.outputs.package }}
33+
34+
steps:
35+
- name: Detect changed paths
36+
id: changed_paths
37+
env:
38+
GH_TOKEN: ${{ github.token }}
39+
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
40+
run: |
41+
github_actions_changed=false
42+
markdown_changed=false
43+
python_changed=false
44+
package_changed=false
45+
46+
if [[ "${{ github.event_name }}" != "pull_request" ]]; then
47+
github_actions_changed=true
48+
markdown_changed=true
49+
python_changed=true
50+
package_changed=true
51+
else
52+
changed_files="$(mktemp)"
53+
gh api --paginate \
54+
"repos/${GITHUB_REPOSITORY}/pulls/${PULL_REQUEST_NUMBER}/files" \
55+
--jq '.[].filename' > "${changed_files}"
56+
57+
while IFS= read -r changed_file; do
58+
case "${changed_file}" in
59+
.github/workflows/*)
60+
github_actions_changed=true
61+
;;
62+
esac
63+
64+
case "${changed_file}" in
65+
*.md|.markdownlint-cli2.yaml)
66+
markdown_changed=true
67+
;;
68+
esac
69+
70+
case "${changed_file}" in
71+
.python-version|pyproject.toml|uv.lock|src/*|tests/*)
72+
python_changed=true
73+
;;
74+
esac
75+
76+
case "${changed_file}" in
77+
.python-version|LICENSE|README.md|pyproject.toml|uv.lock|src/*)
78+
package_changed=true
79+
;;
80+
esac
81+
done < "${changed_files}"
82+
fi
83+
84+
{
85+
echo "github_actions=${github_actions_changed}"
86+
echo "markdown=${markdown_changed}"
87+
echo "python=${python_changed}"
88+
echo "package=${package_changed}"
89+
} >> "${GITHUB_OUTPUT}"
90+
91+
github_actions:
92+
name: Lint GitHub Actions
93+
needs: changes
94+
if: needs.changes.outputs.github_actions == 'true'
2695
runs-on: ubuntu-24.04
2796
env:
2897
ACTIONLINT_VERSION: "1.7.12"
29-
IMPORT_NAME: src_py_lib
30-
MARKDOWNLINT_CLI2_VERSION: "0.22.1"
31-
PYTHON_VERSION: "3.11"
32-
UV_VERSION: "0.11.7"
3398

3499
steps:
35100
- name: Check out code
@@ -38,15 +103,7 @@ jobs:
38103
persist-credentials: false
39104
ref: ${{ inputs.ref || github.ref }}
40105

41-
- name: Cache actionlint
42-
id: cache-actionlint
43-
uses: actions/cache@v5
44-
with:
45-
path: ~/.local/bin/actionlint
46-
key: actionlint-${{ runner.os }}-${{ runner.arch }}-${{ env.ACTIONLINT_VERSION }}
47-
48106
- name: Install actionlint
49-
if: steps.cache-actionlint.outputs.cache-hit != 'true'
50107
run: |
51108
mkdir -p "${HOME}/.local/bin"
52109
asset="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
@@ -63,20 +120,45 @@ jobs:
63120
run: |
64121
"${HOME}/.local/bin/actionlint"
65122
66-
- name: Cache npm
67-
uses: actions/cache@v5
123+
markdown:
124+
name: Lint Markdown
125+
needs: changes
126+
if: needs.changes.outputs.markdown == 'true'
127+
runs-on: ubuntu-24.04
128+
env:
129+
MARKDOWNLINT_CLI2_VERSION: "0.22.1"
130+
131+
steps:
132+
- name: Check out code
133+
uses: actions/checkout@v6
68134
with:
69-
path: ~/.npm
70-
key: npm-${{ runner.os }}-markdownlint-cli2-${{ env.MARKDOWNLINT_CLI2_VERSION }}
135+
persist-credentials: false
136+
ref: ${{ inputs.ref || github.ref }}
71137

72138
- name: Lint Markdown
73139
run: npx --yes "markdownlint-cli2@${MARKDOWNLINT_CLI2_VERSION}"
74140

141+
python:
142+
name: Validate Python
143+
needs: changes
144+
if: needs.changes.outputs.python == 'true'
145+
runs-on: ubuntu-24.04
146+
env:
147+
IMPORT_NAME: src_py_lib
148+
PYTHON_VERSION: "3.11"
149+
UV_VERSION: "0.11.7"
150+
151+
steps:
152+
- name: Check out code
153+
uses: actions/checkout@v6
154+
with:
155+
persist-credentials: false
156+
ref: ${{ inputs.ref || github.ref }}
157+
75158
- name: Set up Python
76159
uses: actions/setup-python@v6
77160
with:
78161
python-version: ${{ env.PYTHON_VERSION }}
79-
cache: pip
80162

81163
- name: Cache uv
82164
uses: actions/cache@v5
@@ -115,12 +197,43 @@ jobs:
115197
raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
116198
PY
117199
200+
package_build:
201+
name: Build and smoke-test package
202+
needs: changes
203+
if: inputs.build-package && needs.changes.outputs.package == 'true'
204+
runs-on: ubuntu-24.04
205+
env:
206+
IMPORT_NAME: src_py_lib
207+
PYTHON_VERSION: "3.11"
208+
UV_VERSION: "0.11.7"
209+
210+
steps:
211+
- name: Check out code
212+
uses: actions/checkout@v6
213+
with:
214+
persist-credentials: false
215+
ref: ${{ inputs.ref || github.ref }}
216+
217+
- name: Set up Python
218+
uses: actions/setup-python@v6
219+
with:
220+
python-version: ${{ env.PYTHON_VERSION }}
221+
222+
- name: Cache uv
223+
uses: actions/cache@v5
224+
with:
225+
path: ~/.cache/uv
226+
key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
227+
restore-keys: |
228+
uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-
229+
230+
- name: Install uv
231+
run: python -m pip install "uv==${UV_VERSION}"
232+
118233
- name: Build wheel
119-
if: inputs.build-package
120234
run: uv build --wheel --out-dir dist --no-create-gitignore
121235

122236
- name: Smoke test installed wheel
123-
if: inputs.build-package
124237
run: |
125238
python -m venv build/ci-venv
126239
. build/ci-venv/bin/activate
@@ -133,3 +246,29 @@ jobs:
133246
if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
134247
raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
135248
PY
249+
250+
package:
251+
name: Validate package
252+
needs: [changes, github_actions, markdown, python, package_build]
253+
if: always()
254+
runs-on: ubuntu-24.04
255+
256+
steps:
257+
- name: Confirm validation results
258+
run: |
259+
for validation_result in \
260+
"${{ needs.changes.result }}" \
261+
"${{ needs.github_actions.result }}" \
262+
"${{ needs.markdown.result }}" \
263+
"${{ needs.python.result }}" \
264+
"${{ needs.package_build.result }}"
265+
do
266+
case "${validation_result}" in
267+
success|skipped)
268+
;;
269+
*)
270+
echo "::error title=Validation failed::At least one validation job ended with '${validation_result}'."
271+
exit 1
272+
;;
273+
esac
274+
done

0 commit comments

Comments
 (0)