From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE9B81946A0 for ; Sat, 26 Jul 2025 01:16:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.137.202.133 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753492616; cv=none; b=mV24TokOh3DHSJiuWl8CFJLdVz5MdBj3w9mmeMlZfxMykhV3cnSsNgQApbxhiUzPX3qz9ZVynIlzE1s+zsl0w4EkJEpaiL/B4zO/G7CP0cVjfF8p8EcoA62hSOXzGKW5BF8d4kP3vKCgRDwUlDjbysGG5GHlkO0Kd8Yd+2X5Ie0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753492616; c=relaxed/simple; bh=PoAInpv2hDvkGcRg7ZRt4aQxmhNGNaxXtP45bXDQ+FQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=uVUOo2uiUnIb0NcBw7GD6w6mg0CFkpX4Q4fcy0vy2l9fi7s9xqWjtbJ3sPi+ejIqXDrlAExqg8a4vyPHptNFCINRBAnUyo0rbFU0aN1vjbBSQu1/4I2NPHbB5kaTpNDrDmz2bBJINJys9TJw310A/ULDkXsh8P7s1OdipZcLmqo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=kernel.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=yfxj6gCy; arc=none smtp.client-ip=198.137.202.133 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=kernel.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="yfxj6gCy" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc: To:From:Reply-To:Content-ID:Content-Description; bh=1Kf1DlEQrLGAU8khz4vKB/VRwDK1ryC98IKSvYMhR88=; b=yfxj6gCyYfzCuv+JpaK0s78sZ1 pIHIIcbojgqOhWTUib9WXvWPTSwlyPEFJg+fCURy6q3FUG8ruxPANsDNASts1oSkXtevv9iRq/3mC cpyHzIm7A9g3iML9d0PkwBwrD2dVtbvWgeGlSBRUGIzNXOXIB2vSwHC03YeCao2cLDjNw0aomsoFI motJ/pCClRn/KecEtYne4/hmsayHkRA3Kn1v0ib8lSPMTPZ4XZpF0TapnQobhRhvm8gRa585/t0Ew X9mPIcKmv7gh4zUJv9BTJejccY7y8Np8yu+wbhEN//VQ69iVN+trhw6mLs8/VtELudezeNXBtTUdx tH+IvOUQ==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.98.2 #2 (Red Hat Linux)) id 1ufTWw-0000000B0HJ-1AqL; Sat, 26 Jul 2025 01:16:54 +0000 From: Luis Chamberlain To: Chuck Lever , Daniel Gomez , kdevops@lists.linux.dev Cc: Luis Chamberlain Subject: [PATCH 1/4] Makefile: add make style for style checking Date: Fri, 25 Jul 2025 18:16:49 -0700 Message-ID: <20250726011653.2622672-2-mcgrof@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250726011653.2622672-1-mcgrof@kernel.org> References: <20250726011653.2622672-1-mcgrof@kernel.org> Precedence: bulk X-Mailing-List: kdevops@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: Luis Chamberlain 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 --- 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 +``` + +**WRONG** - Do NOT add empty lines between Generated-by and Signed-off-by: +``` +Generated-by: Claude AI + +Signed-off-by: Your Name +``` + +**WRONG** - Do NOT add extra empty lines: +``` +Generated-by: Claude AI + + +Signed-off-by: Your Name +``` + +## 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 ") + 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