Skip to content

Commit 7755c05

Browse files
committed
Add read-only real repo validation
1 parent fd5823e commit 7755c05

6 files changed

Lines changed: 203 additions & 39 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ All commands support `--json`.
181181
- [Environment Config](docs/environment-config.md)
182182
- [Context Coverage](docs/context-coverage.md)
183183
- [Integration](docs/integration.md)
184+
- [Real Repo Validation](docs/real-repo-validation.md)
184185
- [Smart Dependency Detection](docs/smart-dependency-detection.md)
185186
- [Reference Docs](docs/references/README.md)
186187
- [Reference: Command and Workflow Surfaces](docs/references/command-surfaces.md)
@@ -199,5 +200,5 @@ bash tests/worker-smoke.sh
199200
```
200201

201202
```bash
202-
bash tests/real-repos.sh /path/to/repo1 /path/to/repo2
203+
bash tests/real-repos.sh --check /path/to/repo1 /path/to/repo2
203204
```

docs/real-repo-validation.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Real Repo Validation
2+
3+
dev.kit is validated at two levels:
4+
5+
- fixtures verify deterministic contracts inside this repo
6+
- real repos verify whether dev.kit reads repo-owned evidence well enough to guide work
7+
8+
Keep fixtures small. They should cover stable output shape, gap categories, manifest handling, and known regressions. They should not try to model every UDX repo.
9+
10+
Use real repos as optimization probes before a release. Run them read-only by default so the probe reports what dev.kit sees without changing the target repo.
11+
12+
## Local UDX Matrix
13+
14+
Use the matrix declared in `src/configs/repo-validation.yaml` when the listed repos are available locally.
15+
16+
Example:
17+
18+
```bash
19+
bash tests/real-repos.sh --check ./reusable-workflows ./github-rabbit-action
20+
```
21+
22+
The summary should be used to compare:
23+
24+
- home context status
25+
- repo workflow status
26+
- repo context status
27+
- gap count
28+
- read-first ref count
29+
30+
When one repo looks noisy or inconsistent, repair the strongest repo-owned gap or dev.kit normalization issue, rerun the matrix, and verify the output changed.
31+
32+
## Public Repo Probes
33+
34+
Public repos are useful for compatibility checks, but they should be optional and pinned when used for repeatable release evidence. Upstream repos change for reasons unrelated to dev.kit.
35+
36+
Use public probes to test broad ecosystem recognition:
37+
38+
- package manifests and scripts
39+
- docs-first repos
40+
- workflow-only repos
41+
- container repos
42+
43+
Do not assert exact output for moving public repos in the default suite.
44+
45+
## Write Mode
46+
47+
`tests/real-repos.sh --write` generates `.rabbit/context.yaml` in the target repo. Use it only for temp clones or repos intentionally selected for context regeneration.

lib/commands/repo.sh

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
# @description: Analyze repo structure and factors
44

55
dev_kit_repo_recommended_repos_text() {
6-
cat <<'EOF'
7-
https://github.com/udx/worker
8-
https://github.com/udx/reusable-workflows
9-
https://github.com/udx/github-rabbit-action
10-
EOF
6+
dev_kit_repo_validation_list "recommended_repos"
117
}
128

139
dev_kit_repo_recommended_repos_json() {

lib/modules/config_catalog.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ dev_kit_context_config_path() {
2424
dev_kit_config_path "src/configs/context-config.yaml"
2525
}
2626

27+
dev_kit_repo_validation_config_path() {
28+
dev_kit_config_path "src/configs/repo-validation.yaml"
29+
}
30+
31+
dev_kit_repo_validation_list() {
32+
dev_kit_yaml_config_list "$(dev_kit_repo_validation_config_path)" "$1"
33+
}
34+
2735
dev_kit_context_list() {
2836
dev_kit_yaml_config_list "$(dev_kit_context_config_path)" "$1"
2937
}

src/configs/repo-validation.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
kind: repoValidationConfig
2+
version: udx.dev/dev.kit/v1
3+
description: Public repo probes and validation defaults for dev.kit release checks
4+
5+
config:
6+
recommended_repos:
7+
- https://github.com/udx/worker
8+
- https://github.com/udx/reusable-workflows
9+
- https://github.com/udx/github-rabbit-action
10+
real_repo_probe_examples:
11+
- udx/reusable-workflows
12+
- udx/github-rabbit-action
13+
real_repo_matrix:
14+
site_enc_apps:
15+
repo: udx/site-enc-apps
16+
purpose: many .rabbit/infra_configs environment definitions; validates manifest coverage without flooding first-read refs
17+
gh_workflows:
18+
repo: udx/gh-workflows
19+
purpose: workflow-heavy repo; validates pipeline and reusable workflow context
20+
rabbit_automation_action:
21+
repo: udx/rabbit-automation-action
22+
purpose: action, container, docs, and workflow mix
23+
dev_kit:
24+
repo: udx/dev.kit
25+
purpose: self-hosting sanity check

tests/real-repos.sh

Lines changed: 120 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,37 @@ TEST_HOME="${DEV_KIT_TEST_HOME:-$(mktemp -d "${TMPDIR:-/tmp}/dev-kit-real-repos.
66
DEV_KIT_BIN_DIR="$TEST_HOME/.local/bin"
77
KEEP_HOME="${DEV_KIT_TEST_KEEP_HOME:-0}"
88
REAL_REPOS_CSV="${DEV_KIT_TEST_REAL_REPOS:-}"
9+
MODE="check"
10+
REPORT_DIR="${DEV_KIT_TEST_REPORT_DIR:-$TEST_HOME/reports}"
11+
COMMAND_SOFT_TIMEOUT="${DEV_KIT_TEST_SOFT_TIMEOUT:-15}"
12+
COMMAND_HARD_TIMEOUT="${DEV_KIT_TEST_HARD_TIMEOUT:-180}"
13+
14+
# shellcheck disable=SC1091
15+
. "$REPO_DIR/lib/modules/output.sh"
916

1017
usage() {
1118
cat <<'EOF'
12-
Usage: bash tests/real-repos.sh [/abs/path/to/repo ...]
19+
Usage: bash tests/real-repos.sh [--check|--write] [/abs/path/to/repo ...]
1320
1421
Runs the current dev.kit working tree against real local repos using a temporary
1522
plain `dev.kit` shim, without changing the global install.
1623
24+
Default mode is --check, which is read-only for target repos.
25+
1726
Options via environment:
1827
DEV_KIT_TEST_REAL_REPOS Colon-separated repo paths when no CLI args are given
1928
DEV_KIT_TEST_HOME Temp home for the test run
29+
DEV_KIT_TEST_REPORT_DIR Directory for per-repo JSON reports
30+
DEV_KIT_TEST_SOFT_TIMEOUT Seconds before a slow-command notice (default: 15)
31+
DEV_KIT_TEST_HARD_TIMEOUT Seconds before stopping a command (default: 180)
2032
DEV_KIT_TEST_KEEP_HOME Keep temp home after exit (default: 0)
2133
2234
Examples:
23-
bash tests/real-repos.sh ~/git/udx/reusable-workflows ~/git/udx/www.peakclt.com
24-
DEV_KIT_TEST_REAL_REPOS="$HOME/git/udx/reusable-workflows:$HOME/git/udx/www.peakclt.com" bash tests/real-repos.sh
35+
bash tests/real-repos.sh --check ./reusable-workflows ./github-rabbit-action
36+
DEV_KIT_TEST_REAL_REPOS="./reusable-workflows:./github-rabbit-action" bash tests/real-repos.sh --check
37+
bash tests/real-repos.sh --write /tmp/dev-kit-probe-clone
38+
39+
Probe examples and release matrix candidates live in src/configs/repo-validation.yaml.
2540
EOF
2641
}
2742

@@ -33,59 +48,131 @@ cleanup() {
3348

3449
trap cleanup EXIT
3550

36-
if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
37-
usage
38-
exit 0
39-
fi
40-
4151
repo_paths=()
42-
if [ "$#" -gt 0 ]; then
43-
while [ "$#" -gt 0 ]; do
44-
repo_paths+=("$1")
45-
shift
46-
done
47-
elif [ -n "$REAL_REPOS_CSV" ]; then
52+
while [ "$#" -gt 0 ]; do
53+
case "$1" in
54+
--check) MODE="check" ;;
55+
--write) MODE="write" ;;
56+
-h|--help) usage; exit 0 ;;
57+
--*) printf 'Unknown option: %s\n' "$1" >&2; usage >&2; exit 1 ;;
58+
*) repo_paths+=("$1") ;;
59+
esac
60+
shift
61+
done
62+
63+
if [ "${#repo_paths[@]}" -eq 0 ] && [ -n "$REAL_REPOS_CSV" ]; then
4864
while IFS= read -r repo_path; do
4965
[ -n "$repo_path" ] || continue
5066
repo_paths+=("$repo_path")
5167
done <<EOF
5268
$(printf '%s' "$REAL_REPOS_CSV" | tr ':' '\n')
5369
EOF
54-
else
70+
fi
71+
72+
if [ "${#repo_paths[@]}" -eq 0 ]; then
5573
usage >&2
5674
exit 1
5775
fi
5876

5977
mkdir -p "$DEV_KIT_BIN_DIR"
78+
mkdir -p "$REPORT_DIR"
6079
ln -sfn "$REPO_DIR/bin/dev-kit" "$DEV_KIT_BIN_DIR/dev.kit"
6180

6281
export HOME="$TEST_HOME"
6382
export PATH="$DEV_KIT_BIN_DIR:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
6483
unset DEV_KIT_HOME
6584
unset DEV_KIT_BIN_DIR
6685

86+
require_jq() {
87+
if ! command -v jq >/dev/null 2>&1; then
88+
printf 'jq is required for real repo report summaries\n' >&2
89+
exit 1
90+
fi
91+
}
92+
93+
report_name_for_repo() {
94+
basename "$1" | tr -c 'A-Za-z0-9._-' '-'
95+
}
96+
97+
print_check_summary() {
98+
local repo_path="$1"
99+
local home_json="$2"
100+
local repo_json="$3"
101+
local refs_count=""
102+
local gap_count=""
103+
local workflow_status=""
104+
local context_status=""
105+
local home_context_status=""
106+
107+
home_context_status="$(jq -r '.synced.context_status // "none"' "$home_json")"
108+
workflow_status="$(jq -r '.workflow.jobs[] | select(.id == "repo") | .status' "$repo_json")"
109+
context_status="$(jq -r '.workflow.jobs[] | select(.id == "repo") | .context_status' "$repo_json")"
110+
gap_count="$(jq -r '.workflow.jobs[] | select(.id == "repo") | .gap_count' "$repo_json")"
111+
refs_count="$(jq -r '[.workflow.jobs[] | select(.id == "repo") | .steps[]? | select(.id == "read_repo") | .refs[]?] | length' "$repo_json")"
112+
113+
printf '%s\tmode=%s\thome_context=%s\trepo_status=%s\trepo_context=%s\tgaps=%s\tread_refs=%s\n' \
114+
"$repo_path" "$MODE" "$home_context_status" "$workflow_status" "$context_status" "$gap_count" "$refs_count"
115+
}
116+
117+
print_write_summary() {
118+
local repo_path="$1"
119+
local repo_json="$2"
120+
local context_yaml="$repo_path/.rabbit/context.yaml"
121+
local gap_count=""
122+
local manifest_count=0
123+
local dep_count=0
124+
125+
gap_count="$(jq -r '.workflow.jobs[] | select(.id == "repo") | .gap_count' "$repo_json")"
126+
if [ -f "$context_yaml" ]; then
127+
manifest_count="$(awk '/^manifests:/{flag=1;next} flag && /^[^[:space:]#]/{exit} flag && /^ - path:/{count += 1} END{print count + 0}' "$context_yaml")"
128+
dep_count="$(awk '/^dependencies:/{flag=1;next} /^# Manifests/{if(flag) exit} flag && /^ - repo:/{count += 1} END{print count + 0}' "$context_yaml")"
129+
fi
130+
131+
printf '%s\tmode=%s\tcontext=%s\tgaps=%s\tmanifests=%s\tdependencies=%s\n' \
132+
"$repo_path" "$MODE" "$context_yaml" "$gap_count" "$manifest_count" "$dep_count"
133+
}
134+
135+
run_report_command() {
136+
local label="$1"
137+
local output_file="$2"
138+
shift 2
139+
140+
local tmp_file="${output_file}.tmp"
141+
rm -f "$tmp_file"
142+
DEV_KIT_SPINNER_DISABLE=1 dev_kit_run_guarded \
143+
"$label" \
144+
"$COMMAND_SOFT_TIMEOUT" \
145+
"$COMMAND_HARD_TIMEOUT" \
146+
"$label is taking longer than usual; still resolving repo evidence" \
147+
"$@" >"$tmp_file"
148+
mv "$tmp_file" "$output_file"
149+
}
150+
151+
require_jq
152+
printf 'report_dir: %s\n' "$REPORT_DIR"
153+
printf 'mode: %s\n' "$MODE"
154+
67155
for repo_path in "${repo_paths[@]}"; do
68156
repo_path="$(cd "$repo_path" 2>/dev/null && pwd || true)"
69157
[ -n "$repo_path" ] || { printf 'repo not found\n' >&2; exit 1; }
70158
[ -d "$repo_path/.git" ] || { printf 'not a git repo: %s\n' "$repo_path" >&2; exit 1; }
71-
run_out="$(mktemp "$TEST_HOME/dev-kit-real.XXXXXX.out")"
159+
repo_report_name="$(report_name_for_repo "$repo_path")"
160+
home_json="$REPORT_DIR/${repo_report_name}.home.json"
161+
repo_json="$REPORT_DIR/${repo_report_name}.repo.json"
72162

73163
printf '\n===== %s =====\n' "$repo_path"
74-
(
75-
cd "$repo_path"
76-
if ! dev.kit >"$run_out"; then
77-
cat "$run_out" >&2
78-
exit 1
79-
fi
80-
dev.kit repo >/dev/null
81-
[ -f .rabbit/context.yaml ] || { printf 'missing .rabbit/context.yaml\n' >&2; exit 1; }
82-
83-
printf 'context: %s\n' "$repo_path/.rabbit/context.yaml"
84-
printf '\nrepo:\n'
85-
sed -n '1,20p' .rabbit/context.yaml
86-
printf '\ngaps:\n'
87-
awk '/^gaps:/{flag=1;next} /^# Dependencies/{if(flag) exit} flag{print}' .rabbit/context.yaml || true
88-
printf '\ndependencies:\n'
89-
awk '/^dependencies:/{flag=1;next} /^# Manifests/{if(flag) exit} flag{print}' .rabbit/context.yaml | sed -n '1,80p'
90-
)
164+
if [ "$MODE" = "check" ]; then
165+
(
166+
cd "$repo_path"
167+
run_report_command "dev.kit home check: $repo_path" "$home_json" dev.kit --json
168+
run_report_command "dev.kit repo check: $repo_path" "$repo_json" dev.kit repo --json --check
169+
)
170+
print_check_summary "$repo_path" "$home_json" "$repo_json"
171+
else
172+
(
173+
cd "$repo_path"
174+
run_report_command "dev.kit repo write: $repo_path" "$repo_json" dev.kit repo --json
175+
)
176+
print_write_summary "$repo_path" "$repo_json"
177+
fi
91178
done

0 commit comments

Comments
 (0)