107 lines
4.5 KiB
YAML
107 lines
4.5 KiB
YAML
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
# FILE INFORMATION
|
|
# DEFGROUP: MokoGitea.Workflow
|
|
# INGROUP: MokoStandards.Cascade
|
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
|
# PATH: /.mokogitea/workflows/cascade-dev.yml
|
|
# VERSION: 02.00.00
|
|
# BRIEF: Cascade main -> dev via PR; auto-merge only if conflict-free, else notify
|
|
|
|
name: "Cascade Main -> Dev"
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
|
|
env:
|
|
MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
|
# ntfy destination is configured via repo or org variables (org vars are inherited).
|
|
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
|
|
NTFY_TOPIC: ${{ vars.CASCADE_NTFY_TOPIC || vars.NTFY_TOPIC || 'gitea-releases' }}
|
|
|
|
jobs:
|
|
cascade:
|
|
name: Cascade main -> dev
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Open main -> dev PR (auto-merge if clean, else notify)
|
|
env:
|
|
TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
REPO: ${{ github.repository }}
|
|
run: |
|
|
set -uo pipefail
|
|
API="${MOKOGITEA_URL}/api/v1/repos/${REPO}"
|
|
AUTH="Authorization: token ${TOKEN}"
|
|
jqnum() { python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('$1',''))" 2>/dev/null; }
|
|
|
|
# 0. dev must exist
|
|
if ! curl -sf -H "$AUTH" "${API}/branches/dev" >/dev/null 2>&1; then
|
|
echo "No dev branch - nothing to cascade."; exit 0
|
|
fi
|
|
|
|
# 1. is main ahead of dev?
|
|
AHEAD=$(curl -sf -H "$AUTH" "${API}/compare/dev...main" \
|
|
| python3 -c "import sys,json; print(json.load(sys.stdin).get('total_commits',0))" 2>/dev/null || echo 0)
|
|
if [ "${AHEAD:-0}" -eq 0 ]; then
|
|
echo "dev already up to date with main."; exit 0
|
|
fi
|
|
echo "main is ${AHEAD} commit(s) ahead of dev."
|
|
|
|
# 2. reuse an open main->dev PR, else create one
|
|
PR=$(curl -sf -H "$AUTH" "${API}/pulls?state=open&base=dev" \
|
|
| python3 -c "import sys,json; d=json.load(sys.stdin); print(next((str(p['number']) for p in d if p.get('head',{}).get('ref')=='main'), ''))" 2>/dev/null || echo "")
|
|
if [ -z "$PR" ]; then
|
|
RESP=$(curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST "${API}/pulls" \
|
|
-d '{"head":"main","base":"dev","title":"chore(sync): cascade main -> dev","body":"Automated cascade of main into dev. Auto-merges only if conflict-free; otherwise left open for manual resolution."}')
|
|
PR=$(printf '%s' "$RESP" | jqnum number)
|
|
if [ -z "$PR" ]; then
|
|
echo "::warning::Could not open cascade PR: $RESP"; exit 0
|
|
fi
|
|
echo "Opened cascade PR #${PR}"
|
|
else
|
|
echo "Reusing open cascade PR #${PR}"
|
|
fi
|
|
|
|
# 3. wait for MokoGitea to compute mergeability (conflict detection)
|
|
MERGEABLE=""
|
|
for _ in 1 2 3 4 5 6; do
|
|
MERGEABLE=$(curl -sf -H "$AUTH" "${API}/pulls/${PR}" | jqnum mergeable)
|
|
case "$MERGEABLE" in True|False) break ;; esac
|
|
sleep 3
|
|
done
|
|
echo "mergeable=${MERGEABLE}"
|
|
|
|
notify() {
|
|
curl -sS \
|
|
-H "Title: ${REPO}: dev cascade needs manual merge" \
|
|
-H "Tags: warning,twisted_rightwards_arrows" \
|
|
-H "Priority: high" \
|
|
-H "Click: ${MOKOGITEA_URL}/${REPO}/pulls/${PR}" \
|
|
-d "main -> dev cascade PR #${PR} $1 It was NOT auto-merged; resolve it manually." \
|
|
"${NTFY_URL}/${NTFY_TOPIC}" || true
|
|
}
|
|
|
|
# 4. auto-merge only if conflict-free; otherwise notify
|
|
if [ "$MERGEABLE" = "True" ]; then
|
|
CODE=$(curl -s -o /tmp/merge.json -w "%{http_code}" -H "$AUTH" -H "Content-Type: application/json" \
|
|
-X POST "${API}/pulls/${PR}/merge" -d '{"Do":"merge","merge_when_checks_succeed":true}')
|
|
if [ "$CODE" -ge 200 ] && [ "$CODE" -lt 300 ]; then
|
|
echo "Cascade PR #${PR} merged (or scheduled to merge when checks pass)."
|
|
else
|
|
echo "::warning::Auto-merge returned HTTP ${CODE}: $(cat /tmp/merge.json)"
|
|
notify "could not be auto-merged (HTTP ${CODE})."
|
|
fi
|
|
else
|
|
echo "::warning::Cascade PR #${PR} has conflicts (mergeable=${MERGEABLE}); sending notification."
|
|
notify "has conflicts and cannot be merged automatically."
|
|
fi
|