Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/scripts/check-ci-per-commit-label.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Check if the ci:per-commit label is present.
#
# For pull_request events, checks labels from the event payload.
# For push events, looks up the originating PR via the GitHub API.
#
# Usage:
# check-ci-per-commit-label.sh <event_name> <repository> <sha> [labels_json]
#
# Arguments:
# event_name - "pull_request" or "push"
# repository - e.g. "owner/repo"
# sha - commit SHA
# labels_json - JSON array of label names (required for pull_request)
#
# Output:
# Prints has_label=true or has_label=false (for GITHUB_OUTPUT)
set -euo pipefail

event_name="${1:?Usage: check-ci-per-commit-label.sh <event_name> <repository> <sha> [labels_json]}"
repository="${2:?Missing repository}"
sha="${3:?Missing sha}"
labels_json="${4:-}"

HAS_LABEL="false"

if [ "$event_name" = "pull_request" ]; then
if echo "$labels_json" | grep -q "ci:per-commit"; then
HAS_LABEL="true"
fi
else
PRS=$(gh api \
"repos/${repository}/commits/${sha}/pulls" \
--jq '.[].number')
for pr in $PRS; do
LABELS=$(gh api \
"repos/${repository}/pulls/${pr}" \
--jq '.labels[].name')
if echo "$LABELS" | grep -q "^ci:per-commit$"; then
HAS_LABEL="true"
break
fi
done
fi

echo "has_label=${HAS_LABEL}"
39 changes: 39 additions & 0 deletions .github/scripts/run-ci-per-commit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Run the full CI checks on each commit in the given range, sequentially.
# Stops at the first commit that fails.
#
# Usage:
# run-ci-per-commit.sh <base_sha> <head_sha>
#
# Arguments:
# base_sha - the base commit (exclusive)
# head_sha - the head commit (inclusive)
set -euo pipefail

base="${1:?Usage: run-ci-per-commit.sh <base_sha> <head_sha>}"
head="${2:?Missing head_sha}"

commits=$(git rev-list --reverse "${base}..${head}")
total=$(echo "$commits" | wc -l | tr -d ' ')
current=0

for commit in $commits; do
current=$((current + 1))
short=$(git rev-parse --short "$commit")
subject=$(git log -1 --format=%s "$commit")
echo ""
echo "=== [$current/$total] Testing ${short}: ${subject} ==="
echo ""

git checkout --quiet "$commit"
make install
make lint
make check-format
make test

echo ""
echo "=== [$current/$total] PASSED: ${short} ==="
done

echo ""
echo "All ${total} commit(s) passed CI checks."
10 changes: 5 additions & 5 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ jobs:
- name: Install poetry
run: pip install poetry==${{ matrix.poetry-version}}
- name: Install deps
run: poetry install
run: make install
- name: Run tests
run: poetry run pytest tests
run: make test
- name: Check formatting
run: poetry run ruff format --check leakix/ tests/ example/ executable/
run: make check-format
- name: Run linter
run: poetry run ruff check leakix/ tests/ example/ executable/
run: make lint
- name: Security audit
run: poetry run pip-audit
run: make audit
66 changes: 66 additions & 0 deletions .github/workflows/ci-per-commit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: CI per commit
on:
push:
branches:
- main
pull_request:
types: [labeled]
branches:
- main

jobs:
check-label:
name: Check for ci:per-commit label
runs-on: ubuntu-latest
outputs:
has_label: ${{ steps.check.outputs.has_label }}
steps:
- uses: actions/checkout@v6
- name: Check for label
id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
.github/scripts/check-ci-per-commit-label.sh \
"${{ github.event_name }}" \
"${{ github.repository }}" \
"${{ github.sha }}" \
'${{ toJSON(github.event.pull_request.labels.*.name) }}' \
>> "$GITHUB_OUTPUT"

ci-per-commit:
name: CI per commit
needs: check-label
if: needs.check-label.outputs.has_label == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Install GNU sed (macOS)
if: runner.os == 'macOS'
run: brew install gnu-sed
- name: Install poetry
run: pip install poetry==2.3.1
- name: Determine commit range
id: range
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
else
BASE="${{ github.event.before }}"
HEAD="${{ github.sha }}"
fi
echo "base=${BASE}" >> "$GITHUB_OUTPUT"
echo "head=${HEAD}" >> "$GITHUB_OUTPUT"
- name: Run CI on each commit
run: |
.github/scripts/run-ci-per-commit.sh \
"${{ steps.range.outputs.base }}" \
"${{ steps.range.outputs.head }}"
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ and this project adheres to

- Updated l9format requirement from =1.3.2 to =1.4.0 ([ae676d9])

### Infrastructure

- CI: use Makefile targets in Windows job and add sequential per-commit
testing triggered by the ci:per-commit label ([3967e42], [#66])

## [0.1.10] - 2024-12-XX

### Changed
Expand Down Expand Up @@ -47,6 +52,7 @@ and this project adheres to
[0.1.9]: https://github.com/LeakIX/LeakIXClient-Python/releases/tag/v0.1.9

<!-- Commit links -->
[3967e42]: https://github.com/LeakIX/LeakIXClient-Python/commit/3967e42
[ae676d9]: https://github.com/LeakIX/LeakIXClient-Python/commit/ae676d9
[65c5121]: https://github.com/LeakIX/LeakIXClient-Python/commit/65c5121
[0975c1c]: https://github.com/LeakIX/LeakIXClient-Python/commit/0975c1c
Expand All @@ -55,3 +61,6 @@ and this project adheres to
[6777ad9]: https://github.com/LeakIX/LeakIXClient-Python/commit/6777ad9
[62550bc]: https://github.com/LeakIX/LeakIXClient-Python/commit/62550bc
[4dd4948]: https://github.com/LeakIX/LeakIXClient-Python/commit/4dd4948

<!-- PR links -->
[#66]: https://github.com/LeakIX/LeakIXClient-Python/pull/66
Loading