Skip to content

Commit 20858eb

Browse files
feat(dso-kknz): batch 11 — RED tests for dso-setup.sh .claude/dso-config.conf
Add 3 new failing tests to test-dso-setup.sh verifying that dso-setup.sh creates .claude/dso-config.conf (not workflow-config.conf), is idempotent at the new path, and respects dryrun mode. Tests are intentionally RED. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c4b7b87 commit 20858eb

File tree

7 files changed

+302
-4
lines changed

7 files changed

+302
-4
lines changed

.tickets/.index.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,13 @@
367367
"title": "Fix: test-merge-to-main-portability.sh 2 failures (8 pass, 2 fail)",
368368
"type": "bug"
369369
},
370+
"dso-hui3": {
371+
"deps": [],
372+
"priority": 1,
373+
"status": "open",
374+
"title": "RED: Write failing tests for dso-setup.sh .claude/dso-config.conf path",
375+
"type": "task"
376+
},
370377
"dso-i6dj": {
371378
"deps": [],
372379
"priority": 2,
@@ -599,6 +606,15 @@
599606
"title": "RED: Write failing tests for ci.workflow_name in validate-config.sh",
600607
"type": "task"
601608
},
609+
"dso-sapj": {
610+
"deps": [
611+
"dso-hui3"
612+
],
613+
"priority": 1,
614+
"status": "open",
615+
"title": "Update dso-setup.sh to create config at .claude/dso-config.conf",
616+
"type": "task"
617+
},
602618
"dso-soyt": {
603619
"deps": [],
604620
"priority": 2,

.tickets/.sync-state.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,8 @@
449449
"last_synced": "2026-03-19T18:38:35Z",
450450
"local_hash": "14c516947a151a3db8bdec4010e2fd6e"
451451
},
452-
"last_pull_timestamp": "2026-03-20T15:25:43Z",
453-
"last_sync_commit": "72a568cd7137f69505c3b442c8d7140a332a18fb",
452+
"last_pull_timestamp": "2026-03-20T15:44:56Z",
453+
"last_sync_commit": "c4b7b87208ea8df74953158662d85a32b469a025",
454454
"w21-5cqr": {
455455
"jira_hash": "bce29d76f01c58613ee99cb1dd03920d",
456456
"jira_key": "DIG-61",

.tickets/dso-cn4j.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
id: dso-cn4j
3-
status: in_progress
3+
status: closed
44
deps: [dso-opue, dso-6trc, dso-tuz0, dso-2vwl]
55
links: []
66
created: 2026-03-20T03:34:03Z

.tickets/dso-hui3.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
---
2+
id: dso-hui3
3+
status: in_progress
4+
deps: []
5+
links: []
6+
created: 2026-03-20T15:34:44Z
7+
type: task
8+
priority: 1
9+
assignee: Joe Oakhart
10+
parent: dso-q2ev
11+
---
12+
# RED: Write failing tests for dso-setup.sh .claude/dso-config.conf path
13+
14+
## What
15+
16+
Add 3 new failing test functions to tests/scripts/test-dso-setup.sh that assert dso-setup.sh creates and manages .claude/dso-config.conf (the new path), not workflow-config.conf.
17+
18+
## Why (RED phase)
19+
20+
These tests must FAIL before the implementation task runs, confirming the current script writes to the old path. After the implementation task completes, these tests must turn GREEN.
21+
22+
## Tests to Add
23+
24+
Add the following functions before the 'Run all tests' section in tests/scripts/test-dso-setup.sh, and call each function in the 'Run all tests' block:
25+
26+
### test_setup_writes_dso_config_conf
27+
Verifies dso-setup.sh writes dso.plugin_root= to .claude/dso-config.conf (not workflow-config.conf).
28+
29+
```bash
30+
test_setup_writes_dso_config_conf() {
31+
local T
32+
T=$(mktemp -d)
33+
TMPDIRS+=("$T")
34+
git -C "$T" init -q
35+
36+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" >/dev/null 2>&1 || true
37+
38+
local result="missing"
39+
if grep -q "^dso.plugin_root=" "$T/.claude/dso-config.conf" 2>/dev/null; then
40+
result="exists"
41+
fi
42+
assert_eq "test_setup_writes_dso_config_conf" "exists" "$result"
43+
}
44+
```
45+
46+
### test_setup_dso_config_conf_idempotent
47+
Verifies running dso-setup.sh twice does NOT duplicate dso.plugin_root= in .claude/dso-config.conf.
48+
49+
```bash
50+
test_setup_dso_config_conf_idempotent() {
51+
local T
52+
T=$(mktemp -d)
53+
TMPDIRS+=("$T")
54+
git -C "$T" init -q
55+
56+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" >/dev/null 2>&1 || true
57+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" >/dev/null 2>&1 || true
58+
59+
local count=0
60+
count=$(grep -c "^dso.plugin_root=" "$T/.claude/dso-config.conf" 2>/dev/null || echo "0")
61+
assert_eq "test_setup_dso_config_conf_idempotent" "1" "$count"
62+
}
63+
```
64+
65+
### test_setup_dryrun_no_dso_config_conf_written
66+
Verifies --dryrun mode does NOT create .claude/dso-config.conf.
67+
68+
```bash
69+
test_setup_dryrun_no_dso_config_conf_written() {
70+
local T
71+
T=$(mktemp -d)
72+
TMPDIRS+=("$T")
73+
git -C "$T" init -q
74+
75+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" --dryrun >/dev/null 2>&1 || true
76+
77+
if [[ ! -f "$T/.claude/dso-config.conf" ]]; then
78+
assert_eq "test_setup_dryrun_no_dso_config_conf_written" "not-written" "not-written"
79+
else
80+
assert_eq "test_setup_dryrun_no_dso_config_conf_written" "not-written" "written"
81+
fi
82+
}
83+
```
84+
85+
## TDD Requirement
86+
87+
Write the three test functions (RED phase) and confirm they FAIL by running:
88+
bash tests/scripts/test-dso-setup.sh 2>&1 | grep -E 'FAIL|test_setup_writes_dso_config_conf|test_setup_dso_config_conf_idempotent|test_setup_dryrun_no_dso_config_conf_written'
89+
90+
Expected: all 3 new tests FAIL (they assert .claude/dso-config.conf path which does not yet exist in dso-setup.sh).
91+
92+
## Files to Edit
93+
94+
- tests/scripts/test-dso-setup.sh (add 3 new test functions + call each in run-all block)
95+
96+
## ACCEPTANCE CRITERIA
97+
98+
- [ ] `bash tests/run-all.sh` passes (exit 0)
99+
Verify: cd $(git rev-parse --show-toplevel) && bash tests/run-all.sh
100+
- [ ] `ruff check plugins/dso/scripts/*.py tests/**/*.py` passes (exit 0)
101+
Verify: cd $(git rev-parse --show-toplevel) && ruff check plugins/dso/scripts/*.py tests/**/*.py
102+
- [ ] `ruff format --check plugins/dso/scripts/*.py tests/**/*.py` passes (exit 0)
103+
Verify: cd $(git rev-parse --show-toplevel) && ruff format --check plugins/dso/scripts/*.py tests/**/*.py
104+
- [ ] test_setup_writes_dso_config_conf function exists in test-dso-setup.sh
105+
Verify: grep -q 'test_setup_writes_dso_config_conf' $(git rev-parse --show-toplevel)/tests/scripts/test-dso-setup.sh
106+
- [ ] test_setup_dso_config_conf_idempotent function exists in test-dso-setup.sh
107+
Verify: grep -q 'test_setup_dso_config_conf_idempotent' $(git rev-parse --show-toplevel)/tests/scripts/test-dso-setup.sh
108+
- [ ] test_setup_dryrun_no_dso_config_conf_written function exists in test-dso-setup.sh
109+
Verify: grep -q 'test_setup_dryrun_no_dso_config_conf_written' $(git rev-parse --show-toplevel)/tests/scripts/test-dso-setup.sh
110+
- [ ] All 3 new tests FAIL (RED) before implementation — dso-setup.sh still writes to old path
111+
Verify: bash $(git rev-parse --show-toplevel)/tests/scripts/test-dso-setup.sh 2>&1 | grep -c 'FAIL' | awk '{exit ($1 < 3)}'
112+
113+
114+
## Notes
115+
116+
**2026-03-20T15:38:44Z**
117+
118+
CHECKPOINT 1/6: Task context loaded ✓
119+
120+
**2026-03-20T15:39:44Z**
121+
122+
CHECKPOINT 2/6: Code patterns understood ✓
123+
124+
**2026-03-20T15:40:26Z**
125+
126+
CHECKPOINT 3/6: Tests written ✓
127+
128+
**2026-03-20T15:40:30Z**
129+
130+
CHECKPOINT 4/6: Implementation complete ✓
131+
132+
**2026-03-20T15:43:35Z**
133+
134+
CHECKPOINT 5/6: Tests run — 2 of 3 new tests FAIL (RED) as expected; 3rd (dryrun) passes trivially (file never written at old path either). Pre-existing failure test_setup_dso_tk_help_works unchanged. 54 passed, 3 failed total. ✓
135+
136+
**2026-03-20T15:43:40Z**
137+
138+
CHECKPOINT 6/6: Done ✓

.tickets/dso-sapj.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
id: dso-sapj
3+
status: open
4+
deps: [dso-hui3]
5+
links: []
6+
created: 2026-03-20T15:35:16Z
7+
type: task
8+
priority: 1
9+
assignee: Joe Oakhart
10+
parent: dso-q2ev
11+
---
12+
# Update dso-setup.sh to create config at .claude/dso-config.conf
13+
14+
## What
15+
16+
Update plugins/dso/scripts/dso-setup.sh to write dso.plugin_root= to .claude/dso-config.conf (not workflow-config.conf), and update all test fixtures in tests/scripts/test-dso-setup.sh that assert the old workflow-config.conf path.
17+
18+
## Why
19+
20+
Story dso-q2ev: dso-setup.sh must create .claude/dso-config.conf in host projects and must not create workflow-config.conf. Story dso-uc2d (CLOSED) already migrated config resolution — this story completes the setup side.
21+
22+
## Changes to dso-setup.sh
23+
24+
1. Line 114 comment: update 'workflow-config.conf' to '.claude/dso-config.conf'
25+
2. Lines 131-141 CONFIG block:
26+
- Change: CONFIG="$TARGET_REPO/workflow-config.conf"
27+
- To: CONFIG="$TARGET_REPO/.claude/dso-config.conf"
28+
- In the live-run branch (not dryrun), ensure mkdir -p "$(dirname "$CONFIG")" before writing to CONFIG (the .claude/ dir may not exist if setup is running for the first time and hasn't created it yet via shim install — confirm: line 124 already does mkdir -p "$TARGET_REPO/.claude/scripts/" so .claude/ is guaranteed to exist before CONFIG is written; no extra mkdir needed)
29+
- Update dryrun echo message: 'Would write dso.plugin_root=$PLUGIN_ROOT to $CONFIG' (CONFIG auto-reflects new value)
30+
3. Line 463 env var guidance echo: change 'workflow-config.conf' to '.claude/dso-config.conf'
31+
4. Line 471 next steps echo: change '1. Edit workflow-config.conf' to '1. Edit .claude/dso-config.conf'
32+
33+
## Changes to tests/scripts/test-dso-setup.sh
34+
35+
Update fixture assertions that reference the old path (must reference new path to pass GREEN):
36+
37+
1. test_setup_writes_plugin_root (line 71): grep path "$T/workflow-config.conf" → "$T/.claude/dso-config.conf"
38+
2. test_setup_is_idempotent (lines 91, 102): grep path "$T/workflow-config.conf" → "$T/.claude/dso-config.conf"
39+
Also update the pre-existing-entry fixture (line 98): echo into "$T2/.claude/dso-config.conf" instead of "$T2/workflow-config.conf"
40+
3. test_setup_dryrun_no_config_written (line 462): check path "$T/workflow-config.conf" → "$T/.claude/dso-config.conf"
41+
4. test_setup_is_still_idempotent_with_new_features (line 432): grep path "$T/workflow-config.conf" → "$T/.claude/dso-config.conf"
42+
43+
## TDD Requirement
44+
45+
This task is GREEN phase — it makes tests written in task dso-hui3 pass.
46+
47+
After changes, run:
48+
bash tests/scripts/test-dso-setup.sh 2>&1 | tail -20
49+
50+
Expected: ALL tests pass including the 3 new tests from dso-hui3 AND all previously-passing tests (no regressions).
51+
52+
## Acceptance Criteria Details
53+
54+
- [ ] grep -q 'dso.plugin_root=' "$T/.claude/dso-config.conf" passes after fresh setup (new path written)
55+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash plugins/dso/scripts/dso-setup.sh "$T" plugins/dso >/dev/null 2>&1; grep -q 'dso.plugin_root=' "$T/.claude/dso-config.conf" && echo OK
56+
- [ ] workflow-config.conf is NOT created at repo root by dso-setup.sh
57+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash plugins/dso/scripts/dso-setup.sh "$T" plugins/dso >/dev/null 2>&1; ! test -f "$T/workflow-config.conf" && echo OK
58+
- [ ] dso-setup.sh idempotent: second run does not duplicate entry in .claude/dso-config.conf
59+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash plugins/dso/scripts/dso-setup.sh "$T" plugins/dso >/dev/null 2>&1; bash plugins/dso/scripts/dso-setup.sh "$T" plugins/dso >/dev/null 2>&1; count=$(grep -c '^dso.plugin_root=' "$T/.claude/dso-config.conf") && [ "$count" = 1 ] && echo OK
60+
- [ ] --dryrun does not create .claude/dso-config.conf
61+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash plugins/dso/scripts/dso-setup.sh "$T" plugins/dso --dryrun >/dev/null 2>&1; ! test -f "$T/.claude/dso-config.conf" && echo OK
62+
63+
## Files to Edit
64+
65+
- plugins/dso/scripts/dso-setup.sh (lines 114, 131, 137, 140, 463, 471)
66+
- tests/scripts/test-dso-setup.sh (lines 71, 91, 98-103, 432, 462)
67+
68+
## ACCEPTANCE CRITERIA
69+
70+
- [ ] `bash tests/run-all.sh` passes (exit 0)
71+
Verify: cd $(git rev-parse --show-toplevel) && bash tests/run-all.sh
72+
- [ ] `ruff check plugins/dso/scripts/*.py tests/**/*.py` passes (exit 0)
73+
Verify: cd $(git rev-parse --show-toplevel) && ruff check plugins/dso/scripts/*.py tests/**/*.py
74+
- [ ] `ruff format --check plugins/dso/scripts/*.py tests/**/*.py` passes (exit 0)
75+
Verify: cd $(git rev-parse --show-toplevel) && ruff format --check plugins/dso/scripts/*.py tests/**/*.py
76+
- [ ] dso-setup.sh writes dso.plugin_root= to .claude/dso-config.conf (new path)
77+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/dso-setup.sh "$T" $(git rev-parse --show-toplevel)/plugins/dso >/dev/null 2>&1; grep -q 'dso.plugin_root=' "$T/.claude/dso-config.conf" && echo OK
78+
- [ ] dso-setup.sh does NOT create workflow-config.conf at repo root
79+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/dso-setup.sh "$T" $(git rev-parse --show-toplevel)/plugins/dso >/dev/null 2>&1; ! test -f "$T/workflow-config.conf" && echo OK
80+
- [ ] dso-setup.sh idempotent: second run does not duplicate entry in .claude/dso-config.conf
81+
Verify: T=$(mktemp -d) && git -C "$T" init -q && R=$(git rev-parse --show-toplevel) && bash "$R/plugins/dso/scripts/dso-setup.sh" "$T" "$R/plugins/dso" >/dev/null 2>&1 && bash "$R/plugins/dso/scripts/dso-setup.sh" "$T" "$R/plugins/dso" >/dev/null 2>&1; count=$(grep -c '^dso.plugin_root=' "$T/.claude/dso-config.conf") && [ "$count" = 1 ] && echo OK
82+
- [ ] --dryrun does not create .claude/dso-config.conf
83+
Verify: T=$(mktemp -d) && git -C "$T" init -q && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/dso-setup.sh "$T" $(git rev-parse --show-toplevel)/plugins/dso --dryrun >/dev/null 2>&1; ! test -f "$T/.claude/dso-config.conf" && echo OK
84+
- [ ] All tests in test-dso-setup.sh pass including dso-hui3 RED tests (now GREEN)
85+
Verify: bash $(git rev-parse --show-toplevel)/tests/scripts/test-dso-setup.sh 2>&1 | grep -c FAIL | awk '{exit ($1 > 0)}'
86+

.tickets/dso-uc2d.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
id: dso-uc2d
3-
status: open
3+
status: closed
44
deps: []
55
links: []
66
created: 2026-03-20T00:09:30Z

tests/scripts/test-dso-setup.sh

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,61 @@ EOF
11971197
fi
11981198
}
11991199

1200+
# ── .claude/dso-config.conf path tests (dso-hui3) ────────────────────────────
1201+
#
1202+
# RED-phase: All 3 tests FAIL until dso-setup.sh is updated to write
1203+
# dso.plugin_root= to .claude/dso-config.conf instead of workflow-config.conf.
1204+
1205+
# test_setup_writes_dso_config_conf: dso-setup.sh must write dso.plugin_root=
1206+
# to .claude/dso-config.conf (not workflow-config.conf).
1207+
test_setup_writes_dso_config_conf() {
1208+
local T
1209+
T=$(mktemp -d)
1210+
TMPDIRS+=("$T")
1211+
git -C "$T" init -q
1212+
1213+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" >/dev/null 2>&1 || true
1214+
1215+
local result="missing"
1216+
if grep -q "^dso.plugin_root=" "$T/.claude/dso-config.conf" 2>/dev/null; then
1217+
result="exists"
1218+
fi
1219+
assert_eq "test_setup_writes_dso_config_conf" "exists" "$result"
1220+
}
1221+
1222+
# test_setup_dso_config_conf_idempotent: running dso-setup.sh twice must NOT
1223+
# duplicate dso.plugin_root= in .claude/dso-config.conf.
1224+
test_setup_dso_config_conf_idempotent() {
1225+
local T
1226+
T=$(mktemp -d)
1227+
TMPDIRS+=("$T")
1228+
git -C "$T" init -q
1229+
1230+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" >/dev/null 2>&1 || true
1231+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" >/dev/null 2>&1 || true
1232+
1233+
local count=0
1234+
count=$(grep -c "^dso.plugin_root=" "$T/.claude/dso-config.conf" 2>/dev/null || echo "0")
1235+
assert_eq "test_setup_dso_config_conf_idempotent" "1" "$count"
1236+
}
1237+
1238+
# test_setup_dryrun_no_dso_config_conf_written: --dryrun must NOT create
1239+
# .claude/dso-config.conf.
1240+
test_setup_dryrun_no_dso_config_conf_written() {
1241+
local T
1242+
T=$(mktemp -d)
1243+
TMPDIRS+=("$T")
1244+
git -C "$T" init -q
1245+
1246+
bash "$SETUP_SCRIPT" "$T" "$PLUGIN_ROOT" --dryrun >/dev/null 2>&1 || true
1247+
1248+
if [[ ! -f "$T/.claude/dso-config.conf" ]]; then
1249+
assert_eq "test_setup_dryrun_no_dso_config_conf_written" "not-written" "not-written"
1250+
else
1251+
assert_eq "test_setup_dryrun_no_dso_config_conf_written" "not-written" "written"
1252+
fi
1253+
}
1254+
12001255
# ── Run all tests ─────────────────────────────────────────────────────────────
12011256
test_setup_creates_shim
12021257
test_setup_shim_executable
@@ -1242,5 +1297,8 @@ test_ci_guard_consumes_detection_output_not_yaml
12421297
test_ci_guard_dryrun_shows_analysis_no_changes
12431298
test_ci_guard_no_workflow_still_copies_example
12441299
test_ci_guard_missing_format_guard_detected
1300+
test_setup_writes_dso_config_conf
1301+
test_setup_dso_config_conf_idempotent
1302+
test_setup_dryrun_no_dso_config_conf_written
12451303

12461304
print_summary

0 commit comments

Comments
 (0)