Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd551bffda | |||
| 48eeb9631f | |||
| 2e3331170f | |||
| 4699686f26 | |||
| a7fe881d84 | |||
| ab02de34f4 | |||
| 64d9a97db1 | |||
| 3ba1c3ead4 | |||
| 4c091805ee | |||
| 0d4e7785a3 | |||
| 6f13a10a34 |
@@ -1,66 +1,66 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokocli.Release
|
# INGROUP: mokocli.Release
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
|
||||||
# PATH: /.mokogitea/workflows/auto-bump.yml
|
# PATH: /.mokogitea/workflows/auto-bump.yml
|
||||||
# VERSION: 09.02.00
|
# VERSION: 09.02.00
|
||||||
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
|
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
|
||||||
|
|
||||||
name: "Universal: Auto Version Bump"
|
name: "Universal: Auto Version Bump"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
- rc
|
- rc
|
||||||
- 'feature/**'
|
- 'feature/**'
|
||||||
- 'patch/**'
|
- 'patch/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
bump:
|
bump:
|
||||||
name: Version Bump
|
name: Version Bump
|
||||||
runs-on: release
|
runs-on: release
|
||||||
if: >-
|
if: >-
|
||||||
!contains(github.event.head_commit.message, '[skip ci]') &&
|
!contains(github.event.head_commit.message, '[skip ci]') &&
|
||||||
!contains(github.event.head_commit.message, '[skip bump]') &&
|
!contains(github.event.head_commit.message, '[skip bump]') &&
|
||||||
!startsWith(github.event.head_commit.message, 'Merge pull request')
|
!startsWith(github.event.head_commit.message, 'Merge pull request')
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Setup mokocli tools
|
- name: Setup mokocli tools
|
||||||
run: |
|
run: |
|
||||||
if ! command -v composer &> /dev/null; then
|
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
|
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
|
fi
|
||||||
if [ -d "/opt/mokocli/cli" ]; then
|
if [ -d "/opt/mokocli/cli" ]; then
|
||||||
echo "MOKO_CLI=/opt/mokocli/cli" >> "$GITHUB_ENV"
|
echo "MOKO_CLI=/opt/mokocli/cli" >> "$GITHUB_ENV"
|
||||||
else
|
else
|
||||||
git clone --depth 1 --branch main --quiet \
|
git clone --depth 1 --branch main --quiet \
|
||||||
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokocli.git" \
|
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokocli.git" \
|
||||||
/tmp/mokocli
|
/tmp/mokocli
|
||||||
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
|
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
|
||||||
echo "MOKO_CLI=/tmp/mokocli/cli" >> "$GITHUB_ENV"
|
echo "MOKO_CLI=/tmp/mokocli/cli" >> "$GITHUB_ENV"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
run: |
|
run: |
|
||||||
php ${MOKO_CLI}/version_auto_bump.php \
|
php ${MOKO_CLI}/version_auto_bump.php \
|
||||||
--path . --branch "${GITHUB_REF_NAME}" \
|
--path . --branch "${GITHUB_REF_NAME}" \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||||
|
|||||||
@@ -1,466 +1,467 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokocli.Release
|
# INGROUP: mokocli.Release
|
||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
|
||||||
# PATH: /templates/workflows/universal/auto-release.yml.template
|
# PATH: /templates/workflows/universal/auto-release.yml.template
|
||||||
# VERSION: 05.00.00
|
# VERSION: 05.00.00
|
||||||
# BRIEF: Universal build & release � detects platform from manifest.xml
|
# BRIEF: Universal build & release � detects platform from manifest.xml
|
||||||
#
|
#
|
||||||
# +=======================================================================+
|
# +=======================================================================+
|
||||||
# | UNIVERSAL BUILD & RELEASE PIPELINE |
|
# | UNIVERSAL BUILD & RELEASE PIPELINE |
|
||||||
# +=======================================================================+
|
# +=======================================================================+
|
||||||
# | |
|
# | |
|
||||||
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
||||||
# | |
|
# | |
|
||||||
# | Platform-specific: |
|
# | Platform-specific: |
|
||||||
# | joomla: XML manifest, type-prefixed packages |
|
# | joomla: XML manifest, type-prefixed packages |
|
||||||
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
||||||
# | generic: README-only, no update stream |
|
# | generic: README-only, no update stream |
|
||||||
# | |
|
# | |
|
||||||
# +=======================================================================+
|
# +=======================================================================+
|
||||||
|
|
||||||
name: "Universal: Build & Release"
|
name: "Universal: Build & Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, closed]
|
types: [opened, synchronize, closed]
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.mokogitea/workflows/**'
|
- '.mokogitea/workflows/**'
|
||||||
- '*.md'
|
- '*.md'
|
||||||
- 'wiki/**'
|
- 'wiki/**'
|
||||||
- '.editorconfig'
|
- '.editorconfig'
|
||||||
- '.gitignore'
|
- '.gitignore'
|
||||||
- '.gitattributes'
|
- '.gitattributes'
|
||||||
- '.gitmessage'
|
- '.gitmessage'
|
||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
action:
|
action:
|
||||||
description: 'Action to perform'
|
description: 'Action to perform'
|
||||||
required: false
|
required: false
|
||||||
type: choice
|
type: choice
|
||||||
default: release
|
default: release
|
||||||
options:
|
options:
|
||||||
- release
|
- release
|
||||||
- promote-rc
|
- promote-rc
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
||||||
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
|
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
|
||||||
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
|
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────────
|
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────────
|
||||||
promote-rc:
|
promote-rc:
|
||||||
name: Promote to RC
|
name: Promote to RC
|
||||||
runs-on: release
|
runs-on: release
|
||||||
if: >-
|
if: >-
|
||||||
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
|
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
|
||||||
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
|
(github.event.action == 'synchronize' && github.event.pull_request.merged != true) ||
|
||||||
|
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
steps:
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
- name: Checkout repository
|
||||||
with:
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
with:
|
||||||
fetch-depth: 1
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
|
fetch-depth: 1
|
||||||
- name: Setup mokocli tools
|
|
||||||
env:
|
- name: Setup mokocli tools
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
env:
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
run: |
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
|
run: |
|
||||||
echo Using pre-installed /opt/mokocli
|
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
|
||||||
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
|
echo Using pre-installed /opt/mokocli
|
||||||
else
|
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
|
||||||
echo Falling back to fresh clone
|
else
|
||||||
if ! command -v composer > /dev/null 2>&1; then
|
echo Falling back to fresh clone
|
||||||
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
|
if ! command -v composer > /dev/null 2>&1; then
|
||||||
fi
|
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
|
||||||
rm -rf /tmp/mokocli
|
fi
|
||||||
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
|
rm -rf /tmp/mokocli
|
||||||
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
|
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
|
||||||
cd /tmp/mokocli
|
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
|
||||||
composer install --no-dev --no-interaction --quiet
|
cd /tmp/mokocli
|
||||||
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
|
composer install --no-dev --no-interaction --quiet
|
||||||
fi
|
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
- name: Rename branch to rc
|
|
||||||
run: |
|
- name: Rename branch to rc
|
||||||
php ${MOKO_CLI}/branch_rename.php \
|
run: |
|
||||||
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
|
php ${MOKO_CLI}/branch_rename.php \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
|
||||||
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
--pr "${{ github.event.pull_request.number }}"
|
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
|
||||||
|
--pr "${{ github.event.pull_request.number }}"
|
||||||
- name: Checkout rc and configure git
|
|
||||||
run: |
|
- name: Checkout rc and configure git
|
||||||
git fetch origin rc
|
run: |
|
||||||
git checkout rc
|
git fetch origin rc
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
git checkout rc
|
||||||
git config --local user.name "gitea-actions[bot]"
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
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"
|
||||||
- name: Publish RC release
|
|
||||||
run: |
|
- name: Publish RC release
|
||||||
php ${MOKO_CLI}/release_publish.php \
|
run: |
|
||||||
--path . --stability rc --bump minor --branch rc \
|
php ${MOKO_CLI}/release_publish.php \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
--path . --stability rc --bump minor --branch rc \
|
||||||
|
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
- name: Update RC release notes from CHANGELOG.md
|
|
||||||
run: |
|
- name: Update RC release notes from CHANGELOG.md
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
run: |
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
# Extract [Unreleased] section from changelog
|
|
||||||
NOTES=""
|
# Extract [Unreleased] section from changelog
|
||||||
if [ -f "CHANGELOG.md" ]; then
|
NOTES=""
|
||||||
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
if [ -f "CHANGELOG.md" ]; then
|
||||||
fi
|
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
||||||
[ -z "$NOTES" ] && NOTES="Release candidate"
|
fi
|
||||||
|
[ -z "$NOTES" ] && NOTES="Release candidate"
|
||||||
# Find the RC release and update its body
|
|
||||||
RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" \
|
# Find the RC release and update its body
|
||||||
"${API_BASE}/releases/tags/release-candidate" \
|
RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" \
|
||||||
| python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
"${API_BASE}/releases/tags/release-candidate" \
|
||||||
|
| python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||||
if [ -n "$RELEASE_ID" ]; then
|
|
||||||
python3 -c "
|
if [ -n "$RELEASE_ID" ]; then
|
||||||
import json, urllib.request
|
python3 -c "
|
||||||
body = open('/dev/stdin').read()
|
import json, urllib.request
|
||||||
payload = json.dumps({'body': body}).encode()
|
body = open('/dev/stdin').read()
|
||||||
req = urllib.request.Request(
|
payload = json.dumps({'body': body}).encode()
|
||||||
'${API_BASE}/releases/${RELEASE_ID}',
|
req = urllib.request.Request(
|
||||||
data=payload, method='PATCH',
|
'${API_BASE}/releases/${RELEASE_ID}',
|
||||||
headers={
|
data=payload, method='PATCH',
|
||||||
'Authorization': 'token ${TOKEN}',
|
headers={
|
||||||
'Content-Type': 'application/json'
|
'Authorization': 'token ${TOKEN}',
|
||||||
})
|
'Content-Type': 'application/json'
|
||||||
urllib.request.urlopen(req)
|
})
|
||||||
" <<< "$NOTES"
|
urllib.request.urlopen(req)
|
||||||
echo "RC release notes updated from CHANGELOG.md"
|
" <<< "$NOTES"
|
||||||
fi
|
echo "RC release notes updated from CHANGELOG.md"
|
||||||
|
fi
|
||||||
- name: Summary
|
|
||||||
if: always()
|
- name: Summary
|
||||||
run: |
|
if: always()
|
||||||
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
run: |
|
||||||
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
|
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
|
||||||
# ── Merged PR → Build & Release (or promote RC to stable) ─────────────────────────
|
|
||||||
release:
|
# ── Merged PR → Build & Release (or promote RC to stable) ─────────────────────────
|
||||||
name: Build & Release Pipeline
|
release:
|
||||||
runs-on: release
|
name: Build & Release Pipeline
|
||||||
if: >-
|
runs-on: release
|
||||||
github.event.pull_request.merged == true ||
|
if: >-
|
||||||
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
|
github.event.pull_request.merged == true ||
|
||||||
|
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
steps:
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
- name: Checkout repository
|
||||||
with:
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
with:
|
||||||
fetch-depth: 0
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
|
fetch-depth: 0
|
||||||
- name: Configure git for bot pushes
|
|
||||||
run: |
|
- name: Configure git for bot pushes
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
run: |
|
||||||
git config --local user.name "gitea-actions[bot]"
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
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"
|
||||||
- name: Check for merge conflict markers
|
|
||||||
run: |
|
- name: Check for merge conflict markers
|
||||||
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
|
run: |
|
||||||
if [ -n "$CONFLICTS" ]; then
|
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
|
||||||
echo "::error::Merge conflict markers found — aborting release"
|
if [ -n "$CONFLICTS" ]; then
|
||||||
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
|
echo "::error::Merge conflict markers found — aborting release"
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
|
||||||
exit 1
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
exit 1
|
||||||
echo "No conflict markers found"
|
fi
|
||||||
|
echo "No conflict markers found"
|
||||||
- name: Setup mokocli tools
|
|
||||||
env:
|
- name: Setup mokocli tools
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
env:
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
run: |
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
|
||||||
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
|
run: |
|
||||||
echo Using pre-installed /opt/mokocli
|
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
|
||||||
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
|
echo Using pre-installed /opt/mokocli
|
||||||
else
|
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
|
||||||
echo Falling back to fresh clone
|
else
|
||||||
if ! command -v composer > /dev/null 2>&1; then
|
echo Falling back to fresh clone
|
||||||
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
|
if ! command -v composer > /dev/null 2>&1; then
|
||||||
fi
|
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
|
||||||
rm -rf /tmp/mokocli
|
fi
|
||||||
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
|
rm -rf /tmp/mokocli
|
||||||
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
|
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
|
||||||
cd /tmp/mokocli
|
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
|
||||||
composer install --no-dev --no-interaction --quiet
|
cd /tmp/mokocli
|
||||||
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
|
composer install --no-dev --no-interaction --quiet
|
||||||
fi
|
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
- name: "Detect platform"
|
|
||||||
id: platform
|
- name: "Detect platform"
|
||||||
run: |
|
id: platform
|
||||||
php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
|
run: |
|
||||||
php ${MOKO_CLI}/manifest_read.php --path . --github-output 2>/dev/null || true
|
php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
|
||||||
|
php ${MOKO_CLI}/manifest_read.php --path . --github-output 2>/dev/null || true
|
||||||
- name: "Determine version bump level"
|
|
||||||
id: bump
|
- name: "Determine version bump level"
|
||||||
run: |
|
id: bump
|
||||||
# Fix/patch branches: version was already bumped by pre-release, just strip suffix
|
run: |
|
||||||
# Feature/dev branches: bump minor for the new stable release
|
# Fix/patch branches: version was already bumped by pre-release, just strip suffix
|
||||||
HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
|
# Feature/dev branches: bump minor for the new stable release
|
||||||
case "$HEAD_REF" in
|
HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
|
||||||
fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
|
case "$HEAD_REF" in
|
||||||
*) BUMP="minor" ;;
|
fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
|
||||||
esac
|
*) BUMP="minor" ;;
|
||||||
echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
|
esac
|
||||||
echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
|
echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
|
||||||
- name: "Publish stable release"
|
|
||||||
run: |
|
- name: "Publish stable release"
|
||||||
BUMP_FLAG=""
|
run: |
|
||||||
if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
|
BUMP_FLAG=""
|
||||||
BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
|
if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
|
||||||
fi
|
BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
|
||||||
php ${MOKO_CLI}/release_publish.php \
|
fi
|
||||||
--path . --stability stable ${BUMP_FLAG} --branch main \
|
php ${MOKO_CLI}/release_publish.php \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
--path . --stability stable ${BUMP_FLAG} --branch main \
|
||||||
|
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
- name: "Read published version"
|
|
||||||
id: version
|
- name: "Read published version"
|
||||||
run: |
|
id: version
|
||||||
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "")
|
run: |
|
||||||
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
|
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "")
|
||||||
[ -z "$VERSION" ] && VERSION="00.00.00" && echo "skip=true" >> "$GITHUB_OUTPUT"
|
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
|
||||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
[ -z "$VERSION" ] && VERSION="00.00.00" && echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
PLATFORM="${{ steps.platform.outputs.platform }}"
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||||
if [[ "$PLATFORM" == joomla* ]]; then
|
PLATFORM="${{ steps.platform.outputs.platform }}"
|
||||||
echo "tag=stable" >> "$GITHUB_OUTPUT"
|
if [[ "$PLATFORM" == joomla* ]]; then
|
||||||
echo "release_tag=stable" >> "$GITHUB_OUTPUT"
|
echo "tag=stable" >> "$GITHUB_OUTPUT"
|
||||||
else
|
echo "release_tag=stable" >> "$GITHUB_OUTPUT"
|
||||||
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"
|
else
|
||||||
echo "release_tag=v${VERSION}" >> "$GITHUB_OUTPUT"
|
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
echo "release_tag=v${VERSION}" >> "$GITHUB_OUTPUT"
|
||||||
echo "branch=main" >> "$GITHUB_OUTPUT"
|
fi
|
||||||
echo "Published version: ${VERSION}"
|
echo "branch=main" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Published version: ${VERSION}"
|
||||||
- name: "Create semver tag for non-Joomla repos"
|
|
||||||
id: semver
|
- name: "Create semver tag for non-Joomla repos"
|
||||||
if: |
|
id: semver
|
||||||
steps.version.outputs.skip != 'true' &&
|
if: |
|
||||||
!startsWith(steps.platform.outputs.platform, 'joomla')
|
steps.version.outputs.skip != 'true' &&
|
||||||
run: |
|
!startsWith(steps.platform.outputs.platform, 'joomla')
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
run: |
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
SEMVER_TAG="v${VERSION}"
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
|
SEMVER_TAG="v${VERSION}"
|
||||||
echo "Creating semver tag: ${SEMVER_TAG}"
|
|
||||||
|
echo "Creating semver tag: ${SEMVER_TAG}"
|
||||||
# Create the git tag via API
|
|
||||||
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \
|
# Create the git tag via API
|
||||||
-X POST -H "Authorization: token ${TOKEN}" \
|
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \
|
||||||
-H "Content-Type: application/json" \
|
-X POST -H "Authorization: token ${TOKEN}" \
|
||||||
"${API_BASE}/tags" \
|
-H "Content-Type: application/json" \
|
||||||
-d "{\"tag_name\":\"${SEMVER_TAG}\",\"target\":\"main\",\"message\":\"Release ${VERSION}\"}" 2>/dev/null || echo "000")
|
"${API_BASE}/tags" \
|
||||||
|
-d "{\"tag_name\":\"${SEMVER_TAG}\",\"target\":\"main\",\"message\":\"Release ${VERSION}\"}" 2>/dev/null || echo "000")
|
||||||
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "200" ]; then
|
|
||||||
echo "Created semver tag: ${SEMVER_TAG}"
|
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "200" ]; then
|
||||||
elif [ "$HTTP_CODE" = "409" ]; then
|
echo "Created semver tag: ${SEMVER_TAG}"
|
||||||
echo "Semver tag ${SEMVER_TAG} already exists (skipped)"
|
elif [ "$HTTP_CODE" = "409" ]; then
|
||||||
else
|
echo "Semver tag ${SEMVER_TAG} already exists (skipped)"
|
||||||
echo "::warning::Failed to create semver tag ${SEMVER_TAG} (HTTP ${HTTP_CODE})"
|
else
|
||||||
fi
|
echo "::warning::Failed to create semver tag ${SEMVER_TAG} (HTTP ${HTTP_CODE})"
|
||||||
|
fi
|
||||||
echo "semver_tag=${SEMVER_TAG}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
echo "semver_tag=${SEMVER_TAG}" >> "$GITHUB_OUTPUT"
|
||||||
- name: Update release notes and promote changelog
|
|
||||||
run: |
|
- name: Update release notes and promote changelog
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
run: |
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
# Get the stable release info (version and ID)
|
|
||||||
RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \
|
# Get the stable release info (version and ID)
|
||||||
"${API_BASE}/releases/tags/stable" 2>/dev/null || echo '{}')
|
RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \
|
||||||
RELEASE_ID=$(python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" <<< "$RELEASE_JSON" 2>/dev/null || true)
|
"${API_BASE}/releases/tags/stable" 2>/dev/null || echo '{}')
|
||||||
# Extract version from release name (e.g. "06.17.00" or "v06.17.00")
|
RELEASE_ID=$(python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" <<< "$RELEASE_JSON" 2>/dev/null || true)
|
||||||
VERSION=$(python3 -c "
|
# Extract version from release name (e.g. "06.17.00" or "v06.17.00")
|
||||||
import json, sys, re
|
VERSION=$(python3 -c "
|
||||||
r = json.load(sys.stdin)
|
import json, sys, re
|
||||||
name = r.get('name', '')
|
r = json.load(sys.stdin)
|
||||||
m = re.search(r'(\d+\.\d+\.\d+)', name)
|
name = r.get('name', '')
|
||||||
print(m.group(1) if m else '')
|
m = re.search(r'(\d+\.\d+\.\d+)', name)
|
||||||
" <<< "$RELEASE_JSON" 2>/dev/null || true)
|
print(m.group(1) if m else '')
|
||||||
|
" <<< "$RELEASE_JSON" 2>/dev/null || true)
|
||||||
# Extract [Unreleased] section from changelog
|
|
||||||
NOTES=""
|
# Extract [Unreleased] section from changelog
|
||||||
if [ -f "CHANGELOG.md" ]; then
|
NOTES=""
|
||||||
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
if [ -f "CHANGELOG.md" ]; then
|
||||||
fi
|
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
||||||
[ -z "$NOTES" ] && NOTES="Stable release"
|
fi
|
||||||
|
[ -z "$NOTES" ] && NOTES="Stable release"
|
||||||
# Update release body via API
|
|
||||||
if [ -n "$RELEASE_ID" ]; then
|
# Update release body via API
|
||||||
python3 -c "
|
if [ -n "$RELEASE_ID" ]; then
|
||||||
import json, urllib.request
|
python3 -c "
|
||||||
body = open('/dev/stdin').read()
|
import json, urllib.request
|
||||||
payload = json.dumps({'body': body}).encode()
|
body = open('/dev/stdin').read()
|
||||||
req = urllib.request.Request(
|
payload = json.dumps({'body': body}).encode()
|
||||||
'${API_BASE}/releases/${RELEASE_ID}',
|
req = urllib.request.Request(
|
||||||
data=payload, method='PATCH',
|
'${API_BASE}/releases/${RELEASE_ID}',
|
||||||
headers={
|
data=payload, method='PATCH',
|
||||||
'Authorization': 'token ${TOKEN}',
|
headers={
|
||||||
'Content-Type': 'application/json'
|
'Authorization': 'token ${TOKEN}',
|
||||||
})
|
'Content-Type': 'application/json'
|
||||||
urllib.request.urlopen(req)
|
})
|
||||||
" <<< "$NOTES"
|
urllib.request.urlopen(req)
|
||||||
echo "Release notes updated from CHANGELOG.md"
|
" <<< "$NOTES"
|
||||||
fi
|
echo "Release notes updated from CHANGELOG.md"
|
||||||
|
fi
|
||||||
# Promote [Unreleased] → [version] in CHANGELOG.md and reset
|
|
||||||
if [ -n "$VERSION" ] && [ -f "CHANGELOG.md" ]; then
|
# Promote [Unreleased] → [version] in CHANGELOG.md and reset
|
||||||
DATE=$(date +%Y-%m-%d)
|
if [ -n "$VERSION" ] && [ -f "CHANGELOG.md" ]; then
|
||||||
python3 -c "
|
DATE=$(date +%Y-%m-%d)
|
||||||
import sys
|
python3 -c "
|
||||||
version, date = sys.argv[1], sys.argv[2]
|
import sys
|
||||||
content = open('CHANGELOG.md').read()
|
version, date = sys.argv[1], sys.argv[2]
|
||||||
old = '## [Unreleased]'
|
content = open('CHANGELOG.md').read()
|
||||||
new = f'## [Unreleased]\n\n## [{version}] --- {date}'
|
old = '## [Unreleased]'
|
||||||
content = content.replace(old, new, 1)
|
new = f'## [Unreleased]\n\n## [{version}] --- {date}'
|
||||||
open('CHANGELOG.md', 'w').write(content)
|
content = content.replace(old, new, 1)
|
||||||
" "$VERSION" "$DATE"
|
open('CHANGELOG.md', 'w').write(content)
|
||||||
git add CHANGELOG.md
|
" "$VERSION" "$DATE"
|
||||||
git commit -m "chore: promote changelog [Unreleased] → [${VERSION}]" || true
|
git add CHANGELOG.md
|
||||||
git push origin main || true
|
git commit -m "chore: promote changelog [Unreleased] → [${VERSION}]" || true
|
||||||
echo "Changelog promoted: [Unreleased] → [${VERSION}]"
|
git push origin main || true
|
||||||
fi
|
echo "Changelog promoted: [Unreleased] → [${VERSION}]"
|
||||||
|
fi
|
||||||
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
|
||||||
- name: "Step 9: Mirror release to GitHub"
|
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
||||||
if: >-
|
- name: "Step 9: Mirror release to GitHub"
|
||||||
steps.version.outputs.skip != 'true' &&
|
if: >-
|
||||||
secrets.GH_MIRROR_TOKEN != ''
|
steps.version.outputs.skip != 'true' &&
|
||||||
continue-on-error: true
|
secrets.GH_MIRROR_TOKEN != ''
|
||||||
run: |
|
continue-on-error: true
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
run: |
|
||||||
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
php ${MOKO_CLI}/release_mirror.php \
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
--version "$VERSION" --tag "$RELEASE_TAG" \
|
php ${MOKO_CLI}/release_mirror.php \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
--version "$VERSION" --tag "$RELEASE_TAG" \
|
||||||
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
||||||
--branch main 2>&1 || true
|
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
|
||||||
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
|
--branch main 2>&1 || true
|
||||||
|
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
|
||||||
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
|
|
||||||
- name: "Step 10: Push main to GitHub mirror"
|
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
|
||||||
if: >-
|
- name: "Step 10: Push main to GitHub mirror"
|
||||||
steps.version.outputs.skip != 'true' &&
|
if: >-
|
||||||
secrets.GH_MIRROR_TOKEN != ''
|
steps.version.outputs.skip != 'true' &&
|
||||||
continue-on-error: true
|
secrets.GH_MIRROR_TOKEN != ''
|
||||||
run: |
|
continue-on-error: true
|
||||||
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
run: |
|
||||||
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
|
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
|
||||||
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
|
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
|
||||||
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
|
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
|
||||||
git fetch origin main --depth=1
|
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
|
||||||
git push github origin/main:refs/heads/main --force 2>/dev/null \
|
git fetch origin main --depth=1
|
||||||
&& echo "main branch pushed to GitHub mirror" \
|
git push github origin/main:refs/heads/main --force 2>/dev/null \
|
||||||
|| echo "WARNING: GitHub mirror push failed"
|
&& echo "main branch pushed to GitHub mirror" \
|
||||||
|
|| echo "WARNING: GitHub mirror push failed"
|
||||||
- name: "Step 11: Delete rc branch and recreate dev from main"
|
|
||||||
if: steps.version.outputs.skip != 'true'
|
- name: "Step 11: Delete rc branch and recreate dev from main"
|
||||||
continue-on-error: true
|
if: steps.version.outputs.skip != 'true'
|
||||||
run: |
|
continue-on-error: true
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
run: |
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
# Delete rc branch (ephemeral — created by promote-rc)
|
|
||||||
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
# Delete rc branch (ephemeral — created by promote-rc)
|
||||||
"${API_BASE}/branches/rc" 2>/dev/null \
|
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
||||||
&& echo "Deleted rc branch" || echo "rc branch not found"
|
"${API_BASE}/branches/rc" 2>/dev/null \
|
||||||
|
&& echo "Deleted rc branch" || echo "rc branch not found"
|
||||||
# Delete dev branch
|
|
||||||
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
# Delete dev branch
|
||||||
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
|
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
|
||||||
|
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
|
||||||
# Recreate dev from main (now includes version bump + changelog promotion)
|
|
||||||
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
|
# Recreate dev from main (now includes version bump + changelog promotion)
|
||||||
-H "Content-Type: application/json" \
|
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
|
||||||
"${API_BASE}/branches" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
|
"${API_BASE}/branches" \
|
||||||
|
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
|
||||||
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
|
||||||
- name: "Step 12: Create version branch from main"
|
|
||||||
if: steps.version.outputs.skip != 'true'
|
- name: "Step 12: Create version branch from main"
|
||||||
continue-on-error: true
|
if: steps.version.outputs.skip != 'true'
|
||||||
run: |
|
continue-on-error: true
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
run: |
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
BRANCH_NAME="version/${VERSION}"
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
MAIN_SHA=$(git rev-parse HEAD)
|
BRANCH_NAME="version/${VERSION}"
|
||||||
|
MAIN_SHA=$(git rev-parse HEAD)
|
||||||
# Delete old version branch if it exists (same version re-release)
|
|
||||||
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
|
# Delete old version branch if it exists (same version re-release)
|
||||||
|
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
|
||||||
# Create version/XX.YY.ZZ from main
|
|
||||||
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
|
# Create version/XX.YY.ZZ from main
|
||||||
|
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
|
||||||
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
|
||||||
# -- Dolibarr post-release: Reset dev version -----------------------------
|
|
||||||
- name: "Post-release: Reset dev version"
|
# -- Dolibarr post-release: Reset dev version -----------------------------
|
||||||
if: steps.version.outputs.skip != 'true'
|
- name: "Post-release: Reset dev version"
|
||||||
continue-on-error: true
|
if: steps.version.outputs.skip != 'true'
|
||||||
run: |
|
continue-on-error: true
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
run: |
|
||||||
php ${MOKO_CLI}/version_reset_dev.php \
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
|
php ${MOKO_CLI}/version_reset_dev.php \
|
||||||
--branch dev --path . 2>&1 || true
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
|
||||||
|
--branch dev --path . 2>&1 || true
|
||||||
# -- Summary --------------------------------------------------------------
|
|
||||||
- name: Pipeline Summary
|
# -- Summary --------------------------------------------------------------
|
||||||
if: always()
|
- name: Pipeline Summary
|
||||||
run: |
|
if: always()
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
run: |
|
||||||
PLATFORM="${{ steps.platform.outputs.platform }}"
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
|
PLATFORM="${{ steps.platform.outputs.platform }}"
|
||||||
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
|
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
|
||||||
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
|
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
|
||||||
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
|
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
|
||||||
else
|
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
else
|
||||||
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
|
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
|
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
# 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
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokocli.Automation
|
# INGROUP: mokocli.Automation
|
||||||
# VERSION: 01.04.00
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Auto-create feature branch when an issue is opened
|
# BRIEF: Auto-create feature branch when an issue is opened
|
||||||
|
|
||||||
name: "Universal: Issue Branch"
|
name: "Universal: Issue Branch"
|
||||||
|
|||||||
+534
-534
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# FILE INFORMATION
|
|
||||||
# DEFGROUP: Gitea.Workflow
|
|
||||||
# INGROUP: MokoStandards.Security
|
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
|
||||||
# PATH: /.gitea/workflows/security-audit.yml
|
|
||||||
# VERSION: 01.00.00
|
|
||||||
# BRIEF: Dependency vulnerability scanning for composer and npm packages
|
|
||||||
|
|
||||||
name: "Universal: Security Audit"
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 6 * * 1' # Weekly on Monday at 06:00 UTC
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- 'composer.json'
|
|
||||||
- 'composer.lock'
|
|
||||||
- 'package.json'
|
|
||||||
- 'package-lock.json'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
|
|
||||||
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
audit:
|
|
||||||
name: Dependency Audit
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Composer audit
|
|
||||||
if: hashFiles('composer.lock') != ''
|
|
||||||
run: |
|
|
||||||
echo "=== Composer Security Audit ==="
|
|
||||||
if ! command -v composer &> /dev/null; then
|
|
||||||
sudo apt-get update -qq
|
|
||||||
sudo apt-get install -y -qq php-cli composer >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
composer audit --format=plain 2>&1 | tee /tmp/composer-audit.txt
|
|
||||||
RESULT=$?
|
|
||||||
if [ $RESULT -ne 0 ]; then
|
|
||||||
echo "::warning::Composer vulnerabilities found"
|
|
||||||
echo "composer_vulnerable=true" >> "$GITHUB_ENV"
|
|
||||||
else
|
|
||||||
echo "No known vulnerabilities in composer dependencies"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: NPM audit
|
|
||||||
if: hashFiles('package-lock.json') != ''
|
|
||||||
run: |
|
|
||||||
echo "=== NPM Security Audit ==="
|
|
||||||
npm audit --production 2>&1 | tee /tmp/npm-audit.txt || true
|
|
||||||
if npm audit --production 2>&1 | grep -q "found 0 vulnerabilities"; then
|
|
||||||
echo "No known vulnerabilities in npm dependencies"
|
|
||||||
else
|
|
||||||
echo "::warning::NPM vulnerabilities found"
|
|
||||||
echo "npm_vulnerable=true" >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Notify on vulnerabilities
|
|
||||||
if: env.composer_vulnerable == 'true' || env.npm_vulnerable == 'true'
|
|
||||||
run: |
|
|
||||||
REPO="${{ github.event.repository.name }}"
|
|
||||||
curl -sS \
|
|
||||||
-H "Title: ${REPO} has vulnerable dependencies" \
|
|
||||||
-H "Tags: lock,warning" \
|
|
||||||
-H "Priority: high" \
|
|
||||||
-d "Security audit found vulnerabilities. Review dependency updates." \
|
|
||||||
"${NTFY_URL}/${NTFY_TOPIC}" || true
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
#
|
|
||||||
# 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] <gitea-actions[bot]@mokoconsulting.tech>"
|
|
||||||
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
|
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# 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 || secrets.GA_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 "<extension" "$XML_FILE" 2>/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 '<version>\K[^<]+' "$MANIFEST" | head -1)
|
||||||
|
sed -i "s|<version>${OLD_VER}</version>|<version>${VERSION}</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
|
||||||
Reference in New Issue
Block a user