项目文件夹

文件
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

290 行
12 KiB
Bash
可执行文件

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/usr/bin/env bash
#
# Local CI-parity gate — mirrors .github/workflows/ci.yml.
#
# A green run here means the *deterministic* CI jobs (Format, Clippy,
# Documentation, and the cross-platform compile) will pass. It exists because
# those failures otherwise only surface after a full ~50-min CI matrix:
# e.g. a private intra-doc link (Documentation job) or test-only code that is
# dead on Windows (Test job) — both invisible to `cargo test` / plain clippy.
#
# Change-aware (#850): the Rust gates can only be broken by Rust/Cargo changes,
# so a docs-only push (README, CHANGELOG, *.md, website, …) skips them and the
# pre-push gate finishes in a second. CI still runs every job unconditionally —
# it stays the source of truth — but a docs-only diff cannot turn a Rust gate
# red, so skipping it locally can never produce a local-green / CI-red split.
# `gen_docs --check` additionally guards the committed generated reference, so it
# also runs whenever a file under docs/reference/generated/** changed by hand.
# `full` (release parity) ignores classification and runs everything + tests.
#
# No-test policy (#849): a change to contract code (proxy / tools / config
# schema — anything feeding deterministic output, #498) that carries no test
# signal is flagged. Advisory by default; LEAN_CTX_PREFLIGHT_STRICT_TESTS=1
# makes it blocking.
#
# Usage:
# scripts/preflight.sh [fast|full] (default: fast)
# fast change-aware: fmt + clippy + doc + gen_docs drift + Windows
# cross-compile, each skipped when no Rust/generated-doc file changed
# full force everything regardless of the diff, plus `cargo test --lib`
#
# Bypass: not from here — use `SKIP_PREFLIGHT=1 git push` / `git push --no-verify`.
#
# CI parity (.github/workflows/ci.yml):
# - global env: RUSTFLAGS=-Dwarnings, LEAN_CTX_EMBEDDINGS_AUTO_DOWNLOAD=0
# - Documentation job: RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features
# cargo run --example gen_docs --features dev-tools -- --check
# - Clippy job: cargo clippy --all-features -- -D warnings
# - Format job: cargo fmt --check
# - Test job (Windows) compiles for x86_64-pc-windows-gnu
set -o pipefail
LEVEL="${1:-fast}"
case "$LEVEL" in
fast|full) ;;
*) echo "usage: $0 [fast|full]" >&2; exit 2 ;;
esac
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# Base ref for changed-file detection. Overridable for forks/CI that track a
# different upstream; defaults to the branch CI gates against.
BASE_REF="${PREFLIGHT_BASE:-origin/main}"
# ── Change classification (#850/#849) ─────────────────────────────────
# Sets: RUST_CHANGED, GENERATED_DOCS_CHANGED, CONTRACT_CHANGED, TEST_SIGNAL,
# CHANGED_COUNT, CLASSIFY_OK. When the base ref is unreachable (fresh clone,
# detached history) CLASSIFY_OK=0 → callers fall back to running everything.
classify_changes() {
RUST_CHANGED=0
GENERATED_DOCS_CHANGED=0
CONTRACT_CHANGED=0
CCR_CHANGED=0
TEST_SIGNAL=0
CHANGED_COUNT=0
CLASSIFY_OK=1
BASE_SHA=""
local base
base="$(git -C "$REPO_ROOT" merge-base "$BASE_REF" HEAD 2>/dev/null || true)"
if [[ -z "$base" ]]; then
CLASSIFY_OK=0
return
fi
BASE_SHA="$base"
# base..working-tree (committed + staged + unstaged) untracked.
local files
files="$( {
git -C "$REPO_ROOT" diff --name-only "$base"
git -C "$REPO_ROOT" ls-files --others --exclude-standard
} 2>/dev/null | sed 's#\\#/#g' | sort -u | sed '/^$/d' )"
CHANGED_COUNT="$(printf '%s\n' "$files" | sed '/^$/d' | grep -c '' || true)"
local f
while IFS= read -r f; do
[[ -z "$f" ]] && continue
case "$f" in
rust/*) RUST_CHANGED=1 ;;
esac
case "$f" in
docs/reference/generated/*) GENERATED_DOCS_CHANGED=1 ;;
esac
case "$f" in
rust/src/proxy/*|rust/src/tools/*|rust/src/core/config/schema/*) CONTRACT_CHANGED=1 ;;
esac
# CCR recovery surface (#983): a change here must keep the robustness suite
# green, so flag it for the change-aware `cargo test --lib ccr_robustness` gate.
case "$f" in
rust/src/proxy/ccr.rs|rust/src/proxy/ccr_robustness_tests.rs|rust/src/tools/ctx_expand.rs|rust/src/tools/registered/ctx_retrieve.rs|rust/src/core/read_stub_index.rs|rust/src/core/tabular_crush.rs) CCR_CHANGED=1 ;;
esac
case "$f" in
rust/tests/*|*/tests/*|*test*.rs|*tests.rs) TEST_SIGNAL=1 ;;
esac
done <<< "$files"
# Inline tests live in the same .rs file as the code (#[cfg(test)] mod tests),
# so a filename check misses them. If no test *file* changed, look for test
# signal inside the Rust diff itself.
if [[ "$TEST_SIGNAL" -eq 0 ]]; then
if git -C "$REPO_ROOT" diff "$base" -- rust 2>/dev/null \
| grep -Eq '^[+-].*(#\[test\]|#\[cfg\(test\)\]|assert(_eq|_ne)?!|proptest!)'; then
TEST_SIGNAL=1
fi
fi
}
cd "$REPO_ROOT/rust"
# Match CI's environment. RUSTFLAGS=-Dwarnings is applied *per step* (only where
# it must change the build fingerprint — the Windows cross-check and the full
# test build) so the fast host checks keep sharing the normal dev target cache
# instead of recompiling the whole dependency tree.
export RUSTDOCFLAGS="-Dwarnings"
export LEAN_CTX_EMBEDDINGS_AUTO_DOWNLOAD=0
# Keep proptest snappy like CI (local default is 256); override if you want more.
export PROPTEST_CASES="${PROPTEST_CASES:-64}"
# Windows test compiles the GNU target. jemalloc needs MinGW (not available on
# a plain dev box), so we cross-*check* with the default feature set minus
# jemalloc — enough to exercise the same cfg/dead-code analysis that bit us.
WIN_TARGET="x86_64-pc-windows-gnu"
WIN_FEATURES="tree-sitter,embeddings,http-server,team-server,secure-update"
BOLD="\033[1m"; CYAN="\033[1;36m"; GREEN="\033[1;32m"; RED="\033[1;31m"
YELLOW="\033[1;33m"; RESET="\033[0m"
PASSED=()
FAILED=()
SKIPPED=()
WARNED=()
step() { # step "Label" cmd...
local label="$1"; shift
printf "\n${CYAN}▶ %s${RESET}\n" "$label"
printf "${BOLD} \$ %s${RESET}\n" "$*"
if "$@"; then
PASSED+=("$label")
else
FAILED+=("$label")
fi
}
skip() { # skip "Label" "reason"
printf "\n${YELLOW}⊘ %s — skipped: %s${RESET}\n" "$1" "$2"
SKIPPED+=("$1: $2")
}
# ── Classify + decide what to run ─────────────────────────────────────
classify_changes
FORCE_ALL=0
[[ "$LEVEL" == "full" ]] && FORCE_ALL=1
[[ "$CLASSIFY_OK" -eq 0 ]] && FORCE_ALL=1
if [[ "$FORCE_ALL" -eq 1 ]]; then
RUN_RUST=1
RUN_GEN_DOCS=1
else
RUN_RUST="$RUST_CHANGED"
RUN_GEN_DOCS=0
{ [[ "$RUST_CHANGED" -eq 1 ]] || [[ "$GENERATED_DOCS_CHANGED" -eq 1 ]]; } && RUN_GEN_DOCS=1
fi
printf "${BOLD}preflight (%s) — CI-parity gate${RESET}\n" "$LEVEL"
if [[ "$CLASSIFY_OK" -eq 1 ]]; then
printf " changed files vs %s: %s (rust=%s, generated-docs=%s, contract=%s)\n" \
"$BASE_REF" "$CHANGED_COUNT" "$RUST_CHANGED" "$GENERATED_DOCS_CHANGED" "$CONTRACT_CHANGED"
else
printf " ${YELLOW}change classification unavailable (no %s) — running full gate${RESET}\n" "$BASE_REF"
fi
# Always-on cheap gate: whitespace errors + leftover conflict markers. Checks
# the pushed range (base..HEAD) when known, else the working tree.
if [[ -n "$BASE_SHA" ]]; then
step "Whitespace / conflict markers (git diff --check)" \
git -C "$REPO_ROOT" diff --check "$BASE_SHA" HEAD
else
step "Whitespace / conflict markers (git diff --check)" \
git -C "$REPO_ROOT" diff --check
fi
if [[ "$RUN_RUST" -eq 1 ]]; then
step "Format (cargo fmt --check)" \
cargo fmt --check
step "Clippy (--all-features -D warnings)" \
cargo clippy --all-features -- -D warnings
step "Docs (rustdoc -D warnings)" \
cargo doc --no-deps --all-features
else
skip "Format / Clippy / Docs" "no Rust/Cargo files changed (docs-only)"
fi
if [[ "$RUN_GEN_DOCS" -eq 1 ]]; then
step "Generated-docs drift (gen_docs --check)" \
cargo run --quiet --example gen_docs --features dev-tools -- --check
else
skip "Generated-docs drift (gen_docs --check)" "no Rust or generated-doc files changed"
fi
if [[ "$RUN_RUST" -eq 1 ]]; then
step "Registry-snapshot drift (gen_registry --check)" \
cargo run --quiet --example gen_registry --features dev-tools -- --check
else
skip "Registry-snapshot drift (gen_registry --check)" "no Rust files changed"
fi
if [[ "$RUN_RUST" -eq 1 ]]; then
if rustup target list --installed 2>/dev/null | grep -qx "$WIN_TARGET"; then
step "Windows cross-compile ($WIN_TARGET)" \
env RUSTFLAGS=-Dwarnings cargo check --target "$WIN_TARGET" --lib --tests \
--no-default-features --features "$WIN_FEATURES"
else
skip "Windows cross-compile ($WIN_TARGET)" \
"target not installed — run: rustup target add $WIN_TARGET"
fi
else
skip "Windows cross-compile ($WIN_TARGET)" "no Rust/Cargo files changed (docs-only)"
fi
# CCR robustness gate (#983) — change-aware: `full` already runs every lib test,
# so only `fast` needs this focused build, and only when the recovery surface
# changed. A test build is otherwise kept out of `fast` by design.
if [[ "$LEVEL" != "full" && "$RUN_RUST" -eq 1 && "$CCR_CHANGED" -eq 1 ]]; then
step "CCR robustness regression (cargo test --lib ccr_robustness)" \
env RUSTFLAGS=-Dwarnings cargo test --lib --all-features ccr_robustness
elif [[ "$LEVEL" != "full" ]]; then
skip "CCR robustness regression" "no CCR recovery files changed"
fi
if [[ "$LEVEL" = "full" ]]; then
step "Unit tests (cargo test --lib)" \
env RUSTFLAGS=-Dwarnings cargo test --lib --all-features
# Entrypoint + rules-drift smoke gates (#902/#903). Integration tests, so they
# build the bin — kept out of `fast` (which deliberately avoids test builds);
# CI runs them unconditionally via `cargo test --all-features`.
step "Entrypoint + rules drift (#902/#903)" \
env RUSTFLAGS=-Dwarnings cargo test --all-features --test entrypoints_wired --test rules_drift
fi
# ── No-test policy (#849) ─────────────────────────────────────────────
# Contract code changed but the diff carries no test signal → flag it. Advisory
# unless LEAN_CTX_PREFLIGHT_STRICT_TESTS=1. Never triggers for docs/metadata-only
# changes (CONTRACT_CHANGED stays 0).
if [[ "$CLASSIFY_OK" -eq 1 && "$CONTRACT_CHANGED" -eq 1 && "$TEST_SIGNAL" -eq 0 ]]; then
MSG="contract code changed (proxy/tools/config-schema) but the diff adds no test signal — add/adjust tests or justify"
if [[ "${LEAN_CTX_PREFLIGHT_STRICT_TESTS:-0}" == "1" ]]; then
printf "\n${RED}▶ No-test policy (#849)${RESET}\n ${RED}%s${RESET}\n" "$MSG"
FAILED+=("No-test policy: $MSG")
else
printf "\n${YELLOW}▶ No-test policy (#849) — advisory${RESET}\n ${YELLOW}%s${RESET}\n" "$MSG"
printf " ${YELLOW}(set LEAN_CTX_PREFLIGHT_STRICT_TESTS=1 to make this blocking)${RESET}\n"
WARNED+=("No-test policy: $MSG")
fi
fi
# ── Summary ───────────────────────────────────────────────────────────
printf "\n${BOLD}── preflight summary ──${RESET}\n"
printf "${GREEN} ok passed: %d${RESET}\n" "${#PASSED[@]}"
if [ "${#SKIPPED[@]}" -gt 0 ]; then
printf "${YELLOW} -- skipped: %d${RESET}\n" "${#SKIPPED[@]}"
for s in "${SKIPPED[@]}"; do printf "${YELLOW} - %s${RESET}\n" "$s"; done
fi
if [ "${#WARNED[@]}" -gt 0 ]; then
printf "${YELLOW} !! warned: %d${RESET}\n" "${#WARNED[@]}"
for w in "${WARNED[@]}"; do printf "${YELLOW} - %s${RESET}\n" "$w"; done
fi
if [ "${#FAILED[@]}" -gt 0 ]; then
printf "${RED} XX failed: %d${RESET}\n" "${#FAILED[@]}"
for f in "${FAILED[@]}"; do printf "${RED} - %s${RESET}\n" "$f"; done
printf "\n${RED}preflight FAILED — fix the above before pushing.${RESET}\n"
exit 1
fi
printf "\n${GREEN}preflight PASSED — safe to push.${RESET}\n"