Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a3186639c | ||
|
|
185fb3303e | ||
|
|
b661ec3153 | ||
|
|
309826ccb6 | ||
|
|
b6d49882ea | ||
|
|
6f85fd3e4b | ||
|
|
7334bd587a |
@@ -0,0 +1,114 @@
|
||||
name: Reusable Deploy via rsync
|
||||
|
||||
# Wiederverwendbarer Deploy-Workflow fuer IDF-Projekte.
|
||||
# Repository-Pfad: ideenfabrik/idf-ci/.gitea/workflows/deploy-rsync.yml
|
||||
#
|
||||
# Aufruf aus einem Caller-Repo:
|
||||
#
|
||||
# jobs:
|
||||
# deploy:
|
||||
# uses: ideenfabrik/idf-ci/.gitea/workflows/deploy-rsync.yml@v1
|
||||
# with:
|
||||
# ssh_host: ${{ vars.SSH_HOST }}
|
||||
# ssh_user: ${{ vars.SSH_USER }}
|
||||
# deploy_path: ${{ vars.DEPLOY_PATH }}
|
||||
# ref: ${{ github.event.inputs.ref || github.ref }}
|
||||
# extra_excludes: |
|
||||
# kiosk-config.php
|
||||
# kiosk-config.example.php
|
||||
# secrets: inherit
|
||||
#
|
||||
# Caller-Repo muss hinterlegen:
|
||||
# Secret SSH_PRIVATE_KEY private Key fuer den Deploy-User
|
||||
# Variable SSH_HOST Host/IP des Live-Servers
|
||||
# Variable SSH_USER SSH-Login-User
|
||||
# Variable DEPLOY_PATH Zielpfad auf dem Server
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ssh_host:
|
||||
required: true
|
||||
type: string
|
||||
description: 'Ziel-Host fuer rsync ueber SSH'
|
||||
ssh_user:
|
||||
required: true
|
||||
type: string
|
||||
description: 'SSH-Login-User'
|
||||
deploy_path:
|
||||
required: true
|
||||
type: string
|
||||
description: 'Zielpfad auf dem Server'
|
||||
ref:
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
description: 'Branch/Tag zum Deployen (default: github.ref)'
|
||||
extra_excludes:
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
description: 'Zusaetzliche rsync --exclude Patterns, eine pro Zeile'
|
||||
secrets:
|
||||
SSH_PRIVATE_KEY:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref || github.ref }}
|
||||
|
||||
- name: Verify rsync + ssh available
|
||||
run: |
|
||||
command -v rsync >/dev/null || { echo "::error::rsync ist auf dem Runner nicht installiert"; exit 1; }
|
||||
command -v ssh >/dev/null || { echo "::error::ssh ist auf dem Runner nicht installiert"; exit 1; }
|
||||
rsync --version | head -1
|
||||
ssh -V
|
||||
|
||||
- name: Setup SSH key
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
KEY_FILE="$HOME/.ssh/id_ed25519_deploy_${{ github.run_id }}"
|
||||
printf '%s\n' "${{ secrets.SSH_PRIVATE_KEY }}" > "$KEY_FILE"
|
||||
chmod 600 "$KEY_FILE"
|
||||
echo "DEPLOY_KEY_FILE=$KEY_FILE" >> "$GITHUB_ENV"
|
||||
ssh-keyscan -H "${{ inputs.ssh_host }}" >> ~/.ssh/known_hosts 2>/dev/null
|
||||
|
||||
- name: Deploy via rsync
|
||||
env:
|
||||
EXTRA_EXCLUDES: ${{ inputs.extra_excludes }}
|
||||
run: |
|
||||
# Standard-Excludes -- gilt fuer alle Deploys
|
||||
BASE_EXCLUDES=(
|
||||
--exclude='.git/'
|
||||
--exclude='.gitea/'
|
||||
--exclude='.gitignore'
|
||||
--exclude='CHANGELOG.md'
|
||||
--exclude='README.md'
|
||||
)
|
||||
|
||||
# Caller-spezifische Excludes (multiline -> array)
|
||||
EXTRA=()
|
||||
while IFS= read -r line; do
|
||||
line="${line#"${line%%[![:space:]]*}"}"
|
||||
line="${line%"${line##*[![:space:]]}"}"
|
||||
[ -n "$line" ] && EXTRA+=( "--exclude=$line" )
|
||||
done <<<"$EXTRA_EXCLUDES"
|
||||
|
||||
rsync -avz "${BASE_EXCLUDES[@]}" "${EXTRA[@]}" \
|
||||
-e "ssh -i $DEPLOY_KEY_FILE -o StrictHostKeyChecking=yes" \
|
||||
./ \
|
||||
"${{ inputs.ssh_user }}@${{ inputs.ssh_host }}:${{ inputs.deploy_path }}/"
|
||||
|
||||
- name: Cleanup deploy key
|
||||
if: always()
|
||||
run: rm -f "$DEPLOY_KEY_FILE"
|
||||
|
||||
- name: Done
|
||||
run: |
|
||||
echo "Deployed ${{ github.ref_name }} to ${{ inputs.deploy_path }} on ${{ inputs.ssh_host }}"
|
||||
@@ -21,7 +21,12 @@ name: Release Plugin
|
||||
# "== Changelog ==" in readme.txt wird beim Build aus CHANGELOG.md
|
||||
# generiert und ist nur im fertigen ZIP vollständig.
|
||||
#
|
||||
# Trigger im aufrufenden Repo: push eines Tags der Form v<MAJOR>.<MINOR>.<PATCH>.
|
||||
# Trigger im aufrufenden Repo:
|
||||
# - push auf main → Auto-Modus: Header-Version wird ausgelesen, Tag v<X.Y.Z>
|
||||
# wird erzeugt (sofern noch nicht vorhanden), Release wird gebaut.
|
||||
# Existiert der Tag bereits, beendet der Workflow still (kein Release).
|
||||
# - push eines Tags v<MAJOR>.<MINOR>.<PATCH> → klassischer Modus: Tag wird
|
||||
# direkt für den Release verwendet.
|
||||
# Ausführung auf dem IDF-Runner (self-hosted, Host-Modus).
|
||||
|
||||
on:
|
||||
@@ -50,14 +55,12 @@ jobs:
|
||||
- name: Checkout Tag
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Variablen ableiten
|
||||
- name: Variablen ableiten (Auto-Modus oder Tag-Modus)
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SLUG="${{ inputs.slug }}"
|
||||
TAG="${GITHUB_REF_NAME}"
|
||||
VERSION="${TAG#v}"
|
||||
MAIN_FILE="${{ inputs.main_file }}"
|
||||
[[ -z "$MAIN_FILE" ]] && MAIN_FILE="${SLUG}.php"
|
||||
CONST="${{ inputs.version_constant }}"
|
||||
@@ -66,6 +69,37 @@ jobs:
|
||||
base_upper="$(echo "$base" | tr '[:lower:]-' '[:upper:]_')"
|
||||
CONST="IDF_${base_upper}_VERSION"
|
||||
fi
|
||||
|
||||
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
|
||||
# Klassischer Modus — Tag-Push
|
||||
MODE="tag"
|
||||
TAG="${GITHUB_REF_NAME}"
|
||||
VERSION="${TAG#v}"
|
||||
else
|
||||
# Auto-Modus — Push auf Branch (z.B. main)
|
||||
MODE="auto"
|
||||
if [[ ! -f "$MAIN_FILE" ]]; then
|
||||
echo "::error::Plugin-Haupt-PHP nicht gefunden: $MAIN_FILE"
|
||||
exit 1
|
||||
fi
|
||||
HEADER_VERSION="$(grep -iE '^[[:space:]]*\*?[[:space:]]*Version:[[:space:]]*' "$MAIN_FILE" | head -n1 | sed -E 's/^[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*$/\1/')"
|
||||
if [[ -z "$HEADER_VERSION" ]]; then
|
||||
echo "::error::Header-Version in $MAIN_FILE nicht lesbar"
|
||||
exit 1
|
||||
fi
|
||||
VERSION="$HEADER_VERSION"
|
||||
TAG="v$VERSION"
|
||||
fi
|
||||
|
||||
# Skip-Check (nur Auto-Modus): existiert der Tag schon, kein neues Release
|
||||
SKIP=false
|
||||
if [[ "$MODE" == "auto" ]]; then
|
||||
if git ls-remote --tags origin "refs/tags/${TAG}" 2>/dev/null | grep -q "refs/tags/${TAG}"; then
|
||||
echo "Tag $TAG existiert bereits — Skip (kein neues Release)."
|
||||
SKIP=true
|
||||
fi
|
||||
fi
|
||||
|
||||
ZIPNAME="${SLUG}_v${VERSION}.zip"
|
||||
{
|
||||
echo "slug=$SLUG"
|
||||
@@ -74,10 +108,13 @@ jobs:
|
||||
echo "main_file=$MAIN_FILE"
|
||||
echo "const=$CONST"
|
||||
echo "zipname=$ZIPNAME"
|
||||
echo "mode=$MODE"
|
||||
echo "skip=$SKIP"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
echo "Ermittelt: slug=$SLUG tag=$TAG version=$VERSION main_file=$MAIN_FILE const=$CONST"
|
||||
echo "Ermittelt: mode=$MODE tag=$TAG version=$VERSION main_file=$MAIN_FILE const=$CONST skip=$SKIP"
|
||||
|
||||
- name: Pre-Flight — Tag-Format
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -89,6 +126,7 @@ jobs:
|
||||
echo "Tag-Format OK: $TAG"
|
||||
|
||||
- name: Pre-Flight — Pflichtdateien
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -102,6 +140,7 @@ jobs:
|
||||
echo "Pflichtdateien OK"
|
||||
|
||||
- name: Pre-Flight — Plugin-Header-Version
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -123,6 +162,7 @@ jobs:
|
||||
echo "Header-Version OK: $HEADER_VERSION"
|
||||
|
||||
- name: Pre-Flight — Versions-Konstante
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -141,6 +181,7 @@ jobs:
|
||||
echo "Konstante OK: $CONST=$CONST_VERSION"
|
||||
|
||||
- name: Pre-Flight — readme.txt Stable tag
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -157,6 +198,7 @@ jobs:
|
||||
echo "Stable tag OK: $STABLE_TAG"
|
||||
|
||||
- name: Changelog-Block aus CHANGELOG.md extrahieren
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
id: changelog
|
||||
shell: bash
|
||||
env:
|
||||
@@ -190,6 +232,7 @@ jobs:
|
||||
echo "Changelog-Block extrahiert (${#BLOCK} Zeichen)."
|
||||
|
||||
- name: ZIP bauen (readme.txt Changelog-Section aus CHANGELOG.md generieren)
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
id: zip
|
||||
shell: bash
|
||||
env:
|
||||
@@ -212,6 +255,7 @@ jobs:
|
||||
--exclude='.DS_Store' \
|
||||
--exclude='node_modules' \
|
||||
--exclude='tests' \
|
||||
--exclude='design' \
|
||||
--exclude='phpunit.xml*' \
|
||||
--exclude='phpcs.xml*' \
|
||||
--exclude='*.zip' \
|
||||
@@ -303,6 +347,7 @@ jobs:
|
||||
echo "zippath=/tmp/$ZIPNAME" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Gitea-Release anlegen und Asset anhängen
|
||||
if: steps.vars.outputs.skip != 'true'
|
||||
shell: bash
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN || github.token }}
|
||||
@@ -314,11 +359,16 @@ jobs:
|
||||
set -euo pipefail
|
||||
SERVER="${GITHUB_SERVER_URL:-https://git.ihre-ideenfabrik.de}"
|
||||
REPO="${GITHUB_REPOSITORY}"
|
||||
# target_commitish setzt den Commit, aus dem der Tag erzeugt wird,
|
||||
# falls er noch nicht existiert (Auto-Modus). Bei Tag-Push ist es egal,
|
||||
# weil der Tag schon den Commit kennt — Gitea ignoriert das Feld dann.
|
||||
TARGET_SHA="${GITHUB_SHA}"
|
||||
PAYLOAD="$(jq -n \
|
||||
--arg tag "$TAG" \
|
||||
--arg name "$TAG" \
|
||||
--arg body "$BODY" \
|
||||
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:false}')"
|
||||
--arg target "$TARGET_SHA" \
|
||||
'{tag_name:$tag, name:$name, body:$body, target_commitish:$target, draft:false, prerelease:false}')"
|
||||
RESP="$(curl -sSf \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Changelog
|
||||
|
||||
## v1.3.0
|
||||
|
||||
### Geändert
|
||||
- `release-plugin.yml`: Top-Level-Ordner `design/` wird vom Plugin-ZIP ausgeschlossen (Dev-Artefakte wie Roh-Sprites, Mockups und Styleguides gehoeren nicht in Kunden-Downloads; idf-deadline v0.6.0 war dadurch 14,7 MB statt 2 MB gross).
|
||||
|
||||
## v1.2.0
|
||||
|
||||
### Hinzugefügt
|
||||
- Auto-Modus für `release-plugin.yml`: Push auf main triggert ein Release, sobald die Header-Version eines Plugins erhöht wurde. Tag wird automatisch erzeugt, kein manueller `git tag` mehr nötig.
|
||||
- Wenn der Tag zur aktuellen Header-Version bereits existiert, beendet der Workflow still (kein neues Release, keine Mail).
|
||||
- Caller-Repos können den Workflow weiterhin im klassischen Modus (Tag-Push) nutzen - beide Trigger werden unterstützt.
|
||||
|
||||
### Geändert
|
||||
- Release-API-Call nutzt jetzt `target_commitish`, damit Tags im Auto-Modus aus dem aktuellen Commit erzeugt werden können.
|
||||
|
||||
## v1.1.0
|
||||
|
||||
### Geändert
|
||||
- Frühere Iteration des Workflows (vor Auto-Modus). Details siehe Git-Historie.
|
||||
|
||||
## v1.0.2
|
||||
|
||||
### Behoben
|
||||
- Diverse Pre-Flight-Korrekturen.
|
||||
|
||||
## v1.0.1
|
||||
|
||||
### Behoben
|
||||
- Initial-Hotfix nach v1.0.0.
|
||||
|
||||
## v1.0.0
|
||||
|
||||
### Hinzugefügt
|
||||
- Erste produktive Version von `release-plugin.yml` (Tag-Push-Modus).
|
||||
@@ -4,17 +4,17 @@ Zentrale CI-Bausteine für IDF-Repos.
|
||||
|
||||
## Zweck
|
||||
|
||||
Dieses Repo ist die Heimat für **geteilte CI-Bausteine**, die von anderen IDF-Repos per `uses:` eingebunden werden. Vorteil: Eine Änderung an einer Stelle wirkt in allen nutzenden Repos — kein 26-facher Copy-Paste-Pflegeaufwand.
|
||||
Dieses Repo ist die Heimat für **geteilte CI-Bausteine**, die von anderen IDF-Repos per `uses:` eingebunden werden. Vorteil: Eine Änderung an einer Stelle wirkt in allen nutzenden Repos - kein 26-facher Copy-Paste-Pflegeaufwand.
|
||||
|
||||
Aktuell enthalten:
|
||||
|
||||
- `.gitea/workflows/release-plugin.yml` — Reusable Workflow für WordPress-Plugin-Releases. Bei Tag-Push (`v*.*.*`) prüft er Versions-Konsistenz über vier Sync-Stellen, extrahiert den Changelog-Block aus `CHANGELOG.md`, generiert daraus die `== Changelog ==`-Section in `readme.txt`, baut das ZIP und legt einen Gitea-Release mit ZIP-Asset an.
|
||||
- `.gitea/workflows/release-plugin.yml` - Reusable Workflow für WordPress-Plugin-Releases. Bei Tag-Push (`v*.*.*`) prüft er Versions-Konsistenz über vier Sync-Stellen, extrahiert den Changelog-Block aus `CHANGELOG.md`, generiert daraus die `== Changelog ==`-Section in `readme.txt`, baut das ZIP und legt einen Gitea-Release mit ZIP-Asset an.
|
||||
|
||||
Geplant:
|
||||
|
||||
- `lint-php.yml` — PHPCS / PHPStan für Plugin-Repos.
|
||||
- `composer/` — geteilte `composer.json`-Snippets.
|
||||
- `scripts/` — Shell-Helfer für lokales Build und Release.
|
||||
- `lint-php.yml` - PHPCS / PHPStan für Plugin-Repos.
|
||||
- `composer/` - geteilte `composer.json`-Snippets.
|
||||
- `scripts/` - Shell-Helfer für lokales Build und Release.
|
||||
|
||||
## Nutzung im Plugin-Repo
|
||||
|
||||
@@ -25,7 +25,8 @@ In jedem Plugin-Repo (`ideenfabrik/idf-<slug>`) liegt ein schlanker Caller-Workf
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags: ['v*.*.*']
|
||||
branches: [main] # Auto-Modus: Release sobald Header-Version hochgezogen wurde
|
||||
tags: ['v*.*.*'] # Klassischer Modus: manuelle Tags sind weiterhin möglich
|
||||
|
||||
jobs:
|
||||
release:
|
||||
@@ -35,13 +36,17 @@ jobs:
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
Für die Anwendung reicht `git tag v1.2.3 && git push --tags`. Alles andere macht der Reusable Workflow. Details und Fehlerdiagnose im [Caller-Template](docs/plugin-caller-template.md).
|
||||
**Auto-Modus (Standard, seit v1.2.0):** Plugin-Header-Version, PHP-Konstante, `Stable tag:` und CHANGELOG-Block hochziehen, committen, nach `main` pushen. Der Workflow erzeugt Tag `v<X.Y.Z>` selbst und legt das Release an. Wenn die Version nicht erhöht wurde, beendet der Workflow still (kein Release, keine Mail).
|
||||
|
||||
**Klassischer Modus:** Falls du lieber explizit taggst - `git tag v1.2.3 && git push --tags` triggert denselben Workflow im Tag-Modus. Beide Pfade können koexistieren.
|
||||
|
||||
Details und Fehlerdiagnose im [Caller-Template](docs/plugin-caller-template.md).
|
||||
|
||||
## Pflichtdateien im Plugin-Repo
|
||||
|
||||
Damit der Reusable Workflow durchläuft, müssen im Plugin-Repo vorhanden sein:
|
||||
|
||||
1. **`<slug>.php`** — Plugin-Haupt-PHP mit WordPress-Plugin-Header inklusive Zeile `Version: X.Y.Z`.
|
||||
1. **`<slug>.php`** - Plugin-Haupt-PHP mit WordPress-Plugin-Header inklusive Zeile `Version: X.Y.Z`.
|
||||
2. **Versions-Konstante** in einer beliebigen PHP-Datei:
|
||||
`define('IDF_<UPPER_SLUG_OHNE_IDF_>_VERSION', 'X.Y.Z');`
|
||||
Beispiel: `idf-login-branding` → `IDF_LOGIN_BRANDING_VERSION`.
|
||||
@@ -66,7 +71,7 @@ Damit der Reusable Workflow durchläuft, müssen im Plugin-Repo vorhanden sein:
|
||||
```markdown
|
||||
# Changelog
|
||||
|
||||
## v1.2.3 — 2026-04-23
|
||||
## v1.2.3 - 2026-04-23
|
||||
|
||||
### Neu
|
||||
- …
|
||||
@@ -76,7 +81,7 @@ Damit der Reusable Workflow durchläuft, müssen im Plugin-Repo vorhanden sein:
|
||||
|
||||
---
|
||||
|
||||
## v1.2.2 — 2026-04-10
|
||||
## v1.2.2 - 2026-04-10
|
||||
…
|
||||
```
|
||||
|
||||
@@ -84,9 +89,9 @@ Alle vier Versionen (Tag, Plugin-Header, PHP-Konstante, `Stable tag:`) müssen i
|
||||
|
||||
## Aufteilung Changelog-Pflege
|
||||
|
||||
- **`CHANGELOG.md`** ist die **einzige Pflege-Stelle für den Changelog** — einheitlich über alle IDF-Projekte (Software, Flow, Plugins). Du schreibst den neuen Block hier, fertig.
|
||||
- **`CHANGELOG.md`** ist die **einzige Pflege-Stelle für den Changelog** - einheitlich über alle IDF-Projekte (Software, Flow, Plugins). Du schreibst den neuen Block hier, fertig.
|
||||
- **`readme.txt`** ist WP-Standard-Metadaten: Plugin-Name, Description, `Requires PHP`, `Tested up to`, `Stable tag` usw. Pflegst du manuell, aber nur diese Felder.
|
||||
- Der Abschnitt `== Changelog ==` in `readme.txt` wird beim Release **von Actions automatisch generiert** — aus `CHANGELOG.md`. Manuelle Einträge in `readme.txt` unter `== Changelog ==` werden beim nächsten Release überschrieben.
|
||||
- Der Abschnitt `== Changelog ==` in `readme.txt` wird beim Release **von Actions automatisch generiert** - aus `CHANGELOG.md`. Manuelle Einträge in `readme.txt` unter `== Changelog ==` werden beim nächsten Release überschrieben.
|
||||
|
||||
So hat jedes Projekt im IDF genau einen Ort, an dem der Changelog lebt: `CHANGELOG.md`. WordPress-Plugins bekommen zusätzlich eine WP-native `readme.txt`, deren Changelog-Teil aber auto-befüllt wird.
|
||||
|
||||
@@ -94,9 +99,9 @@ So hat jedes Projekt im IDF genau einen Ort, an dem der Changelog lebt: `CHANGEL
|
||||
|
||||
Die Reusable Workflows selbst sind per SemVer-Tag versioniert (`v1`, `v1.2`, `v1.2.3`). Plugin-Repos referenzieren einen dieser Tags. Empfehlung:
|
||||
|
||||
- **Major-Tag (`@v1`)** — rolling, nimmt automatisch Patches und Minors mit.
|
||||
- **Minor-Tag (`@v1.2`)** — nimmt nur Patches mit.
|
||||
- **Exakt (`@v1.2.3`)** — einfriert auf genau diese Version.
|
||||
- **Major-Tag (`@v1`)** - rolling, nimmt automatisch Patches und Minors mit.
|
||||
- **Minor-Tag (`@v1.2`)** - nimmt nur Patches mit.
|
||||
- **Exakt (`@v1.2.3`)** - einfriert auf genau diese Version.
|
||||
|
||||
Breaking Changes am Workflow → neuer Major-Tag, nutzende Repos müssen manuell nachziehen.
|
||||
|
||||
@@ -105,5 +110,5 @@ Breaking Changes am Workflow → neuer Major-Tag, nutzende Repos müssen manuell
|
||||
Konzeptionelle Grundlagen und der Plugin-Release-Workflow liegen in Notion:
|
||||
|
||||
- [Deployment & Versionierung](https://www.notion.so/32b36ebfe9178147ad16ee214302c994)
|
||||
- [Plugin-Migration auf Git — Checkliste](https://www.notion.so/34b36ebfe9178195980fd4a723ebfde5)
|
||||
- [Plugin-Migration auf Git - Checkliste](https://www.notion.so/34b36ebfe9178195980fd4a723ebfde5)
|
||||
- [Git- & Issue-Workflow](https://www.notion.so/34b36ebfe91781519276f301aac0d74c)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Plugin-Caller-Workflow — Template
|
||||
# Plugin-Caller-Workflow - Template
|
||||
|
||||
Jedes Plugin-Repo (`ideenfabrik/idf-<slug>`) bekommt genau diese eine Datei, um den Release-Mechanismus zu aktivieren:
|
||||
|
||||
@@ -19,17 +19,17 @@ jobs:
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
**Nur `slug` anpassen** — exakt der Plugin-Slug (= Repo-Name ohne Org-Präfix, z. B. `idf-login-branding`).
|
||||
**Nur `slug` anpassen** - exakt der Plugin-Slug (= Repo-Name ohne Org-Präfix, z. B. `idf-login-branding`).
|
||||
|
||||
## Voraussetzungen im Plugin-Repo
|
||||
|
||||
Damit der Reusable Workflow durchläuft, müssen im Plugin-Repo vorhanden sein:
|
||||
|
||||
1. **`<slug>.php`** — Plugin-Haupt-PHP mit standardmäßigem Plugin-Header, inklusive Zeile `Version: X.Y.Z`.
|
||||
1. **`<slug>.php`** - Plugin-Haupt-PHP mit standardmäßigem Plugin-Header, inklusive Zeile `Version: X.Y.Z`.
|
||||
2. **Versions-Konstante** in einer PHP-Datei des Plugins:
|
||||
`define('IDF_<UPPER_SLUG_OHNE_IDF_>_VERSION', 'X.Y.Z');`
|
||||
Beispiel: Für `idf-login-branding` → `IDF_LOGIN_BRANDING_VERSION`.
|
||||
3. **`readme.txt`** im Repo-Root im WordPress-Standard-Format. Nur die WP-Metadaten pflegen — der Changelog-Abschnitt wird vom Release-Workflow automatisch aus `CHANGELOG.md` gefüllt:
|
||||
3. **`readme.txt`** im Repo-Root im WordPress-Standard-Format. Nur die WP-Metadaten pflegen - der Changelog-Abschnitt wird vom Release-Workflow automatisch aus `CHANGELOG.md` gefüllt:
|
||||
```
|
||||
=== Plugin Name ===
|
||||
Contributors: ideenfabrik
|
||||
@@ -46,11 +46,11 @@ Damit der Reusable Workflow durchläuft, müssen im Plugin-Repo vorhanden sein:
|
||||
== Changelog ==
|
||||
(wird beim Release automatisch aus CHANGELOG.md generiert)
|
||||
```
|
||||
4. **`CHANGELOG.md`** im Repo-Root — SSOT für den Changelog. Format:
|
||||
4. **`CHANGELOG.md`** im Repo-Root - SSOT für den Changelog. Format:
|
||||
```markdown
|
||||
# Changelog
|
||||
|
||||
## v1.2.3 — 2026-04-23
|
||||
## v1.2.3 - 2026-04-23
|
||||
|
||||
### Neu
|
||||
- Feature xyz
|
||||
@@ -60,13 +60,13 @@ Damit der Reusable Workflow durchläuft, müssen im Plugin-Repo vorhanden sein:
|
||||
|
||||
---
|
||||
|
||||
## v1.2.2 — 2026-04-10
|
||||
## v1.2.2 - 2026-04-10
|
||||
…
|
||||
```
|
||||
|
||||
Alle vier Werte (Tag, Plugin-Header-`Version:`, PHP-Konstante, `Stable tag:` in `readme.txt`) müssen identisch sein. Der Pre-Flight-Check im Reusable bricht sonst ab.
|
||||
|
||||
**Pflege-Aufteilung:** Changelog-Einträge nur in `CHANGELOG.md` pflegen. `readme.txt` bekommt seine `== Changelog ==` beim Release automatisch generiert — manuelle Einträge dort werden überschrieben.
|
||||
**Pflege-Aufteilung:** Changelog-Einträge nur in `CHANGELOG.md` pflegen. `readme.txt` bekommt seine `== Changelog ==` beim Release automatisch generiert - manuelle Einträge dort werden überschrieben.
|
||||
|
||||
## Release-Ablauf (Agent/Mensch)
|
||||
|
||||
@@ -91,9 +91,9 @@ Danach läuft die Action automatisch durch. Bei Erfolg liegt auf Gitea ein Relea
|
||||
|
||||
Beim `uses:`-Aufruf die Version pinnen:
|
||||
|
||||
- `@v1` — rolling, zieht Patches und Minors automatisch mit. Empfohlen für die meisten Plugins.
|
||||
- `@v1.2` — Patches ja, Minors nein.
|
||||
- `@v1.2.3` — exakt einfrieren. Nur für Plugins, die gegen eine bestimmte Workflow-Version validiert wurden.
|
||||
- `@v1` - rolling, zieht Patches und Minors automatisch mit. Empfohlen für die meisten Plugins.
|
||||
- `@v1.2` - Patches ja, Minors nein.
|
||||
- `@v1.2.3` - exakt einfrieren. Nur für Plugins, die gegen eine bestimmte Workflow-Version validiert wurden.
|
||||
|
||||
Breaking Changes am Reusable Workflow → neuer Major (`v2`). Plugin-Repos müssen dann bewusst auf `@v2` wechseln.
|
||||
|
||||
@@ -106,7 +106,7 @@ Bei abgebrochenem Release:
|
||||
- **„Plugin-Header-Version ≠ Tag"** → `<slug>.php` Version-Zeile korrigieren, Commit, Tag neu setzen.
|
||||
- **„Konstante ≠ Tag"** → Versions-Konstante im PHP anpassen, Commit, Tag neu setzen.
|
||||
- **„Stable tag ≠ Tag"** → `Stable tag:` in `readme.txt` korrigieren, Commit, Tag neu setzen.
|
||||
- **„Kein Changelog-Block für v…"** → Block `## v1.2.3 — <Datum>` in `CHANGELOG.md` anlegen, Commit, Tag neu setzen.
|
||||
- **„Kein Changelog-Block für v…"** → Block `## v1.2.3 - <Datum>` in `CHANGELOG.md` anlegen, Commit, Tag neu setzen.
|
||||
- **Release-Anlage fehlgeschlagen** → Wahrscheinlich fehlende Token-Berechtigung. `GITEA_TOKEN`-Secret prüfen oder den Standard `github.token` nutzen.
|
||||
|
||||
Wichtig: Ein Tag, unter dem ein Release bereits existiert, kann nicht erneut einen Release erzeugen. Bei Korrekturen eine PATCH-Version höher tagen, nicht denselben Tag neu setzen.
|
||||
|
||||
+15
-15
@@ -1,14 +1,14 @@
|
||||
# Gitea Actions Runner — Setup
|
||||
# Gitea Actions Runner - Setup
|
||||
|
||||
Diese Anleitung beschreibt, wie der Gitea Actions Runner auf einem IDF-Server installiert und registriert wird. Der Runner ist der Dienst, der die Release-Workflows aus diesem Repo ausführt. Ohne laufenden Runner bleiben Tag-Pushes ohne Wirkung — die Runs hängen unendlich in der Queue.
|
||||
Diese Anleitung beschreibt, wie der Gitea Actions Runner auf einem IDF-Server installiert und registriert wird. Der Runner ist der Dienst, der die Release-Workflows aus diesem Repo ausführt. Ohne laufenden Runner bleiben Tag-Pushes ohne Wirkung - die Runs hängen unendlich in der Queue.
|
||||
|
||||
**Wichtig:** Diese Anleitung ist die verbindliche SSOT für das Runner-Setup. Bei jedem Server-Wechsel wird sie von vorn abgearbeitet — es gibt keine versteckten Artefakte außerhalb von Git, nur die hier beschriebenen Schritte.
|
||||
**Wichtig:** Diese Anleitung ist die verbindliche SSOT für das Runner-Setup. Bei jedem Server-Wechsel wird sie von vorn abgearbeitet - es gibt keine versteckten Artefakte außerhalb von Git, nur die hier beschriebenen Schritte.
|
||||
|
||||
## Was der Runner ist und was er nicht ist
|
||||
|
||||
Der Runner ist ein einzelnes ausführbares Binary (`act_runner`), das sich beim IDF-Gitea-Server anmeldet und Jobs aus der Queue abarbeitet. Er ist kein WordPress-, PHP- oder Plesk-Tool, sondern ein unabhängiger Dienst, der nebenher läuft. Technisch ist er vergleichbar mit einem Cron-Daemon, der auf Arbeit wartet.
|
||||
|
||||
Der Runner **baut** die Plugin-ZIPs und legt sie als Gitea-Release-Assets ab. Er **verteilt** nichts an Kunden — das ist Aufgabe des Master-Key-Plugins.
|
||||
Der Runner **baut** die Plugin-ZIPs und legt sie als Gitea-Release-Assets ab. Er **verteilt** nichts an Kunden - das ist Aufgabe des Master-Key-Plugins.
|
||||
|
||||
## Voraussetzungen in Gitea
|
||||
|
||||
@@ -16,11 +16,11 @@ Damit der Runner Reusable-Workflows aus `idf-ci` lesen kann, muss das Repo für
|
||||
|
||||
**Daher: `ideenfabrik/idf-ci` muss auf Sichtbarkeit „Public" (oder „Limited", falls in der Gitea-Version verfügbar) stehen.**
|
||||
|
||||
- **Public** — lesbar für alle, die die Gitea-Instanz erreichen.
|
||||
- **Limited** — lesbar für alle eingeloggten Gitea-User. In neueren Gitea-Versionen verfügbar. Für unseren Fall äquivalent zu Public, weil der Runner eh mit Token angemeldet ist.
|
||||
- **Private** — funktioniert nicht, weil der Job-Token keinen Repo-übergreifenden Lesezugriff hat.
|
||||
- **Public** - lesbar für alle, die die Gitea-Instanz erreichen.
|
||||
- **Limited** - lesbar für alle eingeloggten Gitea-User. In neueren Gitea-Versionen verfügbar. Für unseren Fall äquivalent zu Public, weil der Runner eh mit Token angemeldet ist.
|
||||
- **Private** - funktioniert nicht, weil der Job-Token keinen Repo-übergreifenden Lesezugriff hat.
|
||||
|
||||
**Zusätzlich:** Gitea-weite Einstellung `REQUIRE_SIGNIN_VIEW` muss auf `false` stehen. Sonst überschreibt sie die per-Repo-Sichtbarkeit und erzwingt Login auch für Public-Repos. Bei Docker-Setups wird die `app.ini` oft aus Environment-Variablen regeneriert — Änderungen direkt in der Datei gehen beim Container-Neustart verloren. Korrekter Weg: Environment-Variable setzen:
|
||||
**Zusätzlich:** Gitea-weite Einstellung `REQUIRE_SIGNIN_VIEW` muss auf `false` stehen. Sonst überschreibt sie die per-Repo-Sichtbarkeit und erzwingt Login auch für Public-Repos. Bei Docker-Setups wird die `app.ini` oft aus Environment-Variablen regeneriert - Änderungen direkt in der Datei gehen beim Container-Neustart verloren. Korrekter Weg: Environment-Variable setzen:
|
||||
|
||||
```
|
||||
GITEA__service__REQUIRE_SIGNIN_VIEW=false
|
||||
@@ -53,7 +53,7 @@ Einmalige Aktion pro Instanz.
|
||||
|
||||
- Linux (Debian/Ubuntu; der IDF-Plesk-Host reicht)
|
||||
- Outbound-HTTPS zu `git.ihre-ideenfabrik.de` und zu `github.com` (für standard Gitea-/GitHub-Actions wie `actions/checkout`)
|
||||
- **Node.js 20 (LTS) oder neuer** — zahlreiche Actions (`actions/checkout`, viele weitere) sind JavaScript-basiert und benötigen Node zur Ausführung. Installation (Debian/Ubuntu):
|
||||
- **Node.js 20 (LTS) oder neuer** - zahlreiche Actions (`actions/checkout`, viele weitere) sind JavaScript-basiert und benötigen Node zur Ausführung. Installation (Debian/Ubuntu):
|
||||
```bash
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
|
||||
sudo apt install -y nodejs
|
||||
@@ -112,7 +112,7 @@ Organisation-scoped Runner (empfohlen, läuft für alle IDF-Repos):
|
||||
1. In Gitea einloggen als Admin.
|
||||
2. Navigation: Organization **ideenfabrik** → Settings → **Actions** → **Runners**.
|
||||
3. Button **„Create new Runner"**.
|
||||
4. Registrierungstoken kopieren. Token ist einmalig — für eine zweite Registrierung einen neuen generieren.
|
||||
4. Registrierungstoken kopieren. Token ist einmalig - für eine zweite Registrierung einen neuen generieren.
|
||||
|
||||
Alternativ: Instance-weit unter Site Administration → Actions → Runners (dann verfügbar für alle Organisationen).
|
||||
|
||||
@@ -127,9 +127,9 @@ sudo /opt/act_runner/act_runner register \
|
||||
--no-interactive
|
||||
```
|
||||
|
||||
Kein `--labels`-Flag — die Labels kommen aus der Config (siehe Schritt 2). Falls versehentlich mitgegeben, erscheint die Warnung `Labels from command will be ignored, use labels defined in config file.`
|
||||
Kein `--labels`-Flag - die Labels kommen aus der Config (siehe Schritt 2). Falls versehentlich mitgegeben, erscheint die Warnung `Labels from command will be ignored, use labels defined in config file.`
|
||||
|
||||
Nach erfolgreicher Registrierung liegt eine Datei `.runner` im Arbeitsverzeichnis — die ist der Runner-State, nicht weiterkopieren oder committen.
|
||||
Nach erfolgreicher Registrierung liegt eine Datei `.runner` im Arbeitsverzeichnis - die ist der Runner-State, nicht weiterkopieren oder committen.
|
||||
|
||||
### 5. systemd-Service anlegen
|
||||
|
||||
@@ -183,12 +183,12 @@ Einen Plugin-Repo mit Caller-Workflow nehmen (z. B. `idf-post-prefix`), Tag `v<X
|
||||
- **Neu-Registrierung (z. B. nach kaputtem State):** `sudo rm /opt/act_runner/.runner`, neuen Token aus Gitea holen, Schritt 4 erneut ausführen, Service neu starten.
|
||||
- **Deregistrierung:** Runner in Gitea-UI löschen, `.runner`-Datei auf dem Server entfernen, Service stoppen.
|
||||
|
||||
## Server-Wechsel — Checkliste
|
||||
## Server-Wechsel - Checkliste
|
||||
|
||||
Wenn der IDF-Server gewechselt wird (neuer Plesk-Host o. ä.):
|
||||
|
||||
1. Diese Anleitung auf dem neuen Server von Schritt 1 an durchlaufen.
|
||||
2. In Schritt 3 einen **neuen** Registrierungstoken erzeugen — alte Tokens nicht wiederverwenden.
|
||||
2. In Schritt 3 einen **neuen** Registrierungstoken erzeugen - alte Tokens nicht wiederverwenden.
|
||||
3. Optional: den alten Runner in der Gitea-UI deaktivieren, damit er nicht doppelt zieht.
|
||||
4. Nach Verifikation (Schritt 6 + 7): alte Server-Installation zurückbauen.
|
||||
|
||||
@@ -206,7 +206,7 @@ Entweder `idf-ci` steht auf Private, oder Gitea-weit ist `REQUIRE_SIGNIN_VIEW =
|
||||
Node.js ist nicht installiert oder nicht im PATH. Abschnitt „Voraussetzungen auf dem Server" durchgehen und Node 20 LTS installieren. Nach `sudo apt install -y nodejs` läuft der nächste Re-run.
|
||||
|
||||
**Runs hängen auf `queued`, Runner steht aber auf Online.**
|
||||
Label-Mismatch. Der Workflow schreibt `runs-on: self-hosted`, der Runner muss dasselbe Label anbieten. In der Gitea-UI die Labels des Runners prüfen — stehen dort nicht `self-hosted, linux, x64`, liegt es an Schritt 2.
|
||||
Label-Mismatch. Der Workflow schreibt `runs-on: self-hosted`, der Runner muss dasselbe Label anbieten. In der Gitea-UI die Labels des Runners prüfen - stehen dort nicht `self-hosted, linux, x64`, liegt es an Schritt 2.
|
||||
|
||||
**Runner zeigt `offline` nach systemd-Start.**
|
||||
`sudo journalctl -u act_runner --since '5 min ago'` lesen. Häufige Ursachen: Token abgelaufen, DNS funktioniert nicht, `git.ihre-ideenfabrik.de` nicht erreichbar.
|
||||
|
||||
Reference in New Issue
Block a user