diff options
| author | Anghelo Carvajal <angheloalf95@gmail.com> | 2026-07-31 08:13:58 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-31 08:13:58 -0400 |
| commit | 5b705b1d7fed3bfc596ea80ee5a9a1ca331ae490 (patch) | |
| tree | 90f0a9ca78cdb14c4722c4eb97857cd0969fca11 /.github/scripts | |
| parent | a6850d214927aafa2635177510a5029ab7e989ea (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.py | 112 | ||||
| -rwxr-xr-x | .github/scripts/generate_patch.sh | 10 |
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 |
