diff --git a/.github/workflows/update-manifest.yml b/.github/workflows/update-manifest.yml new file mode 100644 index 0000000..7a6292b --- /dev/null +++ b/.github/workflows/update-manifest.yml @@ -0,0 +1,182 @@ +name: Update manifest.json on release + +on: + release: + types: [published, edited, deleted] + +permissions: + contents: write + +concurrency: + group: update-manifest + cancel-in-progress: false + +jobs: + update-manifest: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.repository.default_branch }} + + - name: Extract version from release tag + id: version + run: | + TAG="${{ github.event.release.tag_name }}" + # Strip leading 'v' if present + VERSION="${TAG#v}" + # Ensure four-part version (append .0 if needed) + DOTS=$(echo "$VERSION" | tr -cd '.' | wc -c | tr -d ' ') + if [ "$DOTS" -eq 2 ]; then + VERSION="${VERSION}.0" + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Version: $VERSION" + + # ── Delete: remove the version entry ────────────────────────────── + + - name: Remove version from manifest.json + if: github.event.action == 'deleted' + run: | + jq --arg ver "${{ steps.version.outputs.version }}" \ + '.[0].versions |= map(select(.version != $ver))' \ + manifest.json > manifest.tmp && mv manifest.tmp manifest.json + + echo "Removed version ${{ steps.version.outputs.version }} from manifest.json" + + # ── Published / Edited: upsert the version entry ────────────────── + + - name: Extract targetAbi from .csproj + if: github.event.action != 'deleted' + id: abi + run: | + ABI=$(grep -oP 'Jellyfin\.Controller"[^>]*Version="\K[^"]+' backend/Moonfin.Server.csproj) + echo "targetAbi=${ABI}.0" >> "$GITHUB_OUTPUT" + echo "Target ABI: ${ABI}.0" + + - name: Download release zip asset + if: github.event.action != 'deleted' + id: asset + env: + GH_TOKEN: ${{ github.token }} + RELEASE_ASSETS: ${{ toJSON(github.event.release.assets) }} + run: | + ASSET_URL=$(echo "$RELEASE_ASSETS" | jq -r '.[] | select(.name | startswith("Moonfin.Server-") and endswith(".zip")) | .browser_download_url' | head -1) + + if [ -z "$ASSET_URL" ]; then + echo "::error::No Moonfin.Server-*.zip asset found on this release" + exit 1 + fi + + ASSET_NAME=$(basename "$ASSET_URL") + echo "Downloading $ASSET_NAME from $ASSET_URL" + curl -fSL -o "$ASSET_NAME" "$ASSET_URL" + + echo "asset_name=$ASSET_NAME" >> "$GITHUB_OUTPUT" + echo "source_url=$ASSET_URL" >> "$GITHUB_OUTPUT" + + - name: Compute MD5 checksum + if: github.event.action != 'deleted' + id: checksum + run: | + CHECKSUM=$(md5sum "${{ steps.asset.outputs.asset_name }}" | awk '{print toupper($1)}') + echo "checksum=$CHECKSUM" >> "$GITHUB_OUTPUT" + echo "MD5: $CHECKSUM" + + - name: Format timestamp + if: github.event.action != 'deleted' + id: timestamp + env: + RELEASE_CREATED_AT: ${{ github.event.release.created_at }} + run: | + TIMESTAMP=$(date -u -d "$RELEASE_CREATED_AT" +"%Y-%m-%dT%H:%M:%S") + echo "timestamp=$TIMESTAMP" >> "$GITHUB_OUTPUT" + echo "Timestamp: $TIMESTAMP" + + - name: Sanitize changelog + if: github.event.action != 'deleted' + id: changelog + env: + RELEASE_BODY: ${{ github.event.release.body }} + run: | + # Write release body to file to preserve multi-line content + printf '%s' "$RELEASE_BODY" > /tmp/raw_changelog.txt + + # Convert markdown release body to clean plain text for Jellyfin manifest: + # 1. Strip carriage returns + # 2. Remove badge images: [![alt](img)](url) + # 3. Remove inline images: ![alt](url) + # 4. Convert links to text: [text](url) → text + # 5. Strip bold markers: **text** → text + # 6. Strip inline code: `text` → text + # 7. Strip header prefixes: ## Title → Title + # 8. Remove horizontal rules: --- + # 9. Trim trailing whitespace + # 10. Remove leading/trailing blank lines + # 11. Collapse consecutive blank lines + sed -i 's/\r$//' /tmp/raw_changelog.txt + cat /tmp/raw_changelog.txt \ + | sed -E 's/\[!\[[^]]*\]\([^)]*\)\]\([^)]*\)//g' \ + | sed -E 's/!\[[^]]*\]\([^)]*\)//g' \ + | sed -E 's/\[([^]]*)\]\([^)]*\)/\1/g' \ + | sed -E 's/\*\*([^*]*)\*\*/\1/g' \ + | sed -E 's/`([^`]*)`/\1/g' \ + | sed -E 's/^#{1,6} +//' \ + | sed -E 's/[[:space:]]+$//' \ + | sed -E '/^---$/d' \ + | sed -E '/^$/N;/^\n$/d' \ + | sed '/./,$!d' \ + > /tmp/changelog.txt + + echo "Sanitized changelog:" + cat /tmp/changelog.txt + + - name: Upsert version in manifest.json + if: github.event.action != 'deleted' + run: | + CHANGELOG=$(cat /tmp/changelog.txt) + + jq --arg ver "${{ steps.version.outputs.version }}" \ + --arg abi "${{ steps.abi.outputs.targetAbi }}" \ + --arg url "${{ steps.asset.outputs.source_url }}" \ + --arg sum "${{ steps.checksum.outputs.checksum }}" \ + --arg time "${{ steps.timestamp.outputs.timestamp }}" \ + --arg log "$CHANGELOG" \ + '.[0].versions |= ( + map(select(.version != $ver)) | + [{ + version: $ver, + changelog: $log, + targetAbi: $abi, + sourceUrl: $url, + checksum: $sum, + timestamp: $time, + dependencies: [] + }] + . + )' \ + manifest.json > manifest.tmp && mv manifest.tmp manifest.json + + echo "Upserted version ${{ steps.version.outputs.version }} in manifest.json" + + # ── Commit ──────────────────────────────────────────────────────── + + - name: Commit and push + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add manifest.json + + ACTION="${{ github.event.action }}" + VERSION="${{ steps.version.outputs.version }}" + + if [ "$ACTION" = "deleted" ]; then + MSG="chore: remove v${VERSION} from manifest.json" + else + MSG="chore: update manifest.json for v${VERSION}" + fi + + git diff --cached --quiet && echo "No changes to commit" && exit 0 + git commit -m "$MSG" + git pull --rebase + git push