Skip to content

Commit 60cdeee

Browse files
committed
feat: add local-testing skill and rhdh local CLI commands
Integrates rhdh-local-setup knowledge into the skill system so agents can guide users through local RHDH testing as part of the plugin development lifecycle (create → export → overlay → test locally). Changes: - skills/local-testing/ — new skill with enable/disable/switch-mode/test workflows and customization-system reference - skills/overlay/references/rhdh-local.md — extended with customization system, container lifecycle, and common operations sections - skills/rhdh/SKILL.md — added menu item 12 and routing for local testing - skills/rhdh/rhdh/config.py — added find_local_setup_dir() with 4-layer cascade, local_setup key in default config and shorthand map - skills/rhdh/rhdh/cli.py — added rhdh local status/apply/remove/plugins commands; extended doctor with local_setup checks - tests/unit/test_local_commands.py — 27 unit tests (TDD) - .gitignore — exclude rhdh-local-setup/ (personal workspace, not repo) - skills/rhdh/references/versions.md — add xml wrapper (fix pre-existing test failure)
1 parent a6dcef1 commit 60cdeee

13 files changed

Lines changed: 1757 additions & 1 deletion

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ Thumbs.db
3232

3333
# Local config (project-specific settings)
3434
.rhdh-plugin/
35+
36+
# Personal workspace wrapper (not part of the skill repo)
37+
rhdh-local-setup/

skills/local-testing/SKILL.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
name: local-testing
3+
description: Skill for testing RHDH plugins locally using the rhdh-local-setup customization system. Covers enabling/disabling plugins, switching modes, and running end-to-end plugin tests.
4+
---
5+
6+
<essential_principles>
7+
8+
<principle name="copy_sync_first">
9+
All configuration edits go in `rhdh-customizations/`, never in `rhdh-local/` directly.
10+
After every edit, run `apply-customizations.sh` to sync copies. This is the fundamental invariant.
11+
</principle>
12+
13+
<principle name="use_scripts">
14+
Use `./up.sh` and `./down.sh` — never `podman compose restart/up/down` directly when Lightspeed or Orchestrator are enabled. Network namespace sharing causes 504 errors if containers are restarted independently.
15+
See `references/customization-system.md` for details.
16+
</principle>
17+
18+
<principle name="data_sources">
19+
Plugin package definitions come from `rhdh-plugin-export-overlays` on GitHub.
20+
Always fetch the OCI reference from `spec.dynamicArtifact` in the package metadata — do NOT construct OCI URLs manually.
21+
</principle>
22+
23+
</essential_principles>
24+
25+
<intake>
26+
## Step 1: Identify What You Want to Do
27+
28+
What would you like to do with your local RHDH instance?
29+
30+
1. **Enable a plugin** — Add a plugin from the export-overlays catalog to your local RHDH
31+
2. **Disable a plugin** — Disable or remove a plugin from your local RHDH
32+
3. **Switch mode** — Switch between Customized (your config) and Pristine (RHDH defaults)
33+
4. **Test a plugin** — Run end-to-end verification after enabling a plugin
34+
5. **Check status** — See which plugins are currently enabled
35+
36+
**Wait for response before proceeding.**
37+
</intake>
38+
39+
<routing>
40+
| Response | Workflow |
41+
|----------|----------|
42+
| 1, "enable", "add plugin", "install plugin" | `workflows/enable-plugin.md` |
43+
| 2, "disable", "remove plugin", "turn off plugin" | `workflows/disable-plugin.md` |
44+
| 3, "switch", "pristine", "customized", "mode" | `workflows/switch-mode.md` |
45+
| 4, "test", "verify", "check plugin" | `workflows/test-plugin.md` |
46+
| 5, "status", "list plugins", "show plugins" | Read `rhdh-customizations/configs/dynamic-plugins/dynamic-plugins.override.yaml` and list entries |
47+
</routing>
48+
49+
<reference_index>
50+
**Customization system (copy-sync, file mapping, edit rules):** `references/customization-system.md`
51+
**Container lifecycle, startup scripts, network namespace:** `../overlay/references/rhdh-local.md` sections `<container_lifecycle>` and `<common_operations>`
52+
**Dynamic plugin YAML format, OCI references:** `../overlay/references/rhdh-local.md` section `<dynamic_plugins_config>`
53+
</reference_index>
54+
55+
<skills_index>
56+
57+
| Skill | Purpose | Path |
58+
|-------|---------|------|
59+
| overlay | Onboard/update plugins in rhdh-plugin-export-overlays | `../overlay/SKILL.md` |
60+
| rhdh | Orchestrator — routes to all skills, runs CLI checks | `../rhdh/SKILL.md` |
61+
62+
</skills_index>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Reference: RHDH Local Customization System
2+
3+
The copy-sync system for managing RHDH Local configuration without modifying the upstream `rhdh-local/` git repository.
4+
5+
<architecture>
6+
**Workspace layout:**
7+
8+
```
9+
rhdh-local-setup/
10+
├── rhdh-local/ # Upstream git repo — NEVER edit directly
11+
│ ├── compose.yaml
12+
│ ├── default.env
13+
│ └── configs/
14+
│ ├── app-config/app-config.yaml
15+
│ └── dynamic-plugins/dynamic-plugins.default.yaml
16+
├── rhdh-customizations/ # Your overrides — ALWAYS edit here
17+
│ ├── apply-customizations.sh # Copies files into rhdh-local/
18+
│ ├── remove-customizations.sh # Deletes copies from rhdh-local/
19+
│ ├── .env
20+
│ ├── compose.override.yaml
21+
│ └── configs/
22+
│ ├── app-config/app-config.local.yaml
23+
│ ├── dynamic-plugins/dynamic-plugins.override.yaml
24+
│ ├── catalog-entities/users.override.yaml
25+
│ └── extra-files/github-app-credentials.yaml
26+
├── up.sh # Start containers (use instead of podman compose up)
27+
├── down.sh # Stop containers (use instead of podman compose down)
28+
└── backup.sh # Archive this workspace
29+
```
30+
31+
**The copy-sync invariant:**
32+
33+
- `rhdh-customizations/` is the single source of truth for all configuration
34+
- `apply-customizations.sh` physically copies files into `rhdh-local/`
35+
- Containers read files from `rhdh-local/` (they cannot access paths outside their mount)
36+
- `remove-customizations.sh` deletes the copies, restoring pristine state
37+
- `rhdh-local/` git status should always be "working tree clean" — the copied files are gitignored
38+
</architecture>
39+
40+
<file_mapping>
41+
**Source → Destination** (what `apply-customizations.sh` copies):
42+
43+
| Edit here (`rhdh-customizations/`) | Copied to (`rhdh-local/`) |
44+
|------------------------------------|---------------------------|
45+
| `compose.override.yaml` | `compose.override.yaml` |
46+
| `.env` | `.env` |
47+
| `configs/app-config/app-config.local.yaml` | `configs/app-config/app-config.local.yaml` |
48+
| `configs/dynamic-plugins/dynamic-plugins.override.yaml` | `configs/dynamic-plugins/dynamic-plugins.override.yaml` |
49+
| `configs/catalog-entities/*.override.yaml` | `configs/catalog-entities/*.override.yaml` |
50+
| `configs/extra-files/*` | `configs/extra-files/*` |
51+
| `developer-lightspeed/configs/app-config/app-config.lightspeed.local.yaml` | same relative path |
52+
</file_mapping>
53+
54+
<configuration_layers>
55+
**Precedence (lowest → highest):**
56+
57+
1. **Layer 1 — Defaults:** `rhdh-local/` version-controlled files
58+
- `default.env`, `app-config.yaml`, `dynamic-plugins.default.yaml`
59+
2. **Layer 2 — Overrides:** Files copied from `rhdh-customizations/`
60+
- `.env`, `app-config.local.yaml`, `dynamic-plugins.override.yaml`
61+
3. **Layer 3 — app-config.local.yaml:** Loads last, highest precedence among config files
62+
4. **Environment variables** from `.env` override `default.env`
63+
</configuration_layers>
64+
65+
<edit_rules>
66+
**ALWAYS:**
67+
68+
- Edit customization files in `rhdh-customizations/` directory
69+
- Run `apply-customizations.sh` after every edit
70+
- Verify pristine state: `cd rhdh-local && git status` → "working tree clean"
71+
- Use `./up.sh` and `./down.sh` scripts for container lifecycle
72+
73+
**NEVER:**
74+
75+
- Modify files in `rhdh-local/` for customization purposes
76+
- Manually copy files (use `apply-customizations.sh`)
77+
- Commit `*.local.yaml`, `*.override.yaml`, or `.env` to the rhdh-local repository
78+
- Edit the copied files in `rhdh-local/` — they get overwritten on the next `apply-customizations.sh`
79+
</edit_rules>
80+
81+
<quick_reference>
82+
**What to edit and where:**
83+
84+
| Change | File |
85+
|--------|------|
86+
| App configuration | `rhdh-customizations/configs/app-config/app-config.local.yaml` |
87+
| Plugin enable/disable | `rhdh-customizations/configs/dynamic-plugins/dynamic-plugins.override.yaml` |
88+
| Environment variables | `rhdh-customizations/.env` |
89+
| Extra services (Jenkins etc.) | `rhdh-customizations/compose.override.yaml` |
90+
| Catalog entities | `rhdh-customizations/configs/catalog-entities/components.override.yaml` |
91+
| Credentials | `rhdh-customizations/configs/extra-files/github-app-credentials.yaml` |
92+
| Lightspeed config | `rhdh-customizations/developer-lightspeed/configs/app-config/app-config.lightspeed.local.yaml` |
93+
94+
**Standard change workflow:**
95+
96+
```bash
97+
# 1. Edit the file in rhdh-customizations/
98+
# 2. Sync into rhdh-local/
99+
cd rhdh-customizations && ./apply-customizations.sh
100+
# 3. Restart
101+
cd .. && ./down.sh && ./up.sh --customized [flags]
102+
```
103+
104+
**Update rhdh-local from upstream:**
105+
106+
```bash
107+
./down.sh
108+
cd rhdh-local && git pull && cd ..
109+
cd rhdh-customizations && ./apply-customizations.sh
110+
cd .. && ./up.sh --customized [flags]
111+
```
112+
113+
</quick_reference>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Workflow: Disable a Plugin in Local RHDH
2+
3+
<required_reading>
4+
5+
- `references/customization-system.md` — copy-sync rules, file locations
6+
- `../overlay/references/rhdh-local.md` section `<container_lifecycle>` — restart procedure
7+
</required_reading>
8+
9+
<process>
10+
## Step 1: Read Current Plugin Configuration
11+
12+
```bash
13+
cat rhdh-customizations/configs/dynamic-plugins/dynamic-plugins.override.yaml
14+
```
15+
16+
Identify the package entries for the plugin to disable.
17+
18+
---
19+
20+
## Step 2: Disable or Remove the Plugin
21+
22+
**Option A — Set `disabled: true`** (preserves config for later re-enabling):
23+
24+
```yaml
25+
plugins:
26+
- package: 'oci://ghcr.io/...'
27+
disabled: true
28+
```
29+
30+
**Option B — Remove entries entirely** (cleaner, use when permanently removing):
31+
Remove the plugin's package entries from the `plugins:` list.
32+
33+
> **Do NOT** remove the `includes:` block — it loads default plugins and is required.
34+
35+
---
36+
37+
## Step 3: Clean Up Related Configuration (if removing permanently)
38+
39+
If the plugin added configuration to `rhdh-customizations/configs/app-config/app-config.local.yaml`, remove the corresponding section.
40+
41+
If the plugin required environment variables in `rhdh-customizations/.env`, remove or comment those out.
42+
43+
---
44+
45+
## Step 4: Apply and Restart
46+
47+
```bash
48+
cd rhdh-customizations && ./apply-customizations.sh
49+
cd .. && ./down.sh && ./up.sh --customized
50+
```
51+
52+
Add `--lightspeed`, `--orchestrator`, or `--both` flags if those components are enabled.
53+
</process>
54+
55+
<success_criteria>
56+
57+
- [ ] Plugin entry shows `disabled: true` or is removed from `dynamic-plugins.override.yaml`
58+
- [ ] `apply-customizations.sh` ran without errors
59+
- [ ] RHDH starts cleanly — no errors referencing the disabled plugin
60+
- [ ] Plugin no longer appears in the Extensions Catalog or entity pages
61+
</success_criteria>

0 commit comments

Comments
 (0)