diff --git a/.github/workflows/auto-dev-issue.yml b/.github/workflows/auto-dev-issue.yml index 38730ab..38c6a53 100644 --- a/.github/workflows/auto-dev-issue.yml +++ b/.github/workflows/auto-dev-issue.yml @@ -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 diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index e9c2570..3e1caf3 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -8,7 +8,7 @@ # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/joomla/auto-release.yml.template # VERSION: 04.05.13 -# BRIEF: Joomla build & release — ZIP package, update.xml, SHA-256 checksum +# BRIEF: Joomla build & release — ZIP package, updates.xml, SHA-256 checksum # # +========================================================================+ # | BUILD & RELEASE PIPELINE (JOOMLA) | @@ -20,10 +20,10 @@ # | 1. Read version from README.md | # | 3. Set platform version (Joomla ) | # | 4. Update [VERSION: XX.YY.ZZ] badges in markdown files | -# | 5. Write update.xml (Joomla update server XML) | +# | 5. Write updates.xml (Joomla update server XML) | # | 6. Create git tag vXX.YY.ZZ | # | 7a. Patch: update existing GitHub Release for this minor | -# | 8. Build ZIP, upload asset, write SHA-256 to update.xml | +# | 8. Build ZIP, upload asset, write SHA-256 to updates.xml | # | | # | Every version change: archives main -> version/XX.YY branch | # | Patch 00 = development (no release). First release = patch 01. | @@ -39,6 +39,9 @@ on: branches: - main - master + paths: + - 'src/**' + - 'htdocs/**' env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true @@ -66,7 +69,7 @@ jobs: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' run: | - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards cd /tmp/mokostandards @@ -90,7 +93,7 @@ jobs: MINOR_NUM=$(echo "$VERSION" | awk -F. '{print $2}') echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "branch=version/${MINOR}" >> "$GITHUB_OUTPUT" + echo "branch=version/${MAJOR}" >> "$GITHUB_OUTPUT" echo "minor=$MINOR" >> "$GITHUB_OUTPUT" echo "major=$MAJOR" >> "$GITHUB_OUTPUT" echo "release_tag=v${MAJOR}" >> "$GITHUB_OUTPUT" @@ -256,8 +259,8 @@ jobs: fi done - # -- STEP 5: Write update.xml (Joomla update server) --------------------- - - name: "Step 5: Write update.xml" + # -- STEP 5: Write updates.xml (Joomla update server) --------------------- + - name: "Step 5: Write updates.xml" if: >- steps.version.outputs.skip != 'true' && steps.check.outputs.already_released != 'true' @@ -268,7 +271,7 @@ jobs: # -- Parse extension metadata from XML manifest ---------------- MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '/dev/null | head -1) if [ -z "$MANIFEST" ]; then - echo "Warning: No Joomla XML manifest found — skipping update.xml" >> $GITHUB_STEP_SUMMARY + echo "Warning: No Joomla XML manifest found — skipping updates.xml" >> $GITHUB_STEP_SUMMARY exit 0 fi @@ -313,34 +316,60 @@ 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}" - # -- Write update.xml (stable release) -------------------------- + # -- Build stable entry ────────────────────────────────────── + STABLE_ENTRY=$(cat < + ${EXT_NAME} + ${EXT_NAME} update + ${EXT_ELEMENT} + ${EXT_TYPE} + ${VERSION} + $([ -n "$CLIENT_TAG" ] && echo " ${CLIENT_TAG}") + $([ -n "$FOLDER_TAG" ] && echo " ${FOLDER_TAG}") + + stable + + ${INFO_URL} + + ${DOWNLOAD_URL} + + ${TARGET_PLATFORM} + $([ -n "$PHP_TAG" ] && echo " ${PHP_TAG}") + Moko Consulting + https://mokoconsulting.tech + +XMLEOF +) + + # -- 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'( .*?rc.*?)', 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'( .*?development.*?)', c, re.DOTALL) +if m: print(m.group(1)) +" 2>/dev/null || true) + fi + { printf '%s\n' '' printf '%s\n' '' - printf '%s\n' ' ' - printf '%s\n' " ${EXT_NAME}" - printf '%s\n' " ${EXT_NAME} update" - printf '%s\n' " ${EXT_ELEMENT}" - printf '%s\n' " ${EXT_TYPE}" - printf '%s\n' " ${VERSION}" - [ -n "$CLIENT_TAG" ] && printf '%s\n' " ${CLIENT_TAG}" - [ -n "$FOLDER_TAG" ] && printf '%s\n' " ${FOLDER_TAG}" - printf '%s\n' ' ' - printf '%s\n' ' stable' - printf '%s\n' ' ' - printf '%s\n' " ${INFO_URL}" - printf '%s\n' ' ' - printf '%s\n' " ${DOWNLOAD_URL}" - printf '%s\n' ' ' - printf '%s\n' " ${TARGET_PLATFORM}" - [ -n "$PHP_TAG" ] && printf '%s\n' " ${PHP_TAG}" - printf '%s\n' ' Moko Consulting' - printf '%s\n' ' https://mokoconsulting.tech' - printf '%s\n' ' ' + echo "$STABLE_ENTRY" + [ -n "$RC_ENTRY" ] && echo "$RC_ENTRY" + [ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY" printf '%s\n' '' - } > update.xml + } > updates.xml - echo "update.xml: ${VERSION} (stable) — ${EXT_TYPE}/${EXT_ELEMENT}" >> $GITHUB_STEP_SUMMARY + echo "updates.xml: ${VERSION} (stable + rc/dev preserved)" >> $GITHUB_STEP_SUMMARY # -- Commit all changes --------------------------------------------------- - name: Commit release changes @@ -469,19 +498,19 @@ jobs: gh release upload "$RELEASE_TAG" "/tmp/${PACKAGE_NAME}" 2>/dev/null || true } - # -- Update update.xml with SHA-256 for latest patch ------------- - if [ -f "update.xml" ]; then - if grep -q '' update.xml; then - sed -i "s|.*|sha256:${SHA256}|" update.xml + # -- Update updates.xml with SHA-256 for latest patch ------------- + if [ -f "updates.xml" ]; then + if grep -q '' updates.xml; then + sed -i "s|.*|sha256:${SHA256}|" updates.xml else - sed -i "s||\n sha256:${SHA256}|" update.xml + sed -i "s||\n sha256:${SHA256}|" updates.xml fi # Also update the download URL to point to this patch's ZIP DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}" - sed -i "s|]*>[^<]*|${DOWNLOAD_URL}|" update.xml + sed -i "s|]*>[^<]*|${DOWNLOAD_URL}|" updates.xml - git add update.xml + git add updates.xml git commit -m "chore(release): SHA-256 + download URL for ${VERSION} [skip ci]" \ --author="github-actions[bot] " || true git push || true diff --git a/.github/workflows/ci-joomla.yml b/.github/workflows/ci-joomla.yml index d7995d2..6281236 100644 --- a/.github/workflows/ci-joomla.yml +++ b/.github/workflows/ci-joomla.yml @@ -57,7 +57,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards @@ -312,11 +312,11 @@ jobs: fi fi - # Check update.xml exists - if [ -f "update.xml" ] || [ -f "updates.xml" ]; then + # Check updates.xml exists + if [ -f "updates.xml" ] || [ -f "updates.xml" ]; then echo "Update XML present." >> $GITHUB_STEP_SUMMARY else - echo "No update.xml found." >> $GITHUB_STEP_SUMMARY + echo "No updates.xml found." >> $GITHUB_STEP_SUMMARY ERRORS=$((ERRORS + 1)) fi diff --git a/.github/workflows/repo_health.yml b/.github/workflows/repo_health.yml index 0129292..885203a 100644 --- a/.github/workflows/repo_health.yml +++ b/.github/workflows/repo_health.yml @@ -595,9 +595,9 @@ jobs: joomla_findings+=("No .ini language files found") fi - # update.xml must exist in root (Joomla update server) - if [ ! -f 'update.xml' ]; then - joomla_findings+=("update.xml missing in root (required for Joomla update server)") + # updates.xml must exist in root (Joomla update server) + if [ ! -f 'updates.xml' ]; then + joomla_findings+=("updates.xml missing in root (required for Joomla update server)") fi # index.html files for directory listing protection diff --git a/.github/workflows/standards-compliance.yml b/.github/workflows/standards-compliance.yml index df8413c..773279d 100644 --- a/.github/workflows/standards-compliance.yml +++ b/.github/workflows/standards-compliance.yml @@ -509,7 +509,7 @@ jobs: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' run: | - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards 2>/dev/null || true if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then @@ -1978,7 +1978,7 @@ jobs: else echo "No composer.json — pulling MokoStandards tools" if [ ! -d "/tmp/mokostandards" ]; then - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards 2>/dev/null || true if [ -f "/tmp/mokostandards/composer.json" ]; then @@ -2050,7 +2050,7 @@ jobs: else echo "No composer.json — pulling MokoStandards tools" if [ ! -d "/tmp/mokostandards" ]; then - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards 2>/dev/null || true if [ -f "/tmp/mokostandards/composer.json" ]; then diff --git a/.github/workflows/sync-version-on-merge.yml b/.github/workflows/sync-version-on-merge.yml index 7b2ef6c..052a7ca 100644 --- a/.github/workflows/sync-version-on-merge.yml +++ b/.github/workflows/sync-version-on-merge.yml @@ -58,7 +58,7 @@ jobs: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' run: | - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards cd /tmp/mokostandards diff --git a/.github/workflows/update-server.yml b/.github/workflows/update-server.yml index 91d9365..28a6dd7 100644 --- a/.github/workflows/update-server.yml +++ b/.github/workflows/update-server.yml @@ -10,7 +10,7 @@ # VERSION: 04.05.13 # BRIEF: Update Joomla update server XML feed with stable/rc/dev entries # -# Writes update.xml with multiple entries: +# Writes updates.xml with multiple entries: # - stable on push to main (from auto-release) # - rc on push to rc/** # - development on push to dev/** @@ -47,7 +47,7 @@ permissions: jobs: update-xml: - name: Update update.xml + name: Update updates.xml runs-on: ubuntu-latest steps: @@ -62,14 +62,14 @@ jobs: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' run: | - git clone --depth 1 --branch version/04.05 --quiet \ + git clone --depth 1 --branch version/04 --quiet \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ /tmp/mokostandards 2>/dev/null || true if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true fi - - name: Generate update.xml entry + - name: Generate updates.xml entry run: | BRANCH="${{ github.ref_name }}" REPO="${{ github.repository }}" @@ -120,10 +120,42 @@ jobs: [ "$STABILITY" = "development" ] && DISPLAY_VERSION="${VERSION}-dev" MAJOR=$(echo "$VERSION" | awk -F. '{print $1}') - RELEASE_TAG="v${MAJOR}" - DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${EXT_ELEMENT}-${VERSION}.zip" + + # Each stability level has its own release tag + if [ "$STABILITY" = "rc" ]; then + RELEASE_TAG="release-candidate" + elif [ "$STABILITY" = "development" ]; then + RELEASE_TAG="development" + else + RELEASE_TAG="v${MAJOR}" + fi + + 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}" + # ── Build install-ready ZIP ───────────────────────────────── + SOURCE_DIR="src" + [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" + if [ -d "$SOURCE_DIR" ]; then + cd "$SOURCE_DIR" + zip -r "/tmp/${PACKAGE_NAME}" . + cd .. + + SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1) + + # Ensure draft release exists for this major + gh release view "$RELEASE_TAG" --json tagName > /dev/null 2>&1 || \ + 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 + + echo "Package: ${PACKAGE_NAME} (SHA: ${SHA256})" >> $GITHUB_STEP_SUMMARY + else + SHA256="" + fi + # ── Build the new entry ─────────────────────────────────────── NEW_ENTRY=$(cat < @@ -141,6 +173,7 @@ jobs: ${DOWNLOAD_URL} + $([ -n "$SHA256" ] && echo " sha256:${SHA256}") ${TARGET_PLATFORM} $([ -n "$PHP_TAG" ] && echo " ${PHP_TAG}") Moko Consulting @@ -149,20 +182,20 @@ jobs: XMLEOF ) - # ── Merge into update.xml ───────────────────────────────────── - if [ ! -f "update.xml" ]; then + # ── Merge into updates.xml ───────────────────────────────────── + if [ ! -f "updates.xml" ]; then # Create fresh - printf '%s\n' '' > update.xml - printf '%s\n' '' >> update.xml - echo "$NEW_ENTRY" >> update.xml - printf '%s\n' '' >> update.xml + printf '%s\n' '' > updates.xml + printf '%s\n' '' >> updates.xml + echo "$NEW_ENTRY" >> updates.xml + printf '%s\n' '' >> 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('update.xml', 'r') as f: +with open('updates.xml', 'r') as f: content = f.read() # Remove existing entry with this stability tag @@ -176,29 +209,29 @@ content = content.replace('', new_entry + '\n') # Clean up empty lines content = re.sub(r'\n{3,}', '\n\n', content) -with open('update.xml', 'w') as f: +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 'stable' update.xml; then - STABLE_ENTRY=$(sed -n '//,/<\/update>/{ /stable<\/tag>/,/<\/update>/p; //,/stable<\/tag>/p }' update.xml | sort -u) + if [ "$STABILITY" != "stable" ] && grep -q 'stable' updates.xml; then + STABLE_ENTRY=$(sed -n '//,/<\/update>/{ /stable<\/tag>/,/<\/update>/p; //,/stable<\/tag>/p }' updates.xml | sort -u) fi RC_ENTRY="" - if [ "$STABILITY" != "rc" ] && grep -q 'rc' update.xml; then + if [ "$STABILITY" != "rc" ] && grep -q 'rc' updates.xml; then RC_ENTRY=$(python3 -c " import re -with open('update.xml') as f: c = f.read() +with open('updates.xml') as f: c = f.read() m = re.search(r'(.*?rc.*?)', c, re.DOTALL) if m: print(m.group(1)) " 2>/dev/null || true) fi DEV_ENTRY="" - if [ "$STABILITY" != "development" ] && grep -q 'development' update.xml; then + if [ "$STABILITY" != "development" ] && grep -q 'development' updates.xml; then DEV_ENTRY=$(python3 -c " import re -with open('update.xml') as f: c = f.read() +with open('updates.xml') as f: c = f.read() m = re.search(r'(.*?development.*?)', c, re.DOTALL) if m: print(m.group(1)) " 2>/dev/null || true) @@ -212,16 +245,16 @@ if m: print(m.group(1)) [ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY" echo "$NEW_ENTRY" printf '%s\n' '' - } > update.xml + } > updates.xml } fi # Commit git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" - git add update.xml + git add updates.xml git diff --cached --quiet || { - git commit -m "chore: update update.xml (${STABILITY}: ${DISPLAY_VERSION}) [skip ci]" \ + git commit -m "chore: update updates.xml (${STABILITY}: ${DISPLAY_VERSION}) [skip ci]" \ --author="github-actions[bot] " git push }