diff --git a/.mokogitea/workflows/auto-bump.yml b/.mokogitea/workflows/auto-bump.yml index 6c13103..12bbf0b 100644 --- a/.mokogitea/workflows/auto-bump.yml +++ b/.mokogitea/workflows/auto-bump.yml @@ -22,7 +22,7 @@ on: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} permissions: contents: write diff --git a/.mokogitea/workflows/auto-release.yml b/.mokogitea/workflows/auto-release.yml index ce90d46..5865324 100644 --- a/.mokogitea/workflows/auto-release.yml +++ b/.mokogitea/workflows/auto-release.yml @@ -52,7 +52,7 @@ on: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }} GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }} @@ -102,7 +102,7 @@ jobs: php ${MOKO_CLI}/branch_rename.php \ --from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \ --token "${{ secrets.MOKOGITEA_TOKEN }}" \ - --api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \ + --api-base "${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \ --pr "${{ github.event.pull_request.number }}" - name: Checkout rc and configure git @@ -121,7 +121,7 @@ jobs: - name: Update RC release notes from CHANGELOG.md run: | - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" # Extract [Unreleased] section from changelog @@ -269,7 +269,7 @@ jobs: !startsWith(steps.platform.outputs.platform, 'joomla') run: | VERSION="${{ steps.version.outputs.version }}" - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" SEMVER_TAG="v${VERSION}" @@ -294,7 +294,7 @@ jobs: - name: Update release notes and promote changelog run: | - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" # Get the stable release info (version and ID) @@ -363,7 +363,7 @@ jobs: VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" RELEASE_TAG="${{ steps.version.outputs.release_tag }}" GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}" - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" php ${MOKO_CLI}/release_mirror.php \ --version "$VERSION" --tag "$RELEASE_TAG" \ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \ @@ -392,7 +392,7 @@ jobs: if: steps.version.outputs.skip != 'true' continue-on-error: true run: | - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" # Delete rc branch (ephemeral — created by promote-rc) @@ -416,7 +416,7 @@ jobs: if: steps.version.outputs.skip != 'true' continue-on-error: true run: | - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" BRANCH_NAME="version/${VERSION}" @@ -437,7 +437,7 @@ jobs: if: steps.version.outputs.skip != 'true' continue-on-error: true run: | - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" php ${MOKO_CLI}/version_reset_dev.php \ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \ --branch dev --path . 2>&1 || true @@ -463,5 +463,5 @@ jobs: echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY + echo "| Release | [View](${MOKOGITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY fi diff --git a/.mokogitea/workflows/ci-generic.yml b/.mokogitea/workflows/ci-generic.yml index 18ae768..92d2685 100644 --- a/.mokogitea/workflows/ci-generic.yml +++ b/.mokogitea/workflows/ci-generic.yml @@ -13,6 +13,12 @@ name: "Generic: Project CI" on: + pull_request: + branches: + - main + - dev + - dev/** + - rc/** workflow_dispatch: permissions: diff --git a/.mokogitea/workflows/ci-issue-reporter.yml b/.mokogitea/workflows/ci-issue-reporter.yml new file mode 100644 index 0000000..7ad19c8 --- /dev/null +++ b/.mokogitea/workflows/ci-issue-reporter.yml @@ -0,0 +1,68 @@ +# 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/ci-issue-reporter.yml +# VERSION: 01.00.00 +# BRIEF: Reusable workflow — creates/updates a Gitea issue when a CI gate fails. +# Clones MokoCLI and runs cli/ci_issue_reporter.sh. + +name: "Universal: CI Issue Reporter" + +on: + workflow_call: + inputs: + gate: + description: "CI gate name (e.g. PR Validation, Repository Health)" + required: true + type: string + details: + description: "Human-readable failure description" + required: true + type: string + severity: + description: "error or warning" + required: false + type: string + default: "error" + workflow: + description: "Workflow name for the issue title" + required: false + type: string + default: "" + secrets: + MOKOGITEA_TOKEN: + required: true + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + report: + name: "Report: ${{ inputs.gate }}" + runs-on: ubuntu-latest + + steps: + - name: Clone MokoCLI + env: + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} + run: | + MOKOGITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}" + git clone --depth 1 --filter=blob:none --sparse "${MOKOGITEA_URL}/MokoConsulting/MokoCLI.git" /tmp/mokocli + cd /tmp/mokocli && git sparse-checkout set cli/ci_issue_reporter.sh + + - name: Report CI failure + env: + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} + MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + run: | + chmod +x /tmp/mokocli/cli/ci_issue_reporter.sh + /tmp/mokocli/cli/ci_issue_reporter.sh \ + --gate "${{ inputs.gate }}" \ + --details "${{ inputs.details }}" \ + --severity "${{ inputs.severity }}" \ + --workflow "${{ inputs.workflow }}" diff --git a/.mokogitea/workflows/cleanup.yml b/.mokogitea/workflows/cleanup.yml index 3a81856..0023862 100644 --- a/.mokogitea/workflows/cleanup.yml +++ b/.mokogitea/workflows/cleanup.yml @@ -21,7 +21,7 @@ permissions: contents: write env: - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} jobs: cleanup: @@ -33,17 +33,17 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - token: ${{ secrets.GA_TOKEN }} + token: ${{ secrets.MOKOGITEA_TOKEN }} - name: Delete merged branches env: - GA_TOKEN: ${{ secrets.GA_TOKEN }} + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} run: | echo "=== Merged Branch Cleanup ===" - API="${GITEA_URL}/api/v1/repos/${{ github.repository }}" + API="${MOKOGITEA_URL}/api/v1/repos/${{ github.repository }}" # List branches via API - BRANCHES=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \ + BRANCHES=$(curl -sS -H "Authorization: token ${MOKOGITEA_TOKEN}" \ "${API}/branches?limit=50" | jq -r '.[].name') DELETED=0 @@ -56,7 +56,7 @@ jobs: # Check if branch is merged into main if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then echo " Deleting merged branch: ${BRANCH}" - curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \ + curl -sS -X DELETE -H "Authorization: token ${MOKOGITEA_TOKEN}" \ "${API}/branches/${BRANCH}" 2>/dev/null || true DELETED=$((DELETED + 1)) fi @@ -66,20 +66,20 @@ jobs: - name: Clean old workflow runs env: - GA_TOKEN: ${{ secrets.GA_TOKEN }} + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} run: | echo "=== Workflow Run Cleanup ===" - API="${GITEA_URL}/api/v1/repos/${{ github.repository }}" + API="${MOKOGITEA_URL}/api/v1/repos/${{ github.repository }}" CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ) # Get old completed runs - RUNS=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \ + RUNS=$(curl -sS -H "Authorization: token ${MOKOGITEA_TOKEN}" \ "${API}/actions/runs?status=completed&limit=50" | \ jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null) DELETED=0 for RUN_ID in $RUNS; do - curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \ + curl -sS -X DELETE -H "Authorization: token ${MOKOGITEA_TOKEN}" \ "${API}/actions/runs/${RUN_ID}" 2>/dev/null || true DELETED=$((DELETED + 1)) done diff --git a/.mokogitea/workflows/deploy-manual.yml b/.mokogitea/workflows/deploy-manual.yml new file mode 100644 index 0000000..1af323c --- /dev/null +++ b/.mokogitea/workflows/deploy-manual.yml @@ -0,0 +1,126 @@ +# Copyright (C) 2026 Moko Consulting +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: Gitea.Workflow +# INGROUP: MokoStandards.Deploy +# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API +# PATH: /templates/workflows/joomla/deploy-manual.yml.template +# VERSION: 04.07.00 +# BRIEF: Manual SFTP deploy to dev server for Joomla repos + +name: "Universal: Deploy to Dev (Manual)" + +on: + workflow_dispatch: + inputs: + clear_remote: + description: 'Delete all remote files before uploading' + required: false + default: 'false' + type: boolean + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +permissions: + contents: read + +jobs: + deploy: + name: SFTP Deploy to Dev + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Setup PHP + run: | + php -v && composer --version + + - name: Setup MokoStandards tools + env: + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN || github.token }} + MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN || github.token }} + MOKO_CLONE_HOST: ${{ secrets.MOKOGITEA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }} + COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.MOKOGITEA_TOKEN || github.token }}"}}' + run: | + git clone --depth 1 --branch main --quiet \ + "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \ + /tmp/mokostandards-api 2>/dev/null || true + if [ -d "/tmp/mokostandards-api" ] && [ -f "/tmp/mokostandards-api/composer.json" ]; then + cd /tmp/mokostandards-api && composer install --no-dev --no-interaction --quiet 2>/dev/null || true + fi + + - name: Check FTP configuration + id: check + env: + HOST: ${{ vars.DEV_FTP_HOST }} + PATH_VAR: ${{ vars.DEV_FTP_PATH }} + PORT: ${{ vars.DEV_FTP_PORT }} + run: | + if [ -z "$HOST" ] || [ -z "$PATH_VAR" ]; then + echo "DEV_FTP_HOST or DEV_FTP_PATH not configured -- cannot deploy" + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "host=$HOST" >> "$GITHUB_OUTPUT" + + REMOTE="${PATH_VAR%/}" + echo "remote=$REMOTE" >> "$GITHUB_OUTPUT" + + [ -z "$PORT" ] && PORT="22" + echo "port=$PORT" >> "$GITHUB_OUTPUT" + + - name: Deploy via SFTP + if: steps.check.outputs.skip != 'true' + env: + SFTP_KEY: ${{ secrets.DEV_FTP_KEY }} + SFTP_PASS: ${{ secrets.DEV_FTP_PASSWORD }} + SFTP_USER: ${{ vars.DEV_FTP_USERNAME }} + run: | + SOURCE_DIR="src" + [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" + [ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ -- nothing to deploy"; exit 0; } + + printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \ + "${{ steps.check.outputs.host }}" "${{ steps.check.outputs.port }}" "$SFTP_USER" "${{ steps.check.outputs.remote }}" \ + > /tmp/sftp-config.json + + if [ -n "$SFTP_KEY" ]; then + echo "$SFTP_KEY" > /tmp/deploy_key + chmod 600 /tmp/deploy_key + printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json + else + printf ',"password":"%s"}' "$SFTP_PASS" >> /tmp/sftp-config.json + fi + + DEPLOY_ARGS=(--path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json) + [ "${{ inputs.clear_remote }}" = "true" ] && DEPLOY_ARGS+=(--clear-remote) + + PLATFORM=$(php /tmp/mokostandards-api/cli/platform_detect.php --path . 2>/dev/null || true) + if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then + php /tmp/mokostandards-api/deploy/deploy-joomla.php "${DEPLOY_ARGS[@]}" + else + php /tmp/mokostandards-api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}" + fi + + rm -f /tmp/deploy_key /tmp/sftp-config.json + + - name: Summary + if: always() + run: | + if [ "${{ steps.check.outputs.skip }}" = "true" ]; then + echo "### Deploy Skipped -- FTP not configured" >> $GITHUB_STEP_SUMMARY + else + echo "### Manual Dev Deploy Complete" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| Host | \`${{ steps.check.outputs.host }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Remote | \`${{ steps.check.outputs.remote }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Clear | ${{ inputs.clear_remote }} |" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 39634c0..11958bd 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 01.43.35 +# VERSION: 01.00.00 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" @@ -19,7 +19,7 @@ permissions: issues: write env: - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} jobs: create-branch: @@ -28,8 +28,8 @@ jobs: steps: - name: Create branch and comment run: | - TOKEN="${{ secrets.GA_TOKEN }}" - API="${GITEA_URL}/api/v1/repos/${{ github.repository }}" + TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" + API="${MOKOGITEA_URL}/api/v1/repos/${{ github.repository }}" ISSUE_NUM="${{ github.event.issue.number }}" ISSUE_TITLE="${{ github.event.issue.title }}" @@ -58,7 +58,7 @@ jobs: echo "Created branch: ${BRANCH}" # Comment on issue with branch link - REPO_URL="${GITEA_URL}/${{ github.repository }}" + REPO_URL="${MOKOGITEA_URL}/${{ github.repository }}" BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`" curl -sf -X POST \ diff --git a/.mokogitea/workflows/pr-check.yml b/.mokogitea/workflows/pr-check.yml index b1037e7..c834bf5 100644 --- a/.mokogitea/workflows/pr-check.yml +++ b/.mokogitea/workflows/pr-check.yml @@ -496,39 +496,26 @@ jobs: steps: - name: Trigger RC pre-release env: - GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} REPO: ${{ github.repository }} BRANCH: ${{ github.head_ref }} - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} run: | - curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}" + curl -s -X POST "${MOKOGITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${MOKOGITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}" echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY # ── Issue Reporter ────────────────────────────────────────────────────── report-issues: name: Report Issues - runs-on: ubuntu-latest needs: [branch-policy, validate] if: >- always() && needs.validate.result == 'failure' - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - sparse-checkout: automation/ci-issue-reporter.sh - sparse-checkout-cone-mode: false - - - name: "File issue for PR validation failure" - env: - GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} - run: | - chmod +x automation/ci-issue-reporter.sh - ./automation/ci-issue-reporter.sh \ - --gate "PR Validation" \ - --workflow "PR Check" \ - --severity error \ - --details "PR validation failed (syntax, manifest, changelog, or source checks). See the CI run for the specific check that failed." + uses: ./.mokogitea/workflows/ci-issue-reporter.yml + with: + gate: "PR Validation" + workflow: "PR Check" + severity: error + details: "PR validation failed (syntax, manifest, changelog, or source checks). See the CI run for the specific check that failed." + secrets: inherit diff --git a/.mokogitea/workflows/pre-release.yml b/.mokogitea/workflows/pre-release.yml index adb3377..efb3d1b 100644 --- a/.mokogitea/workflows/pre-release.yml +++ b/.mokogitea/workflows/pre-release.yml @@ -7,7 +7,7 @@ # INGROUP: mokocli.Release # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # PATH: /templates/workflows/universal/pre-release.yml.template -# VERSION: 05.01.00 +# VERSION: 05.02.00 # BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches name: "Universal: Pre-Release" @@ -63,9 +63,7 @@ jobs: - name: Update submodules to main run: | - if [ -f .gitmodules ]; then - git submodule foreach 'git checkout main && git pull origin main' 2>/dev/null || true - fi + git submodule foreach --quiet 'git checkout main && git pull --quiet origin main' 2>/dev/null || true - name: Setup mokocli tools env: diff --git a/.mokogitea/workflows/rc-revert.yml b/.mokogitea/workflows/rc-revert.yml index 5e61de8..8271593 100644 --- a/.mokogitea/workflows/rc-revert.yml +++ b/.mokogitea/workflows/rc-revert.yml @@ -29,12 +29,20 @@ jobs: steps: - name: Rename branch + env: + BRANCH: ${{ github.event.pull_request.head.ref }} + REPO: ${{ github.repository }} + GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} + TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} run: | - BRANCH="${{ github.event.pull_request.head.ref }}" + set -euo pipefail + # BRANCH is attacker-controlled (PR head ref). Strict allowlist before ANY use. + if ! printf '%s' "$BRANCH" | grep -Eq '^rc/[A-Za-z0-9._/-]+$'; then + echo "::error::Refusing unsafe branch name: $BRANCH"; exit 1 + fi SUFFIX="${BRANCH#rc/}" DEV_BRANCH="dev/${SUFFIX}" - API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches" - TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" + API="${GITEA_URL}/api/v1/repos/${REPO}/branches" # Create dev/ branch from rc/ branch STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \ @@ -42,25 +50,22 @@ jobs: -H "Content-Type: application/json" \ -d "{\"new_branch_name\": \"${DEV_BRANCH}\", \"old_branch_name\": \"${BRANCH}\"}" \ "${API}" 2>/dev/null || true) - if [ "$STATUS" = "201" ]; then - echo "Created branch: ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY + echo "Created branch: ${DEV_BRANCH}" >> "$GITHUB_STEP_SUMMARY" else - echo "::error::Failed to create ${DEV_BRANCH} from ${BRANCH} (HTTP ${STATUS})" - exit 1 + echo "::error::Failed to create ${DEV_BRANCH} from ${BRANCH} (HTTP ${STATUS})"; exit 1 fi - # Delete rc/ branch - ENCODED=$(php -r "echo rawurlencode('${BRANCH}');") + # Read BRANCH from the environment inside PHP (getenv, no string interpolation -> no PHP injection) + ENCODED=$(php -r 'echo rawurlencode(getenv("BRANCH"));') STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \ -H "Authorization: token ${TOKEN}" \ "${API}/${ENCODED}" 2>/dev/null || true) - if [ "$STATUS" = "204" ]; then - echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY + echo "Deleted branch: ${BRANCH}" >> "$GITHUB_STEP_SUMMARY" else echo "::warning::Failed to delete ${BRANCH} (HTTP ${STATUS})" fi - echo "### RC Reverted" >> $GITHUB_STEP_SUMMARY - echo "${BRANCH} → ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY + echo "### RC Reverted" >> "$GITHUB_STEP_SUMMARY" + echo "${BRANCH} → ${DEV_BRANCH}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.mokogitea/workflows/repo-health.yml b/.mokogitea/workflows/repo-health.yml index 6a25f5b..092b60e 100644 --- a/.mokogitea/workflows/repo-health.yml +++ b/.mokogitea/workflows/repo-health.yml @@ -77,7 +77,7 @@ jobs: - name: Check actor permission (admin only) id: perm env: - TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }} + TOKEN: ${{ secrets.MOKOGITEA_TOKEN || github.token }} REPO: ${{ github.repository }} ACTOR: ${{ github.actor }} run: | @@ -671,42 +671,30 @@ jobs: # ═══════════════════════════════════════════════════════════════════════ # Issue Reporter — file issues for failed gates # ═══════════════════════════════════════════════════════════════════════ - report-issues: - name: "Report Issues" - runs-on: ubuntu-latest - needs: [access_check, scripts_governance, repo_health] + report-scripts: + name: "Report: Scripts Governance" + needs: [access_check, scripts_governance] if: >- always() && - (needs.scripts_governance.result == 'failure' || - needs.repo_health.result == 'failure') + needs.scripts_governance.result == 'failure' + uses: ./.mokogitea/workflows/ci-issue-reporter.yml + with: + gate: "Scripts Governance" + workflow: "Repo Health" + severity: error + details: "Scripts directory policy violations detected. Review required and allowed directories." + secrets: inherit - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - sparse-checkout: automation/ci-issue-reporter.sh - sparse-checkout-cone-mode: false - - - name: "File issues for failed gates" - env: - GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} - run: | - chmod +x automation/ci-issue-reporter.sh - REPORTER="./automation/ci-issue-reporter.sh" - WF="Repo Health" - - report_gate() { - local gate="$1" result="$2" details="$3" - if [ "$result" = "failure" ]; then - "$REPORTER" --gate "$gate" --details "$details" --workflow "$WF" --severity error - fi - } - - report_gate "Scripts Governance" \ - "${{ needs.scripts_governance.result }}" \ - "Scripts directory policy violations detected. Review required and allowed directories." - - report_gate "Repository Health" \ - "${{ needs.repo_health.result }}" \ - "Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary." + report-health: + name: "Report: Repository Health" + needs: [access_check, repo_health] + if: >- + always() && + needs.repo_health.result == 'failure' + uses: ./.mokogitea/workflows/ci-issue-reporter.yml + with: + gate: "Repository Health" + workflow: "Repo Health" + severity: error + details: "Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary." + secrets: inherit diff --git a/.mokogitea/workflows/version-set.yml b/.mokogitea/workflows/version-set.yml new file mode 100644 index 0000000..0bedeaa --- /dev/null +++ b/.mokogitea/workflows/version-set.yml @@ -0,0 +1,130 @@ +# Copyright (C) 2026 Moko Consulting +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: Gitea.Workflow.Template +# INGROUP: MokoStandards.CI +# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla +# PATH: /.mokogitea/workflows/version-set.yml +# VERSION: 01.00.00 +# BRIEF: Set or reset the extension version across all version-bearing files + +name: "Joomla: Set Version" + +on: + workflow_dispatch: + inputs: + version: + description: "Version number (e.g. 01.00.00)" + required: true + type: string + branch: + description: "Branch to update (default: current)" + required: false + type: string + +permissions: + contents: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + set-version: + name: Set Version to ${{ inputs.version }} + runs-on: ubuntu-latest + + steps: + - name: Validate version format + run: | + VERSION="${{ inputs.version }}" + if ! echo "$VERSION" | grep -qP '^\d{2}\.\d{2}\.\d{2}$'; then + echo "::error::Invalid version format '${VERSION}' — expected XX.YY.ZZ (e.g. 01.00.00)" + exit 1 + fi + echo "VERSION=${VERSION}" >> "$GITHUB_ENV" + + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.MOKOGITEA_TOKEN || github.token }} + ref: ${{ inputs.branch || github.ref }} + fetch-depth: 1 + + - name: Update manifest version + run: | + MANIFEST="" + for XML_FILE in $(find . -maxdepth 3 -name "*.xml" -not -path "./.git/*" -not -path "./vendor/*"); do + if grep -q "/dev/null; then + MANIFEST="$XML_FILE" + break + fi + done + + if [ -z "$MANIFEST" ]; then + echo "::warning::No Joomla extension manifest found — skipping manifest update" + else + OLD_VER=$(grep -oP '\K[^<]+' "$MANIFEST" | head -1) + sed -i "s|${OLD_VER}|${VERSION}|" "$MANIFEST" + echo "Manifest: ${OLD_VER} → ${VERSION} (${MANIFEST})" + fi + + - name: Update README.md version + run: | + if [ -f "README.md" ]; then + if grep -qP '^\s*VERSION:\s*\d' README.md; then + sed -i -E "s/(VERSION:\s*)[0-9]{2}\.[0-9]{2}\.[0-9]{2}/\1${VERSION}/" README.md + echo "README.md version updated to ${VERSION}" + else + echo "::warning::No VERSION line found in README.md — skipping" + fi + fi + + - name: Update CHANGELOG.md + run: | + if [ -f "CHANGELOG.md" ]; then + DATE=$(date +%Y-%m-%d) + # Check if this version already has an entry + if grep -q "^\#\# \[${VERSION}\]" CHANGELOG.md; then + echo "CHANGELOG.md already has entry for ${VERSION} — skipping" + else + # Insert new version entry after [Unreleased] or at the top after header + if grep -q '^\#\# \[Unreleased\]' CHANGELOG.md; then + sed -i "/^\#\# \[Unreleased\]/a\\\\n## [${VERSION}] --- ${DATE}" CHANGELOG.md + else + sed -i "/^\# Changelog/a\\\\n## [Unreleased]\n\n## [${VERSION}] --- ${DATE}" CHANGELOG.md + fi + echo "CHANGELOG.md: added entry for ${VERSION}" + fi + else + echo "::warning::No CHANGELOG.md found — skipping" + fi + + - name: Update FILE INFORMATION blocks + run: | + # Update VERSION in file header blocks (# VERSION: XX.YY.ZZ) + find . -maxdepth 1 -type f \( -name "*.yml" -o -name "*.yaml" -o -name "*.php" -o -name "*.md" \) \ + -not -path "./.git/*" -not -path "./vendor/*" -print0 2>/dev/null | \ + while IFS= read -r -d '' FILE; do + if head -20 "$FILE" | grep -qP '^\s*#?\s*VERSION:\s*\d{2}\.\d{2}\.\d{2}'; then + sed -i -E "s/(#?\s*VERSION:\s*)[0-9]{2}\.[0-9]{2}\.[0-9]{2}/\1${VERSION}/" "$FILE" + echo "Updated FILE INFORMATION VERSION in ${FILE}" + fi + done + + - name: Commit and push + run: | + git config user.name "Moko Consulting [bot]" + git config user.email "hello@mokoconsulting.tech" + git add -A + if git diff --cached --quiet; then + echo "No version changes detected — nothing to commit" + else + git commit -m "chore: set version to ${VERSION} [skip bump] + +Authored-by: Moko Consulting" + git push + echo "### Version Set" >> $GITHUB_STEP_SUMMARY + echo "Version updated to \`${VERSION}\` on branch \`${GITHUB_REF_NAME}\`" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.mokogitea/workflows/workflow-sync-trigger.yml b/.mokogitea/workflows/workflow-sync-trigger.yml index 371910c..34891e8 100644 --- a/.mokogitea/workflows/workflow-sync-trigger.yml +++ b/.mokogitea/workflows/workflow-sync-trigger.yml @@ -13,6 +13,7 @@ name: "Universal: Workflow Sync Trigger" on: + workflow_dispatch: pull_request: types: [closed] branches: @@ -26,8 +27,9 @@ jobs: 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]') + github.event_name == 'workflow_dispatch' || + (github.event.pull_request.merged == true && + !contains(github.event.pull_request.title, '[skip sync]')) steps: - name: Determine platform from repo name @@ -49,8 +51,14 @@ jobs: 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 + MOKOGITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}" + git clone --depth 1 "${MOKOGITEA_URL}/MokoConsulting/mokocli.git" /tmp/mokocli + + - name: Install PHP + run: | + if ! command -v php &> /dev/null; then + apt-get update -qq && apt-get install -y -qq php-cli php-json php-curl > /dev/null 2>&1 + fi - name: Install dependencies run: |