public inbox for kdevops@lists.linux.dev
 help / color / mirror / Atom feed
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 v2 30/33] Makefile: add make style for style checking
Date: Sun, 27 Jul 2025 18:14:30 -0700	[thread overview]
Message-ID: <20250728011434.3197091-31-mcgrof@kernel.org> (raw)
In-Reply-To: <20250728011434.3197091-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 8bee7c08..ea7c0fff 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 38f7c5a2..ae976865 100644
--- a/Makefile
+++ b/Makefile
@@ -238,6 +238,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 00000000..81206075
--- /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 00000000..f72f9d1a
--- /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 00000000..165a33e2
--- /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 00000000..3e69ea50
--- /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


  parent reply	other threads:[~2025-07-28  1:14 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-28  1:14 [PATCH v2 00/33] remove vagrant and bootlinux shape up Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 01/33] vagrant: remove entire vagrant configuration directory Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 02/33] kconfigs: fix Kconfig references after vagrant removal Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 03/33] scripts: remove Vagrant-specific scripts and Makefiles Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 04/33] playbooks: remove Vagrant-specific playbooks and roles Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 05/33] gitignore: remove Vagrant-specific ignore patterns Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 06/33] docs: remove Vagrant-specific documentation files Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 07/33] Remove all remaining Vagrant references from codebase Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 08/33] terraform: Clean up the destroy tasks Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 09/33] Switch to the cloud.terraform.terraform module Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 10/33] terraform: Make use of the new "terraform_output" module Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 11/33] terraform: Move "wait_for_connection" out of the terraform playbook Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 12/33] terraform: Remove "delegate_to: localhost" Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 13/33] terraform: Replace scripts/status_terraform.sh Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 14/33] Kconfig: Convert the 9p option to a choice menu Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 15/33] bootlinux: fix making 9p default if using libvirt Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 16/33] bootlinux: Relocate tasks that select a kernel .config Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 17/33] bootlinux: Simplify tasks that select the kernel .config to build Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 18/33] bootlinux: Select the kernel .config earlier Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 19/33] bootlinux: Move 9p build tasks to a subrole Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 20/33] bootlinux: Move tasks for building on target nodes " Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 21/33] bootlinux: Clean up a grub set-up task Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 22/33] bootlinux: Harden update-grub/install.yml Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 23/33] Add a guest/instance for building the test kernel Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 24/33] bootlinux: Add a new builder choice Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 25/33] workflows: Add a kconfig setting for installing kernels via package Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 26/33] bootlinux: Enclose tasks to find kernel release name in a block: Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 27/33] bootlinux: Pick up kernel release info for pre-built packages Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 28/33] bootlinux: Install pre-built kernels from packages Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 29/33] bootlinux: Add an option to build with clang instead of gcc Luis Chamberlain
2025-07-28  1:14 ` Luis Chamberlain [this message]
2025-07-28  1:14 ` [PATCH v2 31/33] CLAUDE.md: new workflow guide for hosts and nodes Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 32/33] CLAUDE.md: add don't BS rules Luis Chamberlain
2025-07-28  1:14 ` [PATCH v2 33/33] gen_nodes/gen_hosts: avoid usage of fs_config_path on task names Luis Chamberlain
2025-07-29 20:07 ` [PATCH v2 00/33] remove vagrant and bootlinux shape up 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=20250728011434.3197091-31-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