From 56cc555fc9be3e27a8a96f79f206e5d6726f164f Mon Sep 17 00:00:00 2001 From: wrench-exile-legacy Date: Sun, 12 Jul 2026 20:19:46 +0100 Subject: [PATCH] minecraft-server: support updateScript generated commits --- .../mi/minecraft-server/derivation.nix | 6 +- pkgs/by-name/mi/minecraft-server/update.py | 132 +++++++++++++++++- 2 files changed, 133 insertions(+), 5 deletions(-) diff --git a/pkgs/by-name/mi/minecraft-server/derivation.nix b/pkgs/by-name/mi/minecraft-server/derivation.nix index 4192dff1ccf6..e7e31f2a16ce 100644 --- a/pkgs/by-name/mi/minecraft-server/derivation.nix +++ b/pkgs/by-name/mi/minecraft-server/derivation.nix @@ -36,7 +36,11 @@ stdenv.mkDerivation { passthru = { tests = { inherit (nixosTests) minecraft-server; }; - updateScript = ./update.py; + updateScript = { + command = [ ./update.py ]; + + supportedFeatures = [ "commit" ]; + }; }; meta = { diff --git a/pkgs/by-name/mi/minecraft-server/update.py b/pkgs/by-name/mi/minecraft-server/update.py index f272c8b71a84..de4c9339c576 100755 --- a/pkgs/by-name/mi/minecraft-server/update.py +++ b/pkgs/by-name/mi/minecraft-server/update.py @@ -110,6 +110,32 @@ def group_major_releases(releases: List[Version]) -> Dict[str, List[Version]]: return groups +def slugify(version: str) -> str: + return version.replace(".", "-") + + +def get_changelog_url(version: str) -> Optional[str]: + """ + Attempt to resolve the Minecraft changelog article URL. + Returns the URL if it exists, otherwise None. + """ + url = f"https://www.minecraft.net/en-us/article/minecraft-java-edition-{slugify(version)}" + + # our request is denied without a human user-agent + headers = { + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0" + } + + try: + response = requests.head(url, headers=headers, timeout=3) + if response.status_code == 200: + return url + except requests.RequestException as e: + pass + + return None + + def get_latest_major_releases(releases: List[Version]) -> Dict[str, Version]: """ Return a dictionary containing the latest version for each major release. @@ -118,8 +144,12 @@ def get_latest_major_releases(releases: List[Version]) -> Dict[str, Version]: """ return { major_release: max( - (release for release in releases if get_major_release(release.id) == major_release), - key=lambda x: tuple(map(int, x.id.split('.'))), + ( + release + for release in releases + if get_major_release(release.id) == major_release + ), + key=lambda x: tuple(map(int, x.id.split("."))), ) for major_release in group_major_releases(releases) } @@ -153,7 +183,101 @@ def generate() -> Dict[str, Dict[str, str]]: return servers +def get_latest(servers: Dict[str, Dict[str, str]]) -> str | None: + return max( + (v.get("version") for v in servers.values()), + key=lambda x: tuple(map(int, x.split("."))) if x is not None else (), + ) + + +def generate_commit( + previous_servers: Dict[str, Dict[str, str]], + servers: Dict[str, Dict[str, str]], + versions_file: Path, +) -> List[Dict[str, str | list[str]]]: + actions = [] + commit_body_lines = [] + + old_latest = get_latest(previous_servers) + new_latest = get_latest(servers) + + for major_version, server in servers.items(): + version = server.get("version") + previous_server = previous_servers.get(major_version) + + if version is None: + continue + + attribute = f"minecraftServers.vanilla-{slugify(major_version)}" + + if not previous_server: + # this version didn't exist before + # check if its now the latest version + if version == new_latest: + action = f"{old_latest} -> {new_latest}" + attribute = "minecraft-server" + else: + action = f"init {version}" + + else: + previous_version = previous_server.get("version") + if previous_version == version: + continue + + action = f"{previous_version} -> {version}" + + actions.append(action) + + commit_body_lines.append(f"{attribute}: {action}") + + changelog_url = get_changelog_url(version) + if changelog_url: + commit_body_lines.append(f"Release notes: {changelog_url}") + + if not commit_body_lines: + return [] + + if len(actions) == 1: + commit_message = commit_body_lines[0] + + # the body should only be the release notes to avoid repeatition + # if the release notes don't exist this will be blank + commit_body = "\n".join(commit_body_lines[1:]).strip() + else: + detailed_message = f"minecraft-server: {', '.join(actions)}" + + commit_message = ( + detailed_message + if len(detailed_message) <= 72 + else "minecraft-server: update multiple versions" + ) + + commit_body = "\n".join(commit_body_lines).strip() + + commit_json = { + "attrPath": "minecraftServers.vanilla", + "files": [str(versions_file)], + "commitMessage": commit_message, + } + + if commit_body: + commit_json["commitBody"] = commit_body + + return [commit_json] + + if __name__ == "__main__": - with open(Path(__file__).parent / "versions.json", "w") as file: - json.dump(generate(), file, indent=2) + versions_file = Path(__file__).parent / "versions.json" + + with open(versions_file, "r") as file: + previous_servers = json.load(file) + + servers = generate() + + commit_json = generate_commit(previous_servers, servers, versions_file) + + with open(versions_file, "w") as file: + json.dump(servers, file, indent=2) file.write("\n") + + print(json.dumps(commit_json))