GRM-21: Implement commit validation, CI/CD workflows and repo automation
- Add scripts/validate_commit_msg.py with conventional commit enforcement - Add scripts/configure_repo.py for Gitea branch protection and labels - Add scripts/__init__.py for Python package importability - Create Gitea Actions workflows: ci, auto-merge, post-merge, publish - Update .pre-commit-config.yaml with commit-msg hook - Update pyproject.toml pythonpath and coverage for scripts - Add comprehensive unit tests for both scripts with 100% coverage
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
name: Auto-merge
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
merge:
|
||||
if: github.event.label.name == 'ready-to-merge'
|
||||
runs-on: docker
|
||||
steps:
|
||||
- name: Squash merge with task ID
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
run: |
|
||||
BRANCH="${{ github.head_ref }}"
|
||||
TASK_ID=$(echo "$BRANCH" | grep -oE 'GRM-[0-9]+' || echo "")
|
||||
if [ -z "$TASK_ID" ]; then
|
||||
echo "ERROR: No task ID (GRM-N) found in branch name '$BRANCH'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||
MERGE_TITLE="${TASK_ID}: ${PR_TITLE}"
|
||||
|
||||
curl -X POST \
|
||||
"https://git.oblachno.oblachno.fyi/api/v1/repos/${{ github.repository }}/pulls/${{ github.event.number }}/merge" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Do\": \"squash\", \"MergeTitleField\": \"${MERGE_TITLE}\"}"
|
||||
@@ -0,0 +1,43 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install -e ".[dev]"
|
||||
.venv/bin/ansible-galaxy collection install -r ansible/requirements.yml
|
||||
- name: Lint all
|
||||
run: make lint-all
|
||||
|
||||
unit-tests:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install -e ".[dev]"
|
||||
- name: Unit tests with 100% coverage
|
||||
run: make pytest-cov
|
||||
|
||||
molecule-tests:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install -e ".[dev]"
|
||||
.venv/bin/ansible-galaxy collection install -r ansible/requirements.yml
|
||||
- name: Molecule tests (all 7 scenarios)
|
||||
run: make molecule
|
||||
@@ -0,0 +1,67 @@
|
||||
name: Post-merge Vikunja update
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
vikunja:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Update Vikunja task
|
||||
env:
|
||||
VIKUNJA_TOKEN: ${{ secrets.VIKUNJA_TOKEN }}
|
||||
run: |
|
||||
MERGE_MSG=$(git log -1 --pretty=%B)
|
||||
TASK_ID=$(echo "$MERGE_MSG" | grep -oE 'GRM-[0-9]+' | head -1)
|
||||
|
||||
if [ -z "$TASK_ID" ]; then
|
||||
echo "No task ID in commit message, skipping Vikunja update."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Resolve GRM-N identifier to Vikunja numeric task ID.
|
||||
# Vikunja's filter API does not support filtering by 'identifier' field,
|
||||
# so we list all tasks and filter client-side by project_id=6 and identifier.
|
||||
VIKUNJA_TASK_ID=$(curl -s \
|
||||
"https://work.oblachno.oblachno.fyi/api/v1/tasks/all?per_page=50" \
|
||||
-H "Authorization: Bearer ${VIKUNJA_TOKEN}" | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
tasks = json.load(sys.stdin)
|
||||
matches = [t for t in tasks if t.get('project_id') == 6 and t.get('identifier') == '${TASK_ID}']
|
||||
print(matches[0]['id'] if matches else '')
|
||||
")
|
||||
|
||||
if [ -z "$VIKUNJA_TASK_ID" ]; then
|
||||
echo "ERROR: Could not find Vikunja task for ${TASK_ID} in project 6"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONV_MSG=$(echo "$MERGE_MSG" | head -1 | sed -E 's/^GRM-[0-9]+: //')
|
||||
COMMIT_SHA=$(git rev-parse HEAD)
|
||||
|
||||
# Post HTML comment to Vikunja
|
||||
python3 -c "
|
||||
import json, os
|
||||
html = '<p><strong>${TASK_ID}</strong>: ${CONV_MSG}</p><p>Commit: <code>${COMMIT_SHA}</code></p>'
|
||||
print(json.dumps({'content': html}))
|
||||
" > /tmp/vikunja_comment.json
|
||||
|
||||
curl -X POST \
|
||||
"https://work.oblachno.oblachno.fyi/api/v1/tasks/${VIKUNJA_TASK_ID}/comments" \
|
||||
-H "Authorization: Bearer ${VIKUNJA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @/tmp/vikunja_comment.json
|
||||
|
||||
# Mark task as done
|
||||
curl -X PUT \
|
||||
"https://work.oblachno.oblachno.fyi/api/v1/tasks/${VIKUNJA_TASK_ID}" \
|
||||
-H "Authorization: Bearer ${VIKUNJA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"done": true}'
|
||||
|
||||
echo "Vikunja task ${TASK_ID} (ID ${VIKUNJA_TASK_ID}) updated and marked done."
|
||||
@@ -0,0 +1,40 @@
|
||||
name: Publish Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build and publish release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
||||
run: |
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install build twine
|
||||
|
||||
# Build package
|
||||
.venv/bin/python -m build
|
||||
|
||||
# Publish to PyPI (only if PYPI_TOKEN secret is configured)
|
||||
if [ -n "${PYPI_TOKEN}" ]; then
|
||||
.venv/bin/twine upload dist/* -u __token__ -p "${PYPI_TOKEN}"
|
||||
echo "Published to PyPI."
|
||||
else
|
||||
echo "PYPI_TOKEN not set — skipping PyPI publish."
|
||||
fi
|
||||
|
||||
# Create Gitea release
|
||||
TAG="${{ github.ref_name }}"
|
||||
curl -X POST \
|
||||
"https://git.oblachno.oblachno.fyi/api/v1/repos/${{ github.repository }}/releases" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\": \"${TAG}\", \"name\": \"${TAG}\", \"body\": \"Release ${TAG}\\n\\nSee CHANGELOG.md for details.\", \"draft\": false, \"prerelease\": false}"
|
||||
|
||||
echo "Gitea release ${TAG} created."
|
||||
Reference in New Issue
Block a user