Skip to content

Commit 60a4fe4

Browse files
Add 'validate-rebase-rules' skill
Signed-off-by: Roman Nikitenko <rnikiten@redhat.com> Generated-by: Cursor AI
1 parent 73bb214 commit 60a4fe4

5 files changed

Lines changed: 576 additions & 4 deletions

File tree

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
---
2+
name: add-rebase-rules
3+
description: Generates .rebase add/override/replace rules from a commit that changes code/ files, updates rebase.sh conflict routing, and appends .rebase/CHANGELOG.md. Use when asked to add rebasing rules for a commit or PR.
4+
argument-hint: [commit-sha]
5+
disable-model-invocation: true
6+
---
7+
8+
# Add Rebase Rules
9+
10+
Create or update rebasing rules for Che-specific changes that touch VS Code subtree files under `code/`.
11+
12+
Use this skill when the user gives a commit SHA (or PR/commit URL) and asks to add rebasing rules.
13+
14+
## Required input
15+
16+
- A commit SHA is expected in `$ARGUMENTS`.
17+
- If `$ARGUMENTS` is empty, ask the user for a commit SHA before proceeding.
18+
19+
## Scope and exclusions
20+
21+
Only consider changed files under `code/`.
22+
23+
Never create rebasing rules for:
24+
- `code/extensions/che-*/**`
25+
- any `**/package-lock.json`
26+
27+
Important:
28+
- A file can be under `code/` and still be Che-only (for example `code/src/.../che/...` newly created by Che). Do not create a rule for such files if they are not upstream VS Code files.
29+
- Still create rules for the upstream file(s) that import/use those Che-only helpers.
30+
31+
## Workflow
32+
33+
1. Resolve the target commit and collect changed files
34+
- If input is a URL, extract the SHA.
35+
- Get changed files:
36+
- `git show --name-only --pretty='' <sha> | sort -u`
37+
- Filter to the rule candidate set:
38+
- include: files starting with `code/`
39+
- exclude: `code/extensions/che-*/**`
40+
- exclude: `**/package-lock.json`
41+
42+
2. Classify each candidate file
43+
- `*/package.json` -> JSON merge rule (`.rebase/add/` and/or `.rebase/override/`)
44+
- Other modified upstream files -> replace rule (`.rebase/replace/<path>.json`)
45+
- Newly added Che-only files with no upstream counterpart -> skip (no rule needed)
46+
47+
3. Create or update JSON merge rules for `package.json`
48+
- Preserve only minimal changed subtree (do not copy entire package.json).
49+
- Use:
50+
- `.rebase/add/<path>` for new keys or additive nested values
51+
- `.rebase/override/<path>` when overriding existing values must be explicit
52+
- It is valid to use both for one file.
53+
- Keep file formatting consistent with existing `.rebase` JSON style (2-space indentation).
54+
55+
4. Create or update replace rules for non-JSON files
56+
- File path: `.rebase/replace/<original-path>.json`
57+
- Format: JSON array of objects with `from` and `by`.
58+
- Add one rule per changed hunk, using stable and unique snippets.
59+
- Prefer the smallest safe snippet that is unlikely to change accidentally.
60+
- If replacement is multiline, encode using escaped newlines/tabs in JSON consistently with existing files.
61+
- For multiline `from` snippets, start at the first non-whitespace token (avoid anchoring on leading indentation only).
62+
- Prefer replacing the whole logical block (`if (...) { ... }`) rather than only an inner line fragment, so closing braces remain structurally correct.
63+
64+
5. Update `rebase.sh` conflict routing
65+
- Ensure each file that now has a new rebasing rule is routable in `resolve_conflicts`.
66+
- For `package.json` files:
67+
- add `elif` branch calling `apply_package_changes_by_path "$conflictingFile"` (or equivalent existing pattern).
68+
- For non-JSON replace rules:
69+
- use `apply_changes "$conflictingFile"` for line-based replacements.
70+
- For multiline replacements, `rebase.sh` has **two** handlers — do not always default to one:
71+
- `apply_changes_multi_line "$conflictingFile"` — higher-level wrapper that resets the file (`git checkout --theirs`), calls `apply_multi_line_replace`, then stages the result (`git add`).
72+
- `apply_multi_line_replace "$conflictingFile"` — low-level function that performs the Perl multiline replacement directly, without git checkout/add.
73+
- Before adding a routing branch, inspect the existing `resolve_conflicts` block in `rebase.sh` and look at how other files in the same area are routed. Match the handler already used for similar files. For example, if neighboring entries call `apply_multi_line_replace` directly, use that; if they use `apply_changes_multi_line`, use that instead.
74+
- Do not add duplicate branches.
75+
76+
6. Update `.rebase/CHANGELOG.md`
77+
- Append a new entry in existing format:
78+
- `#### @<author>`
79+
- commit/PR link (or commit SHA if no link is available)
80+
- list only files for which rebasing rules were added/updated
81+
- separator `---`
82+
83+
7. Validate before finishing
84+
- Determine the upstream ref from `rebase.sh` and use that exact ref for validation (do not hardcode a release branch in the skill output).
85+
- Example source of truth in `rebase.sh`: `UPSTREAM_VERSION=$(git rev-parse upstream-code/release/1.108)`
86+
- If the script later points to `upstream-code/main` or another release branch, use that new ref instead.
87+
- `bash -n rebase.sh`
88+
- JSON validation for changed `.rebase/**/*.json` files (`jq empty <file>`)
89+
- For each changed `.rebase/replace/**/*.json`, verify every `from` exists in the upstream file content before finishing.
90+
- Example: `git show <upstream-ref>:<path-without-code-prefix>` and compare with the `from` snippet.
91+
- `path-without-code-prefix` means the same file path but without the leading `code/` (because `upstream-code` stores VS Code sources at repo root).
92+
- Dry-run the generated rule using the same replacement path as `rebase.sh` (Perl-based multiline replace), not a language-native `.replace(...)`.
93+
- Include at least one test case where `from`/`by` contains `$` (for example template literals like `${key}`) and confirm replacement still succeeds.
94+
- Re-check exclusions:
95+
- no rules for `code/extensions/che-*`
96+
- no rules for `package-lock.json`
97+
- Ensure every changed rule file is actually referenced by logic in `rebase.sh` when required.
98+
99+
## Decision notes
100+
101+
- Goal is to protect Che-specific behavior during upstream subtree rebases while keeping deltas in upstream files minimal.
102+
- Prefer moving larger Che logic into Che-owned files and keeping upstream file edits small; then create replace rules only for the upstream file edits.
103+
- When unsure between `add` vs `override` for JSON, follow existing `.rebase` conventions in neighboring files and keep the smallest rule payload that reproduces the required result.
104+
105+
## Examples
106+
107+
- Dependency override updates across many `code/**/package.json` files:
108+
- Example commit: `04b7984047fec31dd6993bd299f6698750c63d08`
109+
- Matching rule-update style: `eec9cd1e9e199ce9a0eb2f6e3bd1dad6fc258413`
110+
111+
- Source-level VS Code file changes protected by replace rules:
112+
- Example PR changes: `https://github.com/che-incubator/che-code/pull/617/changes`
113+
- Matching rule commit: `https://github.com/che-incubator/che-code/pull/617/changes/e794c63f01d116b0b92d5ecd220247e13a5ba946`
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
---
2+
name: validate-rebase-rules
3+
description: Validates that .rebase/ rules (replace, add, override) are still current against upstream VS Code. Generates a rebase-rules-validation.md report with mismatches and proposed fixes. Use when asked to check, validate, or audit rebase rules, or before a rebase.
4+
---
5+
6+
# Validate Rebase Rules
7+
8+
Check whether `.rebase/` rules are still applicable to the current upstream VS Code version and the current che-code branch. Produce a `rebase-rules-validation.md` report listing any problems found.
9+
10+
## Prerequisites
11+
12+
Ensure the `upstream-code` remote exists and is fetched:
13+
14+
```bash
15+
git remote get-url upstream-code || git remote add upstream-code https://github.com/microsoft/vscode
16+
git fetch upstream-code
17+
```
18+
19+
## Step 1 — Resolve versions from rebase.sh
20+
21+
Read `rebase.sh` and extract two variables:
22+
23+
- `CURRENT_UPSTREAM_VERSION` — e.g. `release/1.108`
24+
- `PREVIOUS_UPSTREAM_VERSION` — e.g. `release/1.104`
25+
26+
These are defined near the top of `rebase.sh` as shell variable assignments.
27+
28+
Use the upstream git ref `upstream-code/<version>` when fetching file content:
29+
30+
```bash
31+
git show upstream-code/<version>:<path>
32+
```
33+
34+
Where `<path>` is **without** the `code/` prefix (upstream stores VS Code sources at repo root).
35+
36+
## Step 2 — Validate `.rebase/replace/` rules
37+
38+
Each file under `.rebase/replace/` has the form `.rebase/replace/<code-path>.json` and contains a JSON array of `{ "from": "...", "by": "..." }` objects.
39+
40+
**Path mapping:**
41+
42+
| Context | Path |
43+
|---------|------|
44+
| Rule file | `.rebase/replace/<code-path>.json` |
45+
| Upstream file | `<code-path>` with leading `code/` stripped → use as path in `git show upstream-code/CURRENT_UPSTREAM_VERSION:<stripped-path>` |
46+
| che-code file | `<code-path>` in the current working tree |
47+
48+
**For each rule entry:**
49+
50+
1. **Check `from` in upstream.** Fetch the upstream file at `CURRENT_UPSTREAM_VERSION`. Verify the `from` string exists verbatim in that file content. Handle escape sequences in the JSON: `\n` → newline, `\t` → tab, `\\` → backslash. The actual file content must contain the **decoded** string.
51+
52+
2. **Check `by` in che-code.** Read the che-code file from the current working tree. Verify the decoded `by` string exists in it. Again, decode JSON escapes before matching.
53+
54+
3. **On mismatch — propose a fix.**
55+
- Fetch the same file at `PREVIOUS_UPSTREAM_VERSION`.
56+
- Compare the `PREVIOUS_UPSTREAM_VERSION` content with the `CURRENT_UPSTREAM_VERSION` content around the area where `from` was expected.
57+
- Identify what changed and propose the corrected `from` or `by` value.
58+
59+
**Important note on escape handling in replace rules:**
60+
The replace rules use a custom escaping convention (not standard JSON escapes). For example `\\\n` means literal newline, `\\\t` means literal tab. When reading the JSON with `jq -r`, these are automatically decoded to actual newline/tab characters. Always use `jq -r '.from'` and `jq -r '.by'` to get the real strings for comparison.
61+
62+
## Step 3 — Validate `.rebase/add/` rules
63+
64+
Files under `.rebase/add/` are JSON fragments that get **merged into** upstream files using jq: `jq -s '.[1] * .[0]' <add-file> <upstream-file>` — the add-rule values take priority for conflicting keys. By convention, add rules are intended for keys absent in upstream, so conflicts should not occur.
65+
66+
### 3a — Check upstream for conflicts
67+
68+
The purpose of `add` rules is to add keys that **do not exist** in upstream. If a key now exists in upstream, the rule may be redundant or causing a silent override.
69+
70+
**For each file in `.rebase/add/`:**
71+
72+
1. Identify the upstream file path (strip `code/` prefix).
73+
2. Read the add rule JSON.
74+
3. Fetch the upstream file at `CURRENT_UPSTREAM_VERSION`.
75+
4. For every leaf key/value in the add rule, check if that key exists in the upstream file:
76+
- **Key absent in upstream** → OK, the add rule is still needed.
77+
- **Key exists with the same value** → WARNING: add rule is redundant, upstream already has this value. Consider removing it.
78+
- **Key exists with a different value** → WARNING: the add rule silently overrides the upstream value. This is a potential conflict.
79+
- For version-like values (semver): if upstream version ≥ add-rule version → the add rule may be downgrading. Report as WARNING.
80+
- For non-version values: report the upstream value vs add-rule value for manual review.
81+
82+
### 3b — Check che-code for correct application
83+
84+
Verify that the add rule values are actually present in the current che-code working tree.
85+
86+
**For each file in `.rebase/add/`:**
87+
88+
1. Identify the corresponding che-code file (same path, e.g. `.rebase/add/code/package.json``code/package.json`).
89+
2. Read the che-code file from the working tree.
90+
3. Read the add rule JSON.
91+
4. For every leaf key/value in the add rule, verify it is present in the che-code file:
92+
- For flat key-value pairs, check exact key and value presence.
93+
- For nested objects (e.g. `dependencies`, `devDependencies`, `overrides`), check that each leaf key-value from the add rule appears in the corresponding section of the che-code file.
94+
5. If a value from the add rule is **not** found in the che-code file, report it as ERROR: rule was not applied or was overwritten.
95+
96+
**Note:** For `product.json` add rules, check nested arrays and objects similarly — verify each element/key is present.
97+
98+
## Step 4 — Validate `.rebase/override/` rules
99+
100+
Files under `.rebase/override/` are JSON fragments merged **over** upstream files using jq: `jq -s '.[0] * .[1]' <upstream-file> <override-file>` — override values take priority.
101+
102+
**For each file in `.rebase/override/`:**
103+
104+
1. Identify the upstream file path (strip `code/` prefix).
105+
2. Read the override rule JSON.
106+
3. Fetch the upstream file at `CURRENT_UPSTREAM_VERSION`.
107+
4. For every leaf key in the override rule:
108+
a. **Check key still exists in upstream.** If the key no longer exists in the upstream file at `CURRENT_UPSTREAM_VERSION`, report a warning: the override may be unnecessary or the upstream structure changed.
109+
b. **For version-like values (semver patterns like `^X.Y.Z`):** Compare the upstream value with the override value. Use semver logic:
110+
- If upstream version ≥ override version → report a warning (override may no longer be needed because upstream already meets or exceeds the required version).
111+
- If upstream version < override version → OK, override is still needed.
112+
c. **For non-version values:** If the upstream value already equals the override value, report a warning (override is redundant).
113+
114+
**Semver comparison guidance:**
115+
Strip leading `^`, `~`, `>=` etc. before comparing. Compare major.minor.patch numerically. For example, `^5.1.9` override vs `^5.1.0` upstream → upstream `5.1.0 < 5.1.9` → OK. But `^5.1.9` override vs `^5.2.0` upstream → upstream `5.2.0 > 5.1.9` → warn.
116+
117+
## Step 5 — Generate the report
118+
119+
Create `rebase-rules-validation.md` in the repository root. Only create this file if there are findings to report. If all rules are valid, inform the user and do not create the file.
120+
121+
### Report format
122+
123+
```markdown
124+
# Rebase Rules Validation Report
125+
126+
> Generated against upstream `<CURRENT_UPSTREAM_VERSION>` (previous: `<PREVIOUS_UPSTREAM_VERSION>`)
127+
128+
## Critical findings
129+
130+
<!-- Numbered list of the most important actionable items, e.g.: -->
131+
1. **Short description** — Why it matters and what to do.
132+
2. ...
133+
134+
---
135+
136+
## Replace Rules
137+
138+
| Rule file | Problematic value | Proposed fix |
139+
|-----------|-------------------|--------------|
140+
| `.rebase/replace/code/src/server-main.js.json` | `"from": "const product = ..."` not found in upstream | `"from": "const product = <new value>"` |
141+
142+
## Add Rules
143+
144+
| Rule file | Issue |
145+
|-----------|-------|
146+
| `.rebase/add/code/package.json` | Key `dependencies.ws` with value `8.2.3` not found in `code/package.json` |
147+
148+
## Override Rules
149+
150+
| Rule file | Key | Issue |
151+
|-----------|-----|-------|
152+
| `.rebase/override/code/extensions/npm/package.json` | `dependencies.minimatch` | Upstream already at `^5.2.0` which is ≥ override `^5.1.9` — override may be unnecessary |
153+
```
154+
155+
### Severity indicators
156+
157+
Use these prefixes in the Issue/Proposed fix column:
158+
159+
- **ERROR**`from` or `by` value not found; rule will fail during rebase
160+
- **WARNING** — override may be unnecessary or redundant
161+
- **INFO** — value changed but rule still works
162+
163+
## Workflow summary
164+
165+
1. Fetch upstream remote.
166+
2. Extract versions from `rebase.sh`.
167+
3. Enumerate all files under `.rebase/replace/`, `.rebase/add/`, `.rebase/override/`.
168+
4. For each rule, perform the checks described above.
169+
5. Collect all findings.
170+
6. Generate `rebase-rules-validation.md` if there are findings. Otherwise report success.
171+
172+
## Parallelization guidance
173+
174+
When checking rules, launch parallel subagents or batch operations where possible:
175+
176+
- All `.rebase/replace/` rule files can be checked independently.
177+
- All `.rebase/add/` rule files can be checked independently.
178+
- All `.rebase/override/` rule files can be checked independently.
179+
- Upstream file fetches (`git show`) can be batched.
180+
181+
## Missing file handling
182+
183+
Apply these rules across all steps when a target file cannot be found:
184+
185+
| File missing | Behavior |
186+
|--------------|----------|
187+
| **Upstream file not found** (`git show` fails) | Report as ERROR: the file was likely removed or renamed in VS Code. The entire rule file is suspect and should be reviewed. |
188+
| **Che-code file not found** in working tree | Report as ERROR: the file is missing. The rule targets a file that does not exist in che-code. |
189+
190+
## Edge cases
191+
192+
- Some replace rules use multiline `from`/`by` values with `\\\n` and `\\\t` escapes. Always decode before matching.
193+
- `code/package.json` can have both replace, add, and override rules simultaneously. Check each independently.
194+
- `product.json` uses tab indentation (see `override_json_file` call with `"tab"` parameter in `rebase.sh`).

0 commit comments

Comments
 (0)