Merge pull request #27 from ix-infrastructure/feat/skip-pro-feature-msgs #32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| # Cancel superseded runs on the same ref so rapid pushes don't pile up runners. | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| validate: | |
| name: Validate plugin structure | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| persist-credentials: false | |
| - name: Validate JSON files | |
| run: | | |
| echo "── JSON validation ──" | |
| for f in .claude-plugin/plugin.json .claude-plugin/marketplace.json hooks/hooks.json; do | |
| if jq -e . "$f" >/dev/null 2>&1; then | |
| echo " [ok] $f" | |
| else | |
| echo " [FAIL] $f is invalid JSON" | |
| exit 1 | |
| fi | |
| done | |
| # Belt-and-suspenders: parse every committed JSON file (manifests + | |
| # fixtures), not just the three core manifests above. node is preinstalled | |
| # on ubuntu-latest; node_modules/.git are excluded. | |
| - name: Validate all JSON parses | |
| run: | | |
| set -euo pipefail | |
| fail=0 | |
| while IFS= read -r -d '' f; do | |
| if node -e "JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))" "$f"; then | |
| echo " [ok] $f" | |
| else | |
| echo " [FAIL] invalid JSON: $f" | |
| fail=1 | |
| fi | |
| done < <(find . -name '*.json' \ | |
| -not -path './.git/*' -not -path '*/node_modules/*' -not -path '*/dist/*' -print0) | |
| exit $fail | |
| - name: Validate plugin version consistency | |
| run: | | |
| echo "── Version consistency ──" | |
| PLUGIN_VER=$(jq -r '.version' .claude-plugin/plugin.json) | |
| MARKETPLACE_VER=$(jq -r '.plugins[0].version' .claude-plugin/marketplace.json) | |
| echo " plugin.json: $PLUGIN_VER" | |
| echo " marketplace.json: $MARKETPLACE_VER" | |
| if [ "$PLUGIN_VER" != "$MARKETPLACE_VER" ]; then | |
| echo " [FAIL] version mismatch" | |
| exit 1 | |
| fi | |
| echo " [ok] versions match" | |
| - name: Validate expected skills | |
| run: | | |
| echo "── Skills ──" | |
| FAIL=0 | |
| for skill in ix-understand ix-investigate ix-impact ix-plan ix-debug ix-architecture ix-docs; do | |
| if [ -f "skills/$skill/SKILL.md" ]; then | |
| echo " [ok] $skill" | |
| else | |
| echo " [FAIL] missing: skills/$skill/SKILL.md" | |
| FAIL=1 | |
| fi | |
| done | |
| exit $FAIL | |
| - name: Validate expected agents | |
| run: | | |
| echo "── Agents ──" | |
| FAIL=0 | |
| for agent in ix-explorer ix-system-explorer ix-bug-investigator ix-safe-refactor-planner ix-architecture-auditor; do | |
| if [ -f "agents/$agent.md" ]; then | |
| echo " [ok] $agent" | |
| else | |
| echo " [FAIL] missing: agents/$agent.md" | |
| FAIL=1 | |
| fi | |
| done | |
| exit $FAIL | |
| - name: Validate hooks | |
| run: | | |
| echo "── Hooks ──" | |
| FAIL=0 | |
| for hook in ix-briefing.sh ix-intercept.sh ix-read.sh ix-bash.sh ix-pre-edit.sh ix-ingest.sh ix-map.sh; do | |
| if [ -f "hooks/$hook" ] && [ -x "hooks/$hook" ]; then | |
| echo " [ok] $hook" | |
| elif [ -f "hooks/$hook" ]; then | |
| echo " [FAIL] $hook exists but is not executable" | |
| FAIL=1 | |
| else | |
| echo " [FAIL] missing: hooks/$hook" | |
| FAIL=1 | |
| fi | |
| done | |
| exit $FAIL | |
| shellcheck: | |
| name: Shellcheck | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| persist-credentials: false | |
| # shellcheck is preinstalled on ubuntu-latest. Scope to error severity so | |
| # the gate catches real bugs without failing on stylistic notes. Covers | |
| # every committed *.sh (hooks, libs, installers, tests), not just hooks/. | |
| - name: Run shellcheck on all shell scripts | |
| run: | | |
| set -euo pipefail | |
| shellcheck --version | |
| mapfile -d '' files < <(find . -name '*.sh' \ | |
| -not -path './.git/*' -not -path '*/node_modules/*' -print0) | |
| if [ ${#files[@]} -eq 0 ]; then | |
| echo "no shell scripts found"; exit 0 | |
| fi | |
| printf 'checking: %s\n' "${files[@]}" | |
| shellcheck --severity=error "${files[@]}" | |
| # ── Aggregate gate ─────────────────────────────────────────────────────── | |
| # One stable required-status-check context. Fails if any upstream job failed | |
| # OR was skipped/cancelled, so the job graph can be reshaped without orphaning | |
| # the required check. | |
| ci-success: | |
| name: CI Passed | |
| if: always() | |
| needs: [validate, shellcheck] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Verify all required jobs succeeded | |
| run: | | |
| echo "validate=${{ needs.validate.result }}" | |
| echo "shellcheck=${{ needs.shellcheck.result }}" | |
| [ "${{ needs.validate.result }}" = "success" ] \ | |
| && [ "${{ needs.shellcheck.result }}" = "success" ] |