From: Luis Chamberlain <mcgrof@kernel.org>
To: Chuck Lever <cel@kernel.org>, Daniel Gomez <da.gomez@kruces.com>,
kdevops@lists.linux.dev
Cc: Luis Chamberlain <mcgrof@kernel.org>
Subject: [PATCH 1/4] Makefile: add make style for style checking
Date: Fri, 25 Jul 2025 18:16:49 -0700 [thread overview]
Message-ID: <20250726011653.2622672-2-mcgrof@kernel.org> (raw)
In-Reply-To: <20250726011653.2622672-1-mcgrof@kernel.org>
Add a 'make style' which helps humans and bots follow some sensible
coding conventions.
- Add scripts/detect_whitespace_issues.py check for white space eye sores
- Add scripts/check_commit_format.py to validate Generated-by and the
Signed-off-by spacing
- Add scripts/fix_whitespace_issues.py to help with stupid spacing
eyesores
- Update CLAUDE.md to ensure it runs 'make style'
Generated-by: Claude AI
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
CLAUDE.md | 61 +++++++++++++
Makefile | 5 +
kdevops-ci | 1 +
scripts/check_commit_format.py | 85 +++++++++++++++++
scripts/detect_whitespace_issues.py | 109 ++++++++++++++++++++++
scripts/fix_whitespace_issues.py | 137 ++++++++++++++++++++++++++++
6 files changed, 398 insertions(+)
create mode 160000 kdevops-ci
create mode 100755 scripts/check_commit_format.py
create mode 100755 scripts/detect_whitespace_issues.py
create mode 100755 scripts/fix_whitespace_issues.py
diff --git a/CLAUDE.md b/CLAUDE.md
index 8bee7c0..ea7c0ff 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -89,6 +89,7 @@ make help # Show available targets
make V=1 [target] # Verbose build output
make AV=1-6 [target] # Ansible verbose output (levels 0-6)
make dynconfig # Generate dynamic configuration
+make style # Check for whitespace issues - ALWAYS run before completing work
make mrproper # Clean everything and restart from scratch
```
@@ -211,6 +212,66 @@ Developer Certificate or Origin.
Use this tag for code generated by Claude code AI. Put this before the
Signed-off-by tag.
+**CRITICAL FORMATTING RULE**: When using "Generated-by: Claude AI", it MUST be
+immediately followed by the "Signed-off-by:" tag with NO empty lines between them.
+These two lines must be consecutive.
+
+Correct format:
+```
+Subject line
+
+Detailed description of changes...
+
+Generated-by: Claude AI
+Signed-off-by: Your Name <email@example.com>
+```
+
+**WRONG** - Do NOT add empty lines between Generated-by and Signed-off-by:
+```
+Generated-by: Claude AI
+
+Signed-off-by: Your Name <email@example.com>
+```
+
+**WRONG** - Do NOT add extra empty lines:
+```
+Generated-by: Claude AI
+
+
+Signed-off-by: Your Name <email@example.com>
+```
+
+## Code Quality Requirements
+
+**IMPORTANT**: Before completing any work, you MUST run `make style` to check for
+both whitespace issues and commit message formatting. This ensures code consistency
+and prevents formatting issues from being introduced into the codebase.
+
+The style checker will identify:
+- Trailing whitespace
+- Mixed tabs and spaces
+- Files without newlines at EOF
+- Other whitespace-related issues
+- Incorrect commit message formatting (Generated-by/Signed-off-by spacing)
+
+Fix all reported issues before submitting your work. The `make style` command
+checks both file whitespace and the most recent commit message format.
+
+### Automatic Whitespace Fixing
+
+For convenience, you can automatically fix whitespace issues using:
+```bash
+python3 scripts/fix_whitespace_issues.py # Fix all modified files
+python3 scripts/fix_whitespace_issues.py file1 file2 # Fix specific files
+```
+
+The fixer script will:
+- Remove trailing whitespace from lines
+- Add missing newlines at end of files
+- Reduce excessive blank lines to maximum 2 consecutive
+
+Always run `make style` after using the fixer to verify all issues are resolved.
+
## Prompt Examples
Refer to PROMPTS.md for example set of prompts used to generate code on
diff --git a/Makefile b/Makefile
index c6a5c32..bfff8f9 100644
--- a/Makefile
+++ b/Makefile
@@ -243,6 +243,11 @@ include scripts/ci.Makefile
include scripts/archive.Makefile
include scripts/defconfig.Makefile
+PHONY += style
+style:
+ $(Q)python3 scripts/detect_whitespace_issues.py
+ $(Q)python3 scripts/check_commit_format.py
+
PHONY += clean
clean:
$(Q)$(MAKE) -f scripts/build.Makefile $@
diff --git a/kdevops-ci b/kdevops-ci
new file mode 160000
index 0000000..8120607
--- /dev/null
+++ b/kdevops-ci
@@ -0,0 +1 @@
+Subproject commit 812060752af00e601add5716c3180fbb21c41784
diff --git a/scripts/check_commit_format.py b/scripts/check_commit_format.py
new file mode 100755
index 0000000..f72f9d1
--- /dev/null
+++ b/scripts/check_commit_format.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+"""
+Commit Message Format Checker for kdevops
+
+This script checks the most recent commit message for proper formatting:
+- If "Generated-by: Claude AI" is present, it must be immediately followed by
+ "Signed-off-by:" with no blank lines in between
+"""
+
+import subprocess
+import sys
+import re
+
+def get_latest_commit_message():
+ """Get the latest commit message"""
+ try:
+ result = subprocess.run(['git', 'log', '-1', '--pretty=format:%B'],
+ capture_output=True, text=True, check=True)
+ return result.stdout
+ except subprocess.CalledProcessError:
+ print("Error: Failed to get commit message")
+ return None
+ except FileNotFoundError:
+ print("Error: git command not found")
+ return None
+
+def check_commit_format(commit_msg):
+ """Check commit message formatting"""
+ issues = []
+ if not commit_msg:
+ return ["No commit message found"]
+ lines = commit_msg.strip().split('\n')
+ # Find Generated-by line
+ generated_by_idx = None
+ signed_off_by_idx = None
+ for i, line in enumerate(lines):
+ if line.startswith('Generated-by: Claude AI'):
+ generated_by_idx = i
+ elif line.startswith('Signed-off-by:'):
+ signed_off_by_idx = i
+ # If Generated-by is present, check formatting
+ if generated_by_idx is not None:
+ if signed_off_by_idx is None:
+ issues.append("Generated-by: Claude AI found but no Signed-off-by tag present")
+ else:
+ # Check if Generated-by is immediately followed by Signed-off-by (no lines in between)
+ if signed_off_by_idx != generated_by_idx + 1:
+ lines_between = signed_off_by_idx - generated_by_idx - 1
+ if lines_between > 0:
+ issues.append(f"Generated-by: Claude AI must be immediately followed by Signed-off-by (found {lines_between} lines between them)")
+ for i in range(generated_by_idx + 1, signed_off_by_idx):
+ if lines[i].strip():
+ issues.append(f" - Non-empty line at {i+1}: '{lines[i]}'")
+ else:
+ issues.append(f" - Empty line at {i+1}")
+ return issues
+
+def main():
+ """Main function to check commit message format"""
+ commit_msg = get_latest_commit_message()
+ if commit_msg is None:
+ return 1
+ issues = check_commit_format(commit_msg)
+ if issues:
+ print("❌ Commit message formatting issues found:")
+ for issue in issues:
+ print(f" ⚠️ {issue}")
+ print("\nLatest commit message:")
+ print("=" * 50)
+ print(commit_msg)
+ print("=" * 50)
+ print("\nCorrect format when using Generated-by:")
+ print("Subject line")
+ print("")
+ print("Detailed description...")
+ print("")
+ print("Generated-by: Claude AI")
+ print("Signed-off-by: Your Name <email@example.com>")
+ return 1
+ else:
+ print("✅ Commit message formatting is correct!")
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/scripts/detect_whitespace_issues.py b/scripts/detect_whitespace_issues.py
new file mode 100755
index 0000000..165a33e
--- /dev/null
+++ b/scripts/detect_whitespace_issues.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+"""
+Whitespace Issue Detector for kdevops
+
+This script detects common whitespace issues that Claude AI tends to introduce:
+- Trailing whitespace at end of lines
+- Missing newline at end of file
+- Excessive blank lines
+"""
+
+import os
+import sys
+from pathlib import Path
+
+def check_file_whitespace(file_path):
+ """Check a single file for whitespace issues"""
+ issues = []
+
+ try:
+ with open(file_path, 'rb') as f:
+ content = f.read()
+
+ # Skip binary files
+ if b'\0' in content:
+ return issues
+
+ lines = content.decode('utf-8', errors='ignore').splitlines(keepends=True)
+
+ # Check trailing whitespace
+ for line_num, line in enumerate(lines, 1):
+ if line.rstrip('\n\r').endswith(' ') or line.rstrip('\n\r').endswith('\t'):
+ issues.append(f"Line {line_num}: Trailing whitespace")
+
+ # Check missing newline at end of file
+ if content and not content.endswith(b'\n'):
+ issues.append("Missing newline at end of file")
+
+ # Check for excessive blank lines (more than 2 consecutive)
+ blank_count = 0
+ for line_num, line in enumerate(lines, 1):
+ if line.strip() == '':
+ blank_count += 1
+ else:
+ if blank_count > 2:
+ issues.append(f"Line {line_num - blank_count}: {blank_count} consecutive blank lines")
+ blank_count = 0
+
+ except Exception as e:
+ issues.append(f"Error reading file: {e}")
+
+ return issues
+
+def main():
+ """Main function to scan for whitespace issues"""
+ if len(sys.argv) > 1:
+ paths = sys.argv[1:]
+ else:
+ # Default to git tracked files with modifications
+ import subprocess
+ try:
+ result = subprocess.run(['git', 'diff', '--name-only'],
+ capture_output=True, text=True, check=True)
+ paths = result.stdout.strip().split('\n') if result.stdout.strip() else []
+ if not paths:
+ print("No modified files found in git")
+ return
+ except subprocess.CalledProcessError:
+ print("Error: Not in a git repository or git command failed")
+ return
+ except FileNotFoundError:
+ print("Error: git command not found")
+ return
+
+ total_issues = 0
+ files_with_issues = 0
+
+ for path_str in paths:
+ path = Path(path_str)
+ if not path.exists():
+ print(f"Warning: {path} does not exist")
+ continue
+
+ if path.is_file():
+ # Skip certain file types
+ if path.suffix in ['.pyc', '.so', '.o', '.bin', '.jpg', '.png', '.gif']:
+ continue
+
+ issues = check_file_whitespace(path)
+ if issues:
+ files_with_issues += 1
+ total_issues += len(issues)
+ print(f"\n{path}:")
+ for issue in issues:
+ print(f" ⚠️ {issue}")
+
+ print(f"\nSummary: {total_issues} whitespace issues found in {files_with_issues} files")
+
+ if total_issues > 0:
+ print("\nTo fix these issues:")
+ print("- Remove trailing spaces/tabs from lines")
+ print("- Add newline at end of files")
+ print("- Reduce excessive blank lines to 1-2 maximum")
+ return 1
+ else:
+ print("✅ No whitespace issues found!")
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/scripts/fix_whitespace_issues.py b/scripts/fix_whitespace_issues.py
new file mode 100755
index 0000000..3e69ea5
--- /dev/null
+++ b/scripts/fix_whitespace_issues.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+"""
+Whitespace Issue Fixer for kdevops
+
+This script fixes common whitespace issues that Claude AI tends to introduce:
+- Trailing whitespace at end of lines
+- Missing newline at end of file
+- Excessive blank lines (reduces to maximum 2 consecutive)
+"""
+
+import os
+import sys
+from pathlib import Path
+
+def fix_file_whitespace(file_path):
+ """Fix whitespace issues in a single file"""
+ issues_fixed = []
+
+ try:
+ with open(file_path, 'rb') as f:
+ content = f.read()
+
+ # Skip binary files
+ if b'\0' in content:
+ return issues_fixed
+
+ original_content = content.decode('utf-8', errors='ignore')
+ lines = original_content.splitlines(keepends=True)
+ modified = False
+
+ # Fix trailing whitespace
+ new_lines = []
+ for line_num, line in enumerate(lines, 1):
+ original_line = line
+ # Remove trailing whitespace but preserve line endings
+ if line.endswith('\r\n'):
+ cleaned_line = line.rstrip(' \t\r\n') + '\r\n'
+ elif line.endswith('\n'):
+ cleaned_line = line.rstrip(' \t\n') + '\n'
+ else:
+ cleaned_line = line.rstrip(' \t')
+
+ if original_line != cleaned_line:
+ issues_fixed.append(f"Line {line_num}: Removed trailing whitespace")
+ modified = True
+
+ new_lines.append(cleaned_line)
+
+ # Fix excessive blank lines (reduce to maximum 2 consecutive)
+ final_lines = []
+ blank_count = 0
+ i = 0
+ while i < len(new_lines):
+ line = new_lines[i]
+ if line.strip() == '':
+ blank_count += 1
+ if blank_count <= 2:
+ final_lines.append(line)
+ else:
+ issues_fixed.append(f"Line {i+1}: Removed excessive blank line")
+ modified = True
+ else:
+ blank_count = 0
+ final_lines.append(line)
+ i += 1
+
+ # Fix missing newline at end of file
+ new_content = ''.join(final_lines)
+ if new_content and not new_content.endswith('\n'):
+ new_content += '\n'
+ issues_fixed.append("Added missing newline at end of file")
+ modified = True
+
+ # Write back if modified
+ if modified:
+ with open(file_path, 'w', encoding='utf-8') as f:
+ f.write(new_content)
+
+ except Exception as e:
+ issues_fixed.append(f"Error processing file: {e}")
+
+ return issues_fixed
+
+def main():
+ """Main function to fix whitespace issues"""
+ if len(sys.argv) > 1:
+ paths = sys.argv[1:]
+ else:
+ # Default to git tracked files with modifications
+ import subprocess
+ try:
+ result = subprocess.run(['git', 'diff', '--name-only'],
+ capture_output=True, text=True, check=True)
+ paths = result.stdout.strip().split('\n') if result.stdout.strip() else []
+ if not paths:
+ print("No modified files found in git")
+ return 0
+ except subprocess.CalledProcessError:
+ print("Error: Not in a git repository or git command failed")
+ return 1
+ except FileNotFoundError:
+ print("Error: git command not found")
+ return 1
+
+ total_fixes = 0
+ files_fixed = 0
+
+ for path_str in paths:
+ path = Path(path_str)
+ if not path.exists():
+ print(f"Warning: {path} does not exist")
+ continue
+
+ if path.is_file():
+ # Skip certain file types
+ if path.suffix in ['.pyc', '.so', '.o', '.bin', '.jpg', '.png', '.gif']:
+ continue
+
+ fixes = fix_file_whitespace(path)
+ if fixes:
+ files_fixed += 1
+ total_fixes += len(fixes)
+ print(f"\n{path}:")
+ for fix in fixes:
+ print(f" ✅ {fix}")
+
+ print(f"\nSummary: {total_fixes} whitespace issues fixed in {files_fixed} files")
+
+ if total_fixes > 0:
+ print("✅ Whitespace issues have been automatically fixed!")
+ return 0
+ else:
+ print("✅ No whitespace issues found to fix!")
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
--
2.47.2
next prev parent reply other threads:[~2025-07-26 1:16 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-26 1:16 [PATCH 0/4] kdevops: add support for A/B testing Luis Chamberlain
2025-07-26 1:16 ` Luis Chamberlain [this message]
2025-07-26 1:16 ` [PATCH 2/4] CLAUDE.md: new workflow guide for hosts and nodes Luis Chamberlain
2025-07-26 1:16 ` [PATCH 3/4] gen_nodes/gen_hosts: avoid usage of fs_config_path on task names Luis Chamberlain
2025-07-26 1:16 ` [PATCH 4/4] bootlinux: add support for A/B kernel testing Luis Chamberlain
2025-07-26 18:00 ` Chuck Lever
2025-07-26 20:21 ` Luis Chamberlain
2025-07-26 21:37 ` Luis Chamberlain
2025-07-26 22:46 ` Luis Chamberlain
2025-07-26 23:16 ` Chuck Lever
2025-07-26 23:34 ` Luis Chamberlain
2025-07-26 23:35 ` Chuck Lever
2025-07-27 0:06 ` Luis Chamberlain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250726011653.2622672-2-mcgrof@kernel.org \
--to=mcgrof@kernel.org \
--cc=cel@kernel.org \
--cc=da.gomez@kruces.com \
--cc=kdevops@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox