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
27 changes: 27 additions & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash

commit_msg_file=$1
commit_msg=$(cat "$commit_msg_file")

# Allow merge commits
if echo "$commit_msg" | grep -qE "^Merge "; then
exit 0
fi

# Pattern: <type>[(<scope>)][!]: <description>
if ! echo "$commit_msg" | grep -qE "^(feat|fix|chore|hotfix|docs)(\([a-z0-9/-]+\))?(!)?: .+$"; then
echo ""
echo "❌ BLOCKED: Commit message does not follow convention."
echo ""
echo "✅ Format: <type>[(<scope>)]: <description>"
echo ""
echo "📌 Types: feat | fix | chore | hotfix | docs"
echo ""
echo "📌 Examples:"
echo " feat(deploy): add Cloud Run job support"
echo " fix(build): resolve duplicate step names"
echo " chore: update action pin hashes"
echo " docs: update README with new inputs"
echo ""
exit 1
fi
31 changes: 31 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

branch=$(git symbolic-ref --short HEAD 2>/dev/null)

if [[ -z "$branch" ]]; then
echo "⚠️ Could not determine branch name (detached HEAD?). Skipping check."
exit 0
fi

if [[ "$branch" == "main" ]]; then
echo "❌ BLOCKED: Direct pushes to 'main' are not allowed."
echo ""
echo "✅ Create a feature/fix branch and open a PR instead:"
echo " git checkout -b feat/<description>"
echo " git push origin feat/<description>"
echo " # Then open a Pull Request on GitHub"
exit 1
fi

if ! [[ "$branch" =~ ^(main|(feat|fix|chore|hotfix|docs)/.+)$ ]]; then
echo "❌ BLOCKED: Branch '$branch' does not follow naming convention."
echo ""
echo "✅ Allowed formats:"
echo " main | <type>/<description>"
echo " where <type> ∈ feat | fix | chore | hotfix | docs"
echo ""
echo "📌 Examples:"
echo " git checkout -b feat/docker-build-cloudrun-actions"
echo " git checkout -b fix/scheduler-reconcile"
exit 1
fi
96 changes: 96 additions & 0 deletions .github/workflows/branch-protection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Branch Protection Rules

on:
push:
branches:
- main

jobs:
revert-and-notify:
runs-on: ubuntu-latest
if: github.actor != 'github-actions[bot]'
environment: prod
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Check if merge commit
id: merge_check
run: |
PARENT_COUNT=$(git log -1 --pretty=format:%P | wc -w)
if [ "$PARENT_COUNT" -gt 1 ]; then
echo "is_merge=true" >> "$GITHUB_OUTPUT"
else
echo "is_merge=false" >> "$GITHUB_OUTPUT"
fi

- name: Get actor real name
if: steps.merge_check.outputs.is_merge == 'false'
id: actor_info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REAL_NAME=$(gh api users/${{ github.actor }} --jq '.name')
if [ -z "$REAL_NAME" ] || [ "$REAL_NAME" = "null" ]; then
REAL_NAME="${{ github.actor }}"
fi
echo "name=$REAL_NAME" >> $GITHUB_OUTPUT

- name: Get commit title
if: steps.merge_check.outputs.is_merge == 'false'
id: commit_info
run: |
COMMIT_TITLE=$(git log -1 --pretty=format:%s | sed 's/\\/\\\\/g' | sed 's/"/\\"/g')
echo "title=$COMMIT_TITLE" >> "$GITHUB_OUTPUT"

- name: Revert push to ${{ github.ref_name }}
if: steps.merge_check.outputs.is_merge == 'false'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git revert HEAD --no-edit
git push origin ${{ github.ref_name }}

- name: Notify Slack
if: steps.merge_check.outputs.is_merge == 'false'
uses: slackapi/slack-github-action@v2.1.1
with:
webhook-type: incoming-webhook
payload: |
{
"attachments": [
{
"color": "#ff0000",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":x: *Direct Commit to `${{ github.ref_name }}` Branch Not Allowed*\n\n*Pushed By:* `${{ steps.actor_info.outputs.name }}`\n*Repository:* `${{ github.event.repository.name }}`\n*Commit Message:* <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ steps.commit_info.outputs.title }}>\n\n> :memo: *Note:* Please use a feature branch and open a Pull Request instead."
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Pipeline Run"
},
"style": "danger",
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
]
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.PHONY: setup

## setup : Configure Git hooks from .githooks/
setup:
@echo "Configuring Git hooks..."
@git config core.hooksPath .githooks
@echo "Done. Hooks active."
Loading