Bounty Monitor #489
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Bounty Monitor | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "10 * * * *" | |
| permissions: | |
| contents: read | |
| jobs: | |
| monitor: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Validate secrets | |
| env: | |
| TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} | |
| TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} | |
| run: | | |
| if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then | |
| echo "Missing TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID" | |
| exit 1 | |
| fi | |
| - name: Build status message | |
| id: status | |
| run: | | |
| python - <<'PY' | |
| import json | |
| import urllib.request | |
| from datetime import datetime, timezone | |
| targets = [ | |
| { | |
| "label": "iota_498", | |
| "issue_repo": "iotaledger/iota-rust-sdk", | |
| "issue": 498, | |
| "pr_repo": "iotaledger/iota-rust-sdk", | |
| "pr": 569, | |
| }, | |
| { | |
| "label": "iota_515", | |
| "issue_repo": "iotaledger/iota-rust-sdk", | |
| "issue": 515, | |
| "pr_repo": "iotaledger/iota-rust-sdk", | |
| "pr": 570, | |
| }, | |
| { | |
| "label": "iota_501", | |
| "issue_repo": "iotaledger/iota-rust-sdk", | |
| "issue": 501, | |
| "pr_repo": "iotaledger/iota-rust-sdk", | |
| "pr": 571, | |
| }, | |
| { | |
| "label": "iota_510", | |
| "issue_repo": "iotaledger/iota-rust-sdk", | |
| "issue": 510, | |
| "pr_repo": "iotaledger/iota-rust-sdk", | |
| "pr": 572, | |
| }, | |
| { | |
| "label": "rustchain_123", | |
| "issue_repo": "Scottcjn/rustchain-bounties", | |
| "issue": 123, | |
| "pr_repo": "Scottcjn/Rustchain", | |
| "pr": 115, | |
| }, | |
| { | |
| "label": "rustchain_122_rustchain", | |
| "issue_repo": "Scottcjn/rustchain-bounties", | |
| "issue": 122, | |
| "pr_repo": "Scottcjn/Rustchain", | |
| "pr": 116, | |
| }, | |
| { | |
| "label": "rustchain_122_bottube", | |
| "issue_repo": "Scottcjn/rustchain-bounties", | |
| "issue": 122, | |
| "pr_repo": "Scottcjn/bottube", | |
| "pr": 94, | |
| }, | |
| { | |
| "label": "rustchain_122_ramcoffers", | |
| "issue_repo": "Scottcjn/rustchain-bounties", | |
| "issue": 122, | |
| "pr_repo": "Scottcjn/ram-coffers", | |
| "pr": 1, | |
| }, | |
| { | |
| "label": "rustchain_72_faq", | |
| "issue_repo": "Scottcjn/rustchain-bounties", | |
| "issue": 72, | |
| "pr_repo": "Scottcjn/Rustchain", | |
| "pr": 117, | |
| }, | |
| ] | |
| def get(url): | |
| req = urllib.request.Request( | |
| url, | |
| headers={ | |
| "Accept": "application/vnd.github+json", | |
| "X-GitHub-Api-Version": "2022-11-28", | |
| "User-Agent": "job-subscription-monitor", | |
| }, | |
| ) | |
| with urllib.request.urlopen(req, timeout=20) as resp: | |
| return json.loads(resp.read().decode("utf-8")) | |
| now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") | |
| lines = [f"[Bounty Monitor] {now}"] | |
| payout_ready = [] | |
| for target in targets: | |
| issue_no = target["issue"] | |
| pr_no = target["pr"] | |
| label = target["label"] | |
| issue_repo = target["issue_repo"] | |
| pr_repo = target["pr_repo"] | |
| issue = get( | |
| f"https://api.github.com/repos/{issue_repo}/issues/{issue_no}" | |
| ) | |
| pr = get( | |
| f"https://api.github.com/repos/{pr_repo}/pulls/{pr_no}" | |
| ) | |
| issue_state = issue.get("state", "unknown") | |
| pr_state = pr.get("state", "unknown") | |
| pr_merged = bool(pr.get("merged", False)) | |
| mergeable_state = pr.get("mergeable_state", "unknown") | |
| review_comments = pr.get("review_comments", 0) | |
| comments = pr.get("comments", 0) | |
| commits = pr.get("commits", 0) | |
| changed_files = pr.get("changed_files", 0) | |
| payout_hint = "wait_for_review" | |
| if pr_merged: | |
| payout_hint = "request_bounty_payout_now" | |
| payout_ready.append( | |
| f"{label}(issue_{issue_repo}#{issue_no}/pr_{pr_repo}#{pr_no})" | |
| ) | |
| elif pr_state == "closed": | |
| payout_hint = "pr_closed_without_merge_check_next_action" | |
| elif review_comments > 0 or comments > 0: | |
| payout_hint = "review_feedback_available" | |
| lines.extend( | |
| [ | |
| "", | |
| f"{label}:", | |
| f"issue_{issue_no}_state={issue_state}", | |
| f"pr_{pr_no}_state={pr_state}", | |
| f"pr_{pr_no}_merged={str(pr_merged).lower()}", | |
| f"pr_{pr_no}_mergeable_state={mergeable_state}", | |
| f"pr_{pr_no}_review_comments={review_comments}", | |
| f"pr_{pr_no}_comments={comments}", | |
| f"pr_{pr_no}_commits={commits} changed_files={changed_files}", | |
| f"payout_action={payout_hint}", | |
| f"issue=https://github.com/{issue_repo}/issues/{issue_no}", | |
| f"pr=https://github.com/{pr_repo}/pull/{pr_no}", | |
| ] | |
| ) | |
| lines.extend( | |
| [ | |
| "", | |
| "summary:", | |
| f"payout_ready_count={len(payout_ready)}", | |
| f"payout_ready_jobs={', '.join(payout_ready) if payout_ready else 'none'}", | |
| ] | |
| ) | |
| with open("status_message.txt", "w", encoding="utf-8") as f: | |
| f.write("\n".join(lines)) | |
| with open("status_message.txt", "r", encoding="utf-8") as f: | |
| message = f.read() | |
| with open("/tmp/github_output.txt", "w", encoding="utf-8") as f: | |
| f.write("message<<EOF\n") | |
| f.write(message) | |
| f.write("\nEOF\n") | |
| with open("/tmp/github_output.txt", "r", encoding="utf-8") as src, open( | |
| __import__("os").environ["GITHUB_OUTPUT"], "a", encoding="utf-8" | |
| ) as dst: | |
| dst.write(src.read()) | |
| PY | |
| - name: Send Telegram update | |
| env: | |
| TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} | |
| TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} | |
| MESSAGE: ${{ steps.status.outputs.message }} | |
| run: | | |
| curl -sS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ | |
| --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \ | |
| --data-urlencode "text=${MESSAGE}" \ | |
| --data-urlencode "disable_web_page_preview=true" |