From 030f057ab4caec6fcba0b7e9a906f1cc556f2098 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 26 May 2026 18:52:03 -0500 Subject: [PATCH 1/3] fix: preserve version suffix (-dev, -rc, etc.) during patch bump version_bump.php now detects and preserves the existing suffix from manifest versions. The suffix should only change when the branch changes, not on every patch bump. version_read.php now returns the full version including suffix. Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) --- cli/version_bump.php | 36 +++++++++++++++++++----------------- cli/version_read.php | 16 ++++------------ 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/cli/version_bump.php b/cli/version_bump.php index 5efb6c5..f2ba7c3 100644 --- a/cli/version_bump.php +++ b/cli/version_bump.php @@ -30,7 +30,7 @@ $mokoManifest = "{$root}/.mokogitea/manifest.xml"; $mokoContent = ''; if (file_exists($mokoManifest)) { $mokoContent = file_get_contents($mokoManifest); - if (preg_match('|(\d{2}\.\d{2}\.\d{2})(?:-([a-z]+))?|', $mokoContent, $m)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2})|', $mokoContent, $m)) { $mokoVersion = $m[1]; } } @@ -48,6 +48,7 @@ if (file_exists($readme)) { // -- 3. Fallback: Joomla manifest XML -- $manifestVersion = null; +$manifestSuffix = ''; $manifestFiles = array_merge( glob("{$root}/src/pkg_*.xml") ?: [], glob("{$root}/src/*.xml") ?: [], @@ -56,17 +57,17 @@ $manifestFiles = array_merge( glob("{$root}/*.xml") ?: [] ); -$manifestSuffix = ''; foreach ($manifestFiles as $xmlFile) { $xmlContent = file_get_contents($xmlFile); if (strpos($xmlContent, '') === false) { continue; } - if (preg_match('|(\d{2}\.\d{2}\.\d{2})(?:-([a-z]+))?|', $xmlContent, $xm)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2})(-[a-z]+)?|', $xmlContent, $xm)) { $candidate = $xm[1]; if ($manifestVersion === null || version_compare($candidate, $manifestVersion, '>')) { $manifestVersion = $candidate; - $manifestSuffix = isset($xm[2]) ? $xm[2] : ''; + // Preserve the suffix from the manifest (e.g. -dev, -rc) + $manifestSuffix = $xm[2] ?? ''; } } } @@ -108,15 +109,16 @@ switch ($type) { $new = sprintf('%02d.%02d.%02d', $major, $minor, $patch); -// -- Determine suffix to preserve (from whichever source had the version) -- -$suffix = !empty($manifestSuffix) ? $manifestSuffix : ''; -$newFull = $suffix !== '' ? "{$new}-{$suffix}" : $new; +// Preserve suffix from the original version (e.g. -dev, -rc, -alpha, -beta) +// The suffix only changes when the branch changes, not on patch bumps +$suffix = $manifestSuffix ?? ''; +$newWithSuffix = $new . $suffix; -// -- Update .mokogitea/manifest.xml (canonical target, no suffix) -- +// -- Update .mokogitea/manifest.xml (canonical target) -- if (file_exists($mokoManifest) && !empty($mokoContent)) { $updated = preg_replace( '|\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?|', - "{$new}", + "{$newWithSuffix}", $mokoContent, 1 ); @@ -126,8 +128,8 @@ if (file_exists($mokoManifest) && !empty($mokoContent)) { // -- Update README.md -- if (file_exists($readme) && !empty($readmeContent)) { $updated = preg_replace( - '/(VERSION:\s*)\d{2}\.\d{2}\.\d{2}/m', - '${1}' . $new, + '/(VERSION:\s*)\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?/m', + '${1}' . $newWithSuffix, $readmeContent, 1 ); @@ -152,7 +154,7 @@ foreach ($xmlPatterns as $pattern) { } $newContent = preg_replace( '|\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?|', - "{$newFull}", + "{$newWithSuffix}", $content ); if ($newContent !== $content) { @@ -171,8 +173,8 @@ $packageJsonFile = "{$root}/package.json"; if (file_exists($packageJsonFile)) { $pkgContent = file_get_contents($packageJsonFile); $updatedPkg = preg_replace( - '/("version"\s*:\s*")\d{2}\.\d{2}\.\d{2}(")/m', - '${1}' . $new . '${2}', + '/("version"\s*:\s*")\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?(")/m', + '${1}' . $newWithSuffix . '${2}', $pkgContent ); if ($updatedPkg !== $pkgContent) { @@ -186,8 +188,8 @@ $pyprojectFile = "{$root}/pyproject.toml"; if (file_exists($pyprojectFile)) { $pyContent = file_get_contents($pyprojectFile); $updatedPy = preg_replace( - '/^(version\s*=\s*")\d{2}\.\d{2}\.\d{2}(")/m', - '${1}' . $new . '${2}', + '/^(version\s*=\s*")\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?(")/m', + '${1}' . $newWithSuffix . '${2}', $pyContent ); if ($updatedPy !== $pyContent) { @@ -196,5 +198,5 @@ if (file_exists($pyprojectFile)) { } } -echo "{$old} -> {$newFull}\n"; +echo "{$old}{$suffix} -> {$newWithSuffix}\n"; exit(0); diff --git a/cli/version_read.php b/cli/version_read.php index f4c5457..a6baedf 100644 --- a/cli/version_read.php +++ b/cli/version_read.php @@ -54,7 +54,6 @@ if (file_exists($readme)) { // -- 3. Fallback: Joomla manifest XML -- $manifestVersion = null; -$manifestVersionSuffix = ''; $manifestFiles = array_merge( glob("{$root}/src/pkg_*.xml") ?: [], glob("{$root}/src/*.xml") ?: [], @@ -67,12 +66,12 @@ foreach ($manifestFiles as $xmlFile) { if (strpos($xmlContent, '') === false) { continue; } - if (preg_match('|(\d{2}\.\d{2}\.\d{2})(-[a-z]+)?|', $xmlContent, $xm)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?)|', $xmlContent, $xm)) { $candidate = $xm[1]; - $candidateSuffix = isset($xm[2]) ? $xm[2] : ''; - if ($manifestVersion === null || version_compare($candidate, $manifestVersion, '>')) { + $candidateBase = preg_replace('/-[a-z]+$/', '', $candidate); + $currentBase = $manifestVersion ? preg_replace('/-[a-z]+$/', '', $manifestVersion) : null; + if ($currentBase === null || version_compare($candidateBase, $currentBase, '>')) { $manifestVersion = $candidate; - $manifestVersionSuffix = $candidateSuffix; } } } @@ -106,11 +105,9 @@ $candidates = array_filter([ ]); $version = null; -$versionSource = ''; foreach ($candidates as $candidate) { if ($version === null || version_compare($candidate, $version, '>')) { $version = $candidate; - $versionSource = ($candidate === $manifestVersion) ? 'manifest' : 'other'; } } @@ -119,11 +116,6 @@ if ($version === null) { exit(1); } -// Append suffix if the version came from a Joomla manifest with a suffix -if ($versionSource === 'manifest' && !empty($manifestVersionSuffix)) { - $version .= $manifestVersionSuffix; -} - // -- Backfill: if manifest.xml exists but lacks , insert it -- if (file_exists($mokoManifest)) { $content = file_get_contents($mokoManifest); -- 2.52.0 From c73675234b5ddf6ace31549555a86e4342ad4a13 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Wed, 27 May 2026 02:19:40 +0000 Subject: [PATCH 2/3] feat(ci): add version branch creation on stable release [skip ci] --- .mokogitea/workflows/auto-release.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.mokogitea/workflows/auto-release.yml b/.mokogitea/workflows/auto-release.yml index ef09563..ffd47c8 100644 --- a/.mokogitea/workflows/auto-release.yml +++ b/.mokogitea/workflows/auto-release.yml @@ -456,6 +456,25 @@ jobs: echo "Dev branch reset from main (keeps dev ahead after release)" >> $GITHUB_STEP_SUMMARY + - name: "Step 12: Create version branch from main" + if: steps.version.outputs.skip != 'true' + continue-on-error: true + run: | + API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + TOKEN="${{ secrets.GA_TOKEN }}" + VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" + 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}" + + # 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 + + # -- Dolibarr post-release: Reset dev version ----------------------------- - name: "Post-release: Reset dev version" -- 2.52.0 From 51e599acef4e80d4a227f033215cfe33759e4ca4 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 26 May 2026 22:48:03 -0500 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20add=20branch-cleanup=20workflow=20?= =?UTF-8?q?=E2=80=94=20auto-delete=20merged=20feature=20branches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) --- .mokogitea/workflows/branch-cleanup.yml | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .mokogitea/workflows/branch-cleanup.yml diff --git a/.mokogitea/workflows/branch-cleanup.yml b/.mokogitea/workflows/branch-cleanup.yml new file mode 100644 index 0000000..ef5feb2 --- /dev/null +++ b/.mokogitea/workflows/branch-cleanup.yml @@ -0,0 +1,48 @@ +# Copyright (C) 2026 Moko Consulting +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: Gitea.Workflow +# INGROUP: MokoStandards.Universal +# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform +# PATH: /.mokogitea/workflows/branch-cleanup.yml +# VERSION: 01.00.00 +# BRIEF: Delete feature branches after PR merge + +name: "Branch Cleanup" + +on: + pull_request: + types: [closed] + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + cleanup: + name: Delete merged branch + runs-on: ubuntu-latest + if: >- + github.event.pull_request.merged == true && + github.event.pull_request.head.ref != 'dev' && + github.event.pull_request.head.ref != 'main' + + steps: + - name: Delete source branch + run: | + BRANCH="${{ github.event.pull_request.head.ref }}" + API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches" + ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${BRANCH}', safe=''))") + + STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \ + -H "Authorization: token ${{ secrets.GA_TOKEN }}" \ + "${API}/${ENCODED}" 2>/dev/null || true) + + if [ "$STATUS" = "204" ]; then + echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY + elif [ "$STATUS" = "404" ]; then + echo "Branch already deleted: ${BRANCH}" >> $GITHUB_STEP_SUMMARY + else + echo "::warning::Failed to delete branch ${BRANCH} (HTTP ${STATUS})" + fi -- 2.52.0