refactor(release-plugin): readme.txt als Changelog-SSOT

- Pre-Flight prüft jetzt zusätzlich Stable tag: in readme.txt
- Changelog-Block wird aus readme.txt == Changelog == gezogen
- CHANGELOG.md fällt als Workflow-Abhängigkeit weg
- readme.txt ist Pflichtdatei im Plugin-Repo

Grund: readme.txt ist WP-natives Format, WordPress und Master-Key
parsen es direkt (für CPT-Sync der öffentlichen Plugin-Seite).
Damit gibt es eine SSOT zum Pflegen statt parallele CHANGELOG.md.

Entscheidung dokumentiert in Notion:
https://www.notion.so/32b36ebfe9178147ad16ee214302c994
This commit is contained in:
2026-04-24 11:56:41 +00:00
parent 35d9dcfabf
commit 6aaad24917
+57 -16
View File
@@ -13,7 +13,11 @@ name: Release Plugin
# Erwartete Struktur im aufrufenden Repo:
# - <slug>.php (Plugin-Haupt-PHP mit "Version: X.Y.Z" im Header)
# - Irgendwo in einer PHP-Datei: define('IDF_<UPPER>_VERSION', 'X.Y.Z')
# - CHANGELOG.md mit Block "## v<X.Y.Z> — <Datum>"
# - readme.txt im Repo-Root mit:
# Stable tag: X.Y.Z
# == Changelog ==
# = X.Y.Z =
# * ...
#
# Trigger im aufrufenden Repo: push eines Tags der Form v<MAJOR>.<MINOR>.<PATCH>.
@@ -81,6 +85,16 @@ jobs:
fi
echo "Tag-Format OK: $TAG"
- name: Pre-Flight — readme.txt vorhanden
shell: bash
run: |
set -euo pipefail
if [[ ! -f readme.txt ]]; then
echo "::error::readme.txt fehlt im Repo-Root (Pflichtdatei, siehe idf-ci README)"
exit 1
fi
echo "readme.txt OK"
- name: Pre-Flight — Plugin-Header-Version
shell: bash
run: |
@@ -120,35 +134,56 @@ jobs:
fi
echo "Konstante OK: $CONST=$CONST_VERSION"
- name: Changelog-Block extrahieren
- name: Pre-Flight — readme.txt Stable tag
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.vars.outputs.version }}"
STABLE_TAG="$(grep -iE '^[[:space:]]*Stable tag:[[:space:]]*' readme.txt | head -n1 | sed -E 's/^[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*$/\1/')"
if [[ -z "$STABLE_TAG" ]]; then
echo "::error::Konnte 'Stable tag: …' Zeile in readme.txt nicht finden"
exit 1
fi
if [[ "$STABLE_TAG" != "$VERSION" ]]; then
echo "::error::readme.txt Stable tag '$STABLE_TAG' != Tag '$VERSION'"
exit 1
fi
echo "Stable tag OK: $STABLE_TAG"
- name: Changelog-Block aus readme.txt extrahieren
id: changelog
shell: bash
env:
VERSION: ${{ steps.vars.outputs.version }}
run: |
set -euo pipefail
if [[ ! -f CHANGELOG.md ]]; then
echo "::error::CHANGELOG.md fehlt im Repo"
exit 1
fi
BLOCK="$(python3 - <<'PY'
import re, sys, os
version = os.environ["VERSION"]
with open("CHANGELOG.md", encoding="utf-8") as f:
with open("readme.txt", encoding="utf-8") as f:
content = f.read()
# Match "## v<version>" optionally followed by spaces and any suffix (e.g. date),
# capture until the next "## v<x.y.z>" or a "---" separator line or EOF.
pat = re.compile(
r"^##\s+v" + re.escape(version) + r"(?:\s+.*)?$\n(.*?)(?=^##\s+v\d|^---\s*$|\Z)",
# 1) "== Changelog ==" Abschnitt finden (bis zum nächsten "==…==" oder Dateiende)
section_pat = re.compile(
r"^==\s*Changelog\s*==\s*$\n(.*?)(?=^==[^=\n]+==\s*$|\Z)",
re.MULTILINE | re.DOTALL | re.IGNORECASE,
)
section_m = section_pat.search(content)
if not section_m:
sys.stderr.write("'== Changelog ==' section not found in readme.txt\n")
sys.exit(1)
section = section_m.group(1)
# 2) Block "= <version> =" bis zum nächsten "= x.y.z =" oder Abschnittsende
block_pat = re.compile(
r"^=\s*" + re.escape(version) + r"\s*=\s*$\n(.*?)(?=^=\s*\d+\.\d+\.\d+\s*=\s*$|\Z)",
re.MULTILINE | re.DOTALL,
)
m = pat.search(content)
if not m:
sys.stderr.write(f"No block for v{version} found in CHANGELOG.md\n")
block_m = block_pat.search(section)
if not block_m:
sys.stderr.write(f"No block '= {version} =' found in == Changelog == section\n")
sys.exit(1)
print(m.group(1).strip())
print(block_m.group(1).strip())
PY
)" || { echo "::error::Kein Changelog-Block für v${VERSION} in CHANGELOG.md"; exit 1; }
)" || { echo "::error::Kein Changelog-Block für $VERSION in readme.txt (Abschnitt '== Changelog ==')"; exit 1; }
{
echo "body<<CHANGELOG_EOF"
echo "$BLOCK"
@@ -180,8 +215,14 @@ jobs:
--exclude='tests' \
--exclude='phpunit.xml*' \
--exclude='phpcs.xml*' \
--exclude='CHANGELOG.md' \
--exclude='*.zip' \
./ "$WORK/$SLUG/"
# readme.txt muss im Build enthalten sein (WP-Standard)
if [[ ! -f "$WORK/$SLUG/readme.txt" ]]; then
echo "::error::readme.txt fehlt im gebauten Plugin-Ordner"
exit 1
fi
(cd "$WORK" && zip -qr "/tmp/$ZIPNAME" "$SLUG")
ls -la "/tmp/$ZIPNAME"
# Validierung: Top-Level im ZIP ist genau $SLUG/