@boyingliu01/xp-gate 0.31.3 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/java.sh +256 -4
- package/adapters/powershell.sh +45 -6
- package/bin/xp-gate.js +8 -2
- package/build-integrity/__tests__/gate-10.test.ts +88 -1
- package/build-integrity/gate-10.ts +51 -16
- package/dsh.bundle.patch.yml +15 -0
- package/gate-13-compiler-strictness.sh +1031 -0
- package/gate-3.sh +48 -13
- package/hooks/gate-13-compiler-strictness.sh +1031 -0
- package/hooks/gate-3.sh +48 -13
- package/hooks/lib/coverage-total.sh +18 -2
- package/hooks/lib/java-test-selection.sh +251 -0
- package/hooks/lib/jscpd-run.sh +9 -0
- package/hooks/lib/validate-code-walkthrough.cjs +186 -29
- package/hooks/pre-commit +269 -13
- package/lib/__tests__/detect-deps-dsh-profile.test.js +106 -0
- package/lib/__tests__/doctor-tui-skill-freshness.test.js +140 -0
- package/lib/__tests__/gate-runner.test.js +29 -2
- package/lib/__tests__/issue-586-principles-cmdline.test.js +35 -0
- package/lib/__tests__/issue-618-gate-not-run.test.js +100 -0
- package/lib/__tests__/shared-utils.test.js +21 -0
- package/lib/check.js +6 -2
- package/lib/detect-deps.js +42 -10
- package/lib/doctor-tui.js +111 -21
- package/lib/gate-runner.js +111 -37
- package/lib/mattpocock-license-verdict.json +1 -1
- package/lib/principles.js +48 -6
- package/lib/shared-utils.js +8 -0
- package/mock-policy/AGENTS.md +3 -3
- package/mock-policy/gate-m3.ts +57 -23
- package/mutation/AGENTS.md +3 -3
- package/mutation/__tests__/pitest-gradle-availability.test.ts +74 -0
- package/mutation/__tests__/test-filter-parity.test.ts +5 -2
- package/mutation/gate-m.ts +30 -24
- package/mutation/runners/mutmut-runner.ts +80 -30
- package/mutation/runners/pitest-runner.ts +60 -42
- package/package.json +14 -2
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/dsh/lib/command.d.ts +38 -0
- package/plugins/dsh/lib/command.d.ts.map +1 -0
- package/plugins/dsh/lib/command.js +87 -0
- package/plugins/dsh/lib/credentials.d.ts +39 -0
- package/plugins/dsh/lib/credentials.d.ts.map +1 -0
- package/plugins/dsh/lib/credentials.js +57 -0
- package/plugins/dsh/lib/delphi-config.d.ts +129 -0
- package/plugins/dsh/lib/delphi-config.d.ts.map +1 -0
- package/plugins/dsh/lib/delphi-config.js +369 -0
- package/plugins/dsh/lib/delphi-run.d.ts +24 -0
- package/plugins/dsh/lib/delphi-run.d.ts.map +1 -0
- package/plugins/dsh/lib/delphi-run.js +113 -0
- package/plugins/dsh/lib/delphi.d.ts +94 -0
- package/plugins/dsh/lib/delphi.d.ts.map +1 -0
- package/plugins/dsh/lib/delphi.js +207 -0
- package/plugins/dsh/lib/dialect.d.ts +24 -0
- package/plugins/dsh/lib/dialect.d.ts.map +1 -0
- package/plugins/dsh/lib/dialect.js +36 -0
- package/plugins/dsh/lib/evidence.d.ts +70 -0
- package/plugins/dsh/lib/evidence.d.ts.map +1 -0
- package/plugins/dsh/lib/evidence.js +92 -0
- package/plugins/dsh/lib/gate-runner.d.ts +49 -0
- package/plugins/dsh/lib/gate-runner.d.ts.map +1 -0
- package/plugins/dsh/lib/gate-runner.js +95 -0
- package/plugins/dsh/lib/git-context.d.ts +26 -0
- package/plugins/dsh/lib/git-context.d.ts.map +1 -0
- package/plugins/dsh/lib/git-context.js +30 -0
- package/plugins/dsh/lib/hooks.d.ts +42 -0
- package/plugins/dsh/lib/hooks.d.ts.map +1 -0
- package/plugins/dsh/lib/hooks.js +113 -0
- package/plugins/dsh/lib/index.d.ts +20 -0
- package/plugins/dsh/lib/index.d.ts.map +1 -0
- package/plugins/dsh/lib/index.js +430 -0
- package/plugins/dsh/lib/skill-provider.d.ts +15 -0
- package/plugins/dsh/lib/skill-provider.d.ts.map +1 -0
- package/plugins/dsh/lib/skill-provider.js +205 -0
- package/plugins/dsh/lib/sprint.d.ts +60 -0
- package/plugins/dsh/lib/sprint.d.ts.map +1 -0
- package/plugins/dsh/lib/sprint.js +92 -0
- package/plugins/dsh/package.json +14 -8
- package/plugins/dsh/scripts/verify-skill-provider.mjs +113 -0
- package/plugins/dsh/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/dsh/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/dsh/src/command-single-form.test.ts +67 -0
- package/plugins/dsh/src/command.test.ts +21 -17
- package/plugins/dsh/src/command.ts +19 -21
- package/plugins/dsh/src/compat.test.ts +200 -0
- package/plugins/dsh/src/contract.test.ts +7 -1
- package/plugins/dsh/src/credentials.test.ts +93 -0
- package/plugins/dsh/src/credentials.ts +71 -0
- package/plugins/dsh/src/delphi-cancellation.test.ts +71 -0
- package/plugins/dsh/src/delphi-config-apikey-override.test.ts +94 -0
- package/plugins/dsh/src/delphi-config-credential-refs.test.ts +75 -0
- package/plugins/dsh/src/delphi-config.ts +146 -53
- package/plugins/dsh/src/delphi-run.ts +27 -4
- package/plugins/dsh/src/delphi.ts +133 -65
- package/plugins/dsh/src/evidence.test.ts +74 -0
- package/plugins/dsh/src/evidence.ts +141 -0
- package/plugins/dsh/src/gate-runner.test.ts +14 -6
- package/plugins/dsh/src/gate-runner.ts +68 -5
- package/plugins/dsh/src/git-context.test.ts +39 -0
- package/plugins/dsh/src/git-context.ts +38 -0
- package/plugins/dsh/src/hooks.test.ts +87 -0
- package/plugins/dsh/src/hooks.ts +126 -0
- package/plugins/dsh/src/index.test.ts +63 -6
- package/plugins/dsh/src/index.ts +340 -13
- package/plugins/dsh/src/skill-provider.test.ts +194 -0
- package/plugins/dsh/src/skill-provider.ts +231 -0
- package/plugins/dsh/src/sprint.test.ts +64 -0
- package/plugins/dsh/src/sprint.ts +122 -0
- package/plugins/dsh/src/tri-state.test.ts +123 -0
- package/plugins/opencode/index.ts +192 -58
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
- package/principles/AGENTS.md +3 -3
- package/principles/__tests__/analyze-read-failure.test.ts +70 -0
- package/principles/__tests__/baseline-entry-total-warnings.test.ts +76 -0
- package/principles/__tests__/baseline-prune.test.ts +61 -0
- package/principles/__tests__/cli-files-separators.test.ts +69 -0
- package/principles/__tests__/config-merge-warnings.test.ts +148 -0
- package/principles/adapters/__tests__/cpp-code-block.test.ts +123 -0
- package/principles/adapters/__tests__/cpp-scanner-equivalence.test.ts +67 -0
- package/principles/adapters/__tests__/typescript-block-comment-lines.test.ts +53 -0
- package/principles/adapters/__tests__/typescript-masking.test.ts +96 -0
- package/principles/adapters/cpp.ts +102 -50
- package/principles/adapters/java.ts +22 -3
- package/principles/adapters/typescript.ts +548 -178
- package/principles/analyzer.ts +36 -3
- package/principles/baseline-prune.ts +19 -7
- package/principles/baseline.ts +58 -70
- package/principles/config.ts +56 -35
- package/principles/index.ts +122 -40
- package/principles/rules/clean-code/deep-nesting.ts +36 -22
- package/principles/rules/clean-code/unused-imports.ts +30 -19
- package/principles/rules/solid/dip.ts +30 -20
- package/principles/rules/solid/lsp.ts +17 -2
- package/principles/rules/solid/ocp.ts +33 -23
- package/principles/rules/solid/srp.ts +65 -23
- package/scripts/delphi-external-review.cjs +25 -2
- package/scripts/sync-package-content.js +28 -1
- package/skills/delphi-review/AGENTS.md +3 -3
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/test-specification-alignment/AGENTS.md +3 -3
package/hooks/gate-3.sh
CHANGED
|
@@ -339,17 +339,38 @@ else
|
|
|
339
339
|
if [ -n "$CC_FILES" ]; then
|
|
340
340
|
echo "Checking complexity for source files..."
|
|
341
341
|
|
|
342
|
-
# Run lizard
|
|
343
|
-
# One path per line, into an array. Unquoted $CC_FILES relied on word
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
#
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
342
|
+
# Run lizard in chunks. Two reasons, both load-bearing:
|
|
343
|
+
# - One path per line, into an array. Unquoted $CC_FILES relied on word
|
|
344
|
+
# splitting, which also splits any path containing a space -- handing
|
|
345
|
+
# lizard two bogus paths and checking neither (#457 defect class, same
|
|
346
|
+
# fix as gate-4's PRINCIPLES_ARGS). Quoting the scalar would instead
|
|
347
|
+
# collapse the list into one argument. An array does both.
|
|
348
|
+
# - Chunked instead of one argv. Windows caps a single command line at
|
|
349
|
+
# 32,767 characters, and under `--all` the population is the whole tree
|
|
350
|
+
# (1,000+ sources on a mid-sized repo). The oversized argv never reached
|
|
351
|
+
# lizard, nothing was printed, and the gate graded an empty CSV as if the
|
|
352
|
+
# tree were clean. XP_GATE_LIZARD_ARGV_BUDGET lets a probe force a split
|
|
353
|
+
# without needing a huge fixture.
|
|
354
|
+
LIZARD_ARGV_BUDGET="${XP_GATE_LIZARD_ARGV_BUDGET:-8000}"
|
|
355
|
+
lizard_batches() {
|
|
356
|
+
# stdin: one path per line. stdout: lizard output, batches concatenated.
|
|
357
|
+
local _batch=() _size=0 _path
|
|
358
|
+
while IFS= read -r _path; do
|
|
359
|
+
[ -n "$_path" ] || continue
|
|
360
|
+
if [ "${#_batch[@]}" -gt 0 ] && [ $((_size + ${#_path} + 1)) -gt "$LIZARD_ARGV_BUDGET" ]; then
|
|
361
|
+
"$LIZARD_PATH" "$@" "${_batch[@]}" 2>/dev/null || true
|
|
362
|
+
_batch=()
|
|
363
|
+
_size=0
|
|
364
|
+
fi
|
|
365
|
+
_batch+=("$_path")
|
|
366
|
+
_size=$((_size + ${#_path} + 1))
|
|
367
|
+
done
|
|
368
|
+
if [ "${#_batch[@]}" -gt 0 ]; then
|
|
369
|
+
"$LIZARD_PATH" "$@" "${_batch[@]}" 2>/dev/null || true
|
|
370
|
+
fi
|
|
371
|
+
return 0
|
|
372
|
+
}
|
|
373
|
+
CC_OUTPUT=$(printf '%s\n' "$CC_FILES" | lizard_batches -C "$CCN_THRESHOLD" 2>&1)
|
|
353
374
|
|
|
354
375
|
# REQ-D (sprint-20261018-quality): baseline ratchet. When
|
|
355
376
|
# .ccn-baseline.json exists it replaces the flat threshold verdict:
|
|
@@ -366,7 +387,7 @@ else
|
|
|
366
387
|
# Route the CSV through the same verifier; on rows it cannot verify the
|
|
367
388
|
# helper exits non-zero, and this gate fails closed instead of passing
|
|
368
389
|
# an unvalidated number.
|
|
369
|
-
CC_CSV=$(
|
|
390
|
+
CC_CSV=$(printf '%s\n' "$CC_FILES" | lizard_batches --csv)
|
|
370
391
|
CC_REPORT="$(git rev-parse --show-toplevel 2>/dev/null)/scripts/ccn-report.cjs"
|
|
371
392
|
# Fail closed when the verifier is unavailable. Previously this fell
|
|
372
393
|
# through and graded the RAW lizard CSV, while CI hard-fails on the same
|
|
@@ -392,6 +413,20 @@ else
|
|
|
392
413
|
fi
|
|
393
414
|
RATCHET_LIB="$GATE_DIR/lib/ccn-ratchet.sh"
|
|
394
415
|
[ -f "$RATCHET_LIB" ] || RATCHET_LIB="$(git rev-parse --show-toplevel 2>/dev/null)/githooks/lib/ccn-ratchet.sh"
|
|
416
|
+
# Fail closed when the ratchet library is missing. Sourcing a nonexistent
|
|
417
|
+
# file only prints "No such file or directory" and leaves
|
|
418
|
+
# evaluate_ccn_ratchet undefined; the verdict then came back empty, every
|
|
419
|
+
# counter read 0 and the gate printed "✅ PASSED" — a CCN regression graded
|
|
420
|
+
# green with nothing compared. The installer never created this path
|
|
421
|
+
# (copyAdapters skipped hooks/lib), so this was the normal state after a
|
|
422
|
+
# global install, not an exotic one.
|
|
423
|
+
if [ ! -f "$RATCHET_LIB" ]; then
|
|
424
|
+
echo "❌ BLOCKED - complexity ratchet library unavailable (ccn-ratchet.sh)."
|
|
425
|
+
echo "Expected at \$GATE_DIR/lib/ccn-ratchet.sh or <repo>/githooks/lib/ccn-ratchet.sh."
|
|
426
|
+
echo "Reinstall with 'xp-gate init --global' (or 'xp-gate update-hooks') to restore it."
|
|
427
|
+
GATE_3_DETAIL="mode=ratchet ratchet=MISSING"
|
|
428
|
+
exit 1
|
|
429
|
+
fi
|
|
395
430
|
# shellcheck source=/dev/null
|
|
396
431
|
. "$RATCHET_LIB"
|
|
397
432
|
# NOTE: the thresholds must be plain assignments BEFORE the pipe. As a
|
|
@@ -436,7 +471,7 @@ else
|
|
|
436
471
|
# file,name,signature,...), so the verdict comes from the same numbers
|
|
437
472
|
# lizard uses, independent of version and table formatting. --csv here is
|
|
438
473
|
# the flat-threshold run; the ratchet branch above builds its own.
|
|
439
|
-
CC_CSV_FLAT=$("$
|
|
474
|
+
CC_CSV_FLAT=$(printf '%s\n' "$CC_FILES" | lizard_batches --csv -C "$CCN_THRESHOLD")
|
|
440
475
|
CC_WARNINGS=$(printf '%s\n' "$CC_CSV_FLAT" | awk -F, -v t="$CCN_THRESHOLD" '
|
|
441
476
|
NF > 1 && $2 + 0 > t + 0 { c++ }
|
|
442
477
|
END { print c + 0 }
|
|
@@ -56,9 +56,25 @@ enforce_python_coverage() {
|
|
|
56
56
|
return 0
|
|
57
57
|
fi
|
|
58
58
|
|
|
59
|
+
# #636: this probe is the SAME fail-open #570 closed, only earlier. Returning 0
|
|
60
|
+
# here means "no coverage.py on PATH" silently disables the Python coverage
|
|
61
|
+
# floor — and unlike a deleted .coverage file, a missing tool is a steady state,
|
|
62
|
+
# not an accident: every consumer repo / CI image / colleague machine without
|
|
63
|
+
# coverage.py had this gate switched off behind a ⚠️ that reads as informational.
|
|
64
|
+
# The #570 suite could not see it because its setup installs a coverage stub
|
|
65
|
+
# precisely so this probe succeeds.
|
|
66
|
+
#
|
|
67
|
+
# A subset run stays the one exception: nothing was measured because only part
|
|
68
|
+
# of the suite ran, so there is no total to compare.
|
|
59
69
|
if ! command -v coverage &> /dev/null; then
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
if [ "${PARTIAL_TEST_RUN:-false}" = "true" ]; then
|
|
71
|
+
echo "⚠️ coverage.py not available (subset test run) — not blocking."
|
|
72
|
+
return 0
|
|
73
|
+
fi
|
|
74
|
+
echo "❌ BLOCKED - Python coverage could not be measured: coverage.py is not on PATH,"
|
|
75
|
+
echo " so the ${COVERAGE_THRESHOLD:-80}% floor cannot be verified."
|
|
76
|
+
echo " Install it (pip install coverage) and commit again."
|
|
77
|
+
return 1
|
|
62
78
|
fi
|
|
63
79
|
|
|
64
80
|
COVERAGE_PERCENT=""
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Java smart test selection (#640) — the Java counterpart of the TypeScript
|
|
3
|
+
# selector (#286) and the Python selector (#399).
|
|
4
|
+
#
|
|
5
|
+
# Why: the Java arm of Gate 5 ran the FULL Maven/Gradle suite on every commit.
|
|
6
|
+
# Measured on a 206-file / 1079-test project: `mvn test jacoco:report` takes
|
|
7
|
+
# 77.8s no matter whether one file or a hundred changed. TypeScript and Python
|
|
8
|
+
# have had three-tier selection for a long time; Java had no equivalent — the
|
|
9
|
+
# `PARTIAL_TEST_RUN` capability existed but nothing on the Java path ever set
|
|
10
|
+
# it, so the downgrade channel was dead code for that language.
|
|
11
|
+
#
|
|
12
|
+
# Kept in its own file so the strategy truth table and the related-test lookup
|
|
13
|
+
# are unit-testable without executing the hook
|
|
14
|
+
# (githooks/__tests__/issue-640-java-test-selection.test.bats).
|
|
15
|
+
#
|
|
16
|
+
# Three tiers, matching the TS/Python implementations:
|
|
17
|
+
# 1. changed-tests — only test files changed: run exactly those.
|
|
18
|
+
# 2. related — source files changed, no test files: run the tests the
|
|
19
|
+
# path convention maps to them.
|
|
20
|
+
# 3. full — >20 test files changed, a build manifest changed, or no
|
|
21
|
+
# related tests found: run everything with the real
|
|
22
|
+
# coverage threshold.
|
|
23
|
+
# Tier 1/2 run WITHOUT the global coverage threshold (subset coverage is
|
|
24
|
+
# meaningless globally); the caller sets PARTIAL_TEST_RUN so Gate 5 warns
|
|
25
|
+
# instead of blocking.
|
|
26
|
+
|
|
27
|
+
# Max changed test files before falling back to the full suite. Same value as
|
|
28
|
+
# the TypeScript (#286) and Python (#399) selectors so all three languages
|
|
29
|
+
# behave alike.
|
|
30
|
+
JAVA_MAX_CHANGED_TESTS=20
|
|
31
|
+
|
|
32
|
+
# Build manifests: a change here can break ANY test (dependency bump, surefire
|
|
33
|
+
# config, compiler level), so the selector always escalates to the full suite.
|
|
34
|
+
JAVA_DEPENDENCY_PATTERNS='(^|/)(pom\.xml|build\.gradle(\.kts)?|settings\.gradle(\.kts)?|gradle\.properties|gradle/wrapper/[^/]+|mvnw|mvnw\.cmd|\.mvn/[^/]+)$'
|
|
35
|
+
|
|
36
|
+
# Java test CLASS-name conventions (applied to the basename only).
|
|
37
|
+
#
|
|
38
|
+
# Maven surefire's own defaults are `*Test.java`, `Test*.java`, `*Tests.java`,
|
|
39
|
+
# `*TestCase.java`; Gradle users commonly add `*Spec.java` and `*IT.java`.
|
|
40
|
+
#
|
|
41
|
+
# The `Test[A-Z]\w*` form is deliberately narrowed to `Test[A-Z]` followed by
|
|
42
|
+
# something that looks like a test subject rather than a helper: bare
|
|
43
|
+
# `Test[^/]*` would swallow `TestHelper.java`, `TestUtils.java`,
|
|
44
|
+
# `TestFixtures.java` — production/support classes that happen to start with
|
|
45
|
+
# "Test". Misclassifying a SOURCE as a TEST is the dangerous direction: those
|
|
46
|
+
# helpers are real code whose changing should run `related`, and calling them
|
|
47
|
+
# tests would make the selector run them as if they were suites (Surefire
|
|
48
|
+
# would then find no tests in them) and skip the source-driven lookup.
|
|
49
|
+
#
|
|
50
|
+
# A path under a test source root is caught independently by
|
|
51
|
+
# java_is_test_file, so helpers living in src/test/java are still tests.
|
|
52
|
+
JAVA_TEST_FILE_RE='(^|/)(Test[A-Z]\w*(Test|Tests|Case|Spec|IT)|[A-Z]\w*Test|[A-Z]\w*Tests|[A-Z]\w*TestCase|[A-Z]\w*Spec|[A-Z]\w*IT)\.java$'
|
|
53
|
+
|
|
54
|
+
# Decide the strategy from three counts. Pure function — no filesystem access,
|
|
55
|
+
# so the truth table is exhaustive and cheap to test.
|
|
56
|
+
#
|
|
57
|
+
# $1 test_count changed test files
|
|
58
|
+
# $2 src_count changed non-test Java source files
|
|
59
|
+
# $3 deps_changed 1 when a build manifest changed, else 0
|
|
60
|
+
#
|
|
61
|
+
# Echoes exactly one of: full | changed-tests | related | skip
|
|
62
|
+
select_java_test_strategy() {
|
|
63
|
+
# `${1-0}`, not `${1:-0}`: the `:-` form rewrites an EMPTY argument to "0",
|
|
64
|
+
# which would make the empty check below unreachable — a caller passing ""
|
|
65
|
+
# (e.g. an unset count that reached us as an empty string) would silently
|
|
66
|
+
# mean "0 changed files" and skip the suite. Only a genuinely UNSET argument
|
|
67
|
+
# defaults to 0.
|
|
68
|
+
local test_count="${1-0}"
|
|
69
|
+
local src_count="${2-0}"
|
|
70
|
+
local deps_changed="${3-0}"
|
|
71
|
+
|
|
72
|
+
# Non-numeric OR empty input must not silently become "0" and skip the
|
|
73
|
+
# suite: a caller bug there would run nothing and report PASS. Escalate.
|
|
74
|
+
case "$test_count" in
|
|
75
|
+
''|*[!0-9]*) printf '%s' "full"; return 0 ;;
|
|
76
|
+
esac
|
|
77
|
+
case "$src_count" in
|
|
78
|
+
''|*[!0-9]*) printf '%s' "full"; return 0 ;;
|
|
79
|
+
esac
|
|
80
|
+
|
|
81
|
+
# Dependency/build changes can break anything -> always the full suite.
|
|
82
|
+
if [ "$deps_changed" = "1" ]; then
|
|
83
|
+
printf '%s' "full"
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Large batch: per-file selection loses its point, and the other two
|
|
88
|
+
# language arms use the same cutoff.
|
|
89
|
+
if [ "$test_count" -gt "$JAVA_MAX_CHANGED_TESTS" ]; then
|
|
90
|
+
printf '%s' "full"
|
|
91
|
+
return 0
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
if [ "$test_count" -gt 0 ]; then
|
|
95
|
+
printf '%s' "changed-tests"
|
|
96
|
+
return 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
if [ "$src_count" -gt 0 ]; then
|
|
100
|
+
printf '%s' "related"
|
|
101
|
+
return 0
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
printf '%s' "skip"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# True (0) when the path looks like a Java test source.
|
|
108
|
+
#
|
|
109
|
+
# $1 path, e.g. src/test/java/com/acme/FooTest.java
|
|
110
|
+
java_is_test_file() {
|
|
111
|
+
local path="$1"
|
|
112
|
+
[ -n "$path" ] || return 1
|
|
113
|
+
# A path under a test source root is a test even when the basename does not
|
|
114
|
+
# end in Test/Tests/Spec — surefire includes are configurable, and a `*IT.java`
|
|
115
|
+
# integration test living in src/test/java must not be mistaken for source.
|
|
116
|
+
#
|
|
117
|
+
# The leading "/" matters: git reports repo-relative paths with no leading
|
|
118
|
+
# slash ("src/test/java/..."), so a bare "*/src/test/*" pattern would never
|
|
119
|
+
# match the most common case of all. Prefixing normalises both forms.
|
|
120
|
+
case "/$path" in
|
|
121
|
+
*/src/test/java/*|*/src/test/*|*/src/androidTest/*) return 0 ;;
|
|
122
|
+
esac
|
|
123
|
+
printf '%s' "$path" | grep -qE "$JAVA_TEST_FILE_RE"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# True (0) when any of the given paths is a Java build manifest.
|
|
127
|
+
java_dependency_changed() {
|
|
128
|
+
local path
|
|
129
|
+
for path in "$@"; do
|
|
130
|
+
[ -n "$path" ] || continue
|
|
131
|
+
if echo "$path" | grep -qE "$JAVA_DEPENDENCY_PATTERNS"; then
|
|
132
|
+
return 0
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
return 1
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# Map a Maven/Gradle source path to the test path(s) the convention implies.
|
|
139
|
+
# Echoes one existing path per line, deduplicated, in discovery order. Echoes
|
|
140
|
+
# nothing when no candidate exists — the caller then falls back to tier 3.
|
|
141
|
+
#
|
|
142
|
+
# $1 source path, e.g. src/main/java/com/acme/service/Foo.java
|
|
143
|
+
#
|
|
144
|
+
# The mapping mirrors the standard layout: src/main/java/<pkg>/X.java ->
|
|
145
|
+
# src/test/java/<pkg>/XTest.java. Multi-module builds are handled because the
|
|
146
|
+
# module prefix is preserved verbatim (only `main`->`test` inside the path is
|
|
147
|
+
# rewritten).
|
|
148
|
+
java_related_tests() {
|
|
149
|
+
local src_file="$1"
|
|
150
|
+
[ -n "$src_file" ] || return 0
|
|
151
|
+
|
|
152
|
+
local filename dir base
|
|
153
|
+
base="${src_file%.java}"
|
|
154
|
+
filename="${base##*/}"
|
|
155
|
+
dir="$(dirname "$src_file")"
|
|
156
|
+
|
|
157
|
+
local candidates=""
|
|
158
|
+
# Primary convention: same package, main -> test.
|
|
159
|
+
# "/$dir" for the same reason as java_is_test_file: git's repo-relative paths
|
|
160
|
+
# have no leading slash, so a bare "*/src/main/java/*" would never match.
|
|
161
|
+
case "/$dir" in
|
|
162
|
+
*/src/main/java/*)
|
|
163
|
+
# Rewrite the source root segment. `#` as the sed delimiter keeps the
|
|
164
|
+
# pattern readable: / would need escaping in both the pattern AND the
|
|
165
|
+
# replacement. The leading "/" is prepended BEFORE the substitution and
|
|
166
|
+
# stripped after: the pattern is anchored on "/src/main/java/", and a
|
|
167
|
+
# repo-relative dir ("src/main/java/com/acme") does not contain that
|
|
168
|
+
# leading slash, so a bare substitution would match nothing and every
|
|
169
|
+
# "related" lookup would return empty — quietly downgrading every commit
|
|
170
|
+
# to the full suite (correct, but pointless).
|
|
171
|
+
local test_dir
|
|
172
|
+
test_dir=$(printf '/%s' "$dir" | sed 's#/src/main/java/#/src/test/java/#')
|
|
173
|
+
test_dir="${test_dir#/}"
|
|
174
|
+
candidates="$candidates
|
|
175
|
+
${test_dir}/${filename}Test.java
|
|
176
|
+
${test_dir}/${filename}Tests.java
|
|
177
|
+
${test_dir}/${filename}Spec.java
|
|
178
|
+
${test_dir}/Test${filename}.java"
|
|
179
|
+
;;
|
|
180
|
+
esac
|
|
181
|
+
# Colocated forms (some projects keep tests beside sources).
|
|
182
|
+
candidates="$candidates
|
|
183
|
+
${dir}/${filename}Test.java
|
|
184
|
+
${dir}/${filename}Tests.java
|
|
185
|
+
${dir}/${filename}Spec.java
|
|
186
|
+
${dir}/__tests__/${filename}Test.java"
|
|
187
|
+
|
|
188
|
+
local seen=""
|
|
189
|
+
local candidate
|
|
190
|
+
# IFS-safe iteration over newline-separated candidates.
|
|
191
|
+
while IFS= read -r candidate; do
|
|
192
|
+
[ -n "$candidate" ] || continue
|
|
193
|
+
[ -f "$candidate" ] || continue
|
|
194
|
+
# Dedupe: several patterns resolve to the same file whenever the source
|
|
195
|
+
# already sits under a test-looking root.
|
|
196
|
+
case "$seen" in
|
|
197
|
+
*"|$candidate|"*) continue ;;
|
|
198
|
+
esac
|
|
199
|
+
seen="$seen|$candidate|"
|
|
200
|
+
printf '%s\n' "$candidate"
|
|
201
|
+
done <<EOF
|
|
202
|
+
$candidates
|
|
203
|
+
EOF
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# Turn test file paths into the Maven `-Dtest=` selector list.
|
|
207
|
+
# Echoes one comma-separated argument, or nothing when the input is empty.
|
|
208
|
+
#
|
|
209
|
+
# $1..$N test file paths
|
|
210
|
+
#
|
|
211
|
+
# Maven matches `-Dtest=` against simple class names (not paths), so the
|
|
212
|
+
# directory part is dropped and the `.java` suffix stripped. Duplicates are
|
|
213
|
+
# removed: `-Dtest=A,A` makes Surefire run A twice.
|
|
214
|
+
java_maven_test_selector() {
|
|
215
|
+
local seen=" " out=""
|
|
216
|
+
local path name
|
|
217
|
+
for path in "$@"; do
|
|
218
|
+
[ -n "$path" ] || continue
|
|
219
|
+
name="${path##*/}"
|
|
220
|
+
name="${name%.java}"
|
|
221
|
+
[ -n "$name" ] || continue
|
|
222
|
+
case "$seen" in
|
|
223
|
+
*" $name "*) continue ;;
|
|
224
|
+
esac
|
|
225
|
+
seen="$seen$name "
|
|
226
|
+
if [ -z "$out" ]; then out="$name"; else out="$out,$name"; fi
|
|
227
|
+
done
|
|
228
|
+
[ -n "$out" ] && printf '%s' "$out"
|
|
229
|
+
return 0
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
# Turn test file paths into Gradle `--tests` filter arguments.
|
|
233
|
+
# Echoes one argument per line (Gradle wants a repeated flag, not a list).
|
|
234
|
+
#
|
|
235
|
+
# $1..$N test file paths
|
|
236
|
+
java_gradle_test_filters() {
|
|
237
|
+
local seen=""
|
|
238
|
+
local path name
|
|
239
|
+
for path in "$@"; do
|
|
240
|
+
[ -n "$path" ] || continue
|
|
241
|
+
name="${path##*/}"
|
|
242
|
+
name="${name%.java}"
|
|
243
|
+
[ -n "$name" ] || continue
|
|
244
|
+
case "$seen" in
|
|
245
|
+
*"|$name|"*) continue ;;
|
|
246
|
+
esac
|
|
247
|
+
seen="$seen|$name|"
|
|
248
|
+
printf '%s\n' "$name"
|
|
249
|
+
done
|
|
250
|
+
return 0
|
|
251
|
+
}
|
package/hooks/lib/jscpd-run.sh
CHANGED
|
@@ -38,6 +38,15 @@ jscpd_default_ignore_patterns() {
|
|
|
38
38
|
# XP_GATE_JSCPD_DEFAULT_IGNORE=0 disables the set entirely: a project that
|
|
39
39
|
# genuinely wants YAML compared must be able to say so, or the default would make
|
|
40
40
|
# some real duplicates unreachable.
|
|
41
|
+
#
|
|
42
|
+
# SCOPE CHANGED IN #648: Gate 1's debugger check now calls this too, so the
|
|
43
|
+
# switch governs "what counts as our code" for BOTH gates — not just jscpd.
|
|
44
|
+
# Setting it to 0 makes Gate 1 scan dependencies and build output for debugger
|
|
45
|
+
# statements as well, which is rarely what someone disabling duplicate detection
|
|
46
|
+
# intends. Kept as one switch deliberately: two gates disagreeing about what a
|
|
47
|
+
# build artifact is would be its own defect, and a project that vendors code
|
|
48
|
+
# wants it treated consistently everywhere. Override per-run rather than
|
|
49
|
+
# permanently if you only meant to widen Gate 2's scan.
|
|
41
50
|
jscpd_is_default_ignored() {
|
|
42
51
|
local _path="$1"
|
|
43
52
|
if [ "${XP_GATE_JSCPD_DEFAULT_IGNORE:-1}" = "0" ]; then
|