diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index a2eaa53..6a31303 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -8,15 +8,15 @@ on: workflow_dispatch: {} jobs: - tests_and_lint: + tests: name: Tests & Lint runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Go + id: setup-go uses: actions/setup-go@v4 with: go-version: '1.24.2' @@ -37,3 +37,19 @@ jobs: - name: Coverage (threshold) run: scripts/testing/run_coverage.sh + + bindings: + name: Validate Bindings + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + id: setup-go + uses: actions/setup-go@v4 + with: + go-version: '1.24.2' + + - name: Check Bindings Exports + run: scripts/bindings/check_bindings_exports.sh diff --git a/.github/workflows/conventional-commit.yml b/.github/workflows/conventional-commit.yml new file mode 100644 index 0000000..da7b4bb --- /dev/null +++ b/.github/workflows/conventional-commit.yml @@ -0,0 +1,43 @@ +name: Conventional Commit Check + +on: + pull_request: + types: [opened, edited, synchronize] + +jobs: + validate_pr_title: + name: Validate PR Title + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Validate PR title + id: check_title + run: | + #!/bin/bash + set -euo pipefail + + # Allowed prefixes + PREFIXES=("feat" "fix" "docs" "style" "refactor" "test" "chore") + + # Get PR title + PR_TITLE=$(jq -r .pull_request.title "$GITHUB_EVENT_PATH") + echo "PR title: $PR_TITLE" + + # Regex for conventional commit: prefix[optional scope][optional !]: description + PREFIX_PATTERN=$(IFS="|"; echo "${PREFIXES[*]}") + REGEX="^(${PREFIX_PATTERN})(\\([a-zA-Z0-9_-]+\\))?(!)?: .+" + + if [[ "$PR_TITLE" =~ $REGEX ]]; then + echo "PR title follows Conventional Commits." + else + echo "❌ PR title does NOT follow Conventional Commits." + echo "Expected format: [optional scope][!]: description" + echo "Allowed types: ${PREFIXES[*]}" + echo "Examples:" + echo " feat: add login endpoint" + echo " fix(auth)!: fix critical bug" + exit 1 + fi diff --git a/scripts/bindings/check_bindings_exports.sh b/scripts/bindings/check_bindings_exports.sh index ca529be..a84ada1 100755 --- a/scripts/bindings/check_bindings_exports.sh +++ b/scripts/bindings/check_bindings_exports.sh @@ -1,12 +1,13 @@ #!/usr/bin/env bash set -euo pipefail -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# Move to the repository root reliably +ROOT_DIR="$(git rev-parse --show-toplevel)" cd "$ROOT_DIR" +# Directories/files to exclude from scanning for exported functions EXCLUDE_DIRS=( ".github" - "bindings" "cmd" "examples" "internal" @@ -16,48 +17,35 @@ EXCLUDE_FILES=( "*_test.go" ) -# Build rg/glob exclude arguments -RG_EXCLUDES=() +# Find exported top-level functions +GREP_EXCLUDES=() for d in "${EXCLUDE_DIRS[@]}"; do - RG_EXCLUDES+=(--glob "!$d/**") + GREP_EXCLUDES+=(--exclude-dir="$d") done for f in "${EXCLUDE_FILES[@]}"; do - RG_EXCLUDES+=(--glob "!$f") + GREP_EXCLUDES+=(--exclude="$f") done -# Find exported top-level functions with file context -if command -v rg >/dev/null 2>&1; then - exported=$(rg --no-heading --line-number \ - '^func\s+[A-Z][A-Za-z0-9_]*' \ - "${RG_EXCLUDES[@]}" . | - sed -E 's/^(.+):[0-9]+:func\s+([A-Z][A-Za-z0-9_]*).*/\1:\2/' | - sort -u) -else - GREP_EXCLUDES=() - for d in "${EXCLUDE_DIRS[@]}"; do - GREP_EXCLUDES+=(--exclude-dir="$d") - done - for f in "${EXCLUDE_FILES[@]}"; do - GREP_EXCLUDES+=(--exclude="$f") - done - - exported=$(grep -R --line-number -h \ - -E "^func\s+[A-Z][A-Za-z0-9_]*" \ - "${GREP_EXCLUDES[@]}" . | - sed -E 's/^(.+):[0-9]+:func\s+([A-Z][A-Za-z0-9_]*).*/\1:\2/' | - sort -u) -fi +exported=$(grep -R -n "${GREP_EXCLUDES[@]}" -E '^func[[:space:]]+[A-Z][A-Za-z0-9_]*' . | + while IFS=: read -r file _ rest; do + fn=$(printf '%s' "$rest" | sed -E 's/^func[[:space:]]+([A-Z][A-Za-z0-9_]*).*/\1/') + printf '%s:%s\n' "$file" "$fn" + done | sort -u) if [ -z "$exported" ]; then echo "No exported functions found." exit 0 fi +# Absolute paths to bindings files +BINDINGS_GO="$ROOT_DIR/bindings/c/gspl.go" +BINDINGS_H="$ROOT_DIR/bindings/c/gspl.h" + declare -A missing_by_file missing_count=0 while IFS=: read -r file fn; do - if ! rg -q "\b$fn\b" bindings/c/gspl.go bindings/c/gspl.h 2>/dev/null; then + if ! grep -q -w -- "$fn" "$BINDINGS_GO" "$BINDINGS_H" 2>/dev/null; then missing_by_file["$file"]+=$'\n'" - $fn" missing_count=$((missing_count + 1)) fi