11---
22name : ' 🔍 PR Validation'
3+
34on :
45 workflow_call :
56 inputs :
1819 perf
1920 build
2021 revert
22+
2123 requireScope :
2224 required : false
2325 type : boolean
2426 default : false
27+
2528 subjectPattern :
2629 required : false
2730 type : string
28- default : ' ^[A-Z].+$'
31+ default : ' [A-Za-z].+'
32+
2933 validateSingleCommit :
3034 required : false
3135 type : boolean
3236 default : false
37+
3338 checkLabels :
3439 required : false
3540 type : boolean
3641 default : true
3742
43+ commitlintConfig :
44+ description : " Path to commitlint configuration file"
45+ required : false
46+ type : string
47+ default : " commitlint.config.cjs"
48+
3849jobs :
3950 validate-title :
4051 name : 📝 Validate PR title
4152 runs-on : ubuntu-latest
53+
4254 steps :
4355 - name : Validate PR title format
4456 run : |
4557 TITLE="${{ github.event.pull_request.title }}"
46-
4758 echo "PR Title: $TITLE"
4859
49- PATTERN="^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\([a-zA-Z0-9_-]+\))?: .+"
60+ TYPES=$(echo "${{ inputs.types }}" | tr '\n' '|' | sed 's/|$//')
5061
51- if [[ ! "$TITLE" =~ $PATTERN ]]; then
52- echo "::error::PR title does not follow Conventional Commits format."
53- echo "Valid examples:"
62+ # Allow capitalized types as well
63+ TYPES_REGEX="${TYPES}|$(echo ${TYPES} | sed 's/\([^|]*\)/\u\1|\l\1/g')"
64+
65+ # Full regex for conventional commits
66+ FULL_REGEX="^(${TYPES_REGEX})(\([a-zA-Z0-9_-]+\))?:\s+${{ inputs.subjectPattern }}$"
67+
68+ if [[ ! "$TITLE" =~ $FULL_REGEX ]]; then
69+ echo "::error::PR title does not follow Conventional Commit format."
70+ echo ""
71+ echo "Required format:"
72+ echo " type(scope): subject"
73+ echo " type: subject"
74+ echo ""
75+ echo "Examples:"
5476 echo " feat: Add login API"
5577 echo " fix(auth): Resolve token issue"
78+ echo " docs(readme): Update README"
79+ echo ""
80+ echo "Allowed types:"
81+ echo "${{ inputs.types }}"
5682 exit 1
5783 fi
5884
85+ # Enforce scope if required
86+ if [[ "${{ inputs.requireScope }}" == "true" ]]; then
87+ if [[ ! "$TITLE" =~ ^(${TYPES_REGEX})\([a-zA-Z0-9_-]+\): ]]; then
88+ echo "::error::PR title must include a scope because requireScope=true"
89+ echo "Example:"
90+ echo " feat(auth): Add login API"
91+ exit 1
92+ fi
93+ fi
94+
5995 echo "PR title validation passed."
6096
6197 - name : 🏷️ Check PR labels
@@ -73,14 +109,26 @@ jobs:
73109 validate-commits :
74110 name : 🧾 Validate Commit Messages
75111 runs-on : ubuntu-latest
112+
76113 steps :
77114 - name : 📦 Checkout Repository
78115 uses : actions/checkout@v6
79116 with :
80117 fetch-depth : 0
81118
82- - name : 🧾 Commitlint Validation (Inline Config)
119+ - name : 🔢 Validate single commit
120+ if : ${{ inputs.validateSingleCommit }}
121+ run : |
122+ COUNT=$(git rev-list --count origin/${{ github.base_ref }}..HEAD)
123+ echo "Commit count in PR: $COUNT"
124+
125+ if [ "$COUNT" -ne 1 ]; then
126+ echo "::error::This PR must contain exactly one commit."
127+ exit 1
128+ fi
129+
130+ - name : 🧾 Commitlint Validation
83131 uses : wagoid/commitlint-github-action@v6
84132 with :
85- configFile : commitlint.config.cjs
86- ...
133+ configFile : ${{ inputs.commitlintConfig }}
134+ ...
0 commit comments