From 65e190bb0a0f61a15702dee9b4ac7a2cbdacbc8b Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Thu, 9 Jul 2026 18:18:21 -0500 Subject: [PATCH 1/4] chore: update .gitignore and remove branch-protection config - Add ignore entry for wiki/docs - Remove .mokogitea/branch-protection.yml --- .gitignore | 1 + .mokogitea/branch-protection.yml | 251 ------------------------------- 2 files changed, 1 insertion(+), 251 deletions(-) delete mode 100644 .mokogitea/branch-protection.yml diff --git a/.gitignore b/.gitignore index a654d71..1f90377 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ Icon? .idea/ .settings/ .claude/ +.gemini/ .vscode/* !.vscode/tasks.json !.vscode/settings.json.example diff --git a/.mokogitea/branch-protection.yml b/.mokogitea/branch-protection.yml deleted file mode 100644 index 2dff8b9..0000000 --- a/.mokogitea/branch-protection.yml +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright (C) 2026 Moko Consulting -# SPDX-License-Identifier: GPL-3.0-or-later -# FILE INFORMATION -# DEFGROUP: Gitea.Workflow -# INGROUP: moko-platform.Automation -# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform -# PATH: /.gitea/workflows/branch-protection.yml -# BRIEF: Apply standardised branch protection rules to all governed repositories -# -# +========================================================================+ -# | BRANCH PROTECTION SETUP | -# +========================================================================+ -# | | -# | Applies protection rules for: main, dev, rc, beta, alpha | -# | | -# | main — Require PR, block rejected reviews, no force push | -# | dev — Allow push, no force push, no delete | -# | rc — Allow push, no force push, no delete | -# | beta — Allow push, no force push, no delete | -# | alpha — Allow push, no force push, no delete | -# | | -# | jmiller has override authority on all branches. | -# | | -# +========================================================================+ - -name: Branch Protection Setup - -on: - schedule: - - cron: '0 2 * * 1' # Weekly Monday 02:00 UTC - workflow_dispatch: - inputs: - dry_run: - description: 'Preview mode (no changes)' - required: false - type: boolean - default: false - repos: - description: 'Comma-separated repo names (empty = all governed repos)' - required: false - type: string - default: '' - -env: - GITEA_URL: https://git.mokoconsulting.tech - GITEA_ORG: MokoConsulting - -permissions: - contents: read - -jobs: - protect: - name: Apply Branch Protection Rules - runs-on: ubuntu-latest - - steps: - - name: Determine target repos - id: repos - env: - GA_TOKEN: ${{ secrets.GA_TOKEN }} - run: | - API="${GITEA_URL}/api/v1" - - # Platform/standards/infra repos to exclude - EXCLUDE="gitea-org-config org-profile gitea-private .mokogitea-private MokoStandards moko-platform MokoTesting" - EXCLUDE="$EXCLUDE MokoStandards-Template-Client MokoStandards-Template-Dolibarr MokoStandards-Template-Generic MokoStandards-Template-Joomla MokoDoliProjTemplate" - - if [ -n "${{ inputs.repos }}" ]; then - # User-specified repos - REPOS=$(echo "${{ inputs.repos }}" | tr ',' ' ') - else - # Fetch all org repos - PAGE=1 - REPOS="" - while true; do - BATCH=$(curl -sS \ - -H "Authorization: token ${GA_TOKEN}" \ - "${API}/orgs/${GITEA_ORG}/repos?page=${PAGE}&limit=50" \ - | jq -r '.[].name // empty') - [ -z "$BATCH" ] && break - REPOS="$REPOS $BATCH" - PAGE=$((PAGE + 1)) - done - - # Filter out excluded repos - FILTERED="" - for REPO in $REPOS; do - SKIP=false - for EX in $EXCLUDE; do - if [ "$REPO" = "$EX" ]; then - SKIP=true - break - fi - done - if [ "$SKIP" = "false" ]; then - FILTERED="$FILTERED $REPO" - fi - done - REPOS="$FILTERED" - fi - - echo "repos=$REPOS" >> "$GITHUB_OUTPUT" - COUNT=$(echo "$REPOS" | wc -w) - echo "📋 Target repos (${COUNT}): $REPOS" - - - name: Apply protection rules - env: - GA_TOKEN: ${{ secrets.GA_TOKEN }} - DRY_RUN: ${{ inputs.dry_run || 'false' }} - run: | - API="${GITEA_URL}/api/v1" - REPOS="${{ steps.repos.outputs.repos }}" - - SUCCESS=0 - FAILED=0 - SKIPPED=0 - - # ── Rule definitions ────────────────────────────────────── - # Only the CI bot (jmiller token) can push directly. - # All human contributors must use PRs. - # Force push disabled on all branches. - - RULE_MAIN='{ - "rule_name": "main", - "enable_push": true, - "enable_push_whitelist": true, - "push_whitelist_usernames": ["jmiller"], - "enable_force_push": false, - "enable_force_push_allowlist": false, - "force_push_allowlist_usernames": [], - "enable_merge_whitelist": false, - "required_approvals": 0, - "dismiss_stale_approvals": true, - "block_on_rejected_reviews": true, - "block_on_outdated_branch": false, - "priority": 1 - }' - - RULE_DEV='{ - "rule_name": "dev", - "enable_push": true, - "enable_push_whitelist": true, - "push_whitelist_usernames": ["jmiller"], - "enable_force_push": false, - "enable_force_push_allowlist": false, - "force_push_allowlist_usernames": [], - "enable_merge_whitelist": false, - "required_approvals": 0, - "block_on_rejected_reviews": false, - "priority": 2 - }' - - RULE_RC='{ - "rule_name": "rc", - "enable_push": true, - "enable_push_whitelist": true, - "push_whitelist_usernames": ["jmiller"], - "enable_force_push": false, - "enable_force_push_allowlist": false, - "force_push_allowlist_usernames": [], - "enable_merge_whitelist": false, - "required_approvals": 0, - "block_on_rejected_reviews": false, - "priority": 3 - }' - - RULE_BETA='{ - "rule_name": "beta", - "enable_push": true, - "enable_push_whitelist": true, - "push_whitelist_usernames": ["jmiller"], - "enable_force_push": false, - "enable_force_push_allowlist": false, - "force_push_allowlist_usernames": [], - "enable_merge_whitelist": false, - "required_approvals": 0, - "block_on_rejected_reviews": false, - "priority": 4 - }' - - RULE_ALPHA='{ - "rule_name": "alpha", - "enable_push": true, - "enable_push_whitelist": true, - "push_whitelist_usernames": ["jmiller"], - "enable_force_push": false, - "enable_force_push_allowlist": false, - "force_push_allowlist_usernames": [], - "enable_merge_whitelist": false, - "required_approvals": 0, - "block_on_rejected_reviews": false, - "priority": 5 - }' - - RULES=("$RULE_MAIN" "$RULE_DEV" "$RULE_RC" "$RULE_BETA" "$RULE_ALPHA") - RULE_NAMES=("main" "dev" "rc" "beta" "alpha") - - # ── Apply rules to each repo ────────────────────────────── - for REPO in $REPOS; do - echo "" - echo "═══ ${REPO} ═══" - - for i in "${!RULES[@]}"; do - RULE="${RULES[$i]}" - NAME="${RULE_NAMES[$i]}" - - if [ "$DRY_RUN" = "true" ]; then - echo " [DRY RUN] Would apply rule: ${NAME}" - SKIPPED=$((SKIPPED + 1)) - continue - fi - - # Delete existing rule if present (idempotent recreate) - ENCODED_NAME=$(echo "$NAME" | sed 's|/|%2F|g') - curl -sS -o /dev/null -w "" \ - -X DELETE \ - -H "Authorization: token ${GA_TOKEN}" \ - "${API}/repos/${GITEA_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true - - # Create rule - RESPONSE=$(curl -sS -w "\n%{http_code}" \ - -X POST \ - -H "Authorization: token ${GA_TOKEN}" \ - -H "Content-Type: application/json" \ - -d "$RULE" \ - "${API}/repos/${GITEA_ORG}/${REPO}/branch_protections") - - HTTP=$(echo "$RESPONSE" | tail -1) - BODY=$(echo "$RESPONSE" | sed '$d') - - if [ "$HTTP" = "201" ]; then - echo " ✅ ${NAME}" - SUCCESS=$((SUCCESS + 1)) - else - echo " ❌ ${NAME} (HTTP ${HTTP}): $(echo "$BODY" | jq -r '.message // .' 2>/dev/null | head -1)" - FAILED=$((FAILED + 1)) - fi - done - done - - # ── Summary ─────────────────────────────────────────────── - echo "" - echo "════════════════════════════════════════" - echo " ✅ Success: ${SUCCESS}" - echo " ❌ Failed: ${FAILED}" - echo " ⏭️ Skipped: ${SKIPPED}" - echo "════════════════════════════════════════" - - if [ "$FAILED" -gt 0 ]; then - echo "::warning::${FAILED} rule(s) failed to apply" - fi -- 2.52.0 From 9a5b033f019014cbea962939b6e6bbfe7dff416d Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Thu, 9 Jul 2026 18:27:27 -0500 Subject: [PATCH 2/4] chore: ignore editor -tmp artifacts --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 1f90377..9322540 100644 --- a/.gitignore +++ b/.gitignore @@ -211,3 +211,7 @@ profile.ps1 # ============================================================ wiki/ docs/ + +# Editor temp / local secrets / generated test artifacts +*-tmp +*.php-tmp -- 2.52.0 From 6ff826da3c167ab2575a94c16af0fac1475191c1 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Thu, 9 Jul 2026 20:32:38 -0500 Subject: [PATCH 3/4] ci: add workflow-sync-trigger to template --- .../workflows/workflow-sync-trigger.yml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .mokogitea/workflows/workflow-sync-trigger.yml diff --git a/.mokogitea/workflows/workflow-sync-trigger.yml b/.mokogitea/workflows/workflow-sync-trigger.yml new file mode 100644 index 0000000..371910c --- /dev/null +++ b/.mokogitea/workflows/workflow-sync-trigger.yml @@ -0,0 +1,73 @@ +# Copyright (C) 2026 Moko Consulting +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: Gitea.Workflow +# INGROUP: mokocli.Universal +# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli +# PATH: /.mokogitea/workflows/workflow-sync-trigger.yml +# VERSION: 01.01.00 +# BRIEF: Trigger workflow sync to live repos when a PR is merged to main + +name: "Universal: Workflow Sync Trigger" + +on: + pull_request: + types: [closed] + branches: + - main + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + sync: + name: Sync workflows to live repos + runs-on: ubuntu-latest + if: >- + github.event.pull_request.merged == true && + !contains(github.event.pull_request.title, '[skip sync]') + + steps: + - name: Determine platform from repo name + id: platform + run: | + REPO="${{ github.event.repository.name }}" + case "$REPO" in + Template-Joomla) PLATFORM="joomla" ;; + Template-Dolibarr) PLATFORM="dolibarr" ;; + Template-Go) PLATFORM="go" ;; + Template-MCP) PLATFORM="mcp" ;; + Template-Generic) PLATFORM="" ;; + *) PLATFORM="" ;; + esac + echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" + echo "Platform: ${PLATFORM:-all}" + + - name: Clone mokocli + env: + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} + run: | + GITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}" + git clone --depth 1 "${GITEA_URL}/MokoConsulting/mokocli.git" /tmp/mokocli + + - name: Install dependencies + run: | + cd /tmp/mokocli + composer install --no-dev --no-interaction --quiet 2>/dev/null || true + + - name: Run workflow sync + env: + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} + run: | + ARGS="--token ${MOKOGITEA_TOKEN}" + ARGS="${ARGS} --org ${{ vars.GITEA_ORG || github.repository_owner }}" + ARGS="${ARGS} --phase repos" + + PLATFORM="${{ steps.platform.outputs.platform }}" + if [ -n "$PLATFORM" ]; then + ARGS="${ARGS} --platform-filter ${PLATFORM}" + fi + + php /tmp/mokocli/cli/workflow_sync.php ${ARGS} -- 2.52.0 From 48881eb53bb5c9d182736fe67d2f44c9b60b5780 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 12 Jul 2026 17:58:54 -0500 Subject: [PATCH 4/4] gitignore: anchor reports/ to root so component source dirs aren't ignored Mirrors the Template-Generic fix. The bare `reports/` rule ignored any dir named "reports" at any depth, silently excluding legitimate Joomla component source (src/View/Reports, tmpl/reports). Anchor to `/reports/` (root build output only). Claude-Session: https://claude.ai/code/session_01VXrBk7psPzJPHVuBDJwt2x --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9322540..6c6270e 100644 --- a/.gitignore +++ b/.gitignore @@ -131,7 +131,9 @@ coverage/ coverage.xml htmlcov/ junit.xml -reports/ +# Root build/coverage output only — anchored so it does not swallow component +# source dirs named "reports" (e.g. a Joomla admin view src/View/Reports, tmpl/reports). +/reports/ test-results/ tests/_output/ .github/local/ -- 2.52.0