diff --git a/.github/workflows/required-ci.yml b/.github/workflows/required-ci.yml new file mode 100644 index 000000000..f8a5bc354 --- /dev/null +++ b/.github/workflows/required-ci.yml @@ -0,0 +1,44 @@ +name: Required CI + +on: + pull_request: + branches: + - "develop" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow_ref }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + required-checks: + runs-on: ubuntu-latest + timeout-minutes: 8 + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5.4 + with: + enable-cache: true + prune-cache: false + python-version: "3.13" + version: "0.9.1" + cache-suffix: required-ci + + - name: Install Python dependencies + run: uv sync --frozen + + - name: Run required checks + run: | + uv run pytest \ + -n auto \ + --timeout 15 \ + tests/unit/cli/commands \ + tests/unit/sdk/codebase/test_rust_backend.py \ + tests/unit/sdk/codebase/test_rust_rewrite_readiness.py \ + -q diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cbcd5c268..6f310ad60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,99 +1,29 @@ -name: Tests +name: Legacy Tests on: push: branches: - "develop" - pull_request_target: - types: [opened, synchronize, reopened, labeled] - branches: - - "develop" workflow_dispatch: -jobs: - access-check: - runs-on: ubuntu-latest - steps: - - name: Check if bot account - id: bot-check - run: | - actor="${{ github.triggering_actor }}" - echo "Checking actor: $actor" - if [[ "$actor" == *"[bot]" ]] || [[ "$actor" == "renovate" ]] || [[ "$actor" == "dependabot" ]]; then - echo "is_bot=true" >> $GITHUB_OUTPUT - echo "Detected bot account: $actor - skipping permission check" - exit 0 - else - echo "is_bot=false" >> $GITHUB_OUTPUT - echo "Detected human account: $actor" - fi - - name: Check user permissions - if: steps.bot-check.outputs.is_bot == 'false' - uses: actions-cool/check-user-permission@v2 - with: - require: write - username: ${{ github.triggering_actor }} - error-if-missing: true - - legacy-test-scope: - needs: access-check - runs-on: ubuntu-latest - outputs: - run_legacy_tests: ${{ steps.scope.outputs.run_legacy_tests }} - steps: - - name: Detect changes requiring legacy tests - id: scope - env: - GH_TOKEN: ${{ github.token }} - GH_EVENT_NAME: ${{ github.event_name }} - PR_NUMBER: ${{ github.event.pull_request.number }} - REPOSITORY: ${{ github.repository }} - run: | - if [[ "$GH_EVENT_NAME" != "pull_request_target" ]]; then - echo "run_legacy_tests=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - - run_legacy_tests=false - while IFS= read -r file; do - case "$file" in - .codegen/*|.github/actions/*|.github/workflows/test.yml|Cargo.lock|Cargo.toml|Dockerfile|hatch.toml|mypy.ini|pyproject.toml|ruff.toml|uv.lock|crates/*|examples/*|rust-rewrite/tools/*|scripts/*|src/*|tests/*) - run_legacy_tests=true - ;; - esac - done < <(gh api --paginate "repos/$REPOSITORY/pulls/$PR_NUMBER/files" --jq '.[].filename') - - echo "run_legacy_tests=$run_legacy_tests" >> "$GITHUB_OUTPUT" - if [[ "$run_legacy_tests" == "true" ]]; then - echo "Code, package, test, or workflow files changed; running legacy tests." - else - echo "Only docs/site/planning files changed; skipping expensive legacy tests." - fi +permissions: + contents: read +jobs: unit-tests: - needs: [access-check, legacy-test-scope] runs-on: ubuntu-latest strategy: matrix: group: [1, 2, 3, 4, 5, 6, 7, 8] - steps: - - name: Skip legacy unit tests - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests != 'true' }} - run: echo "Only docs/site/planning files changed; skipping legacy unit test shard ${{ matrix.group }}." - - uses: actions/checkout@v4 - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} with: fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha }} - name: Setup environment - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} uses: ./.github/actions/setup-environment - name: Test with pytest - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} timeout-minutes: 5 run: | uv run pytest \ @@ -105,61 +35,14 @@ jobs: tests/unit - uses: ./.github/actions/report - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} with: flag: unit-tests codecov_token: ${{ secrets.CODECOV_TOKEN }} - codemod-tests: - needs: access-check - # TODO: re-enable when this check is a develop required check - if: false - runs-on: ubuntu-latest - strategy: - matrix: - sync_graph: [true, false] - size: [small, large] - exclude: - # Exclude large codemod tests when not needed - - size: ${{(contains(github.event.pull_request.labels.*.name, 'big-codemod-tests') || github.event_name == 'push' || github.event_name == 'workflow_dispatch') && 'kevin' || 'large'}} - - size: large - sync_graph: true - concurrency: - group: ${{ github.workflow }}-${{github.ref}}-${{matrix.sync_graph}}-${{matrix.size}}-${{github.event_name == 'push'&& github.sha}} - cancel-in-progress: true - name: "Codemod tests ${{matrix.size}}: Sync Graph=${{matrix.sync_graph}}" - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: Setup environment - uses: ./.github/actions/setup-environment - - - name: Cache oss-repos - uses: ./.github/actions/setup-oss-repos - - - name: Run ATS and Tests - uses: ./.github/actions/run-ats - timeout-minutes: 15 - with: - default_tests: "tests/integration/codemod/test_codemods.py" - codecov_static_token: ${{ secrets.CODECOV_STATIC_TOKEN }} - codecov_token: ${{ secrets.CODECOV_TOKEN }} - collect_args: "--size=${{matrix.size}} --sync-graph=${{matrix.sync_graph}}" - ats_collect_args: "--size=${{matrix.size}},--sync-graph=${{matrix.sync_graph}}," - codecov_flags: codemod-tests-${{matrix.size}}-${{matrix.sync_graph}} - env: - GITHUB_WORKSPACE: $GITHUB_WORKSPACE - parse-tests: - needs: access-check - if: contains(github.event.pull_request.labels.*.name, 'parse-tests') || github.event_name == 'push' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - name: Setup environment uses: ./.github/actions/setup-environment @@ -187,65 +70,15 @@ jobs: flag: no-flag codecov_token: ${{ secrets.CODECOV_TOKEN }} - - name: Notify parse tests failure - uses: slackapi/slack-github-action@v2.1.1 - if: failure() && github.event_name == 'push' && false - with: - webhook: ${{ secrets.SLACK_WEBHOOK_URL }} - webhook-type: incoming-webhook - payload: | - { - "blocks": [ - { - "type": "header", - "text": { - "type": "plain_text", - "text": "❌ Parse Tests Failed", - "emoji": true - } - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "*Branch:* ${{ github.ref_name }}\n*Triggered by:* <${{ github.server_url }}/${{ github.actor }}|@${{ github.actor }}>\n\n*Details:*\n• <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View workflow run>" - } - }, - { - "type": "context", - "elements": [ - { - "type": "mrkdwn", - "text": "Failed at " - } - ] - } - ] - } - integration-tests: - needs: [access-check, legacy-test-scope] - # The rust-rewrite baseline PR keeps protected checks focused on local unit, - # Rust, wheel, docs, and large-repo proof. These legacy integration tests push - # branches to an external fixture repo and require a writable PAT. - if: ${{ github.event_name != 'pull_request_target' || github.event.pull_request.head.ref != 'rust-rewrite' }} runs-on: ubuntu-latest steps: - - name: Skip legacy integration tests - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests != 'true' }} - run: echo "Only docs/site/planning files changed; skipping legacy integration tests." - - uses: actions/checkout@v4 - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} - with: - ref: ${{ github.event.pull_request.head.sha }} - name: Setup environment - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} uses: ./.github/actions/setup-environment - name: Test with pytest - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} timeout-minutes: 5 env: GITHUB_WORKSPACE: $GITHUB_WORKSPACE @@ -257,7 +90,6 @@ jobs: tests/integration/codegen - uses: ./.github/actions/report - if: ${{ needs.legacy-test-scope.outputs.run_legacy_tests == 'true' }} with: flag: integration-tests codecov_token: ${{ secrets.CODECOV_TOKEN }} diff --git a/rust-rewrite/tools/check_cli_smoke.sh b/rust-rewrite/tools/check_cli_smoke.sh index 36aa07a7c..7419f42bc 100755 --- a/rust-rewrite/tools/check_cli_smoke.sh +++ b/rust-rewrite/tools/check_cli_smoke.sh @@ -6,11 +6,13 @@ cd "$ROOT" CLI_FILES=( src/graph_sitter/cli/cli.py + src/graph_sitter/cli/commands/diagnose/main.py src/graph_sitter/cli/commands/doctor/main.py src/graph_sitter/cli/commands/parse/main.py src/graph_sitter/cli/commands/run/main.py src/graph_sitter/cli/commands/run/run_local.py src/graph_sitter/cli/commands/transform/main.py + tests/unit/cli/commands/diagnose/test_diagnose.py tests/unit/cli/commands/parse/test_parse.py tests/unit/cli/commands/run/test_run.py tests/unit/cli/commands/transform/test_transform.py @@ -20,6 +22,7 @@ uv run ruff check "${CLI_FILES[@]}" uv run python -m py_compile "${CLI_FILES[@]}" uv run graph-sitter --help >/dev/null +uv run graph-sitter diagnose --help >/dev/null uv run graph-sitter doctor --help >/dev/null uv run graph-sitter doctor --json >/dev/null uv run graph-sitter parse --help >/dev/null @@ -27,6 +30,7 @@ uv run graph-sitter run --help >/dev/null uv run graph-sitter transform --help >/dev/null uv run pytest \ + tests/unit/cli/commands/diagnose/test_diagnose.py \ tests/unit/cli/commands/parse/test_parse.py \ tests/unit/cli/commands/run/test_run.py \ tests/unit/cli/commands/transform/test_transform.py \ diff --git a/src/graph_sitter/cli/commands/diagnose/main.py b/src/graph_sitter/cli/commands/diagnose/main.py index b529bcb29..e6c8e7f09 100644 --- a/src/graph_sitter/cli/commands/diagnose/main.py +++ b/src/graph_sitter/cli/commands/diagnose/main.py @@ -48,7 +48,7 @@ def _memory_payload(samples: list[dict[str, float | str]]) -> dict[str, float | start_rss = float(samples[0]["rss_mb"]) after_parse_rss = float(samples[1]["rss_mb"]) after_stats_rss = float(samples[-1]["rss_mb"]) - peak_rss = max(float(sample["max_rss_mb"]) for sample in samples) + peak_rss = max(max(float(sample["rss_mb"]), float(sample["max_rss_mb"])) for sample in samples) return { "rss_start_mb": round(start_rss, 3), "rss_after_parse_mb": round(after_parse_rss, 3),