Initial commit: OpenClaw ops workspace
This commit is contained in:
145
skills/github-notifications/scripts/check.sh
Executable file
145
skills/github-notifications/scripts/check.sh
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/bin/bash
|
||||
# GitHub Notifications Checker
|
||||
# Filters PRs and releases, tracks state, returns JSON summary
|
||||
|
||||
set -e
|
||||
|
||||
STATE_FILE="${STATE_FILE:-memory/github-check-state.json}"
|
||||
WORKSPACE="${WORKSPACE:-/home/node/.openclaw/workspace}"
|
||||
cd "$WORKSPACE"
|
||||
|
||||
# Initialize state file if missing
|
||||
if [ ! -f "$STATE_FILE" ]; then
|
||||
mkdir -p "$(dirname "$STATE_FILE")"
|
||||
echo '{"lastCheck":"1970-01-01T00:00:00Z","seenPRs":[],"seenReleases":[]}' > "$STATE_FILE"
|
||||
fi
|
||||
|
||||
# Load last check time
|
||||
LAST_CHECK=$(jq -r '.lastCheck' "$STATE_FILE")
|
||||
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# Fetch notifications (PRs only)
|
||||
if ! PR_DATA=$(gh api 'notifications?all=true&per_page=100' 2>&1); then
|
||||
echo '{"error":"GitHub API failed","details":"'"${PR_DATA//\"/\\\"}"'"}' | jq .
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Filter PRs where user is mentioned/author/review requested/subscribed
|
||||
FILTERED_PRS=$(echo "$PR_DATA" | jq -r '[
|
||||
.[] |
|
||||
select(.subject.type == "PullRequest") |
|
||||
select(.reason == "mention" or .reason == "author" or .reason == "review_requested" or .reason == "subscribed") |
|
||||
{
|
||||
repo: .repository.full_name,
|
||||
title: .subject.title,
|
||||
url: .subject.url,
|
||||
updated: .updated_at,
|
||||
reason: .reason,
|
||||
id: (.repository.full_name + "#" + .subject.title)
|
||||
}
|
||||
]')
|
||||
|
||||
# Filter releases
|
||||
RELEASE_DATA=$(echo "$PR_DATA" | jq -r '[
|
||||
.[] |
|
||||
select(.subject.type == "Release") |
|
||||
{
|
||||
repo: .repository.full_name,
|
||||
title: .subject.title,
|
||||
updated: .updated_at,
|
||||
reason: .reason,
|
||||
id: (.repository.full_name + "@" + .subject.title)
|
||||
}
|
||||
]')
|
||||
|
||||
# Filter releases:
|
||||
# - include subscribed releases (user-requested)
|
||||
# - keep legacy inclusion for major releases + whitelist repos
|
||||
# - ignore dev/pre-release markers for non-whitelist repos
|
||||
# - additionally ignore GitHub prerelease=true for non-whitelist repos
|
||||
# - whitelist repos always pass through
|
||||
FILTERED_RELEASES=$(echo "$RELEASE_DATA" | jq -r '[
|
||||
.[] |
|
||||
. as $r |
|
||||
($r.repo == "Mirrowel/LLM-API-Key-Proxy" or $r.repo == "openclaw/openclaw" or $r.repo == "anomalyco/opencode") as $whitelisted |
|
||||
select(
|
||||
($r.reason == "subscribed") or
|
||||
$whitelisted or
|
||||
($r.title | test("^v[0-9]+\\.0\\.0"))
|
||||
) |
|
||||
select(
|
||||
$whitelisted or
|
||||
(($r.title | ascii_downcase) | test("(rc|pre|beta|alpha|nightly|dev|exp|canary|snapshot)") | not)
|
||||
)
|
||||
]')
|
||||
|
||||
# Enrich release candidates with GitHub prerelease flag (best-effort).
|
||||
# Notifications payload lacks prerelease metadata, so look up each candidate by repo+title.
|
||||
# For non-whitelisted repos, exclude prerelease=true.
|
||||
FILTERED_RELEASES=$(echo "$FILTERED_RELEASES" | jq -c '.[]' | while read -r rel; do
|
||||
repo=$(echo "$rel" | jq -r '.repo')
|
||||
title=$(echo "$rel" | jq -r '.title')
|
||||
|
||||
whitelisted=false
|
||||
if [ "$repo" = "Mirrowel/LLM-API-Key-Proxy" ] || [ "$repo" = "openclaw/openclaw" ] || [ "$repo" = "anomalyco/opencode" ]; then
|
||||
whitelisted=true
|
||||
fi
|
||||
|
||||
# Whitelist bypasses prerelease metadata filtering.
|
||||
if [ "$whitelisted" = "true" ]; then
|
||||
echo "$rel"
|
||||
continue
|
||||
fi
|
||||
|
||||
# URL-encode tag (title) using jq for safety.
|
||||
tag_encoded=$(jq -nr --arg s "$title" '$s|@uri')
|
||||
|
||||
# If lookup fails, keep item (fail-open) to avoid dropping potentially important notifications.
|
||||
prerelease=$(gh api "repos/$repo/releases/tags/$tag_encoded" --jq '.prerelease' 2>/dev/null || echo "lookup_failed")
|
||||
|
||||
if [ "$prerelease" = "true" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "$rel"
|
||||
done | jq -s '.')
|
||||
|
||||
# Load seen items
|
||||
SEEN_PRS=$(jq -r '.seenPRs // []' "$STATE_FILE")
|
||||
SEEN_RELEASES=$(jq -r '.seenReleases // []' "$STATE_FILE")
|
||||
|
||||
# Find new items
|
||||
NEW_PRS=$(echo "$FILTERED_PRS" | jq --argjson seen "$SEEN_PRS" '[
|
||||
.[] | select(.id as $id | $seen | index($id) | not)
|
||||
]')
|
||||
|
||||
NEW_RELEASES=$(echo "$FILTERED_RELEASES" | jq --argjson seen "$SEEN_RELEASES" '[
|
||||
.[] | select(.id as $id | $seen | index($id) | not)
|
||||
]')
|
||||
|
||||
# Count new items
|
||||
NEW_PR_COUNT=$(echo "$NEW_PRS" | jq 'length')
|
||||
NEW_RELEASE_COUNT=$(echo "$NEW_RELEASES" | jq 'length')
|
||||
|
||||
# Update state
|
||||
ALL_PR_IDS=$(echo "$FILTERED_PRS" | jq -r '[.[].id]')
|
||||
ALL_RELEASE_IDS=$(echo "$FILTERED_RELEASES" | jq -r '[.[].id]')
|
||||
|
||||
jq -n \
|
||||
--arg now "$NOW" \
|
||||
--argjson prIds "$ALL_PR_IDS" \
|
||||
--argjson relIds "$ALL_RELEASE_IDS" \
|
||||
'{lastCheck:$now, seenPRs:$prIds, seenReleases:$relIds}' \
|
||||
> "$STATE_FILE"
|
||||
|
||||
# Output result
|
||||
if [ "$NEW_PR_COUNT" -eq 0 ] && [ "$NEW_RELEASE_COUNT" -eq 0 ]; then
|
||||
echo '{"hasNew":false}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Return new items
|
||||
jq -n \
|
||||
--argjson prs "$NEW_PRS" \
|
||||
--argjson releases "$NEW_RELEASES" \
|
||||
'{hasNew:true, newPRs:$prs, newReleases:$releases}'
|
||||
Reference in New Issue
Block a user