Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/workflows/test-pr-title-validation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/bash
# Test script for PR title validation
# This script validates that the PR title validation regex works correctly
# Usage: ./test-pr-title-validation.sh

set -eo pipefail

# Use the same pattern as in validate-commits.yml
PATTERN='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_/-]+\))?!?: [a-z].{2,}$'

PASS_COUNT=0
FAIL_COUNT=0

Check warning on line 12 in .github/workflows/test-pr-title-validation.sh

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.github/workflows/test-pr-title-validation.sh#L12

FAIL_COUNT appears unused. Verify use (or export if used externally).
ERROR_COUNT=0

test_title() {
local title="$1"
local should_pass="$2"
local description="$3"

if [[ "$title" =~ $PATTERN ]]; then
result="PASS"
else
result="FAIL"
fi

if [ "$should_pass" = "$result" ]; then
PASS_COUNT=$((PASS_COUNT + 1))
printf " ✅ %-6s: %s\n" "$result" "$title"
else
ERROR_COUNT=$((ERROR_COUNT + 1))
printf " 🔴 %-6s: %s (expected: %s) - %s\n" "$result" "$title" "$should_pass" "$description"
fi
}

echo "=========================================="
echo "PR Title Validation Test Suite"
echo "=========================================="
echo ""
echo "Pattern: $PATTERN"
echo ""

echo "Valid PR titles (should PASS):"
test_title "feat: add wifi support" "PASS" "Basic feature"
test_title "fix: resolve connection issue" "PASS" "Basic fix"
test_title "docs: update readme" "PASS" "Basic docs"
test_title "feat(wifi): add reconnection" "PASS" "Feature with scope"
test_title "fix(mqtt): handle crash" "PASS" "Fix with scope"
test_title "feat!: breaking change" "PASS" "Breaking change without scope"
test_title "feat(api)!: remove endpoint" "PASS" "Breaking change with scope"
test_title "fix(wifi/manager): resolve issue" "PASS" "Scope with slash"
test_title "feat(esp32-s3): add support" "PASS" "Scope with hyphen"
test_title "chore: bump version to 1.0.46" "PASS" "Version bump"
test_title "refactor: simplify config loader" "PASS" "Refactoring"
test_title "perf: reduce memory usage" "PASS" "Performance improvement"
test_title "test: add unit tests" "PASS" "Tests"
test_title "build: update dependencies" "PASS" "Build changes"
test_title "ci: update workflow" "PASS" "CI changes"
test_title "style: format code" "PASS" "Style changes"
test_title "revert: previous commit" "PASS" "Revert"

echo ""
echo "Invalid PR titles (should FAIL):"
test_title "Feat: add feature" "FAIL" "Capitalized type"
test_title "FEAT: add feature" "FAIL" "Uppercase type"
test_title "feat :add feature" "FAIL" "Space before colon"
test_title "feat:add feature" "FAIL" "No space after colon"
test_title "feat(scope):add feature" "FAIL" "No space after colon with scope"
test_title "feat: " "FAIL" "Empty description"
test_title "feat:" "FAIL" "No description"
test_title "Add feature" "FAIL" "No type"
test_title "add feature" "FAIL" "Invalid type"
test_title "feat: a" "FAIL" "Single character description"
test_title "feat: ab" "FAIL" "Two character description"
test_title "feat: double space" "FAIL" "Multiple spaces after colon"
test_title "feat(any scope with spaces): desc" "FAIL" "Scope with spaces"
test_title "feat(CAPS): description" "FAIL" "Capitalized scope"
test_title "feat: Add feature" "FAIL" "Capitalized description"
test_title "feat: ADD FEATURE" "FAIL" "Uppercase description"
test_title "feat(scope!): description" "FAIL" "Exclamation in scope"
test_title "feat(scope@version): desc" "FAIL" "Special char in scope"

echo ""
echo "=========================================="
echo "Test Results"
echo "=========================================="
echo "Correct validations: $PASS_COUNT"
echo "Incorrect validations: $ERROR_COUNT"
echo ""

if [ $ERROR_COUNT -eq 0 ]; then
echo "✅ All tests passed!"
exit 0
else
echo "❌ Some tests failed!"
exit 1
fi
24 changes: 21 additions & 3 deletions .github/workflows/validate-commits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ jobs:

# Conventional commits regex pattern
# Matches: type[(scope)][!]: description
# Where type is one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
PATTERN='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .{1,}'
# Where:
# - type: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert (lowercase)
# - scope: optional, lowercase alphanumeric with hyphens/underscores/slashes
# - !: optional breaking change indicator
# - description: must start with lowercase, at least 3 characters total
PATTERN='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_/-]+\))?!?: [a-z].{2,}$'

if [[ ! "$PR_TITLE" =~ $PATTERN ]]; then
echo "================================================"
Expand All @@ -34,12 +38,26 @@ jobs:
echo ""
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
echo ""
echo "Requirements:"
echo " • Type must be lowercase"
echo " • Scope (optional) must be lowercase, alphanumeric with -/_"
echo " • Must have exactly ONE space after the colon"
echo " • Description must start with lowercase letter"
echo " • Description must be at least 3 characters"
echo ""
echo "Examples:"
echo " ✅ feat: add WiFi reconnection logic"
echo " ✅ fix(mqtt): handle reconnect crash"
echo " ✅ docs: update README with setup steps"
echo " ✅ docs: update readme with setup steps"
echo " ✅ feat!: remove deprecated API"
echo ""
echo "Common mistakes:"
echo " ❌ feat: a (description too short)"
echo " ❌ feat: double space (multiple spaces)"
echo " ❌ Feat: capitalized type"
echo " ❌ feat: Add (capitalized description)"
echo " ❌ feat(Bad Scope): invalid scope"
echo ""
echo "Please see CONTRIBUTING.md for more details."
exit 1
else
Expand Down
27 changes: 24 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,36 @@
BREAKING CHANGE: WiFi.connect() now requires explicit credentials parameter
```

## Requirements

The PR title validation enforces these rules:

- **Type**: Must be lowercase (e.g., `feat`, not `Feat`)
- **Scope**: Optional, must be lowercase alphanumeric with hyphens, underscores, or slashes (e.g., `wifi`, `mqtt`, `esp32-s3`, `wifi/manager`)
- **Separator**: Must have exactly ONE space after the colon (`: `)

Check notice on line 57 in CONTRIBUTING.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

CONTRIBUTING.md#L57

Spaces inside code span elements
- **Description**: Must start with a lowercase letter and be at least 3 characters long
- Individual commits within the PR can use any format

## Common Mistakes

Avoid these common errors:

- ❌ `Feat: add feature` - Type must be lowercase
- ❌ `feat: Add feature` - Description must start with lowercase
- ❌ `feat:add feature` - Missing space after colon
- ❌ `feat: add feature` - Multiple spaces after colon
- ❌ `feat: a` - Description too short (minimum 3 characters)
- ❌ `feat(Bad Scope): add` - Scope must be lowercase
- ❌ `feat(scope with spaces): add` - Scope can't contain spaces
- ✅ `feat: add feature` - Correct format

## Tips

- Keep the PR title under 72 characters
- Use lowercase for type and description
- Don't end the PR title with a period
- Use the imperative mood ("add feature" not "added feature")
- Be concise and specific
- Be concise but meaningful (avoid very short descriptions)
- Reference issues when possible (e.g., `fixes #123`)
- Individual commits within the PR can use any format

## Before pull requests

Expand Down
106 changes: 106 additions & 0 deletions PR_VALIDATION_FIX_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# PR Title Validation Fix Summary

## Problem Statement

The PR title validation workflow was not properly enforcing Conventional Commits specification, allowing non-compliant PR titles to pass validation.

## Bugs Identified

### 1. Single-character descriptions accepted

Check notice on line 9 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L9

Expected: 1; Actual: 0; Below
- ❌ Before: `feat: a` → **PASSED** (should fail)

Check notice on line 10 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L10

Lists should be surrounded by blank lines
- ✅ After: `feat: a` → **FAILED** (correctly)

### 2. Multiple spaces after colon accepted

Check notice on line 13 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L13

Expected: 1; Actual: 0; Below
- ❌ Before: `feat: description` → **PASSED** (should fail)

Check notice on line 14 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L14

Lists should be surrounded by blank lines
- ✅ After: `feat: description` → **FAILED** (correctly)

### 3. Scopes with spaces/special chars accepted

Check notice on line 17 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L17

Expected: 1; Actual: 0; Below
- ❌ Before: `feat(bad scope): desc` → **PASSED** (should fail)

Check notice on line 18 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L18

Lists should be surrounded by blank lines
- ✅ After: `feat(bad scope): desc` → **FAILED** (correctly)

### 4. Uppercase descriptions accepted

Check notice on line 21 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L21

Expected: 1; Actual: 0; Below
- ❌ Before: `feat: Add feature` → **PASSED** (should fail)

Check notice on line 22 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L22

Lists should be surrounded by blank lines
- ✅ After: `feat: Add feature` → **FAILED** (correctly)

### 5. Uppercase scopes accepted

Check notice on line 25 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L25

Expected: 1; Actual: 0; Below
- ❌ Before: `feat(CAPS): desc` → **PASSED** (should fail)

Check notice on line 26 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L26

Lists should be surrounded by blank lines
- ✅ After: `feat(CAPS): desc` → **FAILED** (correctly)

## Changes Made

### 1. Updated Regex Pattern

**Before:**
```regex
^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .{1,}
```

**Issues with old pattern:**
- `\(.+\)` - Allows any characters in scope (spaces, special chars, uppercase)

Check notice on line 39 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L39

Lists should be surrounded by blank lines
- ` .{1,}` - Allows multiple spaces and single-char descriptions

Check notice on line 40 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L40

Spaces inside code span elements

**After:**
```regex
^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_/-]+\))?!?: [a-z].{2,}$
```

**Improvements:**
- `\([a-z0-9_/-]+\)` - Scope limited to lowercase alphanumeric with hyphens, underscores, slashes

Check notice on line 48 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L48

Lists should be surrounded by blank lines
- `: ` - Exactly one space required after colon

Check notice on line 49 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L49

Spaces inside code span elements
- `[a-z].{2,}` - Description must start with lowercase letter and be at least 3 chars total
- `$` - Anchors at end to prevent trailing content

### 2. Enhanced Error Messages

Added detailed requirements and common mistakes to the validation error output:

```
Requirements:
• Type must be lowercase
• Scope (optional) must be lowercase, alphanumeric with -/_
• Must have exactly ONE space after the colon
• Description must start with lowercase letter
• Description must be at least 3 characters

Common mistakes:
❌ feat: a (description too short)
❌ feat: double space (multiple spaces)
❌ Feat: capitalized type
❌ feat: Add (capitalized description)
❌ feat(Bad Scope): invalid scope
```

### 3. Updated CONTRIBUTING.md

- Added explicit "Requirements" section
- Added "Common Mistakes" section with examples
- Clarified that description must be meaningful (3+ chars)
- Documented scope character restrictions

### 4. Added Comprehensive Test Suite

Created `test-pr-title-validation.sh` with 35 test cases covering:
- 17 valid PR title formats

Check notice on line 83 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L83

Lists should be surrounded by blank lines
- 18 invalid PR title formats
- All edge cases that were previously bugs

## Validation Results

All 35 test cases pass:
- ✅ 17 valid titles correctly accepted

Check notice on line 90 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L90

Lists should be surrounded by blank lines
- ✅ 18 invalid titles correctly rejected
- ✅ 0 incorrect validations

## Impact

This fix ensures that:
1. All PR titles strictly follow Conventional Commits specification

Check notice on line 97 in PR_VALIDATION_FIX_SUMMARY.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

PR_VALIDATION_FIX_SUMMARY.md#L97

Lists should be surrounded by blank lines
2. Release notes will have consistent, high-quality commit messages
3. Automated tooling can reliably parse commit types and scopes
4. Contributors get clear, actionable error messages when validation fails

## Files Modified

1. `.github/workflows/validate-commits.yml` - Updated regex and error messages
2. `CONTRIBUTING.md` - Added requirements and common mistakes sections
3. `.github/workflows/test-pr-title-validation.sh` - New test suite (35 tests)
Loading