Skip to content

Commit 67b0a41

Browse files
feat: add pre-commit hooks and CI workflow for plugin repo
Pre-commit hooks: - executable-guard: protect +x on .sh files - format-and-lint (ruff): lint Python scripts and tests - isolation-check: test isolation rules on staged Python - block-sentinel-push: prevent pushing unreviewed checkpoint commits - pre-push-lint: full-tree ruff check before push CI workflow (GitHub Actions): - shellcheck: lint all shell scripts - lint-python: ruff check + format on Python files - test-plugin: run full test suite (1527 tests) with shfmt - create-failure-bug: auto-create tickets on CI failure Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f7a5714 commit 67b0a41

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

.github/workflows/ci.yml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Digital Service Orchestra (DSO) — Continuous Integration
2+
# Runs shellcheck, Python linting, plugin tests, and auto-creates failure tickets.
3+
4+
name: CI
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
- 'feature/**'
11+
- 'bugfix/**'
12+
- 'epic/**'
13+
- 'exp/**'
14+
paths-ignore:
15+
- '.tickets/**'
16+
- '**/*.md'
17+
pull_request:
18+
branches:
19+
- main
20+
paths-ignore:
21+
- '.tickets/**'
22+
- '**/*.md'
23+
workflow_dispatch:
24+
25+
concurrency:
26+
group: ${{ github.workflow }}-${{ github.ref }}
27+
cancel-in-progress: true
28+
29+
jobs:
30+
# ── Fast gates ──────────────────────────────────────────────
31+
32+
shellcheck:
33+
name: ShellCheck
34+
runs-on: ubuntu-latest
35+
timeout-minutes: 5
36+
steps:
37+
- uses: actions/checkout@v4
38+
39+
- name: Install shellcheck
40+
run: sudo apt-get update && sudo apt-get install -y shellcheck
41+
42+
- name: Run shellcheck
43+
run: shellcheck scripts/*.sh hooks/*.sh hooks/**/*.sh
44+
45+
- name: Job timing report
46+
if: always()
47+
run: echo "shellcheck completed at $(date -u +%Y-%m-%dT%H:%M:%SZ)"
48+
49+
lint-python:
50+
name: Lint Python (ruff)
51+
runs-on: ubuntu-latest
52+
timeout-minutes: 5
53+
steps:
54+
- uses: actions/checkout@v4
55+
56+
- name: Install ruff
57+
run: pip install ruff
58+
59+
- name: Ruff check
60+
run: ruff check scripts/*.py tests/**/*.py
61+
62+
- name: Ruff format check
63+
run: ruff format --check scripts/*.py tests/**/*.py
64+
65+
- name: Job timing report
66+
if: always()
67+
run: echo "lint-python completed at $(date -u +%Y-%m-%dT%H:%M:%SZ)"
68+
69+
# ── Full test suite ─────────────────────────────────────────
70+
71+
test-plugin:
72+
name: Plugin Test Suite
73+
runs-on: ubuntu-latest
74+
timeout-minutes: 15
75+
needs: [shellcheck, lint-python]
76+
env:
77+
SERIAL_SUITES: 1
78+
MAX_PARALLEL: 4
79+
steps:
80+
- uses: actions/checkout@v4
81+
82+
- name: Install shfmt
83+
run: |
84+
curl -sS https://webinstall.dev/shfmt | bash
85+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
86+
87+
- name: Configure git identity
88+
run: |
89+
git config --global user.name "CI Bot"
90+
git config --global user.email "ci@example.com"
91+
92+
- name: Run plugin tests
93+
env:
94+
CLAUDE_PLUGIN_ROOT: ${{ github.workspace }}
95+
run: bash tests/run-all.sh
96+
97+
- name: Job timing report
98+
if: always()
99+
run: echo "test-plugin completed at $(date -u +%Y-%m-%dT%H:%M:%SZ)"
100+
101+
# ── Failure ticket ──────────────────────────────────────────
102+
103+
create-failure-bug:
104+
name: Create Failure Bug Ticket
105+
runs-on: ubuntu-latest
106+
needs: [shellcheck, lint-python, test-plugin]
107+
if: failure() && github.event_name == 'push'
108+
steps:
109+
- uses: actions/checkout@v4
110+
111+
- name: Install tk CLI
112+
run: pip install tk
113+
114+
- name: Create failure bug
115+
run: bash scripts/ci-create-failure-bug.sh "${{ github.run_id }}"
116+
117+
- name: Job timing report
118+
if: always()
119+
run: echo "create-failure-bug completed at $(date -u +%Y-%m-%dT%H:%M:%SZ)"

.pre-commit-config.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Digital Service Orchestra (DSO) plugin pre-commit configuration
2+
# These hooks enforce code quality and safety checks for the DSO plugin repository.
3+
fail_fast: true
4+
5+
repos:
6+
- repo: local
7+
hooks:
8+
# --- commit-stage hooks ---
9+
10+
- id: executable-guard
11+
name: Executable Bit Guard (5s timeout)
12+
entry: ./scripts/pre-commit-executable-guard.sh
13+
language: system
14+
pass_filenames: false
15+
stages: [commit]
16+
files: \.sh$
17+
18+
- id: format-and-lint
19+
name: Format + Lint - Ruff (15s timeout)
20+
entry: ./scripts/pre-commit-wrapper.sh format-and-lint 15 "ruff check scripts/*.py tests/**/*.py && ruff format --check scripts/*.py tests/**/*.py"
21+
language: system
22+
pass_filenames: false
23+
types: [python]
24+
stages: [commit]
25+
26+
- id: isolation-check
27+
name: Test Isolation Check (60s timeout)
28+
entry: ./scripts/pre-commit-wrapper.sh isolation-check 60 "STAGED_ONLY=true scripts/check-test-isolation.sh"
29+
language: system
30+
pass_filenames: false
31+
types: [python]
32+
stages: [commit]
33+
34+
# --- push-stage hooks ---
35+
36+
- id: block-sentinel-push
37+
name: Block checkpoint sentinel push
38+
language: system
39+
entry: "bash -c 'git cat-file -t HEAD:.checkpoint-needs-review >/dev/null 2>&1 && exit 1; exit 0'"
40+
pass_filenames: false
41+
always_run: true
42+
stages: [push]
43+
44+
- id: pre-push-lint
45+
name: Pre-push format + lint check
46+
language: system
47+
entry: ./scripts/pre-commit-wrapper.sh pre-push-lint 60 "ruff check scripts/*.py tests/**/*.py && ruff format --check scripts/*.py tests/**/*.py"
48+
pass_filenames: false
49+
always_run: true
50+
stages: [push]

0 commit comments

Comments
 (0)