summaryrefslogtreecommitdiff
path: root/.github/scripts
diff options
context:
space:
mode:
authorAnghelo Carvajal <angheloalf95@gmail.com>2026-07-31 08:13:58 -0400
committerGitHub <noreply@github.com>2026-07-31 08:13:58 -0400
commit5b705b1d7fed3bfc596ea80ee5a9a1ca331ae490 (patch)
tree90f0a9ca78cdb14c4722c4eb97857cd0969fca11 /.github/scripts
parenta6850d214927aafa2635177510a5029ab7e989ea (diff)
Migrate CI to Github Actions (#1884)
Changes the CI system from Jenkins to Github Actions (GHA) like we did for OoT This is an adaptation of the Jenkinsfile we have and the solution made by @Dragorn421 for OoT Relevant OoT PRs: - https://github.com/zeldaret/oot/pull/2740 - https://github.com/zeldaret/oot/pull/2742 - https://github.com/zeldaret/oot/pull/2754 New features include: - Not needing to selfhost a runner - Required private stuff for building is hosted on a private repo - Building multiple versions in parallel - Our old jenkinsfile wasn't building `n64-jp-1.1`. Even if it doesn't match right now, I think it is important checking a PR doesn't completely break it. - Run bss fixer in CI - Upload mapfiles as build artifacts This specific approach to handle GHA for decomp projects was adapted from the one used by the GC/Wii community. It is documented here https://github.com/encounter/dtk-template/blob/main/docs/github_actions.md There's a writeup about this adaptation for N64 projects [here](https://github.com/AngheloAlf/drmario64/pull/19).
Diffstat (limited to '.github/scripts')
-rw-r--r--.github/scripts/apply_fix_bss_patches.py112
-rwxr-xr-x.github/scripts/generate_patch.sh10
2 files changed, 122 insertions, 0 deletions
diff --git a/.github/scripts/apply_fix_bss_patches.py b/.github/scripts/apply_fix_bss_patches.py
new file mode 100644
index 000000000..06c79fe52
--- /dev/null
+++ b/.github/scripts/apply_fix_bss_patches.py
@@ -0,0 +1,112 @@
+# SPDX-FileCopyrightText: © 2026 ZeldaRET
+# SPDX-License-Identifier: CC0-1.0
+
+from pathlib import Path
+import re
+import subprocess
+
+
+def get_increment_block_numbers(p: Path, version: str):
+ increment_block_numbers: list[int] = []
+ is_in_pragma = False
+ n_fake_structs = None
+ for l in p.read_text().splitlines():
+ if l.startswith("#pragma increment_block_number"):
+ is_in_pragma = True
+ n_fake_structs = 0
+ if is_in_pragma:
+ m = next(re.finditer(rf"{version}:(\d+)", l), None)
+ if m is not None:
+ n_fake_structs = int(m.group(1))
+ if is_in_pragma and not l.endswith("\\"):
+ is_in_pragma = False
+ assert n_fake_structs is not None
+ increment_block_numbers.append(n_fake_structs)
+ n_fake_structs = None
+ return increment_block_numbers
+
+
+# Formats #pragma increment_block_number as a list of lines
+def format_pragma(amounts: dict[str, int], max_line_length: int) -> list[str]:
+ lines = []
+ pragma_start = "#pragma increment_block_number "
+ current_line = pragma_start + '"'
+ first = True
+ for version, amount in sorted(amounts.items()):
+ part = f"{version}:{amount}"
+ if len(current_line) + len(" ") + len(part) + len('" \\') > max_line_length:
+ lines.append(current_line + '" ')
+ current_line = " " * len(pragma_start) + '"'
+ first = True
+ if not first:
+ current_line += " "
+ current_line += part
+ first = False
+ lines.append(current_line + '"\n')
+
+ if len(lines) >= 2:
+ # add and align vertically all continuation \ characters
+ n_align = max(map(len, lines[:-1]))
+ for i in range(len(lines) - 1):
+ lines[i] = f"{lines[i]:{n_align}}\\\n"
+
+ return lines
+
+
+def set_increment_block_numbers(
+ p: Path, increment_block_numbers_by_version: dict[str, list[int]]
+):
+ print(p, increment_block_numbers_by_version)
+ i_pragma = 0
+ is_in_pragma = False
+ pragma_lines = []
+ new_lines = []
+ for l in p.read_text().splitlines(keepends=True):
+ if l.startswith("#pragma increment_block_number"):
+ is_in_pragma = True
+ if not is_in_pragma:
+ new_lines.append(l)
+ if is_in_pragma:
+ pragma_lines.append(l.removesuffix("\\\n"))
+ if is_in_pragma and not l.endswith("\\\n"):
+ is_in_pragma = False
+ pragma_string = "".join(pragma_lines)
+ amounts: dict[str, int] = {}
+ for part in pragma_string.replace('"', "").split()[2:]:
+ version, amount_str = part.split(":")
+ amount = int(amount_str)
+ amounts[version] = amount
+ for (
+ version,
+ increment_block_numbers,
+ ) in increment_block_numbers_by_version.items():
+ amounts[version] = increment_block_numbers[i_pragma]
+ i_pragma += 1
+ column_limit = 120 # matches .clang-format's ColumnLimit
+ new_pragma_lines = format_pragma(amounts, column_limit)
+ new_lines.extend(new_pragma_lines)
+ p.write_text("".join(new_lines))
+
+
+increment_block_numbers_by_version_by_file: dict[Path, dict[str, list[int]]] = {}
+for p in Path(".").glob("fix_bss_*.patch"):
+ version = p.name.removeprefix("fix_bss_").removesuffix(".patch")
+ subprocess.check_call(["git", "apply", str(p)])
+ touched_files = subprocess.check_output(
+ "git diff --name-only".split(),
+ text=True,
+ ).splitlines()
+ for file in touched_files:
+ file_p = Path(file)
+ increment_block_numbers = get_increment_block_numbers(file_p, version)
+ increment_block_numbers_by_version_by_file.setdefault(file_p, {})[
+ version
+ ] = increment_block_numbers
+ subprocess.check_call("git checkout -- .".split())
+
+
+for (
+ file,
+ increment_block_numbers_by_version,
+) in increment_block_numbers_by_version_by_file.items():
+ set_increment_block_numbers(file, increment_block_numbers_by_version)
diff --git a/.github/scripts/generate_patch.sh b/.github/scripts/generate_patch.sh
new file mode 100755
index 000000000..04cc431b0
--- /dev/null
+++ b/.github/scripts/generate_patch.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+PATCH=$(git diff | base64 -w 0)
+if [ -n "$PATCH" ]; then
+ echo 'Fixes were made for your PR. To apply these changes to your working directory, copy and run the following command:' >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+ echo "echo -n $PATCH | base64 -d | git apply -" >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+fi