Skip to content

Commit 099cc52

Browse files
committed
feat: add pre-release build flow with custom version support
Add a dedicated Pre-Release On-Demand workflow that builds from the dev branch (branch input, default dev) and publishes a GitHub release marked as --prerelease, with an optional custom version suffix input. Extend tools/gen_version.py with a 'pre-release' BUILD_TYPE (0.0.1-pre-<hash>) and a CUSTOM_VERSION env var that appends a custom string to the base version (0.0.1-umtx2-test), which also shows in the PS5 homescreen app title (param.json). build_release.sh now passes CUSTOM_VERSION into the Docker build.
1 parent 0ba6139 commit 099cc52

3 files changed

Lines changed: 196 additions & 12 deletions

File tree

.github/workflows/pre-release.yml

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
name: Pre-Release On-Demand
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
branch:
7+
description: 'Branch to build from'
8+
type: string
9+
required: false
10+
default: dev
11+
custom_version:
12+
description: 'Optional version suffix appended to the base version (e.g. umtx2-test -> 0.2.2-umtx2-test). Leave empty for auto 0.2.2-pre-<githash>.'
13+
type: string
14+
required: false
15+
16+
jobs:
17+
build-linux:
18+
runs-on: ubuntu-latest
19+
env:
20+
BUILD_TYPE: pre-release
21+
CUSTOM_VERSION: ${{ inputs.custom_version }}
22+
outputs:
23+
tag: ${{ steps.version.outputs.tag }}
24+
version: ${{ steps.version.outputs.version }}
25+
full_version: ${{ steps.version.outputs.full_version }}
26+
steps:
27+
- name: Checkout repository
28+
uses: actions/checkout@v4
29+
with:
30+
ref: ${{ inputs.branch }}
31+
fetch-depth: 0
32+
submodules: recursive
33+
34+
- name: Extract Version
35+
id: version
36+
run: |
37+
VERSION=$(grep '#define WKAL_VERSION' include/wkali.h | awk '{print $3}' | tr -d '"' | tr -d '\r')
38+
if [ -z "$VERSION" ]; then
39+
echo "Error: Could not find WKAL_VERSION in include/wkali.h"
40+
exit 1
41+
fi
42+
echo "Extracted base version: $VERSION"
43+
FULL=$(python3 tools/gen_version.py --print)
44+
echo "Full version: $FULL"
45+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
46+
echo "full_version=${FULL}" >> $GITHUB_OUTPUT
47+
echo "tag=v${FULL}" >> $GITHUB_OUTPUT
48+
49+
- name: Check if release exists
50+
env:
51+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
run: |
53+
TAG="${{ steps.version.outputs.tag }}"
54+
if gh release view "$TAG" >/dev/null 2>&1; then
55+
echo "Release $TAG already exists. Aborting."
56+
exit 1
57+
fi
58+
echo "Release $TAG does not exist. Proceeding."
59+
60+
- name: Build WebKit Autoloader Installer & Host Script
61+
run: |
62+
chmod +x build_release.sh
63+
./build_release.sh
64+
65+
- name: Upload ELF, Script and Icon Artifacts
66+
uses: actions/upload-artifact@v4
67+
with:
68+
name: linux-build
69+
path: |
70+
webkit-autoloader-installer_v*.elf
71+
webkit-autoloader-host_v*.py
72+
assets/icon.ico
73+
retention-days: 1
74+
75+
build-windows:
76+
needs: build-linux
77+
runs-on: windows-latest
78+
steps:
79+
- name: Setup Python
80+
uses: actions/setup-python@v5
81+
with:
82+
python-version: '3.11'
83+
84+
- name: Install PyInstaller
85+
run: pip install pyinstaller
86+
87+
- name: Download Linux Artifacts
88+
uses: actions/download-artifact@v4
89+
with:
90+
name: linux-build
91+
path: .
92+
93+
- name: Build Windows Executable
94+
run: pyinstaller --onefile --noconfirm --icon assets/icon.ico --name webkit-autoloader-host_v${{ needs.build-linux.outputs.full_version }} "webkit-autoloader-host_v${{ needs.build-linux.outputs.full_version }}.py"
95+
96+
- name: Upload Windows Executable Artifact
97+
uses: actions/upload-artifact@v4
98+
with:
99+
name: windows-build
100+
path: dist/webkit-autoloader-host_v*.exe
101+
retention-days: 1
102+
103+
create-release:
104+
needs: [build-linux, build-windows]
105+
runs-on: ubuntu-latest
106+
permissions:
107+
contents: write
108+
steps:
109+
- name: Checkout repository (for git history)
110+
uses: actions/checkout@v4
111+
with:
112+
ref: ${{ inputs.branch }}
113+
fetch-depth: 0
114+
115+
- name: Download Linux Artifacts
116+
uses: actions/download-artifact@v4
117+
with:
118+
name: linux-build
119+
path: .
120+
121+
- name: Download Windows Artifacts
122+
uses: actions/download-artifact@v4
123+
with:
124+
name: windows-build
125+
path: .
126+
127+
- name: Create Pre-Release
128+
env:
129+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
130+
run: |
131+
set -euo pipefail
132+
TAG="${{ needs.build-linux.outputs.tag }}"
133+
FULL="${{ needs.build-linux.outputs.full_version }}"
134+
REPO="${{ github.repository }}"
135+
136+
ELF="webkit-autoloader-installer_v${FULL}.elf"
137+
PY="webkit-autoloader-host_v${FULL}.py"
138+
EXE="webkit-autoloader-host_v${FULL}.exe"
139+
EXE_BASE="$(basename "${EXE}")"
140+
141+
PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
142+
if [ -n "$PREV_TAG" ]; then
143+
CHANGELOG="**Full Changelog** (since [${PREV_TAG}](https://github.com/${REPO}/releases/tag/${PREV_TAG})): https://github.com/${REPO}/compare/${PREV_TAG}...${TAG}"
144+
else
145+
CHANGELOG="First Release."
146+
fi
147+
148+
cat > release_body.md <<EOF
149+
> [!WARNING]
150+
> This is a **pre-release / test build** from branch \`${{ inputs.branch }}\`. It is not intended for end users — expect bugs and changes.
151+
152+
## Downloads
153+
154+
| Platform | File |
155+
|---|---|
156+
| **PS5** (installer payload) | [${ELF}](https://github.com/${REPO}/releases/download/${TAG}/${ELF}) |
157+
| **Linux / macOS / WSL** (installer-host) | [${PY}](https://github.com/${REPO}/releases/download/${TAG}/${PY}) |
158+
| **Windows** (installer-host) | [${EXE_BASE}](https://github.com/${REPO}/releases/download/${TAG}/${EXE_BASE}) |
159+
160+
---
161+
162+
${CHANGELOG}
163+
EOF
164+
165+
gh release create "$TAG" \
166+
--prerelease \
167+
--title "$TAG (pre-release)" \
168+
--notes-file release_body.md \
169+
"$ELF" "$PY" "$EXE"

build_release.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ if [[ "$(docker images -q $IMAGE_NAME 2> /dev/null)" == "" ]]; then
3131
fi
3232

3333
# 4. Build native ELF via Docker (generates icon assets + file registry as deps)
34-
# Note: docker does NOT inherit the host environment, so BUILD_TYPE and
35-
# FORCE_EXPLOIT must be passed explicitly or defaults ("dev"/"auto") apply.
34+
# Note: docker does NOT inherit the host environment, so BUILD_TYPE,
35+
# FORCE_EXPLOIT and CUSTOM_VERSION must be passed explicitly or defaults
36+
# ("dev"/"auto"/empty) apply.
3637
echo "[1/2] Building native ELF via Docker..."
37-
docker run --rm -u "$(id -u):$(id -g)" -e "BUILD_TYPE=${BUILD_TYPE:-dev}" -e "FORCE_EXPLOIT=${FORCE_EXPLOIT:-auto}" -v "$(pwd)":/src -w /src $IMAGE_NAME make clean all
38+
docker run --rm -u "$(id -u):$(id -g)" -e "BUILD_TYPE=${BUILD_TYPE:-dev}" -e "FORCE_EXPLOIT=${FORCE_EXPLOIT:-auto}" -e "CUSTOM_VERSION=${CUSTOM_VERSION:-}" -v "$(pwd)":/src -w /src $IMAGE_NAME make clean all
3839

3940
if [ $? -ne 0 ]; then
4041
echo " !!! ELF build FAILED!"

tools/gen_version.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@
33
44
Version scheme (mirrors the ps5-bdjb-autoloader project):
55
6-
dev: <base>-<build_type>-<suffix>
7-
stable: <base>
6+
dev: <base>-<build_type>-<suffix>
7+
stable: <base>
8+
pre-release: <base>-pre-<suffix>
89
910
e.g. 0.0.1-dev-abc1234 clean tree, dev build
1011
0.0.1-dev-20260806123500 dirty tree — timestamp instead of hash
12+
0.0.1-pre-abc1234 clean tree, pre-release build
1113
0.0.1 stable build — no hash/timestamp suffix
1214
1315
The base version comes from WKAL_VERSION in include/wkali.h. BUILD_TYPE is
1416
taken from the BUILD_TYPE environment variable (default: dev).
1517
18+
When CUSTOM_VERSION is set, it is appended to the base version and takes
19+
precedence over the build type (e.g. CUSTOM_VERSION=umtx2-test -> 0.0.1-umtx2-test).
20+
The custom suffix is also shown in the PS5 homescreen app title.
21+
1622
Usage:
1723
gen_version.py # (re)generate version header and app metadata
1824
gen_version.py --print # print the full version string
@@ -60,22 +66,28 @@ def get_version_info(build_type=None):
6066
version string to display everywhere."""
6167
if build_type is None:
6268
build_type = os.environ.get("BUILD_TYPE", "dev")
63-
if build_type not in ("dev", "stable"):
69+
if build_type not in ("dev", "stable", "pre-release"):
6470
build_type = "dev"
6571

72+
base = read_base_version()
73+
custom = os.environ.get("CUSTOM_VERSION", "").strip()
74+
6675
git_hash = git("rev-parse", "--short", "HEAD")
6776
dirty = git("status", "--porcelain")
6877
suffix = git_hash or "unknown"
6978
if dirty:
7079
suffix = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
7180

72-
if build_type == "stable":
73-
full = read_base_version()
81+
if custom:
82+
full = f"{base}-{custom}"
83+
elif build_type == "stable":
84+
full = base
7485
else:
75-
full = f"{read_base_version()}-{build_type}-{suffix}"
86+
segment = "pre" if build_type == "pre-release" else "dev"
87+
full = f"{base}-{segment}-{suffix}"
7688

7789
return {
78-
"base": read_base_version(),
90+
"base": base,
7991
"build_type": build_type,
8092
"suffix": suffix,
8193
"full": full,
@@ -84,6 +96,7 @@ def get_version_info(build_type=None):
8496
"build_time": datetime.datetime.now(datetime.timezone.utc).strftime(
8597
"%Y-%m-%d %H:%M:%S UTC"
8698
),
99+
"title": full if custom else base,
87100
}
88101

89102

@@ -123,11 +136,12 @@ def main(argv=None):
123136

124137
write_if_changed(HEADER, header_text(info).encode("utf-8"))
125138

126-
# PS5 homescreen app metadata — title gets the base version only (e.g. v0.1.0)
139+
# PS5 homescreen app metadata — title gets the base version (or the full
140+
# custom version) so the app label reflects what was built.
127141
with open(PARAM_TEMPLATE, "rb") as f:
128142
param = f.read()
129143
write_if_changed(
130-
PARAM_JSON, param.replace(VERSION_PLACEHOLDER, info["base"].encode("utf-8"))
144+
PARAM_JSON, param.replace(VERSION_PLACEHOLDER, info["title"].encode("utf-8"))
131145
)
132146
return 0
133147

0 commit comments

Comments
 (0)