Skip to content

Instantly share code, notes, and snippets.

@Kotauror
Last active September 29, 2025 06:45
Show Gist options
  • Select an option

  • Save Kotauror/1d596de16eef400b69c435b6b9ad5e5a to your computer and use it in GitHub Desktop.

Select an option

Save Kotauror/1d596de16eef400b69c435b6b9ad5e5a to your computer and use it in GitHub Desktop.
Check the status of issues mentioned in merge PRs
'''
This script:
- finds all "Staging release" PRs
- gets all issues linked in them
- for all issues - checks their status
and prints:
- status of issues per PR
- summary of all open issues in the PRs
'''
import requests
import re
import time
import os
TOKEN = os.getenv("GH_TOKEN")
OWNER = os.getenv("CUR_COMPANY_OWNER")
REPO = os.getenv("PR_SCRIPT_REPO_NAME")
URL_PATTERN = os.getenv("F_ISSUE_URL_PATTERN")
HEADERS = {
"Authorization": f"Bearer {TOKEN}",
"Accept": "application/vnd.github+json"
}
def search_release_prs():
"""Search all PRs containing 'release' in title/body, paginated."""
url = f"https://api.github.com/search/issues?q=repo:{OWNER}/{REPO}+is:pr+release&per_page=100"
prs = []
while url:
r = requests.get(url, headers=HEADERS)
r.raise_for_status()
data = r.json()
prs.extend(data["items"])
url = r.links.get("next", {}).get("url")
time.sleep(0.2) # avoid hitting rate limits
return prs
def extract_issue_ids(text, pr_num):
print(f"Extracting issues for PR #{pr_num}")
return re.findall(URL_PATTERN, text or "")
def get_issue_state(issue_number):
"""Check if an issue is open/closed."""
url = f"https://api.github.com/repos/{OWNER}/{REPO}/issues/{issue_number}"
r = requests.get(url, headers=HEADERS)
if r.status_code == 404: # might not exist
return "not found"
r.raise_for_status()
data = r.json()
return data.get("state", "unknown")
def main():
prs = search_release_prs()
results = []
processed_issues = {} # {issue_number: state}
for pr in prs:
pr_num = pr["number"]
pr_title = pr["title"]
pr_url = pr["html_url"]
# get full PR body
pr_url_api = f"https://api.github.com/repos/{OWNER}/{REPO}/pulls/{pr_num}"
r = requests.get(pr_url_api, headers=HEADERS)
r.raise_for_status()
pr_data = r.json()
pr_body = pr_data.get("body", "")
issues = extract_issue_ids(pr_body, pr_num)
# collect issues + fetch states once
for issue in issues:
if issue not in processed_issues: # fetch only once
state = get_issue_state(issue)
processed_issues[issue] = state
time.sleep(0.2) # rate limit safety
results.append({
"pr_number": pr_num,
"title": pr_title,
"url": pr_url,
"issues": issues
})
# Print PR details
for r in results:
print(f"\nPR #{r['pr_number']}: {r['title']} ({r['url']})")
if r["issues"]:
for issue in r["issues"]:
state = processed_issues[issue]
color_light = "🟢" if state == "open" else "🟣"
print(f" - {color_light} Issue #{issue}: {state}: https://github.com/{OWNER}/{REPO}/issues/{issue}")
else:
print(" - No linked issues")
# Summary of open issues
open_issues = [i for i, state in processed_issues.items() if state == "open"]
print(f"\n\n✅ Summary: {len(open_issues)} open issues across release PRs:")
for issue in sorted(open_issues, key=int):
print(f"- 🟢 Issue #{issue} → https://github.com/{OWNER}/{REPO}/issues/{issue}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment