Skip to content

ci/workflows: add build automation, release pipeline, and branch protection rules #11

ci/workflows: add build automation, release pipeline, and branch protection rules

ci/workflows: add build automation, release pipeline, and branch protection rules #11

name: Mandatory PR Checks
# Runs all mandatory quality gates on every PR targeting `develop`.
# These checks must pass before a PR is eligible for human review.
# Configure these as required status checks in the branch protection settings.
on:
pull_request:
branches:
- develop
types:
- opened
- reopened
- synchronize
- edited
permissions:
contents: read
jobs:
# ── 1. Detect prohibited file changes ─────────────────────────────────────
check-prohibited-files:
name: Check for Prohibited File Changes
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
persist-credentials: false
- name: Detect changes to protected files
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
PROHIBITED_PATTERNS=(
"^LICENSE"
"^\.github/workflows/"
"^SECURITY\.md"
)
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA")
echo "Changed files:"
echo "$CHANGED_FILES"
VIOLATIONS=0
for pattern in "${PROHIBITED_PATTERNS[@]}"; do
MATCHES=$(echo "$CHANGED_FILES" | grep -E "$pattern" || true)
if [ -n "$MATCHES" ]; then
echo "::warning::The following protected file(s) were modified — a maintainer must review:"
echo "$MATCHES" | while read -r f; do echo " • $f"; done
VIOLATIONS=$((VIOLATIONS + 1))
fi
done
if [ "$VIOLATIONS" -gt 0 ]; then
echo "::warning::This PR modifies one or more protected files. A maintainer must review before merging."
else
echo "No prohibited file changes detected — OK"
fi
# ── 2. Check PR size (lines changed) ──────────────────────────────────────
check-pr-size:
name: Check PR Size
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
persist-credentials: false
- name: Warn on large PRs
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
MAX_LINES=1500
CHANGED=$(git diff --stat "$BASE_SHA" "$HEAD_SHA" | tail -1)
INSERTIONS=$(git diff --numstat "$BASE_SHA" "$HEAD_SHA" | awk '{sum += $1} END {print sum+0}')
DELETIONS=$(git diff --numstat "$BASE_SHA" "$HEAD_SHA" | awk '{sum += $2} END {print sum+0}')
TOTAL=$((INSERTIONS + DELETIONS))
echo "Lines added : $INSERTIONS"
echo "Lines removed : $DELETIONS"
echo "Total changes : $TOTAL"
if [ "$TOTAL" -gt "$MAX_LINES" ]; then
echo "::warning::This PR changes $TOTAL lines (threshold: $MAX_LINES)."
echo "::warning::Consider splitting it into smaller, focused PRs for easier review."
else
echo "PR size is within the recommended limit — OK"
fi
# ── 3. Detect leftover conflict markers ───────────────────────────────────
check-no-conflict-markers:
name: No Conflict Markers
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Scan for unresolved conflict markers
run: |
MARKERS=$(grep -rn --include="*.c" --include="*.h" --include="*.sh" \
--include="*.md" --include="*.yml" --include="*.yaml" \
-E "^(<{7}|>{7}|={7}|\|{7}) " . || true)
if [ -n "$MARKERS" ]; then
echo "::error::Unresolved merge conflict markers found:"
echo "$MARKERS"
exit 1
fi
echo "No conflict markers found — OK"
# ── 4. Summary gate ───────────────────────────────────────────────────────
mandatory-checks-gate:
name: All Mandatory PR Checks Passed
runs-on: ubuntu-latest
needs:
- check-prohibited-files
- check-pr-size
- check-no-conflict-markers
steps:
- name: All checks passed
run: |
echo "All mandatory PR checks passed. Ready for maintainer review."