Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 182 additions & 97 deletions .github/workflows/cl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ on:
push:
branches:
- '*'
tags:
- '*'
pull_request:
workflow_dispatch:
inputs:
release_name:
description: Release name string for prerelease body
required: true
default: manual

jobs:
matrix:
Expand All @@ -26,24 +33,70 @@ jobs:

- name: Generate variant matrix
id: variants
env:
CHUNK_SIZE: 25
run: |
set -euo pipefail
make list-variants > variants.json
cat <<'PY' | sed 's/^ //' | python3 > matrix.json
import json, os
import json

CHUNK_SIZE = int(os.environ.get("CHUNK_SIZE", "25"))
with open("variants.json", "r", encoding="utf-8") as fh:
variants = json.load(fh).get("include", [])
# MMCE+MX4SIO is unsupported (embedded IRX conflict); omit any variant with both.
labels = [
"hdd-normal",
"mmce-normal",
"mx4sio-normal",
"usb-normal",
"xfrom-normal",
"hdd-normal+mmce-normal",
"hdd-normal+mx4sio-normal",
"hdd-normal+usb-normal",
"hdd-normal+xfrom-normal",
"mmce-normal+mx4sio-normal",
"mmce-normal+usb-normal",
"mmce-normal+xfrom-normal",
"mx4sio-normal+usb-normal",
"mx4sio-normal+xfrom-normal",
"usb-normal+xfrom-normal",
"hdd-normal+mmce-normal+mx4sio-normal",
"hdd-normal+mmce-normal+usb-normal",
"hdd-normal+mmce-normal+xfrom-normal",
"hdd-normal+mx4sio-normal+usb-normal",
"hdd-normal+mx4sio-normal+xfrom-normal",
"hdd-normal+usb-normal+xfrom-normal",
"mmce-normal+mx4sio-normal+usb-normal",
"mmce-normal+mx4sio-normal+xfrom-normal",
"mmce-normal+usb-normal+xfrom-normal",
"mx4sio-normal+usb-normal+xfrom-normal",
"hdd-normal+mmce-normal+mx4sio-normal+usb-normal",
"hdd-normal+mmce-normal+mx4sio-normal+xfrom-normal",
"hdd-normal+mmce-normal+usb-normal+xfrom-normal",
"hdd-normal+mx4sio-normal+usb-normal+xfrom-normal",
"mmce-normal+mx4sio-normal+usb-normal+xfrom-normal",
"hdd-normal+mmce-normal+mx4sio-normal+usb-normal+xfrom-normal",
]
device_map = {
"hdd": "HDD",
"mmce": "MMCE",
"mx4sio": "MX4SIO",
"usb": "USB",
"xfrom": "XFROM",
}
flag_order = ["HDD", "MMCE", "MX4SIO", "USB", "XFROM"]

batches = []
for idx in range(0, len(variants), CHUNK_SIZE):
batch = variants[idx : idx + CHUNK_SIZE]
batches.append({"index": idx // CHUNK_SIZE, "batch": json.dumps(batch)})
variants = []
for label in labels:
if "mmce-normal" in label and "mx4sio-normal" in label:
continue
flags = {}
for part in label.split("+"):
device, mode = part.split("-", 1)
if mode != "normal":
raise SystemExit(f"Unsupported mode in label: {label}")
if device not in device_map:
raise SystemExit(f"Unknown device in label: {label}")
flags[device_map[device]] = 1
flag_string = " ".join(f"{key}=1" for key in flag_order if key in flags)
variants.append({"name": label, "flags": flag_string})

print(json.dumps({"include": batches}, sort_keys=False))
print(json.dumps({"include": variants}, sort_keys=False))
with open("count.txt", "w", encoding="utf-8") as fh:
fh.write(str(len(variants)))
PY
Expand Down Expand Up @@ -73,51 +126,120 @@ jobs:
id: meta
run: echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"

- name: Build batch ${{ matrix.index }}
- name: Build ${{ matrix.name }}
env:
BATCH_JSON: ${{ matrix.batch }}
VARIANT_NAME: ${{ matrix.name }}
VARIANT_FLAGS: ${{ matrix.flags }}
SHORT_SHA: ${{ steps.meta.outputs.short_sha }}
run: |
set -euo pipefail
python3 - <<'PY'
import json, os, shlex, subprocess, sys
import os
import shlex
import subprocess

batch = json.loads(os.environ["BATCH_JSON"])
name = os.environ["VARIANT_NAME"]
flags = os.environ.get("VARIANT_FLAGS", "").strip()
short_sha = os.environ["SHORT_SHA"]

for entry in batch:
name = entry["name"]
flags = entry.get("flags", "").strip()
outdir = os.path.join("build", "variants", name)
base = ["make", f"VARIANT={name}", f"OUTDIR={outdir}", f"COMMIT_HASH={short_sha}"]
if flags:
base += shlex.split(flags)
subprocess.run(base + ["clean"], check=True)
subprocess.run(base + ["all"], check=True)
cfg = os.path.join(outdir, "BUILD_CONFIG.txt")
if not os.path.isfile(cfg):
raise SystemExit(f"Missing BUILD_CONFIG.txt for {name}")
outdir = os.path.join("build", "variants", name)
base = ["make", f"VARIANT={name}", f"OUTDIR={outdir}", f"COMMIT_HASH={short_sha}"]
if flags:
base += shlex.split(flags)
subprocess.run(base + ["clean"], check=True)
subprocess.run(base + ["all"], check=True)
cfg = os.path.join(outdir, "BUILD_CONFIG.txt")
if not os.path.isfile(cfg):
raise SystemExit(f"Missing BUILD_CONFIG.txt for {name}")
PY

- name: Package batch ${{ matrix.index }}
- name: Stage built ELF for ${{ matrix.name }}
run: |
set -euo pipefail
mkdir -p staged-elves
variant_dir="build/variants/${{ matrix.name }}"
elf_path="$variant_dir/PS2BBL.ELF"
if [ ! -f "$elf_path" ]; then
echo "Missing ELF for ${{ matrix.name }} at $elf_path" >&2
exit 1
fi
mkdir -p "staged-elves/${{ matrix.name }}"
cp "$elf_path" "staged-elves/${{ matrix.name }}/PS2BBLE.ELF"

- name: Upload staged ELF for ${{ matrix.name }}
uses: actions/upload-artifact@v4
with:
name: built-elf-${{ matrix.name }}
path: staged-elves/${{ matrix.name }}/PS2BBLE.ELF
if-no-files-found: error

- name: Package ${{ matrix.name }}
run: |
set -euo pipefail
mkdir -p artifacts
for variant_dir in build/variants/*; do
[ -d "$variant_dir" ] || continue
name=$(basename "$variant_dir")
tar -czf "artifacts/${name}.tar.gz" -C "$variant_dir" .
done
tar -czf "artifacts/${{ matrix.name }}.tar.gz" -C "build/variants/${{ matrix.name }}" .

- name: Upload batch ${{ matrix.index }}
- name: Upload ${{ matrix.name }}
uses: actions/upload-artifact@v4
with:
name: ps2bbl-batch-${{ matrix.index }}-${{ steps.meta.outputs.short_sha }}
name: ps2bbl-${{ matrix.name }}-${{ steps.meta.outputs.short_sha }}
path: artifacts/*.tar.gz
if-no-files-found: error

prerelease:
package-elves:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download staged ELFs
uses: actions/download-artifact@v4
with:
pattern: built-elf-*
path: dist
merge-multiple: false

- name: Normalize dist layout
run: |
set -euo pipefail
shopt -s nullglob
for artifact_dir in dist/built-elf-*; do
[ -d "$artifact_dir" ] || continue
name="${artifact_dir##*/built-elf-}"
elf_path="$artifact_dir/PS2BBLE.ELF"
if [ ! -f "$elf_path" ]; then
echo "Missing PS2BBLE.ELF for $name in $artifact_dir" >&2
exit 1
fi
mkdir -p "dist/$name"
cp "$elf_path" "dist/$name/PS2BBLE.ELF"
done
for leftover in dist/built-elf-*; do
[ -d "$leftover" ] || continue
rm -rf "$leftover"
done

- name: Show dist tree
run: |
set -euo pipefail
find dist -maxdepth 3 -print

- name: Zip staged ELFs
run: |
set -euo pipefail
if [ ! -d dist ]; then
echo "dist directory not found" >&2
exit 1
fi
zip -r PS2BBLE.zip dist

- name: Upload PS2BBLE zip
uses: actions/upload-artifact@v4
with:
name: ps2bble-zip-${{ github.sha }}
path: PS2BBLE.zip
if-no-files-found: error

prerelease:
needs: package-elves
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
Expand All @@ -131,83 +253,46 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Discover available artifacts
id: discover_artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Resolve release name
id: release_name
run: |
set -euo pipefail
mkdir -p release-artifacts
artifacts=$(gh api --paginate "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/artifacts" -q '.artifacts[].name' | sed -n '/^ps2bbl-/p')
count=$(printf "%s\n" "$artifacts" | sed '/^$/d' | wc -l | tr -d ' ')
echo "count=$count" >> "$GITHUB_OUTPUT"
if [ "$count" = "0" ]; then
echo "No matching artifacts were found for prerelease packaging." >> "$GITHUB_STEP_SUMMARY"
if [ -n "${{ github.event.inputs.release_name }}" ]; then
echo "value=${{ github.event.inputs.release_name }}" >> "$GITHUB_OUTPUT"
else
{
echo "Matched artifacts (${count}):"
printf "%s\n" "$artifacts"
} >> "$GITHUB_STEP_SUMMARY"
tag_name="${GITHUB_REF_NAME}"
echo "value=${tag_name}" >> "$GITHUB_OUTPUT"
fi

- name: Download artifacts
if: steps.discover_artifacts.outputs.count != '0'
- name: Download PS2BBLE zip
uses: actions/download-artifact@v4
with:
name: ps2bble-zip-${{ github.sha }}
path: release-artifacts
pattern: ps2bbl-*
merge-multiple: false

- name: Ensure release directories
run: mkdir -p release-artifacts release-packages

- name: Detect downloaded artifacts
id: artifacts
run: |
echo "Downloaded artifact layout:"
find release-artifacts -maxdepth 2 -print || true
count=$(find release-artifacts -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' ')
echo "count=$count" >> "$GITHUB_OUTPUT"
if [ "$count" = "0" ]; then
echo "No artifacts were downloaded; skipping packaging." >> "$GITHUB_STEP_SUMMARY"
fi

- name: Archive artifacts
if: steps.artifacts.outputs.count != '0'
run: |
for dir in release-artifacts/*; do
[ -d "$dir" ] || continue
base=$(basename "$dir")
tar -czf "release-packages/${base}.tar.gz" -C "$dir" .
done

- name: Check packaged artifacts
id: packages
- name: Verify PS2BBLE.zip
run: |
count=$(find release-packages -type f -name '*.tar.gz' | wc -l | tr -d ' ')
echo "count=$count" >> "$GITHUB_OUTPUT"
if [ "$count" = "0" ]; then
echo "No packaged artifacts found; skipping release publication." >> "$GITHUB_STEP_SUMMARY"
set -euo pipefail
if [ ! -f release-artifacts/PS2BBLE.zip ]; then
echo "PS2BBLE.zip not found in release-artifacts" >&2
exit 1
fi

- name: Generate release notes
run: |
python3 scripts/generate_cl_release_notes.py \
--artifacts-dir release-artifacts \
--packages-dir release-packages \
--output RELEASE_BODY.md \
--release-sha "${GITHUB_SHA}"
echo "### Batch manifest overview" >> "$GITHUB_STEP_SUMMARY"
cat RELEASE_BODY.md >> "$GITHUB_STEP_SUMMARY"

- name: Publish prerelease
if: steps.packages.outputs.count != '0'
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
with:
tag_name: cl-${{ github.sha }}
name: CL prerelease ${{ github.sha }}
body_path: RELEASE_BODY.md
body: |
Automated CL prerelease for `${{ steps.release_name.outputs.value }}`
<img width="1536" height="394" alt="logo" src="https://github.com/user-attachments/assets/e536e2cd-4287-413e-9695-8e2aec3d25fb" />

Check the [readme.md](https://github.com/NathanNeurotic/PlayStation2-Basic-BootLoader-Extended#documentation)
Test Sheet: https://github.com/NathanNeurotic/PlayStation2-Basic-BootLoader-Extended/blob/main/BETA_TEST_CHECKLIST.md

### PS2BBLE.zip contains all versions
Note: MMCE + MX4SIO combined variants are intentionally omitted (unsupported in embedded IRX mode).
prerelease: true
files: release-packages/*
files: release-artifacts/PS2BBLE.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ make
```

cl commonly builds multiple variants by enumerating feature flags (embedded vs runtime drivers, device support, chainload modes, etc.).
Compatibility note: "normal" builds embed IRX for selected devices, and MMCE + MX4SIO embedded modes are mutually exclusive. Automated prerelease artifacts omit MMCE+MX4SIO combinations accordingly.

---

Expand Down