ci: add strict delta lint gate for changed rust lines
This commit is contained in:
parent
6e855cdcf1
commit
b81e4c6c50
7 changed files with 303 additions and 7 deletions
|
|
@ -20,6 +20,14 @@ if [ "${ZEROCLAW_STRICT_LINT:-0}" = "1" ]; then
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "${ZEROCLAW_STRICT_DELTA_LINT:-0}" = "1" ]; then
|
||||||
|
echo "==> pre-push: running strict delta lint gate (ZEROCLAW_STRICT_DELTA_LINT=1)..."
|
||||||
|
./scripts/ci/rust_strict_delta_gate.sh || {
|
||||||
|
echo "FAIL: strict delta lint gate reported issues."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "${ZEROCLAW_DOCS_LINT:-0}" = "1" ]; then
|
if [ "${ZEROCLAW_DOCS_LINT:-0}" = "1" ]; then
|
||||||
echo "==> pre-push: running docs quality gate (ZEROCLAW_DOCS_LINT=1)..."
|
echo "==> pre-push: running docs quality gate (ZEROCLAW_DOCS_LINT=1)..."
|
||||||
./scripts/ci/docs_quality_gate.sh || {
|
./scripts/ci/docs_quality_gate.sh || {
|
||||||
|
|
|
||||||
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
|
@ -136,6 +136,26 @@ jobs:
|
||||||
- name: Run rust quality gate
|
- name: Run rust quality gate
|
||||||
run: ./scripts/ci/rust_quality_gate.sh
|
run: ./scripts/ci/rust_quality_gate.sh
|
||||||
|
|
||||||
|
lint-strict-delta:
|
||||||
|
name: Lint Strict Delta
|
||||||
|
needs: [changes]
|
||||||
|
if: needs.changes.outputs.rust_changed == 'true'
|
||||||
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||||
|
timeout-minutes: 25
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
|
||||||
|
with:
|
||||||
|
toolchain: 1.92.0
|
||||||
|
components: clippy
|
||||||
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
|
||||||
|
- name: Run strict lint delta gate
|
||||||
|
env:
|
||||||
|
BASE_SHA: ${{ needs.changes.outputs.base_sha }}
|
||||||
|
run: ./scripts/ci/rust_strict_delta_gate.sh
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test
|
name: Test
|
||||||
needs: [changes]
|
needs: [changes]
|
||||||
|
|
@ -243,7 +263,7 @@ jobs:
|
||||||
ci-required:
|
ci-required:
|
||||||
name: CI Required Gate
|
name: CI Required Gate
|
||||||
if: always()
|
if: always()
|
||||||
needs: [changes, lint, test, build, docs-only, non-rust, docs-quality]
|
needs: [changes, lint, lint-strict-delta, test, build, docs-only, non-rust, docs-quality]
|
||||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||||
steps:
|
steps:
|
||||||
- name: Enforce required status
|
- name: Enforce required status
|
||||||
|
|
@ -277,15 +297,17 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
lint_result="${{ needs.lint.result }}"
|
lint_result="${{ needs.lint.result }}"
|
||||||
|
lint_strict_delta_result="${{ needs.lint-strict-delta.result }}"
|
||||||
test_result="${{ needs.test.result }}"
|
test_result="${{ needs.test.result }}"
|
||||||
build_result="${{ needs.build.result }}"
|
build_result="${{ needs.build.result }}"
|
||||||
|
|
||||||
echo "lint=${lint_result}"
|
echo "lint=${lint_result}"
|
||||||
|
echo "lint_strict_delta=${lint_strict_delta_result}"
|
||||||
echo "test=${test_result}"
|
echo "test=${test_result}"
|
||||||
echo "build=${build_result}"
|
echo "build=${build_result}"
|
||||||
echo "docs=${docs_result}"
|
echo "docs=${docs_result}"
|
||||||
|
|
||||||
if [ "$lint_result" != "success" ] || [ "$test_result" != "success" ] || [ "$build_result" != "success" ]; then
|
if [ "$lint_result" != "success" ] || [ "$lint_strict_delta_result" != "success" ] || [ "$test_result" != "success" ] || [ "$build_result" != "success" ]; then
|
||||||
echo "Required CI jobs did not pass."
|
echo "Required CI jobs did not pass."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ cargo test --locked
|
||||||
# Format & lint (required before PR)
|
# Format & lint (required before PR)
|
||||||
./scripts/ci/rust_quality_gate.sh
|
./scripts/ci/rust_quality_gate.sh
|
||||||
|
|
||||||
# Optional strict lint audit (recommended periodically)
|
# Optional strict lint audit (full repo, recommended periodically)
|
||||||
./scripts/ci/rust_quality_gate.sh --strict
|
./scripts/ci/rust_quality_gate.sh --strict
|
||||||
|
|
||||||
|
# Optional strict lint delta gate (blocks only changed Rust lines)
|
||||||
|
./scripts/ci/rust_strict_delta_gate.sh
|
||||||
|
|
||||||
# Optional docs lint gate (blocks only markdown issues on changed lines)
|
# Optional docs lint gate (blocks only markdown issues on changed lines)
|
||||||
./scripts/ci/docs_quality_gate.sh
|
./scripts/ci/docs_quality_gate.sh
|
||||||
|
|
||||||
|
|
@ -44,6 +47,12 @@ For an opt-in strict lint pass during pre-push, set:
|
||||||
ZEROCLAW_STRICT_LINT=1 git push
|
ZEROCLAW_STRICT_LINT=1 git push
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For an opt-in strict lint delta pass during pre-push (changed Rust lines only), set:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ZEROCLAW_STRICT_DELTA_LINT=1 git push
|
||||||
|
```
|
||||||
|
|
||||||
For an opt-in docs quality pass during pre-push (changed-line markdown gate), set:
|
For an opt-in docs quality pass during pre-push (changed-line markdown gate), set:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -359,7 +368,8 @@ impl Tool for YourTool {
|
||||||
- [ ] PR template sections are completed (including security + rollback)
|
- [ ] PR template sections are completed (including security + rollback)
|
||||||
- [ ] `./scripts/ci/rust_quality_gate.sh` — merge gate formatter/lint baseline passes
|
- [ ] `./scripts/ci/rust_quality_gate.sh` — merge gate formatter/lint baseline passes
|
||||||
- [ ] `cargo test --locked` — all tests pass locally or skipped tests are explained
|
- [ ] `cargo test --locked` — all tests pass locally or skipped tests are explained
|
||||||
- [ ] Optional strict audit: `./scripts/ci/rust_quality_gate.sh --strict` (run when doing lint cleanup or before release-hardening work)
|
- [ ] Optional strict audit: `./scripts/ci/rust_quality_gate.sh --strict` (full repo, run when doing lint cleanup or release-hardening work)
|
||||||
|
- [ ] Optional strict delta audit: `./scripts/ci/rust_strict_delta_gate.sh` (changed Rust lines only, useful for incremental debt control)
|
||||||
- [ ] New code has inline `#[cfg(test)]` tests
|
- [ ] New code has inline `#[cfg(test)]` tests
|
||||||
- [ ] No new dependencies unless absolutely necessary (we optimize for binary size)
|
- [ ] No new dependencies unless absolutely necessary (we optimize for binary size)
|
||||||
- [ ] README updated if adding user-facing features
|
- [ ] README updated if adding user-facing features
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,17 @@ To run an opt-in strict lint audit locally:
|
||||||
./dev/ci.sh lint-strict
|
./dev/ci.sh lint-strict
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To run the incremental strict gate (changed Rust lines only):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./dev/ci.sh lint-delta
|
||||||
|
```
|
||||||
|
|
||||||
### 3. Run targeted stages
|
### 3. Run targeted stages
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./dev/ci.sh lint
|
./dev/ci.sh lint
|
||||||
|
./dev/ci.sh lint-delta
|
||||||
./dev/ci.sh test
|
./dev/ci.sh test
|
||||||
./dev/ci.sh build
|
./dev/ci.sh build
|
||||||
./dev/ci.sh deny
|
./dev/ci.sh deny
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ Commands:
|
||||||
shell Open an interactive shell inside the CI container
|
shell Open an interactive shell inside the CI container
|
||||||
lint Run rustfmt + clippy correctness gate (container only)
|
lint Run rustfmt + clippy correctness gate (container only)
|
||||||
lint-strict Run rustfmt + full clippy warnings gate (container only)
|
lint-strict Run rustfmt + full clippy warnings gate (container only)
|
||||||
|
lint-delta Run strict lint delta gate on changed Rust lines (container only)
|
||||||
test Run cargo test (container only)
|
test Run cargo test (container only)
|
||||||
build Run release build smoke check (container only)
|
build Run release build smoke check (container only)
|
||||||
audit Run cargo audit (container only)
|
audit Run cargo audit (container only)
|
||||||
|
|
@ -61,6 +62,10 @@ case "$1" in
|
||||||
run_in_ci "./scripts/ci/rust_quality_gate.sh --strict"
|
run_in_ci "./scripts/ci/rust_quality_gate.sh --strict"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
lint-delta)
|
||||||
|
run_in_ci "./scripts/ci/rust_strict_delta_gate.sh"
|
||||||
|
;;
|
||||||
|
|
||||||
test)
|
test)
|
||||||
run_in_ci "cargo test --locked --verbose"
|
run_in_ci "cargo test --locked --verbose"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
|
||||||
### Merge-Blocking
|
### Merge-Blocking
|
||||||
|
|
||||||
- `.github/workflows/ci.yml` (`CI`)
|
- `.github/workflows/ci.yml` (`CI`)
|
||||||
- Purpose: Rust validation (`cargo fmt --all -- --check`, `cargo clippy --locked --all-targets -- -D clippy::correctness`, `test`, release build smoke) + docs quality checks when docs change (`markdownlint` blocks only issues on changed lines; link check scans only links added on changed lines)
|
- Purpose: Rust validation (`cargo fmt --all -- --check`, `cargo clippy --locked --all-targets -- -D clippy::correctness`, strict delta lint gate on changed Rust lines, `test`, release build smoke) + docs quality checks when docs change (`markdownlint` blocks only issues on changed lines; link check scans only links added on changed lines)
|
||||||
- Merge gate: `CI Required Gate`
|
- Merge gate: `CI Required Gate`
|
||||||
- `.github/workflows/workflow-sanity.yml` (`Workflow Sanity`)
|
- `.github/workflows/workflow-sanity.yml` (`Workflow Sanity`)
|
||||||
- Purpose: lint GitHub workflow files (`actionlint`, tab checks)
|
- Purpose: lint GitHub workflow files (`actionlint`, tab checks)
|
||||||
|
|
@ -71,12 +71,14 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
|
||||||
4. Security failures: inspect `.github/workflows/security.yml` and `deny.toml`.
|
4. Security failures: inspect `.github/workflows/security.yml` and `deny.toml`.
|
||||||
5. Workflow syntax/lint failures: inspect `.github/workflows/workflow-sanity.yml`.
|
5. Workflow syntax/lint failures: inspect `.github/workflows/workflow-sanity.yml`.
|
||||||
6. Docs failures in CI: inspect `docs-quality` job logs in `.github/workflows/ci.yml`.
|
6. Docs failures in CI: inspect `docs-quality` job logs in `.github/workflows/ci.yml`.
|
||||||
|
7. Strict delta lint failures in CI: inspect `lint-strict-delta` job logs and compare with `BASE_SHA` diff scope.
|
||||||
|
|
||||||
## Maintenance Rules
|
## Maintenance Rules
|
||||||
|
|
||||||
- Keep merge-blocking checks deterministic and reproducible (`--locked` where applicable).
|
- Keep merge-blocking checks deterministic and reproducible (`--locked` where applicable).
|
||||||
- Keep merge-blocking rust quality policy aligned across `.github/workflows/ci.yml`, `dev/ci.sh`, and `.githooks/pre-push` (`./scripts/ci/rust_quality_gate.sh`).
|
- Keep merge-blocking rust quality policy aligned across `.github/workflows/ci.yml`, `dev/ci.sh`, and `.githooks/pre-push` (`./scripts/ci/rust_quality_gate.sh` + `./scripts/ci/rust_strict_delta_gate.sh`).
|
||||||
- Run strict lint audits regularly via `./scripts/ci/rust_quality_gate.sh --strict` (for example through `./dev/ci.sh lint-strict`) and track cleanup in focused PRs.
|
- Use `./scripts/ci/rust_strict_delta_gate.sh` (or `./dev/ci.sh lint-delta`) as the incremental strict merge gate for changed Rust lines.
|
||||||
|
- Run full strict lint audits regularly via `./scripts/ci/rust_quality_gate.sh --strict` (for example through `./dev/ci.sh lint-strict`) and track cleanup in focused PRs.
|
||||||
- Keep docs markdown gating incremental via `./scripts/ci/docs_quality_gate.sh` (block changed-line issues, report baseline issues separately).
|
- Keep docs markdown gating incremental via `./scripts/ci/docs_quality_gate.sh` (block changed-line issues, report baseline issues separately).
|
||||||
- Keep docs link gating incremental via `./scripts/ci/collect_changed_links.py` + lychee (check only links added on changed lines).
|
- Keep docs link gating incremental via `./scripts/ci/collect_changed_links.py` + lychee (check only links added on changed lines).
|
||||||
- Prefer explicit workflow permissions (least privilege).
|
- Prefer explicit workflow permissions (least privilege).
|
||||||
|
|
|
||||||
242
scripts/ci/rust_strict_delta_gate.sh
Executable file
242
scripts/ci/rust_strict_delta_gate.sh
Executable file
|
|
@ -0,0 +1,242 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BASE_SHA="${BASE_SHA:-}"
|
||||||
|
RUST_FILES_RAW="${RUST_FILES:-}"
|
||||||
|
|
||||||
|
if [ -z "$BASE_SHA" ] && git rev-parse --verify origin/main >/dev/null 2>&1; then
|
||||||
|
BASE_SHA="$(git merge-base origin/main HEAD)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$BASE_SHA" ] && git rev-parse --verify HEAD~1 >/dev/null 2>&1; then
|
||||||
|
BASE_SHA="$(git rev-parse HEAD~1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$BASE_SHA" ] || ! git cat-file -e "$BASE_SHA^{commit}" 2>/dev/null; then
|
||||||
|
echo "BASE_SHA is missing or invalid for strict delta gate."
|
||||||
|
echo "Set BASE_SHA explicitly or ensure origin/main is available."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$RUST_FILES_RAW" ]; then
|
||||||
|
RUST_FILES_RAW="$(git diff --name-only "$BASE_SHA" HEAD | awk '/\.rs$/ { print }')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ALL_FILES=()
|
||||||
|
while IFS= read -r file; do
|
||||||
|
if [ -n "$file" ]; then
|
||||||
|
ALL_FILES+=("$file")
|
||||||
|
fi
|
||||||
|
done < <(printf '%s\n' "$RUST_FILES_RAW")
|
||||||
|
|
||||||
|
if [ "${#ALL_FILES[@]}" -eq 0 ]; then
|
||||||
|
echo "No Rust source files changed; skipping strict delta gate."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXISTING_FILES=()
|
||||||
|
for file in "${ALL_FILES[@]}"; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
EXISTING_FILES+=("$file")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${#EXISTING_FILES[@]}" -eq 0 ]; then
|
||||||
|
echo "No existing changed Rust files to lint; skipping strict delta gate."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Strict delta linting changed Rust files: ${EXISTING_FILES[*]}"
|
||||||
|
|
||||||
|
CHANGED_LINES_JSON_FILE="$(mktemp)"
|
||||||
|
CLIPPY_JSON_FILE="$(mktemp)"
|
||||||
|
CLIPPY_STDERR_FILE="$(mktemp)"
|
||||||
|
FILTERED_OUTPUT_FILE="$(mktemp)"
|
||||||
|
trap 'rm -f "$CHANGED_LINES_JSON_FILE" "$CLIPPY_JSON_FILE" "$CLIPPY_STDERR_FILE" "$FILTERED_OUTPUT_FILE"' EXIT
|
||||||
|
|
||||||
|
python3 - "$BASE_SHA" "${EXISTING_FILES[@]}" >"$CHANGED_LINES_JSON_FILE" <<'PY'
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
base = sys.argv[1]
|
||||||
|
files = sys.argv[2:]
|
||||||
|
hunk = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@")
|
||||||
|
changed = {}
|
||||||
|
|
||||||
|
for path in files:
|
||||||
|
proc = subprocess.run(
|
||||||
|
["git", "diff", "--unified=0", base, "HEAD", "--", path],
|
||||||
|
check=False,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
ranges = []
|
||||||
|
for line in proc.stdout.splitlines():
|
||||||
|
match = hunk.match(line)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
start = int(match.group(1))
|
||||||
|
count = int(match.group(2) or "1")
|
||||||
|
if count > 0:
|
||||||
|
ranges.append([start, start + count - 1])
|
||||||
|
changed[path] = ranges
|
||||||
|
|
||||||
|
print(json.dumps(changed))
|
||||||
|
PY
|
||||||
|
|
||||||
|
set +e
|
||||||
|
cargo clippy --quiet --locked --all-targets --message-format=json -- -D warnings >"$CLIPPY_JSON_FILE" 2>"$CLIPPY_STDERR_FILE"
|
||||||
|
CLIPPY_EXIT=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$CLIPPY_EXIT" -eq 0 ]; then
|
||||||
|
echo "Strict delta gate passed: no strict warnings/errors."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
python3 - "$CLIPPY_JSON_FILE" "$CHANGED_LINES_JSON_FILE" >"$FILTERED_OUTPUT_FILE" <<'PY'
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
messages_file = sys.argv[1]
|
||||||
|
changed_file = sys.argv[2]
|
||||||
|
|
||||||
|
with open(changed_file, "r", encoding="utf-8") as f:
|
||||||
|
changed = json.load(f)
|
||||||
|
|
||||||
|
cwd = Path.cwd().resolve()
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_path(path_value: str) -> str:
|
||||||
|
path = Path(path_value)
|
||||||
|
if path.is_absolute():
|
||||||
|
try:
|
||||||
|
return path.resolve().relative_to(cwd).as_posix()
|
||||||
|
except Exception:
|
||||||
|
return path.as_posix()
|
||||||
|
return path.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
blocking = []
|
||||||
|
baseline = []
|
||||||
|
unclassified = []
|
||||||
|
classified_count = 0
|
||||||
|
|
||||||
|
with open(messages_file, "r", encoding="utf-8", errors="ignore") as f:
|
||||||
|
for raw_line in f:
|
||||||
|
line = raw_line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = json.loads(line)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if payload.get("reason") != "compiler-message":
|
||||||
|
continue
|
||||||
|
|
||||||
|
message = payload.get("message", {})
|
||||||
|
level = message.get("level")
|
||||||
|
if level not in {"warning", "error"}:
|
||||||
|
continue
|
||||||
|
|
||||||
|
code_obj = message.get("code") or {}
|
||||||
|
code = code_obj.get("code") if isinstance(code_obj, dict) else None
|
||||||
|
text = message.get("message", "")
|
||||||
|
spans = message.get("spans") or []
|
||||||
|
|
||||||
|
candidate_spans = [span for span in spans if span.get("is_primary")]
|
||||||
|
if not candidate_spans:
|
||||||
|
candidate_spans = spans
|
||||||
|
|
||||||
|
span_entries = []
|
||||||
|
for span in candidate_spans:
|
||||||
|
file_name = span.get("file_name")
|
||||||
|
line_start = span.get("line_start")
|
||||||
|
line_end = span.get("line_end")
|
||||||
|
if not file_name or line_start is None:
|
||||||
|
continue
|
||||||
|
norm_path = normalize_path(file_name)
|
||||||
|
span_entries.append((norm_path, int(line_start), int(line_end or line_start)))
|
||||||
|
|
||||||
|
if not span_entries:
|
||||||
|
unclassified.append(f"{level.upper()} {code or '-'} {text}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
is_changed_line = False
|
||||||
|
best_path, best_line, _ = span_entries[0]
|
||||||
|
for path, line_start, line_end in span_entries:
|
||||||
|
ranges = changed.get(path)
|
||||||
|
if ranges is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not ranges:
|
||||||
|
is_changed_line = True
|
||||||
|
best_path, best_line = path, line_start
|
||||||
|
break
|
||||||
|
|
||||||
|
for start, end in ranges:
|
||||||
|
if line_end >= start and line_start <= end:
|
||||||
|
is_changed_line = True
|
||||||
|
best_path, best_line = path, line_start
|
||||||
|
break
|
||||||
|
if is_changed_line:
|
||||||
|
break
|
||||||
|
|
||||||
|
entry = f"{best_path}:{best_line} {level.upper()} {code or '-'} {text}"
|
||||||
|
classified_count += 1
|
||||||
|
if is_changed_line:
|
||||||
|
blocking.append(entry)
|
||||||
|
else:
|
||||||
|
baseline.append(entry)
|
||||||
|
|
||||||
|
if baseline:
|
||||||
|
print("Existing strict lint issues outside changed Rust lines (non-blocking):")
|
||||||
|
for entry in baseline:
|
||||||
|
print(f" - {entry}")
|
||||||
|
|
||||||
|
if blocking:
|
||||||
|
print("Strict lint issues introduced on changed Rust lines (blocking):")
|
||||||
|
for entry in blocking:
|
||||||
|
print(f" - {entry}")
|
||||||
|
print(f"Blocking strict lint issues: {len(blocking)}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if classified_count > 0:
|
||||||
|
print("No blocking strict lint issues on changed Rust lines.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if unclassified:
|
||||||
|
print("Strict lint exited non-zero with unclassified diagnostics; failing safe:")
|
||||||
|
for entry in unclassified[:20]:
|
||||||
|
print(f" - {entry}")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
print("Strict lint exited non-zero without parsable diagnostics; failing safe.")
|
||||||
|
sys.exit(2)
|
||||||
|
PY
|
||||||
|
FILTER_EXIT=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cat "$FILTERED_OUTPUT_FILE"
|
||||||
|
|
||||||
|
if [ "$FILTER_EXIT" -eq 0 ]; then
|
||||||
|
if [ -s "$CLIPPY_STDERR_FILE" ]; then
|
||||||
|
echo "clippy stderr summary (informational):"
|
||||||
|
cat "$CLIPPY_STDERR_FILE"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$CLIPPY_STDERR_FILE" ]; then
|
||||||
|
echo "clippy stderr summary:"
|
||||||
|
cat "$CLIPPY_STDERR_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit "$FILTER_EXIT"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue