Skip to content

feat: Dashboard contract improvement #29

feat: Dashboard contract improvement

feat: Dashboard contract improvement #29

name: PR Conventional Commits Check
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened, edited]
jobs:
validate-commits:
runs-on: ubuntu-latest
# Skip validation for Release Please PRs (auto-generated)
if: |
!startsWith(github.event.pull_request.title, 'chore(main): release') &&
!contains(github.event.pull_request.labels.*.name, 'autorelease: pending')
permissions:
contents: read
pull-requests: write
statuses: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-commitlint-${{ hashFiles('.github/workflows/pr-conventional-commits.yml') }}
restore-keys: |
${{ runner.os }}-commitlint-
- name: Install Commitlint
run: npm install --save-dev @commitlint/config-conventional @commitlint/cli
- name: Create Commitlint Config
run: |
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'build', 'chore', 'ci', 'docs', 'feat', 'fix',
'perf', 'refactor', 'revert', 'style', 'test'
]],
'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
'subject-max-length': [2, 'always', 100],
'body-max-line-length': [2, 'always', 100],
'footer-max-line-length': [2, 'always', 100]
}
}
EOF
- name: Check PR Title
id: check_title
run: |
PR_TITLE="${{ github.event.pull_request.title }}"
echo "Checking PR title: $PR_TITLE"
if echo "$PR_TITLE" | npx commitlint; then
echo "title_valid=true" >> "$GITHUB_OUTPUT"
else
echo "title_valid=false" >> "$GITHUB_OUTPUT"
fi
- name: Check PR Commits
id: check_commits
run: |
COMMITS=$(git rev-list --reverse ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }})
COMMIT_COUNT=$(echo "$COMMITS" | wc -l)
VALID=0
INVALID=""
for commit in $COMMITS; do
MSG=$(git log --format=%B -n 1 "$commit" | head -n 1)
if echo "$MSG" | npx commitlint 2>/dev/null; then
VALID=$((VALID + 1))
else
INVALID="$INVALID\n- \`${commit:0:7}\`: $MSG"
fi
done
echo "commit_count=$COMMIT_COUNT" >> "$GITHUB_OUTPUT"
echo "valid_commits=$VALID" >> "$GITHUB_OUTPUT"
if [ "$VALID" -eq "$COMMIT_COUNT" ]; then
echo "commits_valid=true" >> "$GITHUB_OUTPUT"
else
echo "commits_valid=false" >> "$GITHUB_OUTPUT"
{
echo "invalid_commits<<EOF"
echo -e "$INVALID"
echo "EOF"
} >> "$GITHUB_OUTPUT"
fi
- name: Update PR comment
if: always()
run: |
BODY="## Conventional Commits Validation\n\n"
if [ "${{ steps.check_title.outputs.title_valid }}" = "true" ]; then
BODY="${BODY}**PR Title**: valid\n"
else
BODY="${BODY}**PR Title**: invalid — please use \`type(scope): description\`\n"
fi
if [ "${{ steps.check_commits.outputs.commits_valid }}" = "true" ]; then
BODY="${BODY}**Commits**: all ${{ steps.check_commits.outputs.commit_count }} follow conventional format\n"
else
BODY="${BODY}**Commits**: some do not follow conventional format\n"
BODY="${BODY}${{ steps.check_commits.outputs.invalid_commits }}\n"
fi
if [ "${{ steps.check_title.outputs.title_valid }}" != "true" ] || \
[ "${{ steps.check_commits.outputs.commits_valid }}" != "true" ]; then
BODY="${BODY}\n### Format\n\n\`type(scope): description\`\n\n"
BODY="${BODY}**Types**: \`feat\`, \`fix\`, \`docs\`, \`style\`, \`refactor\`, \`test\`, \`chore\`, \`ci\`, \`build\`, \`perf\`, \`revert\`\n"
fi
COMMENT_ID=$(gh pr view ${{ github.event.pull_request.number }} --json comments \
--jq '.comments[] | select(.author.login == "github-actions[bot]" and (.body | test("Conventional Commits Validation"))) | .id' \
| head -n 1)
if [ -n "$COMMENT_ID" ]; then
gh api -X PATCH "repos/${{ github.repository }}/issues/comments/$COMMENT_ID" \
-f body="$(echo -e "$BODY")"
else
gh pr comment ${{ github.event.pull_request.number }} --body "$(echo -e "$BODY")"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set commit status
if: always()
run: |
SHA="${{ github.event.pull_request.head.sha }}"
title_state="success"
title_desc="PR title follows conventional commits"
if [ "${{ steps.check_title.outputs.title_valid }}" != "true" ]; then
title_state="failure"
title_desc="PR title does not follow conventional commits"
fi
commits_state="success"
commits_desc="All commits follow conventional commits"
if [ "${{ steps.check_commits.outputs.commits_valid }}" != "true" ]; then
commits_state="failure"
commits_desc="Some commits do not follow conventional commits"
fi
gh api -X POST "repos/${{ github.repository }}/statuses/$SHA" \
-f state="$title_state" \
-f context="conventional-commits/title" \
-f description="$title_desc"
gh api -X POST "repos/${{ github.repository }}/statuses/$SHA" \
-f state="$commits_state" \
-f context="conventional-commits/commits" \
-f description="$commits_desc"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Label PR
uses: bcoe/conventional-release-labels@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Final validation
run: |
if [ "${{ steps.check_title.outputs.title_valid }}" = "true" ] && \
[ "${{ steps.check_commits.outputs.commits_valid }}" = "true" ]; then
echo "All conventional commits validations passed"
else
echo "Conventional commits validation failed"
exit 1
fi