Skip to content

Commit

Permalink
Add workflow for when a mod is ported to a new Minecraft version
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander01998 committed Dec 6, 2024
1 parent b6d6351 commit 2cf580f
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 0 deletions.
61 changes: 61 additions & 0 deletions .github/workflows/add_mod_port.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Adds the necessary Hugo metadata when an existing mod update is ported to a new Minecraft version.
name: Add Mod Port
run-name: Add ${{ github.event.inputs.mod }} ${{ github.event.inputs.mod_version }} build for ${{ github.event.inputs.mc_version }}

on:
workflow_dispatch:
inputs:
mod:
description: "Mod ID (as it appears in config.toml)"
required: true
mod_version:
description: "Mod version (without v or -MC)"
required: true
mc_version:
description: "Minecraft version"
required: true
fapi_version:
description: "Fabric API version"
required: true
file_id:
description: "CurseForge file ID"
required: true

jobs:
update-post:
runs-on: ubuntu-latest
steps:

- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: _scripts/requirements.txt

- name: Install dependencies
run: |
pip install -r _scripts/requirements.txt
- name: Run add_mod_port.py
run: |
python _scripts/add_mod_port.py \
"${{ github.event.inputs.mod }}" \
"${{ github.event.inputs.mod_version }}" \
"${{ github.event.inputs.mc_version }}" \
"${{ github.event.inputs.fapi_version }}" \
"${{ github.event.inputs.file_id }}"
- name: Commit changes
run: |
MOD="${{ github.event.inputs.mod }}"
MOD_VERSION="${{ github.event.inputs.mod_version }}"
MC_VERSION="${{ github.event.inputs.mc_version }}"
git config --local user.email "[email protected]"
git config --local user.name "Wurst-Bot"
git add .
git commit -m "[Wurst-Bot] Port $MOD $MOD_VERSION to Minecraft $MC_VERSION"
git push
199 changes: 199 additions & 0 deletions scripts/add_mod_port.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import json
import os
import requests
from argparse import ArgumentParser
from io import StringIO
from ruamel.yaml import YAML

yaml = YAML()
yaml.preserve_quotes = True

manifest_url = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"
manifest = requests.get(manifest_url).json()

version_info = {
version["id"]: {"type": version["type"], "releaseTime": version["releaseTime"]}
for version in manifest["versions"]
}


def read_front_matter(path):
"""Read YAML front matter from a Jekyll/Hugo post."""
with open(path, "r", encoding="utf-8") as file:
content = file.read()

# Split on the first two "---" markers
parts = content.split("---", 2)
if len(parts) < 3:
raise ValueError(f"Invalid front matter format in {path}")

# Parse the YAML between the markers
return yaml.load(parts[1])


def write_front_matter(path, front_matter):
"""Write YAML front matter to a Jekyll/Hugo post while preserving content."""
with open(path, "r", encoding="utf-8") as file:
content = file.read()

# Split the original content
parts = content.split("---", 2)
if len(parts) < 3:
raise ValueError(f"Invalid front matter format in {path}")

# Create new content with updated front matter
output = StringIO()
yaml.dump(front_matter, output)
new_content = f"---\n{output.getvalue()}---{parts[2]}"

# Write the updated content
with open(path, "w", encoding="utf-8") as file:
file.write(new_content)


def find_mod_update_post(mod, version):
"""Find the mod update post for a specific version."""
posts_folder = os.path.join("content", mod)
for root, _, files in os.walk(posts_folder):
for file in files:
version_slug = version.replace(".", "-")
if version_slug not in file:
continue

post_path = os.path.join(root, file)
front_matter = read_front_matter(post_path)
if front_matter["modversion"] == version:
return front_matter, post_path

raise ValueError(f"Could not find post for mod {mod} version {version}")


def update_mod_post(mod, mod_version, mc_version):
"""Add a new Minecraft version to a mod update post."""
mc_version_type = version_info[mc_version]["type"]
front_matter, post_path = find_mod_update_post(mod, mod_version)

if mc_version_type == "snapshot":
if "snapshots" not in front_matter:
front_matter["snapshots"] = []
if mc_version not in front_matter["snapshots"]:
front_matter["snapshots"].insert(0, mc_version)
front_matter["snapshots"].sort(
key=lambda v: version_info[v]["releaseTime"],
reverse=True,
)
elif mc_version not in front_matter["mcversions"]:
front_matter["mcversions"].insert(0, mc_version)
front_matter["mcversions"].sort(
key=lambda v: version_info[v]["releaseTime"],
reverse=True,
)

write_front_matter(post_path, front_matter)


def update_fabric_api_data(mod, mod_version, mc_version, fapi_version):
"""Add a new entry to the Fabric API data file for a mod."""
data_file = os.path.join("data", "fabric_api", f"{mod}.json")
with open(data_file, "r") as f:
data = json.load(f)

# Add mod_version -> mc_version -> fabric_api mapping unless it is already there
if mod_version not in data:
data[mod_version] = {}
if mc_version not in data[mod_version]:
data[mod_version][mc_version] = fapi_version

# Sort fabric_api by release time and version type
for mod_version in data:
data[mod_version] = {
k: v
for k, v in sorted(
data[mod_version].items(),
key=lambda item: (
version_info[item[0]]["type"] == "release",
version_info[item[0]]["releaseTime"],
),
reverse=True,
)
}

with open(data_file, "w") as f:
json.dump(data, f, indent=2)


def update_curseforge_data(mod, mod_version, mc_version, file_id: int, modloader="fabric"):
"""Add a new entry to the CurseForge data file for a mod."""
data_file = os.path.join("data", "curseforge", f"{mod}", f"{modloader}.json")
with open(data_file, "r") as f:
data = json.load(f)

# Add mod_version -> mc_version mapping unless it is already there
if mod_version not in data:
data[mod_version] = {}
if mc_version not in data[mod_version]:
data[mod_version][mc_version] = file_id

# Sort curseforge IDs by release time and version type
for mod_version in data:
data[mod_version] = {
k: v
for k, v in sorted(
data[mod_version].items(),
key=lambda item: (
version_info[item[0]]["type"] == "release",
version_info[item[0]]["releaseTime"],
),
reverse=True,
)
}

with open(data_file, "w") as f:
json.dump(data, f, indent=2)


def add_download_category(mod, new_mcversion, old_mcversion):
"""Add a new download category when a mod is ported to a new Minecraft version."""
old_page_path = os.path.join(
"content", mod, f"minecraft-{old_mcversion.replace('.', '-')}.html"
)
new_page_path = os.path.join(
"content", mod, f"minecraft-{new_mcversion.replace('.', '-')}.html"
)

front_matter = read_front_matter(old_page_path)
title = front_matter["title"]
description = front_matter["description"]

front_matter["title"] = title.replace(old_mcversion, new_mcversion)
front_matter["description"] = description.replace(old_mcversion, new_mcversion)
front_matter["mcversion"] = new_mcversion

with open(new_page_path, "w", encoding="utf-8") as f:
f.writelines(["---", "---", "\n"])
write_front_matter(new_page_path, front_matter)


if __name__ == "__main__":
parser = ArgumentParser(
description="Adds the necessary Hugo metadata when an existing mod update is ported to a new Minecraft version"
)
parser.add_argument("mod", help="Mod ID (as it appears in config.toml)")
parser.add_argument("mod_version", help="Mod version (without v or -MC)")
parser.add_argument("mc_version", help="Minecraft version")
parser.add_argument("fapi_version", help="Fabric API version")
parser.add_argument("file_id", help="CurseForge file ID")

args = parser.parse_args()
update_mod_post(args.mod, args.mod_version, args.mc_version)
update_fabric_api_data(args.mod, args.mod_version, args.mc_version, args.fapi_version)
update_curseforge_data(args.mod, args.mod_version, args.mc_version, args.file_id)

mc_version_type = version_info[args.mc_version]["type"]
if mc_version_type == "release" and args.mc_version == manifest["latest"]["release"]:
old_latest = sorted(
[v for v in manifest["versions"] if v["type"] == "release"],
key=lambda v: v["releaseTime"],
reverse=True,
)[1]["id"]
add_download_category(args.mod, args.mc_version, old_latest)
2 changes: 2 additions & 0 deletions scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
requests
ruamel.yaml

0 comments on commit 2cf580f

Please sign in to comment.