ci: separate release tags (development/release-candidate/vXX) [skip ci]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 20:08:24 -05:00
parent 2b437f1a31
commit b86e5f841d
3 changed files with 114 additions and 140 deletions
+9 -17
View File
@@ -156,30 +156,22 @@ jobs:
done
fi
# ── RC: Create or update draft release ────────────────────────────
# ── RC: Create or update release-candidate release ──────────────
if [[ "$BRANCH" == rc/* ]]; then
MAJOR=$(echo "$VERSION" | awk -F. '{print $1}')
RELEASE_TAG="v${MAJOR}"
DRAFT_EXISTS=$(gh release view "$RELEASE_TAG" --json isDraft -q .isDraft 2>/dev/null || true)
RELEASE_TAG="release-candidate"
EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
if [ -z "$DRAFT_EXISTS" ]; then
# No release exists — create draft
if [ -z "$EXISTING" ]; then
gh release create "$RELEASE_TAG" \
--title "v${MAJOR} (RC: ${VERSION})" \
--title "release-candidate (${VERSION})" \
--notes "## Release Candidate ${VERSION}\n\nRC branch: \`${BRANCH}\`\nTracking issue: ${PARENT_URL}" \
--draft \
--prerelease \
--target main 2>/dev/null || true
echo "Draft release created: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
elif [ "$DRAFT_EXISTS" = "true" ]; then
# Draft exists — update title
gh release edit "$RELEASE_TAG" \
--title "v${MAJOR} (RC: ${VERSION})" --draft 2>/dev/null || true
echo "Draft release updated: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
echo "RC release created: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
else
# Release exists and is published — set back to draft for RC
gh release edit "$RELEASE_TAG" \
--title "v${MAJOR} (RC: ${VERSION})" --draft 2>/dev/null || true
echo "Release ${RELEASE_TAG} set to draft for RC" >> $GITHUB_STEP_SUMMARY
--title "release-candidate (${VERSION})" --prerelease 2>/dev/null || true
echo "RC release updated: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
fi
fi
+31 -38
View File
@@ -316,54 +316,47 @@ jobs:
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${EXT_ELEMENT}-${VERSION}.zip"
INFO_URL="https://github.com/${REPO}/releases/tag/v${VERSION}"
# -- Build stable entry ──────────────────────────────────────
STABLE_ENTRY=$(cat <<XMLEOF
<update>
<name>${EXT_NAME}</name>
<description>${EXT_NAME} update</description>
<element>${EXT_ELEMENT}</element>
<type>${EXT_TYPE}</type>
<version>${VERSION}</version>
$([ -n "$CLIENT_TAG" ] && echo " ${CLIENT_TAG}")
$([ -n "$FOLDER_TAG" ] && echo " ${FOLDER_TAG}")
<tags>
<tag>stable</tag>
</tags>
<infourl title="${EXT_NAME}">${INFO_URL}</infourl>
<downloads>
<downloadurl type="full" format="zip">${DOWNLOAD_URL}</downloadurl>
</downloads>
${TARGET_PLATFORM}
$([ -n "$PHP_TAG" ] && echo " ${PHP_TAG}")
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
XMLEOF
)
# -- Build stable entry to temp file ─────────────────────────
{
printf '%s\n' ' <update>'
printf '%s\n' " <name>${EXT_NAME}</name>"
printf '%s\n' " <description>${EXT_NAME} update</description>"
printf '%s\n' " <element>${EXT_ELEMENT}</element>"
printf '%s\n' " <type>${EXT_TYPE}</type>"
printf '%s\n' " <version>${VERSION}</version>"
[ -n "$CLIENT_TAG" ] && printf '%s\n' " ${CLIENT_TAG}"
[ -n "$FOLDER_TAG" ] && printf '%s\n' " ${FOLDER_TAG}"
printf '%s\n' ' <tags>'
printf '%s\n' ' <tag>stable</tag>'
printf '%s\n' ' </tags>'
printf '%s\n' " <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>"
printf '%s\n' ' <downloads>'
printf '%s\n' " <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>"
printf '%s\n' ' </downloads>'
printf '%s\n' " ${TARGET_PLATFORM}"
[ -n "$PHP_TAG" ] && printf '%s\n' " ${PHP_TAG}"
printf '%s\n' ' <maintainer>Moko Consulting</maintainer>'
printf '%s\n' ' <maintainerurl>https://mokoconsulting.tech</maintainerurl>'
printf '%s\n' ' </update>'
} > /tmp/stable_entry.xml
# -- Write updates.xml preserving dev/rc entries ──────────────
# Extract existing dev and rc entries if present
RC_ENTRY=""
DEV_ENTRY=""
if [ -f "updates.xml" ]; then
RC_ENTRY=$(python3 -c "
import re
with open('updates.xml') as f: c = f.read()
m = re.search(r'( <update>.*?<tag>rc</tag>.*?</update>)', c, re.DOTALL)
if m: print(m.group(1))
" 2>/dev/null || true)
DEV_ENTRY=$(python3 -c "
import re
with open('updates.xml') as f: c = f.read()
m = re.search(r'( <update>.*?<tag>development</tag>.*?</update>)', c, re.DOTALL)
if m: print(m.group(1))
" 2>/dev/null || true)
printf 'import re\n' > /tmp/extract.py
printf 'with open("updates.xml") as f: c = f.read()\n' >> /tmp/extract.py
printf 'import sys; tag = sys.argv[1]\n' >> /tmp/extract.py
printf 'm = re.search(r"( <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)", c, re.DOTALL)\n' >> /tmp/extract.py
printf 'if m: print(m.group(1))\n' >> /tmp/extract.py
RC_ENTRY=$(python3 /tmp/extract.py rc 2>/dev/null || true)
DEV_ENTRY=$(python3 /tmp/extract.py development 2>/dev/null || true)
fi
{
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
printf '%s\n' '<updates>'
echo "$STABLE_ENTRY"
cat /tmp/stable_entry.xml
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
printf '%s\n' '</updates>'
+74 -85
View File
@@ -23,6 +23,8 @@ on:
push:
branches:
- 'dev/**'
- 'alpha/**'
- 'beta/**'
- 'rc/**'
paths:
- 'src/**'
@@ -30,12 +32,14 @@ on:
workflow_dispatch:
inputs:
stability:
description: 'Stability tag (development, rc, stable)'
description: 'Stability tag'
required: true
default: 'development'
type: choice
options:
- development
- alpha
- beta
- rc
- stable
@@ -80,6 +84,10 @@ jobs:
STABILITY="${{ inputs.stability }}"
elif [[ "$BRANCH" == rc/* ]]; then
STABILITY="rc"
elif [[ "$BRANCH" == beta/* ]]; then
STABILITY="beta"
elif [[ "$BRANCH" == alpha/* ]]; then
STABILITY="alpha"
elif [[ "$BRANCH" == dev/* ]]; then
STABILITY="development"
else
@@ -116,11 +124,24 @@ jobs:
# Version suffix for non-stable
DISPLAY_VERSION="$VERSION"
[ "$STABILITY" = "rc" ] && DISPLAY_VERSION="${VERSION}-rc"
[ "$STABILITY" = "development" ] && DISPLAY_VERSION="${VERSION}-dev"
case "$STABILITY" in
development) DISPLAY_VERSION="${VERSION}-dev" ;;
alpha) DISPLAY_VERSION="${VERSION}-alpha" ;;
beta) DISPLAY_VERSION="${VERSION}-beta" ;;
rc) DISPLAY_VERSION="${VERSION}-rc" ;;
esac
MAJOR=$(echo "$VERSION" | awk -F. '{print $1}')
RELEASE_TAG="v${MAJOR}"
# Each stability level has its own release tag
case "$STABILITY" in
development) RELEASE_TAG="development" ;;
alpha) RELEASE_TAG="alpha" ;;
beta) RELEASE_TAG="beta" ;;
rc) RELEASE_TAG="release-candidate" ;;
*) RELEASE_TAG="v${MAJOR}" ;;
esac
PACKAGE_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.zip"
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
INFO_URL="https://github.com/${REPO}"
@@ -137,7 +158,7 @@ jobs:
# Ensure draft release exists for this major
gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || \
gh release create "$RELEASE_TAG" --title "v${MAJOR}" --notes "Development release" --draft --target main 2>/dev/null || true
gh release create "$RELEASE_TAG" --title "${RELEASE_TAG} (${DISPLAY_VERSION})" --notes "${STABILITY} release" --prerelease --target main 2>/dev/null || true
# Upload ZIP to the major release
gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" --clobber 2>/dev/null || true
@@ -148,95 +169,63 @@ jobs:
fi
# ── Build the new entry ───────────────────────────────────────
NEW_ENTRY=$(cat <<XMLEOF
<update>
<name>${EXT_NAME}</name>
<description>${EXT_NAME} (${STABILITY})</description>
<element>${EXT_ELEMENT}</element>
<type>${EXT_TYPE}</type>
<version>${DISPLAY_VERSION}</version>
$([ -n "$CLIENT_TAG" ] && echo " ${CLIENT_TAG}")
$([ -n "$FOLDER_TAG" ] && echo " ${FOLDER_TAG}")
<tags>
<tag>${STABILITY}</tag>
</tags>
<infourl title="${EXT_NAME}">${INFO_URL}</infourl>
<downloads>
<downloadurl type="full" format="zip">${DOWNLOAD_URL}</downloadurl>
</downloads>
$([ -n "$SHA256" ] && echo " <sha256>sha256:${SHA256}</sha256>")
${TARGET_PLATFORM}
$([ -n "$PHP_TAG" ] && echo " ${PHP_TAG}")
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
XMLEOF
)
NEW_ENTRY=""
NEW_ENTRY="${NEW_ENTRY} <update>\n"
NEW_ENTRY="${NEW_ENTRY} <name>${EXT_NAME}</name>\n"
NEW_ENTRY="${NEW_ENTRY} <description>${EXT_NAME} (${STABILITY})</description>\n"
NEW_ENTRY="${NEW_ENTRY} <element>${EXT_ELEMENT}</element>\n"
NEW_ENTRY="${NEW_ENTRY} <type>${EXT_TYPE}</type>\n"
NEW_ENTRY="${NEW_ENTRY} <version>${DISPLAY_VERSION}</version>\n"
[ -n "$CLIENT_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${CLIENT_TAG}\n"
[ -n "$FOLDER_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${FOLDER_TAG}\n"
NEW_ENTRY="${NEW_ENTRY} <tags>\n"
NEW_ENTRY="${NEW_ENTRY} <tag>${STABILITY}</tag>\n"
NEW_ENTRY="${NEW_ENTRY} </tags>\n"
NEW_ENTRY="${NEW_ENTRY} <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>\n"
NEW_ENTRY="${NEW_ENTRY} <downloads>\n"
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>\n"
NEW_ENTRY="${NEW_ENTRY} </downloads>\n"
[ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} <sha256>sha256:${SHA256}</sha256>\n"
NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n"
[ -n "$PHP_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${PHP_TAG}\n"
NEW_ENTRY="${NEW_ENTRY} <maintainer>Moko Consulting</maintainer>\n"
NEW_ENTRY="${NEW_ENTRY} <maintainerurl>https://mokoconsulting.tech</maintainerurl>\n"
NEW_ENTRY="${NEW_ENTRY} </update>"
# ── Write new entry to temp file ───────────────────────────────
printf '%b' "$NEW_ENTRY" > /tmp/new_entry.xml
# ── Merge into updates.xml ─────────────────────────────────────
if [ ! -f "updates.xml" ]; then
# Create fresh
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>' > updates.xml
printf '%s\n' '<updates>' >> updates.xml
echo "$NEW_ENTRY" >> updates.xml
printf '%s\n' '</updates>' >> updates.xml
cat /tmp/new_entry.xml >> updates.xml
printf '\n%s\n' '</updates>' >> updates.xml
else
# Remove existing entry for this stability, add new one
# Use python for reliable XML manipulation
python3 -c "
import re, sys
with open('updates.xml', 'r') as f:
content = f.read()
# Remove existing entry with this stability tag
pattern = r' <update>.*?<tag>${STABILITY}</tag>.*?</update>\n?'
content = re.sub(pattern, '', content, flags=re.DOTALL)
# Insert new entry before </updates>
new_entry = '''${NEW_ENTRY}'''
content = content.replace('</updates>', new_entry + '\n</updates>')
# Clean up empty lines
content = re.sub(r'\n{3,}', '\n\n', content)
with open('updates.xml', 'w') as f:
f.write(content)
" 2>/dev/null || {
# Fallback: just rewrite the whole file if python fails
# Keep existing stable entry if present
STABLE_ENTRY=""
if [ "$STABILITY" != "stable" ] && grep -q '<tag>stable</tag>' updates.xml; then
STABLE_ENTRY=$(sed -n '/<update>/,/<\/update>/{ /<tag>stable<\/tag>/,/<\/update>/p; /<update>/,/<tag>stable<\/tag>/p }' updates.xml | sort -u)
fi
RC_ENTRY=""
if [ "$STABILITY" != "rc" ] && grep -q '<tag>rc</tag>' updates.xml; then
RC_ENTRY=$(python3 -c "
import re
with open('updates.xml') as f: c = f.read()
m = re.search(r'(<update>.*?<tag>rc</tag>.*?</update>)', c, re.DOTALL)
if m: print(m.group(1))
" 2>/dev/null || true)
fi
DEV_ENTRY=""
if [ "$STABILITY" != "development" ] && grep -q '<tag>development</tag>' updates.xml; then
DEV_ENTRY=$(python3 -c "
import re
with open('updates.xml') as f: c = f.read()
m = re.search(r'(<update>.*?<tag>development</tag>.*?</update>)', c, re.DOTALL)
if m: print(m.group(1))
" 2>/dev/null || true)
fi
# Remove existing entry for this stability, insert new one
printf 'import re\nstability = "%s"\n' "${STABILITY}" > /tmp/merge_xml.py
printf 'with open("updates.xml") as f: content = f.read()\n' >> /tmp/merge_xml.py
printf 'with open("/tmp/new_entry.xml") as f: new_entry = f.read()\n' >> /tmp/merge_xml.py
printf 'pattern = r" <update>.*?<tag>" + re.escape(stability) + r"</tag>.*?</update>\\n?"\n' >> /tmp/merge_xml.py
printf 'content = re.sub(pattern, "", content, flags=re.DOTALL)\n' >> /tmp/merge_xml.py
printf 'content = content.replace("</updates>", new_entry + "\\n</updates>")\n' >> /tmp/merge_xml.py
printf 'content = re.sub(r"\\n{3,}", "\\n\\n", content)\n' >> /tmp/merge_xml.py
printf 'with open("updates.xml", "w") as f: f.write(content)\n' >> /tmp/merge_xml.py
python3 /tmp/merge_xml.py 2>/dev/null || {
# Fallback: rebuild keeping other stability entries
{
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
printf '%s\n' '<updates>'
[ -n "$STABLE_ENTRY" ] && echo "$STABLE_ENTRY"
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
echo "$NEW_ENTRY"
printf '%s\n' '</updates>'
} > updates.xml
for TAG in stable rc development; do
[ "$TAG" = "${STABILITY}" ] && continue
if grep -q "<tag>${TAG}</tag>" updates.xml 2>/dev/null; then
sed -n "/<update>/,/<\/update>/{ /<tag>${TAG}<\/tag>/p; }" updates.xml
fi
done
cat /tmp/new_entry.xml
printf '\n%s\n' '</updates>'
} > /tmp/updates_new.xml
mv /tmp/updates_new.xml updates.xml
}
fi