diff --git a/.github/scripts/publish/build-zips.sh b/.github/scripts/publish/build-zips.sh index 70bf579..8116dbe 100644 --- a/.github/scripts/publish/build-zips.sh +++ b/.github/scripts/publish/build-zips.sh @@ -133,13 +133,39 @@ for plugin_dir in plugins/*/; do fi release_notes+="**README:** [Plugin README](${readme_url})" - # Upload versioned GitHub Release + # Upload versioned GitHub Release (retry with numeric suffix on immutable tag conflict) echo " $plugin_name v$version - uploading to GitHub Releases" - gh release create "$release_tag" \ - --repo "$GITHUB_REPOSITORY" \ - --title "${plugin_name} v${version}" \ - --notes "$release_notes" \ - "$zip_path" + final_tag="$release_tag" + tag_suffix=0 + upload_skipped=false + while true; do + if gh release create "$final_tag" \ + --repo "$GITHUB_REPOSITORY" \ + --title "${plugin_name} v${version}" \ + --notes "$release_notes" \ + "$zip_path" 2>/tmp/rel_err; then + break + fi + if grep -q "already exists" /tmp/rel_err; then + echo " $plugin_name v$version - release already exists, skipping upload" + upload_skipped=true + break + elif grep -q "immutable\|Cannot create ref" /tmp/rel_err; then + tag_suffix=$(( tag_suffix + 1 )) + final_tag="${release_tag}-${tag_suffix}" + echo " Tag conflict on $release_tag, retrying as $final_tag" + else + cat /tmp/rel_err >&2; rm -f "$zip_path" /tmp/rel_err; exit 1 + fi + done + rm -f /tmp/rel_err + + # If the upload was skipped (release already existed), discard the fresh metadata + # so generate-manifest.sh falls back to the existing manifest's checksums, which + # reflect the zip that is actually in the release rather than the one we just built. + if [[ "$upload_skipped" == "true" ]]; then + rm -f "$BUILD_META_DIR/$plugin_key/${plugin_key}-${version}.json" + fi rm -f "$zip_path" done diff --git a/.github/scripts/publish/generate-manifest.sh b/.github/scripts/publish/generate-manifest.sh index 01738fe..842bf90 100644 --- a/.github/scripts/publish/generate-manifest.sh +++ b/.github/scripts/publish/generate-manifest.sh @@ -12,9 +12,17 @@ set -e generated_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" registry_url="https://github.com/${GITHUB_REPOSITORY}" registry_name="${GITHUB_REPOSITORY}" -root_url="https://github.com/${GITHUB_REPOSITORY}/releases/download" +download_base_url="https://github.com/${GITHUB_REPOSITORY}/releases/download" raw_releases_url="https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/${RELEASES_BRANCH}" +# Use GitHub Pages URL for metadata if configured; fall back to raw.githubusercontent.com +pages_url=$(gh api "repos/${GITHUB_REPOSITORY}/pages" --jq '.html_url // empty' 2>/dev/null || true) +if [[ -n "$pages_url" ]]; then + metadata_base_url="${pages_url%/}" +else + metadata_base_url="$raw_releases_url" +fi + # GPG signing setup - optional; set GPG_PRIVATE_KEY (armored) and optionally GPG_PASSPHRASE gpg_key_id="" gpg_signing_failed=0 @@ -134,6 +142,16 @@ for plugin_dir in plugins/*/; do existing_manifest_file="metadata/$plugin_name/manifest.json" mkdir -p "metadata/$plugin_name" + # Sync icon from source branch; prefer png > svg > jpg > webp + icon_rel="" + for ext in png svg jpg webp; do + if [[ -f "$plugin_dir/logo.$ext" ]]; then + cp "$plugin_dir/logo.$ext" "metadata/$plugin_name/logo.$ext" + icon_rel="metadata/${plugin_name}/logo.$ext" + break + fi + done + # Discover published versions from GitHub Releases (newest first) versioned_tags=$(echo "$all_release_tags" \ | grep "^${plugin_name}-" \ @@ -145,10 +163,11 @@ for plugin_dir in plugins/*/; do while IFS= read -r release_tag; do [[ -z "$release_tag" ]] && continue zip_version="${release_tag#${plugin_name}-}" - zip_url="${plugin_name}-${zip_version}/${plugin_name}-${zip_version}.zip" - # Strip a plain-integer migration retry suffix (e.g. 1.0.0-1 -> 1.0.0) so the - # canonical version is used for metadata lookup and manifest entries. + # Strip a plain-integer retry suffix (e.g. 1.0.0-1 -> 1.0.0) for metadata lookup and the ZIP filename. canonical_version=$(sed 's/-[0-9][0-9]*$//' <<< "$zip_version") + # Release directory uses the full tag version (may include retry suffix); + # the ZIP asset filename uses the canonical version (how build-zips.sh named it). + zip_url="${plugin_name}-${zip_version}/${plugin_name}-${canonical_version}.zip" # Fresh metadata from this run takes priority; fall back to existing manifest fresh_meta_file="${BUILD_META_DIR:-}/$plugin_key/${plugin_key}-${canonical_version}.json" @@ -201,7 +220,10 @@ for plugin_dir in plugins/*/; do # Use the actual tag-derived zip_version (which may include a retry suffix) for the URL, # so the URL resolves to the real release asset. latest_url="" - [[ -n "$latest_zip_version" ]] && latest_url="${plugin_name}-${latest_zip_version}/${plugin_name}-${latest_zip_version}.zip" + if [[ -n "$latest_zip_version" ]]; then + latest_canonical=$(sed 's/-[0-9][0-9]*$//' <<< "$latest_zip_version") + latest_url="${plugin_name}-${latest_zip_version}/${plugin_name}-${latest_canonical}.zip" + fi # Overwrite min/max_dispatcharr_version for the current version's entry from plugin.json, # so metadata-only updates (no version bump) are reflected without a rebuild. @@ -276,8 +298,8 @@ for plugin_dir in plugins/*/; do desc_trimmed="$desc_raw" fi - # manifest_url is absolute: per-plugin manifest stays in the releases branch (raw.githubusercontent.com) - plugin_manifest_url="${raw_releases_url}/metadata/${plugin_name}/manifest.json" + # manifest_url is relative: clients compose with metadata_base_url from the root manifest + plugin_manifest_url="metadata/${plugin_name}/manifest.json" root_entry=$(jq -n \ --argjson latest_metadata "$latest_metadata" \ @@ -318,7 +340,8 @@ inner_root=$( echo '{' echo ' "registry_url": '"$(jq -n --arg u "$registry_url" '$u')"',' echo ' "registry_name": '"$(jq -n --arg u "$registry_name" '$u')"',' - echo ' "root_url": '"$(jq -n --arg u "$root_url" '$u')"',' + echo ' "download_base_url": '"$(jq -n --arg u "$download_base_url" '$u')"',' + echo ' "metadata_base_url": '"$(jq -n --arg u "$metadata_base_url" '$u')"',' echo ' "plugins": [' first=true for entry in "${root_entries[@]}"; do diff --git a/.github/scripts/publish/plugin-readmes.sh b/.github/scripts/publish/plugin-readmes.sh index b8dea2e..89eee96 100644 --- a/.github/scripts/publish/plugin-readmes.sh +++ b/.github/scripts/publish/plugin-readmes.sh @@ -24,8 +24,8 @@ shields_encode() { printf '%s' "$s" } -# Read root_url from the root manifest (set by generate-manifest.sh) -root_url=$(jq -r '.manifest.root_url // ""' "manifest.json" 2>/dev/null || echo "") +# Read download_base_url from the root manifest (set by generate-manifest.sh) +root_url=$(jq -r '.manifest.download_base_url // ""' "manifest.json" 2>/dev/null || echo "") for plugin_dir in plugins/*/; do [[ ! -d "$plugin_dir" ]] && continue diff --git a/.github/scripts/publish/releases-readme.sh b/.github/scripts/publish/releases-readme.sh index 0219324..d68cbfd 100644 --- a/.github/scripts/publish/releases-readme.sh +++ b/.github/scripts/publish/releases-readme.sh @@ -43,7 +43,7 @@ render_plugin() { local manifest_file="./metadata/${plugin_name}/manifest.json" local root_url - root_url=$(jq -r '.manifest.root_url // ""' "manifest.json" 2>/dev/null || echo "") + root_url=$(jq -r '.manifest.download_base_url // ""' "manifest.json" 2>/dev/null || echo "") local latest_url_path="" [[ -f "$manifest_file" ]] && latest_url_path=$(jq -r '.manifest.latest.latest_url // empty' "$manifest_file") local zip_url=""