Skip to content

Commit 637b452

Browse files
Fix workflow
Signed-off-by: Roman Nikitenko <rnikiten@redhat.com>
1 parent fe4f818 commit 637b452

2 files changed

Lines changed: 100 additions & 116 deletions

File tree

Lines changed: 97 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,64 @@
11
#!/bin/bash
22
# This file was generated using AI assistance (Cursor AI) and reviewed by the maintainers.
33
#
4-
# Detect files under code/ changed since the last rebase that have no rebase
5-
# rule. Such modifications would be silently lost on the next upstream rebase.
4+
# Detect files under code/ changed in a PR whose modifications are NOT fully
5+
# protected by rebase rules. Two categories:
6+
# - "Missing rule" — no rebase rule exists for the file at all
7+
# - "Incomplete rule" — a rule exists but doesn't reproduce the current content
68
#
7-
# How it works:
8-
# 1. Finds the last rebase commit (message starts with "Rebase against the upstream")
9-
# 2. Lists files in code/ changed since that commit
10-
# 3. Filters out Che-only additions (che-* extensions, che/ subdirs) and lockfiles
11-
# 4. For remaining files, checks whether a rebase rule exists in:
12-
# - resolve_conflicts() elif chain in rebase.sh
13-
# - .rebase/replace/ (from→by rules)
14-
# - .rebase/add/ (JSON fragments merged in)
15-
# - .rebase/override/ (JSON overrides)
16-
# 5. Reports any uncovered files
9+
# For "incomplete" detection the script runs the actual rebase handler against
10+
# upstream content and diffs the result against the working tree, reusing the
11+
# test infrastructure from .claude/skills/test-rebase-rules/.
1712
#
1813
# Usage:
19-
# bash check-unprotected-changes.sh # default: changes since last rebase
20-
# bash check-unprotected-changes.sh <base>..<head> # explicit commit range
21-
# bash check-unprotected-changes.sh --verbose # show covered files too
22-
# bash check-unprotected-changes.sh --pr-comment # output as GitHub PR comment (markdown)
23-
# bash check-unprotected-changes.sh --list # output bare file paths only
14+
# bash check-unprotected-changes.sh --pr-comment <base>..<head>
15+
#
16+
# Prerequisites (for incomplete-rule detection):
17+
# - upstream-code remote must be fetched for the current upstream version
2418
#
2519
# Exit codes:
26-
# 0 — All modifications are covered by rebase rules (or are Che-only additions)
27-
# 1 — Unprotected modifications found
28-
# 2 — Error (can't find rebase commit, etc.)
20+
# 0 — All modifications are fully covered
21+
# 1 — Problems found
22+
# 2 — Error
2923
set -u
3024

3125
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3226
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
3327
cd "$REPO_ROOT"
3428

35-
VERBOSE=false
3629
OUTPUT_MODE="text"
3730
COMMIT_RANGE=""
3831
for arg in "$@"; do
3932
case "$arg" in
40-
--verbose|-v) VERBOSE=true ;;
4133
--pr-comment) OUTPUT_MODE="pr-comment" ;;
42-
--list) OUTPUT_MODE="list" ;;
4334
*..*) COMMIT_RANGE="$arg" ;;
4435
esac
4536
done
4637

47-
# --- Locate the last rebase commit ---
4838
if [ -z "$COMMIT_RANGE" ]; then
4939
REBASE_COMMIT=$(git log --format='%H' --grep="^Rebase against the upstream" -1)
5040
if [ -z "$REBASE_COMMIT" ]; then
51-
if [ "$OUTPUT_MODE" = "list" ]; then
52-
exit 2
53-
fi
54-
echo "ERROR: Could not find a rebase commit in the history."
55-
echo "Expected a commit whose message starts with 'Rebase against the upstream'."
41+
echo "ERROR: Could not find a rebase commit and no commit range provided." >&2
5642
exit 2
5743
fi
58-
REBASE_MSG=$(git log -1 --format='%s' "$REBASE_COMMIT")
5944
COMMIT_RANGE="${REBASE_COMMIT}..HEAD"
6045
fi
6146

62-
if [ "$OUTPUT_MODE" = "text" ]; then
63-
if [ -n "${REBASE_MSG:-}" ]; then
64-
echo "=== Unprotected Changes Check ==="
65-
echo "Base: $REBASE_COMMIT (${REBASE_MSG})"
66-
else
67-
echo "=== Unprotected Changes Check ==="
68-
echo "Range: $COMMIT_RANGE"
69-
fi
70-
echo ""
71-
fi
47+
UPSTREAM_VERSION=$(grep '^CURRENT_UPSTREAM_VERSION=' rebase.sh | head -1 | sed 's/.*="\(.*\)"/\1/')
48+
49+
HANDLER_SCRIPT="$REPO_ROOT/.claude/skills/test-rebase-rules/test-rebase-handler.sh"
50+
RUN_ALL_TESTS="$REPO_ROOT/.claude/skills/test-rebase-rules/run-all-tests.sh"
7251

7352
# --- Build the set of files covered by rebase rules ---
7453
COVERED_LIST=$(mktemp)
7554
trap 'rm -f "$COVERED_LIST"' EXIT
7655

77-
# 1. Parse resolve_conflicts() elif chain for explicit file paths.
7856
while IFS= read -r line; do
7957
if [[ "$line" =~ \[\[.*==.*\"([^\"]+)\".*\]\] ]]; then
8058
echo "${BASH_REMATCH[1]}"
8159
fi
8260
done < <(sed -n '/^resolve_conflicts()/,/^}/p' rebase.sh) >> "$COVERED_LIST"
8361

84-
# 2. .rebase/replace/ rules
8562
find .rebase/replace -name '*.json' -type f 2>/dev/null | while IFS= read -r rule_file; do
8663
code_path="${rule_file#.rebase/replace/}"
8764
code_path="${code_path%.json}"
@@ -91,103 +68,109 @@ find .rebase/replace -name '*.json' -type f 2>/dev/null | while IFS= read -r rul
9168
echo "$code_path"
9269
done >> "$COVERED_LIST"
9370

94-
# 3. .rebase/add/ rules
95-
find .rebase/add -type f 2>/dev/null | while IFS= read -r rule_file; do
96-
echo "${rule_file#.rebase/add/}"
97-
done >> "$COVERED_LIST"
98-
99-
# 4. .rebase/override/ rules
100-
find .rebase/override -type f 2>/dev/null | while IFS= read -r rule_file; do
101-
echo "${rule_file#.rebase/override/}"
102-
done >> "$COVERED_LIST"
71+
find .rebase/add -type f 2>/dev/null | while IFS= read -r f; do echo "${f#.rebase/add/}"; done >> "$COVERED_LIST"
72+
find .rebase/override -type f 2>/dev/null | while IFS= read -r f; do echo "${f#.rebase/override/}"; done >> "$COVERED_LIST"
10373

10474
sort -u -o "$COVERED_LIST" "$COVERED_LIST"
10575

106-
# --- Check changed files ---
107-
UNCOVERED=()
108-
COVERED_COUNT=0
109-
SKIPPED_COUNT=0
76+
# --- Collect changed files and classify ---
77+
MISSING_RULE=()
78+
TO_TEST=()
11079

11180
while IFS= read -r file_path; do
112-
# Skip package-lock.json (handled by resolve_package_lock during rebase)
11381
case "$file_path" in
114-
*/package-lock.json) ((SKIPPED_COUNT++)); continue ;;
115-
esac
116-
117-
# Skip Che-only additions — these don't exist in upstream and won't conflict
118-
case "$file_path" in
119-
code/extensions/che-*) ((SKIPPED_COUNT++)); continue ;;
120-
*/che/*.ts|*/che/*.js) ((SKIPPED_COUNT++)); continue ;;
82+
*/package-lock.json) continue ;;
83+
code/extensions/che-*) continue ;;
84+
*/che/*.ts|*/che/*.js) continue ;;
12185
esac
12286

12387
if grep -qxF "$file_path" "$COVERED_LIST"; then
124-
((COVERED_COUNT++))
125-
continue
88+
TO_TEST+=("$file_path")
89+
else
90+
MISSING_RULE+=("$file_path")
12691
fi
127-
128-
UNCOVERED+=("$file_path")
12992
done < <(git diff --name-only "$COMMIT_RANGE" -- code/)
13093

131-
# --- Output ---
94+
# --- Test files that have rules: are rules complete? ---
95+
INCOMPLETE_RULE=()
96+
HAS_UPSTREAM=false
97+
if [ -n "$UPSTREAM_VERSION" ]; then
98+
git rev-parse "upstream-code/$UPSTREAM_VERSION" > /dev/null 2>&1 && HAS_UPSTREAM=true
99+
fi
100+
101+
if [ "$HAS_UPSTREAM" = true ] && [ ${#TO_TEST[@]} -gt 0 ] && [ -f "$RUN_ALL_TESTS" ]; then
102+
TEST_OUTPUT=$(bash "$RUN_ALL_TESTS" "${TO_TEST[@]}" 2>&1) || true
132103

133-
# --list mode: bare file paths, nothing else
134-
if [ "$OUTPUT_MODE" = "list" ]; then
135-
for f in "${UNCOVERED[@]+${UNCOVERED[@]}}"; do
136-
echo "$f"
137-
done
138-
[ ${#UNCOVERED[@]} -eq 0 ] && exit 0 || exit 1
104+
while IFS= read -r line; do
105+
if [[ "$line" =~ ^\|\ \`([^\`]+)\`\ \| ]]; then
106+
failed_file="${BASH_REMATCH[1]}"
107+
INCOMPLETE_RULE+=("$failed_file")
108+
fi
109+
done < <(echo "$TEST_OUTPUT" | sed -n '/^### Failures/,/^### /p' | grep '^| `')
139110
fi
140111

141-
# --pr-comment mode: markdown for a GitHub PR comment
112+
# --- Output ---
113+
TOTAL_ISSUES=$(( ${#MISSING_RULE[@]} + ${#INCOMPLETE_RULE[@]} ))
114+
142115
if [ "$OUTPUT_MODE" = "pr-comment" ]; then
143-
if [ ${#UNCOVERED[@]} -eq 0 ]; then
116+
if [ $TOTAL_ISSUES -eq 0 ]; then
144117
exit 0
145118
fi
146-
cat <<'HEADER'
147-
<!-- rebase-rules-check -->
148-
### Missing Rebase Rules
149-
150-
The following files were modified in this PR but do not have corresponding rebase rules.
151-
Without these rules, the changes **will be lost** during the next upstream rebase.
152-
153-
| # | File |
154-
|---|------|
155-
HEADER
156-
i=1
157-
for f in "${UNCOVERED[@]}"; do
158-
echo "| $i | \`$f\` |"
159-
((i++))
160-
done
161-
echo ""
162-
echo "Comment \`/add-rebase-rules\` on this PR to add the missing rules automatically."
163-
exit 1
164-
fi
165119

166-
# Default text mode
167-
if [ "$VERBOSE" = true ]; then
168-
echo "Covered: $COVERED_COUNT | Skipped: $SKIPPED_COUNT | Uncovered: ${#UNCOVERED[@]}"
120+
echo "<!-- rebase-rules-check -->"
121+
echo "### Rebase Rules Check"
169122
echo ""
170-
echo "Rebase rules on file:"
171-
sed 's/^/ /' "$COVERED_LIST"
123+
echo "The following files were modified in this PR but their changes are **not fully protected** by rebase rules."
124+
echo "Without proper rules, these changes **will be lost** during the next upstream rebase."
172125
echo ""
126+
127+
if [ ${#MISSING_RULE[@]} -gt 0 ]; then
128+
echo "#### Missing rules (no rebase rule exists)"
129+
echo ""
130+
echo "| # | File |"
131+
echo "|---|------|"
132+
i=1
133+
for f in "${MISSING_RULE[@]}"; do
134+
echo "| $i | \`$f\` |"
135+
((i++))
136+
done
137+
echo ""
138+
fi
139+
140+
if [ ${#INCOMPLETE_RULE[@]} -gt 0 ]; then
141+
echo "#### Incomplete rules (rule exists but doesn't cover new changes)"
142+
echo ""
143+
echo "| # | File |"
144+
echo "|---|------|"
145+
i=1
146+
for f in "${INCOMPLETE_RULE[@]}"; do
147+
echo "| $i | \`$f\` |"
148+
((i++))
149+
done
150+
echo ""
151+
fi
152+
153+
echo "Comment \`/add-rebase-rules\` on this PR to add or update the rules automatically."
154+
exit 1
173155
fi
174156

175-
if [ ${#UNCOVERED[@]} -eq 0 ]; then
176-
echo "All modified files in code/ are covered by rebase rules (or are Che-only additions)."
177-
echo " Covered: $COVERED_COUNT Skipped (lockfiles/Che-only): $SKIPPED_COUNT"
157+
# Default text mode
158+
if [ $TOTAL_ISSUES -eq 0 ]; then
159+
echo "All modified files in code/ are fully covered by rebase rules."
178160
exit 0
179161
fi
180162

181-
echo "**Found ${#UNCOVERED[@]} file(s) modified since the last rebase without rebase rules:**"
182-
echo ""
183-
for f in "${UNCOVERED[@]}"; do
184-
echo " - $f"
185-
done
186-
echo ""
187-
echo "These changes will be lost on the next upstream rebase unless a rule is added."
163+
echo "Found $TOTAL_ISSUES file(s) with rebase rule problems:"
188164
echo ""
189-
echo "To fix, for each file above either:"
190-
echo " 1. Add a .rebase/replace/<path>.json with {\"from\": ..., \"by\": ...} rules"
191-
echo " 2. Add a .rebase/add/<path> or .rebase/override/<path> JSON fragment"
192-
echo " 3. Add an elif branch in resolve_conflicts() in rebase.sh"
165+
if [ ${#MISSING_RULE[@]} -gt 0 ]; then
166+
echo "Missing rules:"
167+
for f in "${MISSING_RULE[@]}"; do echo " - $f"; done
168+
echo ""
169+
fi
170+
if [ ${#INCOMPLETE_RULE[@]} -gt 0 ]; then
171+
echo "Incomplete rules:"
172+
for f in "${INCOMPLETE_RULE[@]}"; do echo " - $f"; done
173+
echo ""
174+
fi
175+
echo "Comment /add-rebase-rules on this PR to fix automatically."
193176
exit 1

.github/workflows/check-rebase-rules.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ jobs:
3131
with:
3232
fetch-depth: 0
3333

34-
- name: Fetch upstream remote
34+
- name: Fetch upstream for rule validation
3535
run: |
36+
UPSTREAM_VERSION=$(grep '^CURRENT_UPSTREAM_VERSION=' rebase.sh | head -1 | sed 's/.*="\(.*\)"/\1/')
3637
git remote add upstream-code https://github.com/microsoft/vscode || true
37-
git fetch upstream-code --no-tags --depth=1
38+
git fetch upstream-code "$UPSTREAM_VERSION" --no-tags --depth=1
3839
3940
- name: Run rebase rules check
4041
id: check

0 commit comments

Comments
 (0)