diff --git a/.mokogitea/release.yml b/.mokogitea/release.yml new file mode 100644 index 00000000..07d1b248 --- /dev/null +++ b/.mokogitea/release.yml @@ -0,0 +1,600 @@ +# Copyright (C) 2026 Moko Consulting +# +# This file is part of a Moko Consulting project. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: Gitea.Workflow +# INGROUP: MokoStandards.Joomla +# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards +# PATH: /.gitea/workflows/release.yml +# VERSION: 02.00.00 +# BRIEF: Generic Joomla release — auto-detects element from manifest, stream tags, cascade + +name: Create Release + +on: + push: + tags: + - 'stable' + - 'release-candidate' + - 'beta' + - 'alpha' + - 'development' + workflow_dispatch: + inputs: + stability: + description: 'Stability tag' + required: true + default: 'stable' + type: choice + options: + - stable + - release-candidate + - beta + - alpha + - development + +permissions: + contents: write + +env: + 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 }} + +jobs: + build: + name: Build Release Package + runs-on: release + + steps: + # Always checkout main for tag triggers (avoids detached HEAD). + # For workflow_dispatch, checkout whatever branch was selected. + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'push' && 'main' || github.ref }} + fetch-depth: 0 + token: ${{ secrets.GA_TOKEN }} + + - 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 + echo "PHP: $(php -v | head -1)" + echo "Composer: $(composer --version 2>&1 | head -1)" + + - name: Get version and stability + id: meta + run: | + echo "=== Meta ===" + echo "event_name: ${{ github.event_name }}" + echo "ref: ${{ github.ref }}" + echo "ref_name: ${{ github.ref_name }}" + echo "sha: ${{ github.sha }}" + + # Derive stability from tag name or dispatch input + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + STABILITY="${{ inputs.stability }}" + else + TAG_PUSHED="${GITHUB_REF#refs/tags/}" + case "$TAG_PUSHED" in + stable) STABILITY="stable" ;; + release-candidate) STABILITY="rc" ;; + beta) STABILITY="beta" ;; + alpha) STABILITY="alpha" ;; + development) STABILITY="development" ;; + *) STABILITY="stable" ;; + esac + fi + + # Read version from README.md (will be bumped in next step) + VERSION=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1) + [ -z "$VERSION" ] && VERSION="00.00.00" + + # Auto-detect extension element from Joomla manifest + # Search depth 3 covers src/admin/com_xxx.xml and similar nested structures + MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "./build/*" -exec grep -l '/dev/null | head -1) + EXT_ELEMENT="" + if [ -n "$MANIFEST" ]; then + EXT_ELEMENT=$(sed -n 's/.*\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1) + # If no tag, derive from manifest filename or repo name + if [ -z "$EXT_ELEMENT" ]; then + EXT_ELEMENT=$(basename "$MANIFEST" .xml | tr '[:upper:]' '[:lower:]') + case "$EXT_ELEMENT" in + templatedetails|manifest) EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') ;; + esac + fi + echo "Manifest: ${MANIFEST}, element: ${EXT_ELEMENT}" + else + EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') + echo "No manifest found, using repo name: ${EXT_ELEMENT}" + fi + + case "$STABILITY" in + development) SUFFIX="-dev"; TAG_NAME="development" ;; + alpha) SUFFIX="-alpha"; TAG_NAME="alpha" ;; + beta) SUFFIX="-beta"; TAG_NAME="beta" ;; + rc) SUFFIX="-rc"; TAG_NAME="release-candidate" ;; + stable) SUFFIX=""; TAG_NAME="stable" ;; + *) SUFFIX="-dev"; TAG_NAME="development" ;; + esac + + PRERELEASE="true" + [ "$STABILITY" = "stable" ] && PRERELEASE="false" + + ZIP_NAME="${EXT_ELEMENT}-${VERSION}${SUFFIX}.zip" + + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT" + echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT" + echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT" + echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT" + echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT" + echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT" + + echo "=== Resolved ===" + echo "VERSION=${VERSION}" + echo "STABILITY=${STABILITY}" + echo "TAG_NAME=${TAG_NAME}" + echo "ZIP_NAME=${ZIP_NAME}" + echo "Branch: $(git branch --show-current)" + + - name: Auto-bump patch version + id: bump + env: + GA_TOKEN: ${{ secrets.GA_TOKEN }} + INPUT_VERSION: ${{ steps.meta.outputs.version }} + INPUT_STABILITY: ${{ steps.meta.outputs.stability }} + INPUT_SUFFIX: ${{ steps.meta.outputs.suffix }} + EXT_ELEMENT: ${{ steps.meta.outputs.ext_element }} + run: | + BRANCH=$(git branch --show-current) + GITEA_API="${GITEA_URL}/api/v1/repos/${{ github.repository }}" + + echo "=== Version Bump ===" + echo "On branch: ${BRANCH}" + + # Read current version from README.md + CURRENT=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1) + echo "Current version in README: ${CURRENT}" + + if [ -z "$CURRENT" ]; then + echo "No VERSION in README.md — using input version" + echo "version=${INPUT_VERSION}" >> "$GITHUB_OUTPUT" + echo "zip_name=${EXT_ELEMENT}-${INPUT_VERSION}${INPUT_SUFFIX}.zip" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Bump patch: XX.YY.ZZ → XX.YY.(ZZ+1) + MAJOR=$(echo "$CURRENT" | cut -d. -f1) + MINOR=$(echo "$CURRENT" | cut -d. -f2) + PATCH=$(echo "$CURRENT" | cut -d. -f3) + NEW_PATCH=$(printf "%02d" $((10#$PATCH + 1))) + NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" + TODAY=$(date +%Y-%m-%d) + + echo "Bumping: ${CURRENT} → ${NEW_VERSION} (date: ${TODAY})" + + # Update README.md + sed -i "s/VERSION:[[:space:]]*${CURRENT}/VERSION: ${NEW_VERSION}/" README.md + + # Update manifest (templateDetails.xml / *.xml with ) + MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "./build/*" -exec grep -l '/dev/null | head -1) + if [ -n "$MANIFEST" ]; then + echo "Manifest: ${MANIFEST}" + sed -i "s|${CURRENT}|${NEW_VERSION}|" "$MANIFEST" + sed -i "s|[^<]*|${TODAY}|" "$MANIFEST" + fi + + # Update matching stability channel in updates.xml + if [ -f "updates.xml" ]; then + export PY_OLD="$CURRENT" PY_NEW="$NEW_VERSION" PY_STABILITY="$INPUT_STABILITY" PY_DATE="$TODAY" + python3 << 'PYEOF' + import re, os + old = os.environ["PY_OLD"] + new = os.environ["PY_NEW"] + stability = os.environ["PY_STABILITY"] + date = os.environ["PY_DATE"] + with open("updates.xml") as f: + content = f.read() + pattern = r"((?:(?!).)*?" + re.escape(stability) + r".*?)" + match = re.search(pattern, content, re.DOTALL) + if match: + block = match.group(1) + updated = block.replace(old, new) + updated = re.sub(r"[^<]*", f"{date}", updated) + content = content.replace(block, updated) + print(f"Updated {stability} channel: {old} -> {new}") + else: + print(f"WARNING: No block found for {stability}") + with open("updates.xml", "w") as f: + f.write(content) + PYEOF + fi + + # Commit and push version bump + git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" + git config --local user.name "gitea-actions[bot]" + git remote set-url origin "https://jmiller:${GA_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git" + git add -A + git diff --cached --quiet && echo "No changes to commit" || { + git commit -m "chore(version): bump ${CURRENT} → ${NEW_VERSION} [skip ci]" \ + --author="gitea-actions[bot] " + echo "Pushing version bump to ${BRANCH}..." + git push origin HEAD:${BRANCH} 2>&1 + echo "Push exit code: $?" + } + + # For stable releases from non-main: merge to main via Gitea API + if [ "$INPUT_STABILITY" = "stable" ] && [ "$BRANCH" != "main" ]; then + echo "Merging ${BRANCH} → main via Gitea API..." + HTTP_CODE=$(curl -sS -o /tmp/merge_response.json -w "%{http_code}" \ + -X POST -H "Authorization: token ${GA_TOKEN}" \ + -H "Content-Type: application/json" \ + "${GITEA_API}/merges" \ + -d "$(jq -n \ + --arg base "main" \ + --arg head "${BRANCH}" \ + --arg msg "chore(release): merge ${BRANCH} for stable ${NEW_VERSION} [skip ci]" \ + '{base: $base, head: $head, merge_message_field: $msg}' + )") + echo "Merge response (HTTP ${HTTP_CODE}):" + cat /tmp/merge_response.json 2>/dev/null; echo + fi + + echo "version=${NEW_VERSION}" >> "$GITHUB_OUTPUT" + echo "zip_name=${EXT_ELEMENT}-${NEW_VERSION}${INPUT_SUFFIX}.zip" >> "$GITHUB_OUTPUT" + echo "=== Bump complete: ${NEW_VERSION} ===" + + - name: Install dependencies + env: + COMPOSER_AUTH: '{"http-basic":{"git.mokoconsulting.tech":{"username":"token","password":"${{ secrets.GA_TOKEN }}"}}}' + run: | + if [ -f "composer.json" ]; then + echo "Installing composer dependencies..." + composer install --no-dev --optimize-autoloader --no-interaction 2>&1 + else + echo "No composer.json — skipping" + fi + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Minify CSS and JS + run: | + if [ -f "package.json" ] && [ -f "scripts/minify.js" ]; then + npm ci --ignore-scripts + node scripts/minify.js + else + echo "No minify setup — skipping" + fi + + - name: Create package + run: | + # Detect source directory (src/ or htdocs/) + SOURCE_DIR="src" + [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" + if [ ! -d "$SOURCE_DIR" ]; then + echo "::error::No src/ or htdocs/ directory found" + exit 1 + fi + echo "Source directory: ${SOURCE_DIR}" + + mkdir -p build/package + rsync -av \ + --exclude='sftp-config*' \ + --exclude='.ftpignore' \ + --exclude='*.ppk' \ + --exclude='*.pem' \ + --exclude='*.key' \ + --exclude='.env*' \ + --exclude='*.local' \ + --exclude='.build-trigger' \ + --exclude='.beta-trigger' \ + --exclude='.rc-trigger' \ + "${SOURCE_DIR}/" build/package/ + echo "Package contents:" + ls -la build/package/ | head -20 + + - name: Build ZIP + id: zip + run: | + ZIP_NAME="${{ steps.bump.outputs.zip_name }}" + echo "Building: ${ZIP_NAME}" + cd build/package + zip -r "../${ZIP_NAME}" . + cd .. + + SHA256=$(sha256sum "${ZIP_NAME}" | cut -d' ' -f1) + SIZE=$(stat -c%s "${ZIP_NAME}") + + echo "sha256=${SHA256}" >> "$GITHUB_OUTPUT" + echo "size=${SIZE}" >> "$GITHUB_OUTPUT" + echo "=== Package Built ===" + echo "ZIP: ${ZIP_NAME}" + echo "SHA-256: ${SHA256}" + echo "Size: ${SIZE} bytes" + + # ── Gitea Release (PRIMARY) ─────────────────────────���──────────── + - name: "Gitea: Create or update release" + id: gitea_release + env: + EXT_ELEMENT: ${{ steps.meta.outputs.ext_element }} + run: | + TAG="${{ steps.meta.outputs.tag_name }}" + VERSION="${{ steps.bump.outputs.version }}" + STABILITY="${{ steps.meta.outputs.stability }}" + SHA256="${{ steps.zip.outputs.sha256 }}" + TOKEN="${{ secrets.GA_TOKEN }}" + API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + BRANCH=$(git branch --show-current) + MAX_HISTORY=5 + + IS_PRE="true" + [ "$STABILITY" = "stable" ] && IS_PRE="false" + + # Build this version's entry + NEW_ENTRY="## ${VERSION} ($(date +%Y-%m-%d)) + **SHA-256:** \`${SHA256}\`" + + if [ -f "CHANGELOG.md" ]; then + NOTES=$(awk "/## \[${VERSION}\]/,/## \[/{if(/## \[${VERSION}\]/)next;if(/## \[/)exit;print}" CHANGELOG.md) + [ -n "$NOTES" ] && NEW_ENTRY="## ${VERSION} ($(date +%Y-%m-%d)) + ${NOTES} + **SHA-256:** \`${SHA256}\`" + fi + + # Check for existing release — keep last N versions in body + EXISTING_BODY="" + EXISTING_ID="" + RELEASE_JSON=$(curl -sS -H "Authorization: token ${TOKEN}" \ + "${API}/releases/tags/${TAG}" 2>/dev/null) + EXISTING_ID=$(echo "$RELEASE_JSON" | jq -r '.id // empty') + + if [ -n "$EXISTING_ID" ]; then + echo "Existing release found: id=${EXISTING_ID}" + EXISTING_BODY=$(echo "$RELEASE_JSON" | jq -r '.body // ""') + + # Keep only last (MAX_HISTORY - 1) version entries to make room for new one + TRIMMED_BODY=$(echo "$EXISTING_BODY" | python3 -c " + import sys, re + content = sys.stdin.read() + # Split on version headers (## XX.YY.ZZ) + parts = re.split(r'(?=^## \d)', content, flags=re.MULTILINE) + # Keep only version entries (skip any preamble) + versions = [p for p in parts if re.match(r'^## \d', p)] + # Keep last $((MAX_HISTORY - 1)) entries + kept = versions[:$((MAX_HISTORY - 1))] + print('\n---\n'.join(kept)) + " 2>/dev/null || echo "") + + # Delete old release and tag so we can recreate + curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \ + "${API}/releases/${EXISTING_ID}" 2>/dev/null || true + curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \ + "${API}/tags/${TAG}" 2>/dev/null || true + fi + + # Compose full body: new entry + previous entries + if [ -n "$TRIMMED_BODY" ]; then + FULL_BODY="${NEW_ENTRY} + + --- + + ${TRIMMED_BODY}" + else + FULL_BODY="${NEW_ENTRY}" + fi + + echo "=== Create Release ===" + echo "TAG=${TAG} VERSION=${VERSION} BRANCH=${BRANCH} PRE=${IS_PRE} HISTORY=${MAX_HISTORY}" + + HTTP_CODE=$(curl -sS -o /tmp/create_release.json -w "%{http_code}" \ + -X POST -H "Authorization: token ${TOKEN}" \ + -H "Content-Type: application/json" \ + "${API}/releases" \ + -d "$(jq -n \ + --arg tag "$TAG" \ + --arg target "$BRANCH" \ + --arg name "${EXT_ELEMENT} ${VERSION} (${STABILITY})" \ + --arg body "$FULL_BODY" \ + --argjson pre "$IS_PRE" \ + '{tag_name: $tag, target_commitish: $target, name: $name, body: $body, prerelease: $pre}' + )") + + echo "Response (HTTP ${HTTP_CODE}):" + cat /tmp/create_release.json | jq . 2>/dev/null || cat /tmp/create_release.json + echo + + RELEASE_ID=$(jq -r '.id // empty' /tmp/create_release.json) + if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then + echo "::error::Failed to create release (HTTP ${HTTP_CODE})" + exit 1 + fi + + echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT" + echo "Release created: id=${RELEASE_ID}" + + - name: "Gitea: Upload ZIP" + run: | + RELEASE_ID="${{ steps.gitea_release.outputs.release_id }}" + ZIP_NAME="${{ steps.bump.outputs.zip_name }}" + TOKEN="${{ secrets.GA_TOKEN }}" + API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + + echo "Uploading ${ZIP_NAME} to release ${RELEASE_ID}..." + HTTP_CODE=$(curl -sS -o /tmp/upload_response.json -w "%{http_code}" \ + -X POST \ + -H "Authorization: token ${TOKEN}" \ + -H "Content-Type: application/octet-stream" \ + "${API}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" \ + --data-binary "@build/${ZIP_NAME}") + + echo "Upload response (HTTP ${HTTP_CODE}):" + cat /tmp/upload_response.json | jq . 2>/dev/null || cat /tmp/upload_response.json + echo + + if [ "$HTTP_CODE" -ge 400 ]; then + echo "::error::Upload failed (HTTP ${HTTP_CODE})" + exit 1 + fi + echo "Uploaded ${ZIP_NAME}" + + # ── Update updates.xml ────────────────────────────────────────── + - name: "Update updates.xml with SHA and sync to main" + run: | + STABILITY="${{ steps.meta.outputs.stability }}" + VERSION="${{ steps.bump.outputs.version }}" + SHA256="${{ steps.zip.outputs.sha256 }}" + ZIP_NAME="${{ steps.bump.outputs.zip_name }}" + TAG="${{ steps.meta.outputs.tag_name }}" + DATE=$(date +%Y-%m-%d) + BRANCH=$(git branch --show-current) + + echo "=== Update updates.xml ===" + echo "STABILITY=${STABILITY} VERSION=${VERSION} SHA=${SHA256:0:16}..." + + if [ ! -f "updates.xml" ] || [ -z "$SHA256" ]; then + echo "No updates.xml or no SHA — skipping" + exit 0 + fi + + # Cascade map: each stability level updates itself + all lower levels + # stable → all | rc → rc,beta,alpha,dev | beta → beta,alpha,dev | alpha → alpha,dev | dev → dev + case "$STABILITY" in + stable) CASCADE="development,alpha,beta,rc,stable" ;; + rc) CASCADE="development,alpha,beta,rc" ;; + beta) CASCADE="development,alpha,beta" ;; + alpha) CASCADE="development,alpha" ;; + development) CASCADE="development" ;; + *) CASCADE="$STABILITY" ;; + esac + + echo "Cascade: ${STABILITY} → ${CASCADE}" + + export PY_CASCADE="$CASCADE" PY_VERSION="$VERSION" PY_SHA256="$SHA256" \ + PY_ZIP_NAME="$ZIP_NAME" PY_TAG="$TAG" PY_DATE="$DATE" \ + PY_GITEA_ORG="$GITEA_ORG" PY_GITEA_REPO="$GITEA_REPO" + python3 << 'PYEOF' + import re, os + + cascade = os.environ["PY_CASCADE"].split(",") + version = os.environ["PY_VERSION"] + sha256 = os.environ["PY_SHA256"] + zip_name = os.environ["PY_ZIP_NAME"] + tag = os.environ["PY_TAG"] + date = os.environ["PY_DATE"] + gitea_org = os.environ["PY_GITEA_ORG"] + gitea_repo = os.environ["PY_GITEA_REPO"] + + gitea_url = f"https://git.mokoconsulting.tech/{gitea_org}/{gitea_repo}/releases/download/{tag}/{zip_name}" + + with open("updates.xml", "r") as f: + content = f.read() + + for xml_tag in cascade: + xml_tag = xml_tag.strip() + block_pattern = r"((?:(?!).)*?" + re.escape(xml_tag) + r".*?)" + match = re.search(block_pattern, content, re.DOTALL) + + if not match: + print(f" SKIP: no {xml_tag} block found") + continue + + block = match.group(1) + original_block = block + + # Update version and date + block = re.sub(r"[^<]*", f"{version}", block) + block = re.sub(r"[^<]*", f"{date}", block) + + # Set SHA — add if missing, update if present, never leave empty + if "" in block: + block = re.sub(r"[^<]*", f"{sha256}", block) + else: + block = block.replace("", f"\n {sha256}") + + # Update download URL + block = re.sub( + r"(]*>)https://git\.mokoconsulting\.tech/[^<]*()", + rf"\g<1>{gitea_url}\g<2>", + block + ) + + content = content.replace(original_block, block) + print(f" OK: {xml_tag} → version={version}, sha={sha256[:16]}...") + + with open("updates.xml", "w") as f: + f.write(content) + + print(f"Cascaded {len(cascade)} channel(s)") + PYEOF + + # Commit and push + if git diff --quiet updates.xml 2>/dev/null; then + echo "No changes to updates.xml" + exit 0 + fi + + git add updates.xml + git commit -m "chore: update ${STABILITY} SHA-256 for ${VERSION} [skip ci]" \ + --author="gitea-actions[bot] " + echo "Pushing updates.xml to ${BRANCH}..." + git push origin HEAD:${BRANCH} 2>&1 || echo "WARNING: push to ${BRANCH} failed" + + # Always sync updates.xml to main via API (Joomla reads from main) + GA_TOKEN="${{ secrets.GA_TOKEN }}" + API="${GITEA_URL}/api/v1/repos/${{ github.repository }}" + + echo "Syncing updates.xml to main via API..." + FILE_SHA=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \ + "${API}/contents/updates.xml?ref=main" | jq -r '.sha // empty') + + if [ -n "$FILE_SHA" ]; then + CONTENT=$(base64 -w0 updates.xml) + HTTP_CODE=$(curl -sS -o /tmp/sync_response.json -w "%{http_code}" \ + -X PUT -H "Authorization: token ${GA_TOKEN}" \ + -H "Content-Type: application/json" \ + "${API}/contents/updates.xml" \ + -d "$(jq -n \ + --arg content "$CONTENT" \ + --arg sha "$FILE_SHA" \ + --arg msg "chore: sync updates.xml ${STABILITY} ${VERSION} [skip ci]" \ + --arg branch "main" \ + '{content: $content, sha: $sha, message: $msg, branch: $branch}' + )") + echo "Sync response (HTTP ${HTTP_CODE}):" + cat /tmp/sync_response.json | jq -r '.content.name // .message // "unknown"' 2>/dev/null + if [ "$HTTP_CODE" -ge 400 ]; then + echo "::warning::Sync to main failed (HTTP ${HTTP_CODE})" + fi + else + echo "::warning::Could not get updates.xml SHA from main" + fi + + - name: Summary + if: always() + run: | + VERSION="${{ steps.bump.outputs.version }}" + STABILITY="${{ steps.meta.outputs.stability }}" + ZIP_NAME="${{ steps.bump.outputs.zip_name }}" + SHA256="${{ steps.zip.outputs.sha256 }}" + TAG="${{ steps.meta.outputs.tag_name }}" + + echo "### Release Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Stability | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY + echo "| Tag | \`${TAG}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY + echo "| SHA-256 | \`${SHA256}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Gitea | [Release](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${TAG}) |" >> $GITHUB_STEP_SUMMARY