@@ -2317,7 +2317,105 @@ function fetch_and_deploy_codeberg_release() {
23172317#
23182318# # 4. Single binary (chmod +x) like Argus, Promtail etc.
23192319# fetch_and_deploy_gh_release "argus" "release-argus/Argus" "singlefile" "0.26.3" "/opt/argus" "Argus-.*linux-amd64"
2320+ #
2321+ # Notes:
2322+ # - For binary/prebuild/singlefile modes: if the target release has no
2323+ # matching asset, the function scans older releases and prompts the user
2324+ # (60s timeout, default yes) to use a previous version that has the asset.
2325+ # ------------------------------------------------------------------------------
2326+
2327+ # ------------------------------------------------------------------------------
2328+ # Scans older GitHub releases for a matching asset when the latest release
2329+ # is missing the expected file. Used internally by fetch_and_deploy_gh_release.
2330+ #
2331+ # Arguments:
2332+ # $1 - GitHub repo (owner/repo)
2333+ # $2 - mode (binary|prebuild|singlefile)
2334+ # $3 - asset_pattern (glob pattern for asset filename)
2335+ # $4 - tag to skip (the already-checked release)
2336+ #
2337+ # Output:
2338+ # Prints the release JSON of the first older release that has a matching asset.
2339+ # Returns 0 on success, 1 if no matching release found or user declined.
23202340# ------------------------------------------------------------------------------
2341+ _gh_scan_older_releases () {
2342+ local repo=" $1 "
2343+ local mode=" $2 "
2344+ local asset_pattern=" $3 "
2345+ local skip_tag=" $4 "
2346+
2347+ local header=()
2348+ [[ -n " ${GITHUB_TOKEN:- } " ]] && header=(-H " Authorization: token $GITHUB_TOKEN " )
2349+
2350+ local releases_list
2351+ releases_list=$( curl --connect-timeout 10 --max-time 30 -fsSL \
2352+ -H ' Accept: application/vnd.github+json' \
2353+ -H ' X-GitHub-Api-Version: 2022-11-28' \
2354+ " ${header[@]} " \
2355+ " https://api.github.com/repos/${repo} /releases?per_page=15" 2> /dev/null) || return 1
2356+
2357+ local count
2358+ count=$( echo " $releases_list " | jq ' length' )
2359+
2360+ for (( i = 0 ; i < count; i++ )) ; do
2361+ local rel_tag rel_draft rel_prerelease
2362+ rel_tag=$( echo " $releases_list " | jq -r " .[$i ].tag_name" )
2363+ rel_draft=$( echo " $releases_list " | jq -r " .[$i ].draft" )
2364+ rel_prerelease=$( echo " $releases_list " | jq -r " .[$i ].prerelease" )
2365+
2366+ # Skip drafts, prereleases, and the tag we already checked
2367+ [[ " $rel_draft " == " true" || " $rel_prerelease " == " true" ]] && continue
2368+ [[ " $rel_tag " == " $skip_tag " ]] && continue
2369+
2370+ local has_match=false
2371+
2372+ if [[ " $mode " == " binary" ]]; then
2373+ local arch
2374+ arch=$( dpkg --print-architecture 2> /dev/null || uname -m)
2375+ [[ " $arch " == " x86_64" ]] && arch=" amd64"
2376+ [[ " $arch " == " aarch64" ]] && arch=" arm64"
2377+
2378+ # Check with explicit pattern first, then arch heuristic, then any .deb
2379+ if [[ -n " $asset_pattern " ]]; then
2380+ has_match=$( echo " $releases_list " | jq -r --arg pat " $asset_pattern " " .[$i ].assets[].name" | while read -r name; do
2381+ case " $name " in $asset_pattern ) echo true ; break ;; esac
2382+ done)
2383+ fi
2384+ if [[ " $has_match " != " true" ]]; then
2385+ has_match=$( echo " $releases_list " | jq -r " .[$i ].assets[].browser_download_url" | grep -qE " ($arch |amd64|x86_64|aarch64|arm64).*\.deb$" && echo true)
2386+ fi
2387+ if [[ " $has_match " != " true" ]]; then
2388+ has_match=$( echo " $releases_list " | jq -r " .[$i ].assets[].browser_download_url" | grep -qE ' \.deb$' && echo true)
2389+ fi
2390+
2391+ elif [[ " $mode " == " prebuild" || " $mode " == " singlefile" ]]; then
2392+ has_match=$( echo " $releases_list " | jq -r " .[$i ].assets[].name" | while read -r name; do
2393+ case " $name " in $asset_pattern ) echo true ; break ;; esac
2394+ done)
2395+ fi
2396+
2397+ if [[ " $has_match " == " true" ]]; then
2398+ local rel_version=" $rel_tag "
2399+ [[ " $rel_tag " =~ ^v ]] && rel_version=" ${rel_tag: 1} "
2400+
2401+ local use_fallback=" y"
2402+ if [[ -t 0 ]]; then
2403+ msg_warn " Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
2404+ read -rp " Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback || use_fallback=" y"
2405+ use_fallback=" ${use_fallback:- y} "
2406+ fi
2407+
2408+ if [[ " ${use_fallback,,} " == " y" || " ${use_fallback,,} " == " yes" ]]; then
2409+ echo " $releases_list " | jq " .[$i ]"
2410+ return 0
2411+ else
2412+ return 1
2413+ fi
2414+ fi
2415+ done
2416+
2417+ return 1
2418+ }
23212419
23222420function fetch_and_deploy_gh_release() {
23232421 local app=" $1 "
@@ -2458,6 +2556,33 @@ function fetch_and_deploy_gh_release() {
24582556 done
24592557 fi
24602558
2559+ # Fallback: scan older releases for a matching .deb asset
2560+ if [[ -z " $url_match " ]]; then
2561+ local fallback_json
2562+ if fallback_json=$( _gh_scan_older_releases " $repo " " binary" " $asset_pattern " " $tag_name " ) ; then
2563+ json=" $fallback_json "
2564+ tag_name=$( echo " $json " | jq -r ' .tag_name // .name // empty' )
2565+ [[ " $tag_name " =~ ^v ]] && version=" ${tag_name: 1} " || version=" $tag_name "
2566+ msg_info " Fetching GitHub release: $app ($version )"
2567+ assets=$( echo " $json " | jq -r ' .assets[].browser_download_url' )
2568+ if [[ -n " $asset_pattern " ]]; then
2569+ for u in $assets ; do
2570+ case " ${u##*/ } " in $asset_pattern ) url_match=" $u " ; break ;; esac
2571+ done
2572+ fi
2573+ if [[ -z " $url_match " ]]; then
2574+ for u in $assets ; do
2575+ if [[ " $u " =~ ($arch | amd64| x86_64| aarch64| arm64).* \. deb$ ]]; then url_match=" $u " ; break ; fi
2576+ done
2577+ fi
2578+ if [[ -z " $url_match " ]]; then
2579+ for u in $assets ; do
2580+ [[ " $u " =~ \. deb$ ]] && url_match=" $u " && break
2581+ done
2582+ fi
2583+ fi
2584+ fi
2585+
24612586 if [[ -z " $url_match " ]]; then
24622587 msg_error " No suitable .deb asset found for $app "
24632588 rm -rf " $tmpdir "
@@ -2506,6 +2631,21 @@ function fetch_and_deploy_gh_release() {
25062631 esac
25072632 done
25082633
2634+ # Fallback: scan older releases for a matching asset
2635+ if [[ -z " $asset_url " ]]; then
2636+ local fallback_json
2637+ if fallback_json=$( _gh_scan_older_releases " $repo " " prebuild" " $pattern " " $tag_name " ) ; then
2638+ json=" $fallback_json "
2639+ tag_name=$( echo " $json " | jq -r ' .tag_name // .name // empty' )
2640+ [[ " $tag_name " =~ ^v ]] && version=" ${tag_name: 1} " || version=" $tag_name "
2641+ msg_info " Fetching GitHub release: $app ($version )"
2642+ for u in $( echo " $json " | jq -r ' .assets[].browser_download_url' ) ; do
2643+ filename_candidate=" ${u##*/ } "
2644+ case " $filename_candidate " in $pattern ) asset_url=" $u " ; break ;; esac
2645+ done
2646+ fi
2647+ fi
2648+
25092649 [[ -z " $asset_url " ]] && {
25102650 msg_error " No asset matching '$pattern ' found"
25112651 rm -rf " $tmpdir "
@@ -2603,6 +2743,20 @@ function fetch_and_deploy_gh_release() {
26032743 esac
26042744 done
26052745
2746+ # Fallback: scan older releases for a matching asset
2747+ if [[ -z " $asset_url " ]]; then
2748+ local fallback_json
2749+ if fallback_json=$( _gh_scan_older_releases " $repo " " singlefile" " $pattern " " $tag_name " ) ; then
2750+ json=" $fallback_json "
2751+ tag_name=$( echo " $json " | jq -r ' .tag_name // .name // empty' )
2752+ [[ " $tag_name " =~ ^v ]] && version=" ${tag_name: 1} " || version=" $tag_name "
2753+ msg_info " Fetching GitHub release: $app ($version )"
2754+ for u in $( echo " $json " | jq -r ' .assets[].browser_download_url' ) ; do
2755+ filename_candidate=" ${u##*/ } "
2756+ case " $filename_candidate " in $pattern ) asset_url=" $u " ; break ;; esac
2757+ done
2758+ fi
2759+ fi
26062760 [[ -z " $asset_url " ]] && {
26072761 msg_error " No asset matching '$pattern ' found"
26082762 rm -rf " $tmpdir "
0 commit comments