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.

Revisions

  1. Kotauror revised this gist Sep 29, 2025. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    "
    '''
    This script:
    - finds all "Staging release" PRs
    - gets all issues linked in them
    @@ -7,7 +7,7 @@
    and prints:
    - status of issues per PR
    - summary of all open issues in the PRs
    "
    '''

    import requests
    import re
  2. Kotauror revised this gist Sep 29, 2025. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,4 @@
    '''
    "
    This script:
    - finds all "Staging release" PRs
    - gets all issues linked in them
    @@ -8,7 +7,7 @@
    and prints:
    - status of issues per PR
    - summary of all open issues in the PRs
    '''
    "

    import requests
    import re
  3. Kotauror renamed this gist Sep 29, 2025. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions gistfile1.txt → gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    '''
    This script:
    - finds all "Staging release" PRs
    - gets all issues linked in them
    @@ -6,8 +8,8 @@
    and prints:
    - status of issues per PR
    - summary of all open issues in the PRs
    '''

    ```py
    import requests
    import re
    import time
    @@ -104,4 +106,3 @@ def main():

    if __name__ == "__main__":
    main()
    ```
  4. Kotauror renamed this gist Sep 29, 2025. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions gistfile1.py → gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,13 @@
    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

    ```py
    import requests
    import re
    import time
    @@ -94,3 +104,4 @@ def main():

    if __name__ == "__main__":
    main()
    ```
  5. Kotauror revised this gist Sep 29, 2025. 1 changed file with 21 additions and 16 deletions.
    37 changes: 21 additions & 16 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -18,17 +18,17 @@ 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 and len(prs) < 15:
    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[:15]
    return prs

    def extract_issue_ids(text, pr_num):
    print(f"Extracting issues for PR # #{pr_num}")
    print(f"Extracting issues for PR #{pr_num}")
    return re.findall(URL_PATTERN, text or "")

    def get_issue_state(issue_number):
    @@ -44,7 +44,7 @@ def get_issue_state(issue_number):
    def main():
    prs = search_release_prs()
    results = []
    all_issues = set() # unique issues across PRs
    processed_issues = {} # {issue_number: state}

    for pr in prs:
    pr_num = pr["number"]
    @@ -59,7 +59,13 @@ def main():
    pr_body = pr_data.get("body", "")

    issues = extract_issue_ids(pr_body, pr_num)
    all_issues.update(issues) # collect into global set

    # 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,
    @@ -70,22 +76,21 @@ def main():

    # Print PR details
    for r in results:
    print(f"\n PR #{r['pr_number']}: {r['title']} ({r['url']})")
    print(f"\nPR #{r['pr_number']}: {r['title']} ({r['url']})")
    if r["issues"]:
    for issue in r["issues"]:
    issue_state = get_issue_state(issue)
    color_light = "🟢" if issue_state == "open" else "🟣"

    print(f" - {color_light} Issue #{issue}: {issue_state}: https://github.com/{OWNER}/{REPO}/issues/{issue}")
    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")

    # Check states for all issues
    print("\n\n✅ Summary of all referenced issues across release PRs:")
    for issue in sorted(all_issues, key=int):
    state = get_issue_state(issue)
    print(f"- Issue #{issue}: {state} → https://github.com/{OWNER}/{REPO}/issues/{issue}")
    time.sleep(0.5) # stay under API rate limits
    # 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()
  6. Kotauror renamed this gist Sep 29, 2025. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  7. Kotauror created this gist Sep 29, 2025.
    91 changes: 91 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    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 and len(prs) < 15:
    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[:15]

    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 = []
    all_issues = set() # unique issues across PRs

    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)
    all_issues.update(issues) # collect into global set

    results.append({
    "pr_number": pr_num,
    "title": pr_title,
    "url": pr_url,
    "issues": issues
    })

    # Print PR details
    for r in results:
    print(f"\n PR #{r['pr_number']}: {r['title']} ({r['url']})")
    if r["issues"]:
    for issue in r["issues"]:
    issue_state = get_issue_state(issue)
    color_light = "🟢" if issue_state == "open" else "🟣"

    print(f" - {color_light} Issue #{issue}: {issue_state}: https://github.com/{OWNER}/{REPO}/issues/{issue}")
    else:
    print(" - No linked issues")

    # Check states for all issues
    print("\n\n✅ Summary of all referenced issues across release PRs:")
    for issue in sorted(all_issues, key=int):
    state = get_issue_state(issue)
    print(f"- Issue #{issue}: {state} → https://github.com/{OWNER}/{REPO}/issues/{issue}")
    time.sleep(0.5) # stay under API rate limits

    if __name__ == "__main__":
    main()