fix: enable agentic recovery for sub-recipe failures (#2953) #3601
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
| # GitHub Actions CI Pipeline | |
| # Runs formatting, linting, and tests on every pull request | |
| # Complements pre-commit hooks configured in issue #24 | |
| name: CI | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| push: | |
| branches: [main] | |
| workflow_dispatch: # Allow manual triggering | |
| # Cancel in-progress runs for the same PR | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| validate: | |
| name: Validate Code | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Full history for better git operations | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| cache: "pip" | |
| cache-dependency-path: | | |
| pyproject.toml | |
| requirements*.txt | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| continue-on-error: true # Node.js is optional, no package.json in repo | |
| - name: Cache pre-commit environments | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pre-commit | |
| key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }} | |
| restore-keys: | | |
| pre-commit-${{ runner.os }}- | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pre-commit detect-secrets | |
| # Install project dependencies if they exist | |
| if [ -f pyproject.toml ]; then | |
| pip install -e ".[dev]" 2>/dev/null || pip install -e . 2>/dev/null || true | |
| elif [ -f requirements-dev.txt ]; then | |
| pip install -r requirements-dev.txt | |
| elif [ -f requirements.txt ]; then | |
| pip install -r requirements.txt | |
| fi | |
| - name: Install Node dependencies | |
| run: | | |
| if [ -f package-lock.json ]; then | |
| npm ci | |
| elif [ -f package.json ]; then | |
| npm install | |
| fi | |
| continue-on-error: true # Don't fail if no Node project | |
| - name: Run pre-commit hooks | |
| id: pre-commit | |
| run: | | |
| pre-commit run --all-files --show-diff-on-failure --color=always | |
| continue-on-error: true | |
| - name: Run Python tests | |
| id: python-tests | |
| timeout-minutes: 10 | |
| env: | |
| CI: "true" | |
| DEBIAN_FRONTEND: noninteractive | |
| NPX_NO_INSTALL: "1" | |
| run: | | |
| if command -v pytest &> /dev/null; then | |
| echo "Running Python tests with pytest..." | |
| echo "Skipping SDK tests in CI (requires Claude Code SDK)" | |
| PYTHONPATH=. pytest -m "not requires_sdk" --tb=short -v --color=yes --durations=10 --maxfail=1 -x | |
| else | |
| echo "pytest not found, skipping Python tests" | |
| fi | |
| continue-on-error: true | |
| - name: Run JavaScript/TypeScript tests | |
| id: js-tests | |
| if: hashFiles('package.json') != '' | |
| run: | | |
| if [ -f package.json ] && grep -q '"test"' package.json; then | |
| echo "Running JavaScript/TypeScript tests..." | |
| npm test | |
| else | |
| echo "No test script found in package.json" | |
| fi | |
| continue-on-error: true | |
| - name: Report status | |
| if: always() | |
| run: | | |
| echo "## CI Results Summary" | |
| echo "" | |
| # Pre-commit status | |
| if [ "${{ steps.pre-commit.conclusion }}" == "success" ]; then | |
| echo "✅ Pre-commit checks: PASSED" | |
| else | |
| echo "❌ Pre-commit checks: FAILED" | |
| echo " Run 'pre-commit run --all-files' locally to see details" | |
| fi | |
| # Python tests status | |
| if [ "${{ steps.python-tests.conclusion }}" == "success" ]; then | |
| echo "✅ Python tests: PASSED" | |
| elif [ "${{ steps.python-tests.conclusion }}" == "skipped" ]; then | |
| echo "⏭️ Python tests: SKIPPED (no tests found)" | |
| else | |
| echo "❌ Python tests: FAILED" | |
| fi | |
| # JavaScript tests status | |
| if [ "${{ steps.js-tests.conclusion }}" == "success" ]; then | |
| echo "✅ JavaScript tests: PASSED" | |
| elif [ "${{ steps.js-tests.conclusion }}" == "skipped" ]; then | |
| echo "⏭️ JavaScript tests: SKIPPED (no JS project)" | |
| else | |
| echo "❌ JavaScript tests: FAILED" | |
| fi | |
| echo "" | |
| # Overall status | |
| if [ "${{ steps.pre-commit.conclusion }}" == "success" ] && \ | |
| [ "${{ steps.python-tests.conclusion }}" != "failure" ] && \ | |
| [ "${{ steps.js-tests.conclusion }}" != "failure" ]; then | |
| echo "🎉 All checks passed!" | |
| exit 0 | |
| else | |
| echo "💔 Some checks failed. Please fix the issues and push again." | |
| exit 1 | |
| fi |