#!/usr/bin/env python3
"""Compose desktop-first release notes and refresh published download links."""
import json
from html import escape
import os
import re
import subprocess
import sys
from pathlib import Path
ISSUES_QUERY = """query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
closingIssuesReferences(first: 100) { nodes { title url state } }
}
}
}"""
def gh(*args):
return json.loads(subprocess.check_output(["gh", "api", *args], text=True))
def fixed_issues(notes, repository):
owner, repo = repository.split("/", 1)
pattern = rf"https://github\.com/{re.escape(repository)}/pull/(\d+)"
issues = []
seen = set()
for number in dict.fromkeys(re.findall(pattern, notes)):
try:
result = gh(
"graphql", "-f", f"query={ISSUES_QUERY}", "-f", f"owner={owner}",
"-f", f"repo={repo}", "-F", f"number={number}",
)
linked = result["data"]["repository"]["pullRequest"]["closingIssuesReferences"]["nodes"]
except (subprocess.CalledProcessError, KeyError, TypeError, ValueError) as error:
print(f"::warning::Could not list fixed issues for PR #{number}: {error}", file=sys.stderr)
continue
for issue in linked:
if issue["state"] == "CLOSED" and issue["url"] not in seen:
seen.add(issue["url"])
title = issue["title"].replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]")
issues.append(
f"- [{title}]({issue['url']}) — fixed by "
f"[#{number}](https://github.com/{repository}/pull/{number})"
)
return issues
DOWNLOAD_START = ""
DOWNLOAD_END = ""
DESKTOP_ASSETS = (
("OpenResearch.dmg", "Download for macOS — Apple silicon and Intel", "macos"),
("OpenResearch-Setup.exe", "Download for Windows", "windows"),
("OpenResearch-x86_64.AppImage", "Download for Linux (x86)", "linux-x86"),
("OpenResearch-aarch64.AppImage", "Download for Linux (ARM64)", "linux-arm64"),
)
def downloads(assets=()):
urls = {asset["name"]: asset["browser_download_url"] for asset in assets}
images = "https://raw.githubusercontent.com/alphaXiv/OpenResearch/main/.github/readme-assets"
buttons = [
f''
'
\n" + "\n".join(buttons) + "\n
"] if buttons else [] if not links: links = ["[Download the desktop app](https://openresearch.sh/)"] return "\n\n".join(( DOWNLOAD_START, "## Download OpenResearch", "Install the desktop app to get everything you need. No separate installation or terminal setup required.", "\n\n".join(links), "The desktop app updates automatically by default. You can manage updates in Settings.", DOWNLOAD_END, )) def refresh_downloads(body, assets): before, start, rest = body.partition(DOWNLOAD_START) _, end, after = rest.partition(DOWNLOAD_END) if not start and DOWNLOAD_END not in body: return body if not start or not end: raise ValueError("Release has no managed desktop download section") return before + downloads(assets) + after def remote_install(repository, tag): url = f"https://github.com/{repository}/releases/download/{tag}/openresearch-cli-installer.sh" return ( "