Fix large GitHub release JSON handling
This commit is contained in:
committed by
latypov
parent
aa4c241f99
commit
8f84934c46
@@ -57,3 +57,11 @@ At 09:00 server-local time:
|
||||
```
|
||||
|
||||
Run the monitor under a dedicated user where possible. Keep `.env` private and do not commit it. Use `./monitor.sh --test-telegram` to verify Telegram and proxy connectivity.
|
||||
|
||||
### Large release histories
|
||||
|
||||
GitHub response pages are processed through temporary files, rather than passed
|
||||
through command-line arguments. The state file is read directly by `jq`.
|
||||
This prevents `Argument list too long` for repositories with large release notes.
|
||||
|
||||
Run `bash -n monitor.sh` and `./monitor.sh --dry-run --verbose` to verify.
|
||||
|
||||
Regular → Executable
+41
-16
@@ -93,29 +93,48 @@ test_telegram() {
|
||||
if send_telegram "$message"; then log INFO 'Test notification sent'; else log ERROR 'Test notification failed'; return 1; fi
|
||||
}
|
||||
fetch_releases() {
|
||||
local repo="$1" page response count result='[]'
|
||||
local repo="$1" page count response_file releases_file
|
||||
response_file="$(mktemp)" || return 1
|
||||
releases_file="$(mktemp)" || { rm -f "$response_file"; return 1; }
|
||||
|
||||
for ((page=1; page<=GITHUB_MAX_PAGES; page++)); do
|
||||
debug "Fetching $repo page=$page"
|
||||
response="$(curl "${CURL_OPTIONS[@]}" "${GITHUB_HEADERS[@]}" \
|
||||
"${GITHUB_API}/repos/${repo}/releases?per_page=${GITHUB_PER_PAGE}&page=${page}")" || return 1
|
||||
jq -e 'type == "array"' <<< "$response" >/dev/null || return 1
|
||||
count="$(jq 'length' <<< "$response")"
|
||||
result="$(jq -cn --argjson old "$result" --argjson new "$response" '$old + $new')" || return 1
|
||||
if ! curl "${CURL_OPTIONS[@]}" "${GITHUB_HEADERS[@]}" \
|
||||
--output "$response_file" \
|
||||
"${GITHUB_API}/repos/${repo}/releases?per_page=${GITHUB_PER_PAGE}&page=${page}"; then
|
||||
rm -f "$response_file" "$releases_file"
|
||||
return 1
|
||||
fi
|
||||
if ! count="$(jq -er 'if type == "array" then length else error("Invalid releases response") end' "$response_file")"; then
|
||||
rm -f "$response_file" "$releases_file"
|
||||
return 1
|
||||
fi
|
||||
if ! jq -c --argjson prereleases "$INCLUDE_PRERELEASES" '
|
||||
.[] | select(.draft == false) |
|
||||
select($prereleases or (.prerelease == false)) |
|
||||
{id: (.id | tostring), tag: .tag_name, name: .name,
|
||||
url: .html_url, published: .published_at, prerelease: .prerelease}
|
||||
' "$response_file" >> "$releases_file"; then
|
||||
rm -f "$response_file" "$releases_file"
|
||||
return 1
|
||||
fi
|
||||
if (( count < GITHUB_PER_PAGE )); then break; fi
|
||||
done
|
||||
jq -c --argjson prereleases "$INCLUDE_PRERELEASES" '
|
||||
[.[] | select(.draft == false) | select($prereleases or (.prerelease == false)) |
|
||||
{id: (.id | tostring), tag: .tag_name, name: .name, url: .html_url,
|
||||
published: .published_at, prerelease: .prerelease}]
|
||||
' <<< "$result"
|
||||
|
||||
local status=0
|
||||
jq -sc '.' "$releases_file" || status=$?
|
||||
rm -f "$response_file" "$releases_file"
|
||||
return "$status"
|
||||
}
|
||||
|
||||
write_state() {
|
||||
local repo="$1" ids="$2" mode="$3" temp
|
||||
temp="$(mktemp "${STATE_FILE}.tmp.XXXXXX")" || return 1
|
||||
if ! jq --arg repo "$repo" --argjson ids "$ids" --arg mode "$mode" '
|
||||
if $mode == "replace" then .[$repo] = $ids
|
||||
else .[$repo] = ((.[$repo] // []) + $ids | unique) end
|
||||
' "$STATE_FILE" > "$temp"; then rm -f "$temp"; return 1; fi
|
||||
if ! jq --arg repo "$repo" --arg mode "$mode" --slurpfile ids /dev/stdin '
|
||||
($ids[0] // []) as $new_ids |
|
||||
if $mode == "replace" then .[$repo] = $new_ids
|
||||
else .[$repo] = ((.[$repo] // []) + $new_ids | unique) end
|
||||
' "$STATE_FILE" <<< "$ids" > "$temp"; then rm -f "$temp"; return 1; fi
|
||||
if ! mv -f "$temp" "$STATE_FILE"; then rm -f "$temp"; return 1; fi
|
||||
}
|
||||
format_message() {
|
||||
@@ -151,7 +170,13 @@ process_repo() {
|
||||
log INFO "Baseline initialized: $repo ($count releases)"
|
||||
return 0
|
||||
fi
|
||||
new_releases="$(jq -c --argjson seen "$previous" '[.[] | select(.id as $id | $seen | index($id) | not)] | reverse' <<< "$releases")" || return 1
|
||||
# Read the existing state from a file, not from argv (ARG_MAX).
|
||||
local state_source="$STATE_FILE"
|
||||
[[ -f "$state_source" ]] || state_source=/dev/null
|
||||
new_releases="$(jq -c --slurpfile state "$state_source" --arg repo "$repo" '
|
||||
($state[0][$repo] // []) as $seen |
|
||||
[.[] | select(.id as $id | $seen | index($id) | not)] | reverse
|
||||
' <<< "$releases")" || return 1
|
||||
count="$(jq 'length' <<< "$new_releases")"
|
||||
if (( count == 0 )); then log INFO "No new releases: $repo"; return 0; fi
|
||||
log INFO "Found $count new releases: $repo"
|
||||
|
||||
Reference in New Issue
Block a user