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 18b67de..5865324 100644 --- a/.mokogitea/workflows/auto-release.yml +++ b/.mokogitea/workflows/auto-release.yml @@ -27,7 +27,7 @@ name: "Universal: Build & Release" on: pull_request: - types: [opened, closed] + types: [opened, synchronize, closed] branches: - main paths-ignore: @@ -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 }} @@ -66,6 +66,7 @@ jobs: runs-on: release if: >- (github.event.action == 'opened' && github.event.pull_request.merged != true) || + (github.event.action == 'synchronize' && github.event.pull_request.merged != true) || (github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc') steps: @@ -101,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 @@ -120,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 @@ -268,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}" @@ -293,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) @@ -362,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" \ @@ -391,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) @@ -415,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}" @@ -436,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 @@ -462,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 index b396c34..7ad19c8 100644 --- a/.mokogitea/workflows/ci-issue-reporter.yml +++ b/.mokogitea/workflows/ci-issue-reporter.yml @@ -1 +1,68 @@ -IyBDb3B5cmlnaHQgKEMpIDIwMjYgTW9rbyBDb25zdWx0aW5nIDxoZWxsb0Btb2tvY29uc3VsdGluZy50ZWNoPgojCiMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0zLjAtb3ItbGF0ZXIKIwojIEZJTEUgSU5GT1JNQVRJT04KIyBERUZHUk9VUDogR2l0ZWEuV29ya2Zsb3cKIyBJTkdST1VQOiBtb2tvY2xpLlVuaXZlcnNhbAojIFJFUE86IGh0dHBzOi8vZ2l0Lm1va29jb25zdWx0aW5nLnRlY2gvTW9rb0NvbnN1bHRpbmcvbW9rb2NsaQojIFBBVEg6IC8ubW9rb2dpdGVhL3dvcmtmbG93cy9jaS1pc3N1ZS1yZXBvcnRlci55bWwKIyBWRVJTSU9OOiAwMS4wMC4wMAojIEJSSUVGOiBSZXVzYWJsZSB3b3JrZmxvdyDigJQgY3JlYXRlcy91cGRhdGVzIGEgR2l0ZWEgaXNzdWUgd2hlbiBhIENJIGdhdGUgZmFpbHMuCiMgICAgICAgIENsb25lcyBNb2tvQ0xJIGFuZCBydW5zIGNsaS9jaV9pc3N1ZV9yZXBvcnRlci5zaC4KCm5hbWU6ICJVbml2ZXJzYWw6IENJIElzc3VlIFJlcG9ydGVyIgoKb246CiAgd29ya2Zsb3dfY2FsbDoKICAgIGlucHV0czoKICAgICAgZ2F0ZToKICAgICAgICBkZXNjcmlwdGlvbjogIkNJIGdhdGUgbmFtZSAoZS5nLiBQUiBWYWxpZGF0aW9uLCBSZXBvc2l0b3J5IEhlYWx0aCkiCiAgICAgICAgcmVxdWlyZWQ6IHRydWUKICAgICAgICB0eXBlOiBzdHJpbmcKICAgICAgZGV0YWlsczoKICAgICAgICBkZXNjcmlwdGlvbjogIkh1bWFuLXJlYWRhYmxlIGZhaWx1cmUgZGVzY3JpcHRpb24iCiAgICAgICAgcmVxdWlyZWQ6IHRydWUKICAgICAgICB0eXBlOiBzdHJpbmcKICAgICAgc2V2ZXJpdHk6CiAgICAgICAgZGVzY3JpcHRpb246ICJlcnJvciBvciB3YXJuaW5nIgogICAgICAgIHJlcXVpcmVkOiBmYWxzZQogICAgICAgIHR5cGU6IHN0cmluZwogICAgICAgIGRlZmF1bHQ6ICJlcnJvciIKICAgICAgd29ya2Zsb3c6CiAgICAgICAgZGVzY3JpcHRpb246ICJXb3JrZmxvdyBuYW1lIGZvciB0aGUgaXNzdWUgdGl0bGUiCiAgICAgICAgcmVxdWlyZWQ6IGZhbHNlCiAgICAgICAgdHlwZTogc3RyaW5nCiAgICAgICAgZGVmYXVsdDogIiIKICAgIHNlY3JldHM6CiAgICAgIE1PS09HSVRFQV9UT0tFTjoKICAgICAgICByZXF1aXJlZDogdHJ1ZQoKZW52OgogIEZPUkNFX0pBVkFTQ1JJUFRfQUNUSU9OU19UT19OT0RFMjQ6IHRydWUKCmpvYnM6CiAgcmVwb3J0OgogICAgbmFtZTogIlJlcG9ydDogJHt7IGlucHV0cy5nYXRlIH19IgogICAgcnVucy1vbjogdWJ1bnR1LWxhdGVzdAoKICAgIHN0ZXBzOgogICAgICAtIG5hbWU6IENsb25lIE1va29DTEkKICAgICAgICBlbnY6CiAgICAgICAgICBNT0tPR0lURUFfVE9LRU46ICR7eyBzZWNyZXRzLk1PS09HSVRFQV9UT0tFTiB9fQogICAgICAgIHJ1bjogfAogICAgICAgICAgTU9LT0dJVEVBX1VSTD0iJHt7IHZhcnMuR0lURUFfVVJMIHx8ICdodHRwczovL2dpdC5tb2tvY29uc3VsdGluZy50ZWNoJyB9fSIKICAgICAgICAgIGdpdCBjbG9uZSAtLWRlcHRoIDEgLS1maWx0ZXI9YmxvYjpub25lIC0tc3BhcnNlICIke01PS09HSVRFQV9VUkx9L01va29Db25zdWx0aW5nL01va29DTEkuZ2l0IiAvdG1wL21va29jbGkKICAgICAgICAgIGNkIC90bXAvbW9rb2NsaSAmJiBnaXQgc3BhcnNlLWNoZWNrb3V0IHNldCBjbGkvY2lfaXNzdWVfcmVwb3J0ZXIuc2gKCiAgICAgIC0gbmFtZTogUmVwb3J0IENJIGZhaWx1cmUKICAgICAgICBlbnY6CiAgICAgICAgICBNT0tPR0lURUFfVE9LRU46ICR7eyBzZWNyZXRzLk1PS09HSVRFQV9UT0tFTiB9fQogICAgICAgICAgTU9LT0dJVEVBX1VSTDogJHt7IHZhcnMuR0lURUFfVVJMIHx8ICdodHRwczovL2dpdC5tb2tvY29uc3VsdGluZy50ZWNoJyB9fQogICAgICAgIHJ1bjogfAogICAgICAgICAgY2htb2QgK3ggL3RtcC9tb2tvY2xpL2NsaS9jaV9pc3N1ZV9yZXBvcnRlci5zaAogICAgICAgICAgL3RtcC9tb2tvY2xpL2NsaS9jaV9pc3N1ZV9yZXBvcnRlci5zaCBcCiAgICAgICAgICAgIC0tZ2F0ZSAiJHt7IGlucHV0cy5nYXRlIH19IiBcCiAgICAgICAgICAgIC0tZGV0YWlscyAiJHt7IGlucHV0cy5kZXRhaWxzIH19IiBcCiAgICAgICAgICAgIC0tc2V2ZXJpdHkgIiR7eyBpbnB1dHMuc2V2ZXJpdHkgfX0iIFwKICAgICAgICAgICAgLS13b3JrZmxvdyAiJHt7IGlucHV0cy53b3JrZmxvdyB9fSIK \ No newline at end of file +# 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/composer-publish.yml b/.mokogitea/workflows/composer-publish.yml deleted file mode 100644 index 03735c9..0000000 --- a/.mokogitea/workflows/composer-publish.yml +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (C) 2026 Moko Consulting -# SPDX-License-Identifier: GPL-3.0-or-later - -name: "Publish to Composer" - -on: - push: - tags: - - 'v*' - - '[0-9]*.[0-9]*.[0-9]*' - release: - types: [published] - workflow_dispatch: - -env: - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} - -jobs: - publish: - name: Publish Package - runs-on: ubuntu-latest - if: >- - !contains(github.event.head_commit.message, '[skip ci]') && - !contains(github.event.head_commit.message, '[skip publish]') - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP - run: | - if ! command -v php &> /dev/null; then - sudo apt-get update -qq - sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1 - fi - - - name: Install dependencies - run: composer install --no-dev --no-interaction --prefer-dist --quiet - - - name: Determine version - id: version - run: | - VERSION=$(php -r "echo json_decode(file_get_contents('composer.json'))->version;") - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "Package version: ${VERSION}" - - # Gitea Composer Registry — auto-publishes from tags - # The tag push itself registers the package at: - # https://git.mokoconsulting.tech/api/packages/MokoConsulting/composer - - name: Verify Gitea registry - run: | - echo "Gitea Composer registry auto-publishes from tags." - echo "Package available at: ${GITEA_URL}/api/packages/MokoConsulting/composer" - echo "Install: composer require mokoconsulting/mokocli" - - # Packagist — notify of new version - - name: Notify Packagist - if: secrets.PACKAGIST_TOKEN != '' - run: | - VERSION="${{ steps.version.outputs.version }}" - echo "Notifying Packagist of version ${VERSION}..." - curl -sf -X POST \ - -H "Content-Type: application/json" \ - -d '{"repository":{"url":"https://git.mokoconsulting.tech/MokoConsulting/mokocli"}}' \ - "https://packagist.org/api/update-package?username=mokoconsulting&apiToken=${{ secrets.PACKAGIST_TOKEN }}" \ - && echo "Packagist notified" \ - || echo "::warning::Packagist notification failed (package may not be registered yet)" - - - name: Summary - run: | - VERSION="${{ steps.version.outputs.version }}" - echo "## Composer Package Published" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Registry | Status |" >> $GITHUB_STEP_SUMMARY - echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY - echo "| Gitea | \`composer require mokoconsulting/mokocli:${VERSION}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Packagist | \`composer require mokoconsulting/mokocli\` |" >> $GITHUB_STEP_SUMMARY diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index f8b70b8..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.04.13 +# 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/pr-metadata-check.yml b/.mokogitea/workflows/pr-metadata-check.yml index 68b7589..b4c9cbd 100644 --- a/.mokogitea/workflows/pr-metadata-check.yml +++ b/.mokogitea/workflows/pr-metadata-check.yml @@ -20,7 +20,7 @@ permissions: contents: read env: - 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 }} @@ -55,14 +55,14 @@ jobs: - name: Validate metadata against Joomla manifest env: - GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} + MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} run: | php ${MOKO_CLI}/joomla_metadata_validate.php \ --path . \ - --token "${GITEA_TOKEN}" \ + --token "${MOKOGITEA_TOKEN}" \ --org "${GITEA_ORG}" \ --repo "${GITEA_REPO}" \ - --api-base "${GITEA_URL}/api/v1" \ + --api-base "${MOKOGITEA_URL}/api/v1" \ --ci if [ $? -ne 0 ]; then diff --git a/.mokogitea/workflows/pre-release.yml b/.mokogitea/workflows/pre-release.yml index 4fd80eb..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" @@ -59,6 +59,11 @@ jobs: fetch-depth: 0 token: ${{ secrets.MOKOGITEA_TOKEN }} ref: ${{ github.ref_name }} + submodules: recursive + + - name: Update submodules to main + run: | + 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/update-server.yml b/.mokogitea/workflows/update-server.yml deleted file mode 100644 index 339d3f5..0000000 --- a/.mokogitea/workflows/update-server.yml +++ /dev/null @@ -1,312 +0,0 @@ -# Copyright (C) 2026 Moko Consulting -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# FILE INFORMATION -# DEFGROUP: Gitea.Workflow -# INGROUP: moko-platform.Universal -# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform -# PATH: /templates/workflows/update-server.yml -# VERSION: 05.00.00 -# BRIEF: Pre-release build + update server XML for dev/alpha/beta/rc branches -# -# Thin wrapper around moko-platform CLI tools. -# Builds packages, updates updates.xml, and optionally deploys via SFTP. -# -# Joomla filters update entries by the user's "Minimum Stability" setting. - -name: "Update Server" - -on: - push: - branches: - - 'dev' - - 'dev/**' - - 'alpha/**' - - 'beta/**' - - 'rc/**' - paths: - - 'src/**' - - 'htdocs/**' - pull_request: - types: [closed] - branches: - - 'dev' - - 'dev/**' - - 'alpha/**' - - 'beta/**' - - 'rc/**' - paths: - - 'src/**' - - 'htdocs/**' - workflow_dispatch: - inputs: - stability: - description: 'Stability tag' - required: true - default: 'development' - type: choice - options: - - development - - alpha - - beta - - rc - - stable - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - GITEA_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 }} - -permissions: - contents: write - -jobs: - update-xml: - name: Update Server - runs-on: release - if: >- - github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' || github.event_name == 'push' - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.MOKOGITEA_TOKEN }} - fetch-depth: 0 - - - name: Setup moko-platform tools - env: - MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} - MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting - COMPOSER_AUTH: '{"http-basic":{"git.mokoconsulting.tech":{"username":"token","password":"${{ secrets.MOKOGITEA_TOKEN }}"}}}' - run: | - if ! command -v composer &> /dev/null; then - sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1 - fi - # Always fetch latest CLI tools — never use stale cache from previous runs - rm -rf /tmp/moko-platform - git clone --depth 1 --branch main --quiet \ - "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ - /tmp/moko-platform 2>/dev/null || true - if [ -d "/tmp/moko-platform" ] && [ -f "/tmp/moko-platform/composer.json" ]; then - cd /tmp/moko-platform && composer install --no-dev --no-interaction --quiet 2>/dev/null || true - fi - echo "MOKO_CLI=/tmp/moko-platform/cli" >> "$GITHUB_ENV" - - - name: Detect platform - id: platform - run: php ${MOKO_CLI}/manifest_read.php --path . --github-output - - - name: Resolve stability and bump version - id: meta - run: | - BRANCH="${{ github.ref_name }}" - - # Configure git for bot pushes - git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" - git config --local user.name "gitea-actions[bot]" - git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" - - # Auto-bump patch version - php ${MOKO_CLI}/version_bump.php --path . 2>/dev/null || true - - VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "0.0.0") - - # Strip any existing suffix before applying stability - VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//') - - # Determine stability from branch or manual input - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - STABILITY="${{ inputs.stability }}" - elif [[ "$BRANCH" == rc/* ]]; then - STABILITY="rc" - elif [[ "$BRANCH" == beta/* ]]; then - STABILITY="beta" - elif [[ "$BRANCH" == alpha/* ]]; then - STABILITY="alpha" - else - STABILITY="development" - fi - - # Version suffix per stability stream - case "$STABILITY" in - development) SUFFIX="-dev"; TAG="development" ;; - alpha) SUFFIX="-alpha"; TAG="alpha" ;; - beta) SUFFIX="-beta"; TAG="beta" ;; - rc) SUFFIX="-rc"; TAG="release-candidate" ;; - *) SUFFIX=""; TAG="stable" ;; - esac - - # Propagate version with stability suffix to all manifest files - php ${MOKO_CLI}/version_set_platform.php \ - --path . --version "$VERSION" --branch "$BRANCH" --stability "$STABILITY" 2>/dev/null || true - php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true - - # Re-read version (now includes suffix from version_set_platform) - if [ -n "$SUFFIX" ]; then - VERSION="${VERSION}${SUFFIX}" - fi - - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT" - echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT" - echo "tag=${TAG}" >> "$GITHUB_OUTPUT" - echo "display_version=${VERSION}" >> "$GITHUB_OUTPUT" - - # Commit version bump if changed - git add -A - git diff --cached --quiet || { - git commit -m "chore(version): auto-bump ${VERSION} [skip ci]" \ - --author="gitea-actions[bot] " - git push - } - - - name: Create release and upload package - id: package - run: | - VERSION="${{ steps.meta.outputs.version }}" - TAG="${{ steps.meta.outputs.tag }}" - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" - - # Create or update Gitea release - php ${MOKO_CLI}/release_create.php \ - --path . --version "$VERSION" --tag "$TAG" \ - --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \ - --repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease - - # Build package and upload - php ${MOKO_CLI}/release_package.php \ - --path . --version "$VERSION" --tag "$TAG" \ - --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \ - --repo "${GITEA_REPO}" --output /tmp || true - - - name: Update updates.xml - if: steps.platform.outputs.platform == 'joomla' - run: | - VERSION="${{ steps.meta.outputs.version }}" - STABILITY="${{ steps.meta.outputs.stability }}" - SHA256="${{ steps.package.outputs.sha256_zip }}" - - if [ ! -f "updates.xml" ]; then - echo "No updates.xml — skipping" - exit 0 - fi - - SHA_FLAG="" - [ -n "$SHA256" ] && SHA_FLAG="--sha ${SHA256}" - - php ${MOKO_CLI}/updates_xml_build.php \ - --path . --version "${VERSION}" --stability "${STABILITY}" \ - --gitea-url "${GITEA_URL}" --org "${GITEA_ORG}" --repo "${GITEA_REPO}" \ - ${SHA_FLAG} - - # Commit and push updates.xml - git add updates.xml - git diff --cached --quiet || { - git commit -m "chore: update ${STABILITY} channel ${VERSION} [skip ci]" - git push - } - - - name: Sync updates.xml to main - if: github.ref_name != 'main' && steps.platform.outputs.platform == 'joomla' - run: | - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" - GITEA_TOKEN="${{ secrets.MOKOGITEA_TOKEN }}" - - FILE_SHA=$(curl -sf -H "Authorization: token ${GITEA_TOKEN}" \ - "${API_BASE}/contents/updates.xml?ref=main" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true) - - if [ -n "$FILE_SHA" ] && [ -f "updates.xml" ]; then - python3 -c " - import base64, json, urllib.request, sys - with open('updates.xml', 'rb') as f: - content = base64.b64encode(f.read()).decode() - payload = json.dumps({ - 'content': content, - 'sha': '${FILE_SHA}', - 'message': 'chore: sync updates.xml from ${{ steps.meta.outputs.stability }} [skip ci]', - 'branch': 'main' - }).encode() - req = urllib.request.Request( - '${API_BASE}/contents/updates.xml', - data=payload, method='PUT', - headers={ - 'Authorization': 'token ${GITEA_TOKEN}', - 'Content-Type': 'application/json' - }) - try: - urllib.request.urlopen(req) - print('updates.xml synced to main') - except Exception as e: - print(f'WARNING: sync to main failed: {e}', file=sys.stderr) - " - fi - - - name: SFTP deploy to dev server - if: contains(github.ref, 'dev/') || github.ref == 'refs/heads/dev' - env: - DEV_HOST: ${{ vars.DEV_FTP_HOST }} - DEV_PATH: ${{ vars.DEV_FTP_PATH }} - DEV_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }} - DEV_USER: ${{ vars.DEV_FTP_USERNAME }} - DEV_PORT: ${{ vars.DEV_FTP_PORT }} - DEV_KEY: ${{ secrets.DEV_FTP_KEY }} - DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }} - run: | - # Permission check: admin or maintain role required - ACTOR="${{ github.actor }}" - API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" - - PERMISSION=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \ - "${API_BASE}/collaborators/${ACTOR}/permission" 2>/dev/null | \ - python3 -c "import sys,json; print(json.load(sys.stdin).get('permission','read'))" 2>/dev/null || echo "read") - case "$PERMISSION" in - admin|maintain|write) ;; - *) - echo "Deploy denied: ${ACTOR} has '${PERMISSION}' — requires admin, maintain, or write" - exit 0 - ;; - esac - - [ -z "$DEV_HOST" ] || [ -z "$DEV_PATH" ] && { echo "DEV FTP not configured — skipping SFTP"; exit 0; } - - SOURCE_DIR="src" - [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" - [ ! -d "$SOURCE_DIR" ] && exit 0 - - PORT="${DEV_PORT:-22}" - REMOTE="${DEV_PATH%/}" - [ -n "$DEV_SUFFIX" ] && REMOTE="${REMOTE}/${DEV_SUFFIX#/}" - - printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \ - "$DEV_HOST" "$PORT" "$DEV_USER" "$REMOTE" > /tmp/sftp-config.json - if [ -n "$DEV_KEY" ]; then - echo "$DEV_KEY" > /tmp/deploy_key && chmod 600 /tmp/deploy_key - printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json - else - printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json - fi - - PLATFORM=$(php ${MOKO_CLI}/platform_detect.php --path . 2>/dev/null || true) - if [ "$PLATFORM" = "waas-component" ] && [ -f "${MOKO_CLI}/../deploy/deploy-joomla.php" ]; then - php ${MOKO_CLI}/../deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json - elif [ -f "${MOKO_CLI}/../deploy/deploy-sftp.php" ]; then - php ${MOKO_CLI}/../deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json - fi - rm -f /tmp/deploy_key /tmp/sftp-config.json - echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY - - - name: Summary - if: always() - run: | - VERSION="${{ steps.meta.outputs.version }}" - STABILITY="${{ steps.meta.outputs.stability }}" - DISPLAY="${{ steps.meta.outputs.display_version }}" - echo "## Update Server" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY - echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY - echo "| Stability | \`${STABILITY}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Version | \`${DISPLAY}\` |" >> $GITHUB_STEP_SUMMARY diff --git a/.mokogitea/workflows/version-set.yml b/.mokogitea/workflows/version-set.yml index 20afb6d..0bedeaa 100644 --- a/.mokogitea/workflows/version-set.yml +++ b/.mokogitea/workflows/version-set.yml @@ -1 +1,130 @@ -IyBDb3B5cmlnaHQgKEMpIDIwMjYgTW9rbyBDb25zdWx0aW5nIDxoZWxsb0Btb2tvY29uc3VsdGluZy50ZWNoPgojCiMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0zLjAtb3ItbGF0ZXIKIwojIEZJTEUgSU5GT1JNQVRJT04KIyBERUZHUk9VUDogR2l0ZWEuV29ya2Zsb3cuVGVtcGxhdGUKIyBJTkdST1VQOiBNb2tvU3RhbmRhcmRzLkNJCiMgUkVQTzogaHR0cHM6Ly9naXQubW9rb2NvbnN1bHRpbmcudGVjaC9Nb2tvQ29uc3VsdGluZy9UZW1wbGF0ZS1Kb29tbGEKIyBQQVRIOiAvLm1va29naXRlYS93b3JrZmxvd3MvdmVyc2lvbi1zZXQueW1sCiMgVkVSU0lPTjogMDEuMDAuMDAKIyBCUklFRjogU2V0IG9yIHJlc2V0IHRoZSBleHRlbnNpb24gdmVyc2lvbiBhY3Jvc3MgYWxsIHZlcnNpb24tYmVhcmluZyBmaWxlcwoKbmFtZTogIkpvb21sYTogU2V0IFZlcnNpb24iCgpvbjoKICB3b3JrZmxvd19kaXNwYXRjaDoKICAgIGlucHV0czoKICAgICAgdmVyc2lvbjoKICAgICAgICBkZXNjcmlwdGlvbjogIlZlcnNpb24gbnVtYmVyIChlLmcuIDAxLjAwLjAwKSIKICAgICAgICByZXF1aXJlZDogdHJ1ZQogICAgICAgIHR5cGU6IHN0cmluZwogICAgICBicmFuY2g6CiAgICAgICAgZGVzY3JpcHRpb246ICJCcmFuY2ggdG8gdXBkYXRlIChkZWZhdWx0OiBjdXJyZW50KSIKICAgICAgICByZXF1aXJlZDogZmFsc2UKICAgICAgICB0eXBlOiBzdHJpbmcKCnBlcm1pc3Npb25zOgogIGNvbnRlbnRzOiB3cml0ZQoKZW52OgogIEZPUkNFX0pBVkFTQ1JJUFRfQUNUSU9OU19UT19OT0RFMjQ6IHRydWUKCmpvYnM6CiAgc2V0LXZlcnNpb246CiAgICBuYW1lOiBTZXQgVmVyc2lvbiB0byAke3sgaW5wdXRzLnZlcnNpb24gfX0KICAgIHJ1bnMtb246IHVidW50dS1sYXRlc3QKCiAgICBzdGVwczoKICAgICAgLSBuYW1lOiBWYWxpZGF0ZSB2ZXJzaW9uIGZvcm1hdAogICAgICAgIHJ1bjogfAogICAgICAgICAgVkVSU0lPTj0iJHt7IGlucHV0cy52ZXJzaW9uIH19IgogICAgICAgICAgaWYgISBlY2hvICIkVkVSU0lPTiIgfCBncmVwIC1xUCAnXlxkezJ9XC5cZHsyfVwuXGR7Mn0kJzsgdGhlbgogICAgICAgICAgICBlY2hvICI6OmVycm9yOjpJbnZhbGlkIHZlcnNpb24gZm9ybWF0ICcke1ZFUlNJT059JyDigJQgZXhwZWN0ZWQgWFguWVkuWlogKGUuZy4gMDEuMDAuMDApIgogICAgICAgICAgICBleGl0IDEKICAgICAgICAgIGZpCiAgICAgICAgICBlY2hvICJWRVJTSU9OPSR7VkVSU0lPTn0iID4+ICIkR0lUSFVCX0VOViIKCiAgICAgIC0gbmFtZTogQ2hlY2tvdXQKICAgICAgICB1c2VzOiBhY3Rpb25zL2NoZWNrb3V0QHY0CiAgICAgICAgd2l0aDoKICAgICAgICAgIHRva2VuOiAke3sgc2VjcmV0cy5NT0tPR0lURUFfVE9LRU4gfHwgZ2l0aHViLnRva2VuIH19CiAgICAgICAgICByZWY6ICR7eyBpbnB1dHMuYnJhbmNoIHx8IGdpdGh1Yi5yZWYgfX0KICAgICAgICAgIGZldGNoLWRlcHRoOiAxCgogICAgICAtIG5hbWU6IFVwZGF0ZSBtYW5pZmVzdCB2ZXJzaW9uCiAgICAgICAgcnVuOiB8CiAgICAgICAgICBNQU5JRkVTVD0iIgogICAgICAgICAgZm9yIFhNTF9GSUxFIGluICQoZmluZCAuIC1tYXhkZXB0aCAzIC1uYW1lICIqLnhtbCIgLW5vdCAtcGF0aCAiLi8uZ2l0LyoiIC1ub3QgLXBhdGggIi4vdmVuZG9yLyoiKTsgZG8KICAgICAgICAgICAgaWYgZ3JlcCAtcSAiPGV4dGVuc2lvbiIgIiRYTUxfRklMRSIgMj4vZGV2L251bGw7IHRoZW4KICAgICAgICAgICAgICBNQU5JRkVTVD0iJFhNTF9GSUxFIgogICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIGZpCiAgICAgICAgICBkb25lCgogICAgICAgICAgaWYgWyAteiAiJE1BTklGRVNUIiBdOyB0aGVuCiAgICAgICAgICAgIGVjaG8gIjo6d2FybmluZzo6Tm8gSm9vbWxhIGV4dGVuc2lvbiBtYW5pZmVzdCBmb3VuZCDigJQgc2tpcHBpbmcgbWFuaWZlc3QgdXBkYXRlIgogICAgICAgICAgZWxzZQogICAgICAgICAgICBPTERfVkVSPSQoZ3JlcCAtb1AgJzx2ZXJzaW9uPlxLW148XSsnICIkTUFOSUZFU1QiIHwgaGVhZCAtMSkKICAgICAgICAgICAgc2VkIC1pICJzfDx2ZXJzaW9uPiR7T0xEX1ZFUn08L3ZlcnNpb24+fDx2ZXJzaW9uPiR7VkVSU0lPTn08L3ZlcnNpb24+fCIgIiRNQU5JRkVTVCIKICAgICAgICAgICAgZWNobyAiTWFuaWZlc3Q6ICR7T0xEX1ZFUn0g4oaSICR7VkVSU0lPTn0gKCR7TUFOSUZFU1R9KSIKICAgICAgICAgIGZpCgogICAgICAtIG5hbWU6IFVwZGF0ZSBSRUFETUUubWQgdmVyc2lvbgogICAgICAgIHJ1bjogfAogICAgICAgICAgaWYgWyAtZiAiUkVBRE1FLm1kIiBdOyB0aGVuCiAgICAgICAgICAgIGlmIGdyZXAgLXFQICdeXHMqVkVSU0lPTjpccypcZCcgUkVBRE1FLm1kOyB0aGVuCiAgICAgICAgICAgICAgc2VkIC1pIC1FICJzLyhWRVJTSU9OOlxzKilbMC05XXsyfVwuWzAtOV17Mn1cLlswLTldezJ9L1wxJHtWRVJTSU9OfS8iIFJFQURNRS5tZAogICAgICAgICAgICAgIGVjaG8gIlJFQURNRS5tZCB2ZXJzaW9uIHVwZGF0ZWQgdG8gJHtWRVJTSU9OfSIKICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgIGVjaG8gIjo6d2FybmluZzo6Tm8gVkVSU0lPTiBsaW5lIGZvdW5kIGluIFJFQURNRS5tZCDigJQgc2tpcHBpbmciCiAgICAgICAgICAgIGZpCiAgICAgICAgICBmaQoKICAgICAgLSBuYW1lOiBVcGRhdGUgQ0hBTkdFTE9HLm1kCiAgICAgICAgcnVuOiB8CiAgICAgICAgICBpZiBbIC1mICJDSEFOR0VMT0cubWQiIF07IHRoZW4KICAgICAgICAgICAgREFURT0kKGRhdGUgKyVZLSVtLSVkKQogICAgICAgICAgICAjIENoZWNrIGlmIHRoaXMgdmVyc2lvbiBhbHJlYWR5IGhhcyBhbiBlbnRyeQogICAgICAgICAgICBpZiBncmVwIC1xICJeXCNcIyBcWyR7VkVSU0lPTn1cXSIgQ0hBTkdFTE9HLm1kOyB0aGVuCiAgICAgICAgICAgICAgZWNobyAiQ0hBTkdFTE9HLm1kIGFscmVhZHkgaGFzIGVudHJ5IGZvciAke1ZFUlNJT059IOKAlCBza2lwcGluZyIKICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICMgSW5zZXJ0IG5ldyB2ZXJzaW9uIGVudHJ5IGFmdGVyIFtVbnJlbGVhc2VkXSBvciBhdCB0aGUgdG9wIGFmdGVyIGhlYWRlcgogICAgICAgICAgICAgIGlmIGdyZXAgLXEgJ15cI1wjIFxbVW5yZWxlYXNlZFxdJyBDSEFOR0VMT0cubWQ7IHRoZW4KICAgICAgICAgICAgICAgIHNlZCAtaSAiL15cI1wjIFxbVW5yZWxlYXNlZFxdL2FcXFxcbiMjIFske1ZFUlNJT059XSAtLS0gJHtEQVRFfSIgQ0hBTkdFTE9HLm1kCiAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgc2VkIC1pICIvXlwjIENoYW5nZWxvZy9hXFxcXG4jIyBbVW5yZWxlYXNlZF1cblxuIyMgWyR7VkVSU0lPTn1dIC0tLSAke0RBVEV9IiBDSEFOR0VMT0cubWQKICAgICAgICAgICAgICBmaQogICAgICAgICAgICAgIGVjaG8gIkNIQU5HRUxPRy5tZDogYWRkZWQgZW50cnkgZm9yICR7VkVSU0lPTn0iCiAgICAgICAgICAgIGZpCiAgICAgICAgICBlbHNlCiAgICAgICAgICAgIGVjaG8gIjo6d2FybmluZzo6Tm8gQ0hBTkdFTE9HLm1kIGZvdW5kIOKAlCBza2lwcGluZyIKICAgICAgICAgIGZpCgogICAgICAtIG5hbWU6IFVwZGF0ZSBGSUxFIElORk9STUFUSU9OIGJsb2NrcwogICAgICAgIHJ1bjogfAogICAgICAgICAgIyBVcGRhdGUgVkVSU0lPTiBpbiBmaWxlIGhlYWRlciBibG9ja3MgKCMgVkVSU0lPTjogWFguWVkuWlopCiAgICAgICAgICBmaW5kIC4gLW1heGRlcHRoIDEgLXR5cGUgZiBcKCAtbmFtZSAiKi55bWwiIC1vIC1uYW1lICIqLnlhbWwiIC1vIC1uYW1lICIqLnBocCIgLW8gLW5hbWUgIioubWQiIFwpIFwKICAgICAgICAgICAgLW5vdCAtcGF0aCAiLi8uZ2l0LyoiIC1ub3QgLXBhdGggIi4vdmVuZG9yLyoiIC1wcmludDAgMj4vZGV2L251bGwgfCBcCiAgICAgICAgICB3aGlsZSBJRlM9IHJlYWQgLXIgLWQgJycgRklMRTsgZG8KICAgICAgICAgICAgaWYgaGVhZCAtMjAgIiRGSUxFIiB8IGdyZXAgLXFQICdeXHMqIz9ccypWRVJTSU9OOlxzKlxkezJ9XC5cZHsyfVwuXGR7Mn0nOyB0aGVuCiAgICAgICAgICAgICAgc2VkIC1pIC1FICJzLygjP1xzKlZFUlNJT046XHMqKVswLTldezJ9XC5bMC05XXsyfVwuWzAtOV17Mn0vXDEke1ZFUlNJT059LyIgIiRGSUxFIgogICAgICAgICAgICAgIGVjaG8gIlVwZGF0ZWQgRklMRSBJTkZPUk1BVElPTiBWRVJTSU9OIGluICR7RklMRX0iCiAgICAgICAgICAgIGZpCiAgICAgICAgICBkb25lCgogICAgICAtIG5hbWU6IENvbW1pdCBhbmQgcHVzaAogICAgICAgIHJ1bjogfAogICAgICAgICAgZ2l0IGNvbmZpZyB1c2VyLm5hbWUgIk1va28gQ29uc3VsdGluZyBbYm90XSIKICAgICAgICAgIGdpdCBjb25maWcgdXNlci5lbWFpbCAiaGVsbG9AbW9rb2NvbnN1bHRpbmcudGVjaCIKICAgICAgICAgIGdpdCBhZGQgLUEKICAgICAgICAgIGlmIGdpdCBkaWZmIC0tY2FjaGVkIC0tcXVpZXQ7IHRoZW4KICAgICAgICAgICAgZWNobyAiTm8gdmVyc2lvbiBjaGFuZ2VzIGRldGVjdGVkIOKAlCBub3RoaW5nIHRvIGNvbW1pdCIKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgZ2l0IGNvbW1pdCAtbSAiY2hvcmU6IHNldCB2ZXJzaW9uIHRvICR7VkVSU0lPTn0gW3NraXAgYnVtcF0KCkF1dGhvcmVkLWJ5OiBNb2tvIENvbnN1bHRpbmciCiAgICAgICAgICAgIGdpdCBwdXNoCiAgICAgICAgICAgIGVjaG8gIiMjIyBWZXJzaW9uIFNldCIgPj4gJEdJVEhVQl9TVEVQX1NVTU1BUlkKICAgICAgICAgICAgZWNobyAiVmVyc2lvbiB1cGRhdGVkIHRvIFxgJHtWRVJTSU9OfVxgIG9uIGJyYW5jaCBcYCR7R0lUSFVCX1JFRl9OQU1FfVxgIiA+PiAkR0lUSFVCX1NURVBfU1VNTUFSWQogICAgICAgICAgZmkK \ No newline at end of file +# 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: | diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 2d63a38..809e983 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,28 +1,46 @@ -# Code of Conduct + + +# Contributor Covenant Code of Conduct ## Our Pledge - -We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. ## Our Standards +- Be empathetic and kind +- Be respectful of differing opinions +- Accept constructive feedback +- Own mistakes and learn from them -Examples of behavior that contributes to a positive environment: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community - -Examples of unacceptable behavior: - -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information without explicit permission +Unacceptable behavior includes sexualized language/imagery, trolling, harassment, doxing, and other inappropriate conduct. ## Enforcement +Report incidents to **hello@mokoconsulting.tech** or through GitHub Discussions if you prefer a community-visible approach. Private complaints will be reviewed promptly and fairly. -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project team at hello@mokoconsulting.tech. All complaints will be reviewed and investigated. +## Enforcement Guidelines +1. **Correction** — Private warning +2. **Warning** — Formal warning and limited interaction +3. **Temporary Ban** — Time-boxed exclusion +4. **Permanent Ban** — Removal from the community ## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1. +Adapted from the Contributor Covenant v2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e566bdf..c0b4858 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,34 +1,161 @@ -# Contributing to MokoJoomOpenGraph +# Contributing to Moko Consulting Projects -Thank you for your interest in contributing to MokoJoomOpenGraph. +Thank you for your interest in contributing. All Moko Consulting repositories follow this universal workflow and version policy. -## Getting Started +## Branching Workflow -1. Fork the repository on Gitea -2. Create a feature branch from `dev` (`feature/your-feature`) -3. Make your changes following the coding standards below -4. Submit a pull request targeting `dev` +``` +feature/* ──PR──> dev ──draft PR──> (renamed to rc) ──merge──> main +``` -## Branch Strategy +### Step by step -- `main` — stable releases only -- `dev` — active development -- `feature/*` — new features (target `dev`) -- `fix/*` — bug fixes (target `dev`) -- `hotfix/*` — urgent fixes (target `dev` or `main`) +1. **Create a feature branch** from `dev`: + ```bash + git checkout dev && git pull + git checkout -b feature/my-change + ``` -## Coding Standards +2. **Work and commit** on your feature branch. Push to origin. -- PHP 8.1+ required -- Follow Joomla coding standards -- SPDX license headers on all PHP files -- Use `SubscriberInterface` for event subscription -- Use `bind() -> check() -> store()` for Table operations +3. **Open a PR**: `feature/my-change` → `dev`. After review and checks, merge it. + +4. **When ready for release**, open a **draft PR**: `dev` → `main`. + - This automatically renames the source branch to `rc` (release candidate) + - An RC pre-release is built and uploaded + +5. **Alpha and beta branches** are created by manually renaming the branch before the RC stage: + - Rename `dev` to `alpha` for early testing → alpha pre-release is built + - Rename `alpha` to `beta` for feature-complete testing → beta pre-release is built + - When the draft PR is created, the branch is renamed to `rc` + +6. **Once PR checks pass** on the `rc` branch, mark the PR as ready and merge to `main`. + +7. **Merging to main** triggers the stable release pipeline: + - Minor version bump (e.g., `02.09.xx` → `02.10.00`) + - Stability suffix stripped (clean version) + - Gitea release created with ZIP/tar.gz packages + - `updates.xml` updated (Joomla extensions) + - `dev` branch recreated from `main` + +### Branch summary + +| Branch | Purpose | Created by | +|--------|---------|-----------| +| `feature/*` | New features and fixes | Developer | +| `dev` | Integration branch | Auto-recreated after release | +| `alpha` | Alpha pre-release testing | Manual rename from `dev` | +| `beta` | Beta pre-release testing | Manual rename from `alpha` | +| `rc` | Release candidate | Auto-renamed on draft PR to main | +| `main` | Stable releases | Protected, merge only | +| `version/XX.YY.ZZ` | Archived release snapshots | Auto-created by CI | + +### Protected branches + +| Branch | Direct push | Merge via | +|--------|------------|-----------| +| `main` | Blocked (CI bot whitelisted) | PR merge only | +| `dev` | Blocked (CI bot whitelisted) | PR merge from feature/* | +| `rc` | Blocked (CI bot whitelisted) | Auto-created on draft PR | +| `alpha` | Blocked (CI bot whitelisted) | Manual rename | +| `beta` | Blocked (CI bot whitelisted) | Manual rename | +| `feature/*` | Open | N/A (source branch) | + +## Version Policy + +### Format + +All versions use `XX.YY.ZZ` — three two-digit segments, zero-padded: + +- **XX** — Major version (breaking changes) +- **YY** — Minor version (new features, bumped on release to main) +- **ZZ** — Patch version (auto-incremented on every push to dev/feature branches) + +Rollover: patch `99` → `00` increments minor; minor `99` → `00` increments major. + +### Stability suffixes + +Each branch appends a suffix to indicate stability: + +| Branch | Suffix | Example | +|--------|--------|---------| +| `main` | (none) | `02.09.00` | +| `dev` | `-dev` | `02.09.01-dev` | +| `feature/*` | `-dev` | `02.09.01-dev` | +| `alpha` | `-alpha` | `02.09.01-alpha` | +| `beta` | `-beta` | `02.09.01-beta` | +| `rc` | `-rc` | `02.09.01-rc` | + +### Auto version bump + +On every push to `dev`, `feature/*`, or `patch/*`: + +1. Patch version incremented +2. Stability suffix `-dev` applied +3. All version-bearing files updated (manifests, CHANGELOG, PHP headers, etc.) +4. Commit created with `[skip ci]` to avoid loops + +### Release version flow + +Version bumps happen at specific release events: + +| Event | Bump | Example | +|-------|------|---------| +| Feature merged to dev | Patch bump after dev release | `02.09.01-dev` → release → `02.09.02-dev` | +| Dev promoted to RC | Minor bump | `02.09.02-dev` → `02.10.00-rc` | +| RC merged to main | Minor bump | `02.10.00-rc` → `02.11.00` (stable) | +| Dev recreated from main | Patch bump | `02.11.00` → `02.11.01-dev` | + +### Release stream copies + +When a higher-stability release is published, copies are created for all lesser streams with the same base version: + +- **RC `02.10.00-rc`** also creates: `02.10.00-dev`, `02.10.00-alpha`, `02.10.00-beta` +- **Stable `02.11.00`** also creates: `02.11.00-dev`, `02.11.00-alpha`, `02.11.00-beta`, `02.11.00-rc` + +This ensures Joomla sites on ANY stability channel see the update (Joomla only shows versions higher than what's installed). + +### Version files + +The version tools update all files containing version stamps: + +- `.mokogitea/manifest.xml` (canonical source) +- Joomla XML manifests (`` tag) +- `README.md`, `CHANGELOG.md` (`VERSION:` pattern) +- `package.json`, `pyproject.toml` +- Any text file with a `VERSION: XX.YY.ZZ` label + +Files synced from other repos (with a `# REPO:` header) are not touched. + +## Code Standards + +- **PHP**: PSR-12, tabs for indentation +- **Copyright**: all files must include the Moko Consulting copyright header +- **License**: SPDX identifier `GPL-3.0-or-later` (or as specified per repo) +- **Attribution**: use `Authored-by: Moko Consulting` in commits, not individual names + +## Commit Messages + +Use conventional commit format: + +``` +type(scope): short description + +Optional body with context. + +Authored-by: Moko Consulting +``` + +Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `test`, `ci` + +Special flags in commit messages: +- `[skip ci]` — skip all CI workflows +- `[skip bump]` — skip auto version bump only ## Reporting Issues -Report bugs and feature requests via [Issues](https://git.mokoconsulting.tech/MokoConsulting/MokoJoomOpenGraph/issues). +Use the repository's issue tracker with the appropriate template. -## License +--- -By contributing, you agree that your contributions will be licensed under GPL-3.0-or-later. +*Moko Consulting * diff --git a/GOVERNANCE.md b/GOVERNANCE.md index bad8ed0..47fa254 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1 +1,119 @@ -PCEtLQogQ29weXJpZ2h0IChDKSAyMDI2IE1va28gQ29uc3VsdGluZyA8aGVsbG9AbW9rb2NvbnN1bHRpbmcudGVjaD4KCiBUaGlzIGZpbGUgaXMgcGFydCBvZiBhIE1va28gQ29uc3VsdGluZyBwcm9qZWN0LgoKIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMy4wLW9yLWxhdGVyCgogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mCiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDMKIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLgoKIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7CiB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLgogU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgoKIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlICguL0xJQ0VOU0UpLgoKIEZJTEUgSU5GT1JNQVRJT04KIERFRkdST1VQOiBtb2tvY29uc3VsdGluZy10ZWNoLlRlbXBsYXRlLUpvb21sYQogSU5HUk9VUDogTW9rb1N0YW5kYXJkcy5Hb3Zlcm5hbmNlCiBSRVBPOiBodHRwczovL2dpdGh1Yi5jb20vbW9rb2NvbnN1bHRpbmctdGVjaC9UZW1wbGF0ZS1Kb29tbGEKIFZFUlNJT046IDAxLjAxLjAwCiBQQVRIOiAvR09WRVJOQU5DRS5tZAogQlJJRUY6IFByb2plY3QgZ292ZXJuYW5jZSBydWxlcywgcm9sZXMsIGFuZCBkZWNpc2lvbiBwcm9jZXNzIGZvciBUZW1wbGF0ZS1Kb29tbGEKLS0+CgpbIVtNb2tvU3RhbmRhcmRzXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL01va29TdGFuZGFyZHMtMDQuMDAuMDQtYmx1ZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9tb2tvY29uc3VsdGluZy10ZWNoL01va29TdGFuZGFyZHMpCgojIFByb2plY3QgR292ZXJuYW5jZQoKIyMgT3ZlcnZpZXcKClRoaXMgZG9jdW1lbnQgZGVmaW5lcyB0aGUgZ292ZXJuYW5jZSBtb2RlbCBmb3IgdGhlIGBUZW1wbGF0ZS1Kb29tbGFgIHJlcG9zaXRvcnkgd2l0aGluIHRoZQpgbW9rb2NvbnN1bHRpbmctdGVjaGAgb3JnYW5pemF0aW9uLiBJdCBpcyBhdXRvbWF0aWNhbGx5IG1haW50YWluZWQgYnkKW01va29TdGFuZGFyZHNdKGh0dHBzOi8vZ2l0aHViLmNvbS9tb2tvY29uc3VsdGluZy10ZWNoL01va29TdGFuZGFyZHMpIHYwNC4wMC4wNC4KCkZ1bGwgZ292ZXJuYW5jZSBwb2xpY3kgaXMgZGVmaW5lZCBpbiB0aGUgTW9rb1N0YW5kYXJkcyBzb3VyY2UgcmVwb3NpdG9yeToKW2RvY3MvcG9saWN5L0dPVkVSTkFOQ0UubWRdKGh0dHBzOi8vZ2l0aHViLmNvbS9tb2tvY29uc3VsdGluZy10ZWNoL01va29TdGFuZGFyZHMvYmxvYi9tYWluL2RvY3MvcG9saWN5L0dPVkVSTkFOQ0UubWQpCgotLS0KCiMjIFJvbGVzIGFuZCBSZXNwb25zaWJpbGl0aWVzCgojIyMgTWFpbnRhaW5lcgoKKipHaXRIdWIqKjogQG1va29jb25zdWx0aW5nLXRlY2gKCioqQXV0aG9yaXR5Kio6IEZpbmFsIGRlY2lzaW9uLW1ha2luZyBhdXRob3JpdHkgb24gYWxsIG1hdHRlcnMgZm9yIHRoaXMgcmVwb3NpdG9yeS4KCioqUmVzcG9uc2liaWxpdGllcyoqOgotIFJldmlldyBhbmQgbWVyZ2UgcHVsbCByZXF1ZXN0cwotIE1haW50YWluIGNvZGUgcXVhbGl0eSBhbmQgc3RhbmRhcmRzIGNvbXBsaWFuY2UKLSBNYW5hZ2UgcmVsZWFzZXMgYW5kIHZlcnNpb25pbmcKLSBSZXNwb25kIHRvIGlzc3VlcyBhbmQgc2VjdXJpdHkgcmVwb3J0cwoKIyMjIENvbnRyaWJ1dG9ycwoKKipBdXRob3JpdHkqKjogU3VibWl0IGNoYW5nZXMgdmlhIHB1bGwgcmVxdWVzdHMuCgoqKlJlcXVpcmVtZW50cyoqOgotIFJlYWQgYW5kIGFjY2VwdCBgQ09ERV9PRl9DT05EVUNULm1kYAotIEZvbGxvdyBgQ09OVFJJQlVUSU5HLm1kYCBndWlkZWxpbmVzCgotLS0KCiMjIERlY2lzaW9uLU1ha2luZwoKQWxsIGNoYW5nZXMgbXVzdCBiZSBzdWJtaXR0ZWQgYXMgcHVsbCByZXF1ZXN0cy4gVGhlIG1haW50YWluZXIgKEBtb2tvY29uc3VsdGluZy10ZWNoKQpyZXZpZXdzIGFuZCBhcHByb3ZlcyBhbGwgY2hhbmdlcyBiZWZvcmUgdGhleSBhcmUgbWVyZ2VkLgoKIyMjIFNvbGUgT3BlcmF0b3IgUG9saWN5CgpUaGlzIG9yZ2FuaXphdGlvbiBvcGVyYXRlcyB1bmRlciBhICoqc29sZSBvcGVyYXRvcioqIG1vZGVsLiBUaGUgbWFpbnRhaW5lciAoQG1va29jb25zdWx0aW5nLXRlY2gpCmlzIHRoZSBzb2xlIGVtcGxveWVlIGFuZCBvd25lciBhbmQgbWF5IHNlbGYtYXBwcm92ZSBwdWxsIHJlcXVlc3RzIHdoZW4gbm8gc2Vjb25kIHJldmlld2VyIGlzCmF2YWlsYWJsZS4gVGhlIGZvbGxvd2luZyByZXF1aXJlbWVudHMgcmVtYWluIG1hbmRhdG9yeSByZWdhcmRsZXNzOgoKMS4gKipQdWxsIFJlcXVlc3RzIFJlcXVpcmVkKiog4oCUIGFsbCBjaGFuZ2VzIHRvIHByb3RlY3RlZCBicmFuY2hlcyBnbyB0aHJvdWdoIGEgUFIuCjIuICoqQXV0b21hdGVkIENoZWNrcyoqIOKAlCBhbGwgQ0kgY2hlY2tzIG11c3QgcGFzcyBiZWZvcmUgbWVyZ2luZy4KMy4gKipBdWRpdCBUcmFpbCoqIOKAlCBpc3N1ZXMsIHB1bGwgcmVxdWVzdHMsIGFuZCBjb21taXQgaGlzdG9yeSBhcmUgcHJlc2VydmVkLgo0LiAqKkRvY3VtZW50YXRpb24qKiDigJQgY2hhbmdlcyBhcmUgZG9jdW1lbnRlZCBpbiBgQ0hBTkdFTE9HLm1kYC4KClNlZSB0aGUgZnVsbCBwb2xpY3k6CltTb2xlIE9wZXJhdG9yIFBvbGljeV0oaHR0cHM6Ly9naXRodWIuY29tL21va29jb25zdWx0aW5nLXRlY2gvTW9rb1N0YW5kYXJkcy9ibG9iL21haW4vZG9jcy9wb2xpY3kvR09WRVJOQU5DRS5tZCNzb2xlLW9wZXJhdG9yLXBvbGljeSkKCi0tLQoKIyMgQ2hhbmdlIE1hbmFnZW1lbnQKCnwgQ2hhbmdlIFR5cGUgfCBBcHByb3ZhbCB8IFByb2Nlc3MgfAp8LS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLXwKfCBSb3V0aW5lIChkb2NzLCBidWcgZml4ZXMpIHwgTWFpbnRhaW5lciB8IFBSIOKGkiBDSSBwYXNzIOKGkiBtZXJnZSB8CnwgU2lnbmlmaWNhbnQgKG5ldyBmZWF0dXJlcykgfCBNYWludGFpbmVyIHwgUFIgd2l0aCBkZXNjcmlwdGlvbiDihpIgQ0kgcGFzcyDihpIgbWVyZ2UgfAp8IE1ham9yIChicmVha2luZywgYXJjaGl0ZWN0dXJlKSB8IE1haW50YWluZXIgfCBJc3N1ZSBkaXNjdXNzaW9uIOKGkiBQUiDihpIgQ0kgcGFzcyDihpIgbWVyZ2UgfAp8IEVtZXJnZW5jeSAoc2VjdXJpdHkpIHwgTWFpbnRhaW5lciB8IExhYmVsbGVkIGBFTUVSR0VOQ1lgIOKGkiBpbW1lZGlhdGUgbWVyZ2Ug4oaSIHBvc3QtbW9ydGVtIHwKCi0tLQoKIyMgUmVwb3J0aW5nIElzc3VlcwoKLSAqKkJ1Z3MgLyBGZWF0dXJlcyoqOiBPcGVuIGEgW0dpdEh1YiBJc3N1ZV0oaHR0cHM6Ly9naXRodWIuY29tL21va29jb25zdWx0aW5nLXRlY2gvVGVtcGxhdGUtSm9vbWxhL2lzc3VlcykKLSAqKlNlY3VyaXR5IHZ1bG5lcmFiaWxpdGllcyoqOiBTZWUgW1NFQ1VSSVRZLm1kXSguL1NFQ1VSSVRZLm1kKQotICoqQ29kZSBvZiBDb25kdWN0Kio6IFNlZSBbQ09ERV9PRl9DT05EVUNULm1kXSguL0NPREVfT0ZfQ09ORFVDVC5tZCkKLSAqKkNvbnRhY3QqKjogZGV2QG1va29jb25zdWx0aW5nLnRlY2gKCi0tLQoKIyMgTWV0YWRhdGEKCnwgRmllbGQgICAgICAgICB8IFZhbHVlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAtLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfAp8IERvY3VtZW50IFR5cGUgfCBQb2xpY3kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgRG9tYWluICAgICAgICB8IEdvdmVybmFuY2UgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBBcHBsaWVzIFRvICAgIHwgbW9rb2NvbnN1bHRpbmctdGVjaC9UZW1wbGF0ZS1Kb29tbGEgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgSnVyaXNkaWN0aW9uICB8IFRlbm5lc3NlZSwgVVNBICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBNYWludGFpbmVyICAgIHwgQG1va29jb25zdWx0aW5nLXRlY2ggICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IFN0YW5kYXJkcyAgICAgfCBNb2tvU3RhbmRhcmRzIHYwNC4wMC4wNCAgICAgICAgICAgIHwKfCBSZXBvICAgICAgICAgIHwgaHR0cHM6Ly9naXRodWIuY29tL21va29jb25zdWx0aW5nLXRlY2gvVGVtcGxhdGUtSm9vbWxhICAgICAgICB8CnwgUGF0aCAgICAgICAgICB8IC9HT1ZFUk5BTkNFLm1kICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBTdGF0dXMgICAgICAgIHwgQWN0aXZlIOKAlCBhdXRvLW1haW50YWluZWQgYnkgTW9rb1N0YW5kYXJkcyAgICAgICB8Cg== \ No newline at end of file + + +[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.00.04-blue)](https://github.com/mokoconsulting-tech/MokoStandards) + +# Project Governance + +## Overview + +This document defines the governance model for the `Template-Joomla` repository within the +`mokoconsulting-tech` organization. It is automatically maintained by +[MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) v04.00.04. + +Full governance policy is defined in the MokoStandards source repository: +[docs/policy/GOVERNANCE.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/GOVERNANCE.md) + +--- + +## Roles and Responsibilities + +### Maintainer + +**GitHub**: @mokoconsulting-tech + +**Authority**: Final decision-making authority on all matters for this repository. + +**Responsibilities**: +- Review and merge pull requests +- Maintain code quality and standards compliance +- Manage releases and versioning +- Respond to issues and security reports + +### Contributors + +**Authority**: Submit changes via pull requests. + +**Requirements**: +- Read and accept `CODE_OF_CONDUCT.md` +- Follow `CONTRIBUTING.md` guidelines + +--- + +## Decision-Making + +All changes must be submitted as pull requests. The maintainer (@mokoconsulting-tech) +reviews and approves all changes before they are merged. + +### Sole Operator Policy + +This organization operates under a **sole operator** model. The maintainer (@mokoconsulting-tech) +is the sole employee and owner and may self-approve pull requests when no second reviewer is +available. The following requirements remain mandatory regardless: + +1. **Pull Requests Required** — all changes to protected branches go through a PR. +2. **Automated Checks** — all CI checks must pass before merging. +3. **Audit Trail** — issues, pull requests, and commit history are preserved. +4. **Documentation** — changes are documented in `CHANGELOG.md`. + +See the full policy: +[Sole Operator Policy](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/GOVERNANCE.md#sole-operator-policy) + +--- + +## Change Management + +| Change Type | Approval | Process | +|-------------|----------|---------| +| Routine (docs, bug fixes) | Maintainer | PR → CI pass → merge | +| Significant (new features) | Maintainer | PR with description → CI pass → merge | +| Major (breaking, architecture) | Maintainer | Issue discussion → PR → CI pass → merge | +| Emergency (security) | Maintainer | Labelled `EMERGENCY` → immediate merge → post-mortem | + +--- + +## Reporting Issues + +- **Bugs / Features**: Open a [GitHub Issue](https://github.com/mokoconsulting-tech/Template-Joomla/issues) +- **Security vulnerabilities**: See [SECURITY.md](./SECURITY.md) +- **Code of Conduct**: See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) +- **Contact**: dev@mokoconsulting.tech + +--- + +## Metadata + +| Field | Value | +| ------------- | ----------------------------------------------- | +| Document Type | Policy | +| Domain | Governance | +| Applies To | mokoconsulting-tech/Template-Joomla | +| Jurisdiction | Tennessee, USA | +| Maintainer | @mokoconsulting-tech | +| Standards | MokoStandards v04.00.04 | +| Repo | https://github.com/mokoconsulting-tech/Template-Joomla | +| Path | /GOVERNANCE.md | +| Status | Active — auto-maintained by MokoStandards | diff --git a/SECURITY.md b/SECURITY.md index fc4b025..86b35ed 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 01.04.13 +VERSION: 01.01.00 BRIEF: Security vulnerability reporting and handling policy --> @@ -224,10 +224,10 @@ The following are explicitly out of scope: ## Metadata -| Field | Value | +| Field | Value | | ------------ | ------------------------------------------------------------------------------------------------------------ | -| Document | Security Policy | -| Path | /SECURITY.md | +| Document | Security Policy | +| Path | /SECURITY.md | | Repository | [https://github.com/mokoconsulting-tech/Template-Joomla](https://github.com/mokoconsulting-tech/Template-Joomla) | | Owner | Moko Consulting | | Scope | Security vulnerability handling |