Skip to content

Commit 5dcfdb0

Browse files
chore: CI + release pipeline (#133)
* ci: add GitHub Actions workflow for building and releasing the project * ci(build.yml): update comments for clarity and consistency ci(build.yml): add detailed comments explaining each step in the build process ci(build.yml): correct comment about MSBuild property precedence and toolset version ci(build.yml): update artifact collection comments to reflect current directory structure ci(build.yml): add comments explaining the purpose of the release job * chore: update release.lua to support PDB packaging * chore: improve build.yml * chore: auto detect final release to remove "Development Build" from logs * test1 * test2 * test3 * test4 * fix(ci): include hidden artifact paths and correct release zip layout * final test --------- Co-authored-by: Fabio Rossini Sluzala <fabio3rs@gmail.com>
1 parent cd44423 commit 5dcfdb0

5 files changed

Lines changed: 193 additions & 49 deletions

File tree

.github/workflows/build.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [master, develop]
6+
tags: ["v*.*.*"]
7+
pull_request:
8+
paths-ignore: ["**/*.md", "doc/**"]
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
build:
16+
runs-on: windows-latest
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
submodules: recursive
22+
23+
- name: Install premake5
24+
run: |
25+
winget install -e --id Premake.Premake.5.Beta --accept-source-agreements --accept-package-agreements --disable-interactivity
26+
$env:Path = [System.Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path','User')
27+
echo "$((Get-Command premake5).Path | Split-Path -Parent)" >> $env:GITHUB_PATH
28+
29+
- name: Install v141_xp toolset
30+
shell: cmd
31+
run: |
32+
"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\setup.exe" modify ^
33+
--passive --norestart ^
34+
--installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" ^
35+
--add Microsoft.VisualStudio.Component.VC.v141.x86.x64 ^
36+
--add Microsoft.VisualStudio.Component.WinXP
37+
38+
- uses: microsoft/setup-msbuild@v2
39+
40+
- name: Add pdbcopy to PATH
41+
run: echo "${env:ProgramFiles(x86)}\Windows Kits\10\Debuggers\x86" >> $env:GITHUB_PATH
42+
43+
- name: Build
44+
env:
45+
CL: /MP
46+
run: |
47+
if ("${{ github.ref }}" -like "refs/tags/v*") {
48+
premake5 --file=release.lua prepare --toolset=vs2022 --final-release
49+
} else {
50+
premake5 --file=release.lua prepare --toolset=vs2022
51+
}
52+
53+
- uses: actions/upload-artifact@v4
54+
with:
55+
name: modloader-${{ github.sha }}
56+
path: release
57+
include-hidden-files: true
58+
if-no-files-found: error
59+
retention-days: 30
60+
61+
release:
62+
if: startsWith(github.ref, 'refs/tags/v')
63+
needs: build
64+
runs-on: ubuntu-latest
65+
permissions:
66+
contents: write
67+
68+
steps:
69+
- uses: actions/checkout@v4
70+
71+
- uses: actions/download-artifact@v4
72+
with:
73+
name: modloader-${{ github.sha }}
74+
path: dist/
75+
76+
- name: Package zip files
77+
run: |
78+
(cd dist/binaries && zip -r ../modloader.zip .)
79+
(cd dist/symbols && zip -r ../pdb-symbols.zip .)
80+
81+
- name: Prepare release notes
82+
env:
83+
TAG: ${{ github.ref_name }}
84+
run: |
85+
python3 <<'PY'
86+
import os, re, sys
87+
tag = os.environ["TAG"]
88+
lines = open("doc/CHANGELOG.md").readlines()
89+
i = next((i for i, l in enumerate(lines) if l.startswith(tag + " ")), None)
90+
if i is None:
91+
sys.exit(f"No changelog for {tag} in CHANGELOG.md")
92+
j = next((j for j in range(i + 1, len(lines)) if re.match(r"^v\d+\.\d+", lines[j])), len(lines))
93+
open("release-body.md", "w").writelines(lines[i:j])
94+
PY
95+
96+
- uses: softprops/action-gh-release@v2
97+
with:
98+
tag_name: ${{ github.ref_name }}
99+
name: Mod Loader ${{ github.ref_name }}
100+
body_path: release-body.md
101+
files: |
102+
dist/modloader.zip
103+
dist/pdb-symbols.zip
104+
fail_on_unmatched_files: true

include/modloader/modloader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ extern "C" {
3030
#define MODLOADER_VERSION_MAJOR 0
3131
#define MODLOADER_VERSION_MINOR 3
3232
#define MODLOADER_VERSION_REVISION 9
33-
#ifdef NDEBUG
34-
#define MODLOADER_VERSION_ISDEV 1
33+
#ifdef MODLOADER_FINAL_RELEASE
34+
#define MODLOADER_VERSION_ISDEV 0
3535
#else
3636
#define MODLOADER_VERSION_ISDEV 1
3737
#endif

premake5.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ newoption {
2424
description = "Post-build install directory"
2525
}
2626

27+
newoption {
28+
trigger = "final-release",
29+
description = "Public release build (defines MODLOADER_FINAL_RELEASE for the whole solution)"
30+
}
31+
2732
newaction {
2833
trigger = "clean",
2934
description = "Cleans the binary and build files on the directory (bin/, build_temp/)",
@@ -204,6 +209,10 @@ solution "modloader"
204209
"_SCL_SECURE_NO_WARNINGS"
205210
}
206211

212+
if _OPTIONS["final-release"] then
213+
defines { "MODLOADER_FINAL_RELEASE" }
214+
end
215+
207216
includedirs {
208217
"include",
209218
"deps/cereal/include",

release.bat

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
@echo off
2+
echo Are you sure this is a final release?
3+
echo This will not be tagged in the logs as a development build.
4+
choice /C YN /M "Continue"
5+
if errorlevel 2 exit /b 1
6+
27
set CL=/MP
3-
premake5 --file=release.lua prepare --toolset=vs2015
4-
pause
5-
goto:eof
8+
set "PATH=%ProgramFiles(x86)%\Windows Kits\10\Debuggers\x86;%PATH%"
9+
premake5 --file=release.lua prepare --toolset=vs2022 --final-release
10+
11+
pause

release.lua

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,67 +10,64 @@ newaction {
1010
execute = function() main() end
1111
}
1212

13-
newoption {
14-
trigger = "debug-symbols",
15-
description = "Makes a release which contains public debug symbols, which allows better user debugging",
16-
}
17-
1813
newoption {
1914
trigger = "toolset",
2015
value = "tools",
21-
description = "The toolset used to compile the release build",
22-
allowed = {
23-
{ "vs2013", "Microsoft Visual Studio 2013" },
24-
{ "vs2015", "Microsoft Visual Studio 2015" },
25-
{ "gcc", "GNU Compiler Collection" }
26-
}
16+
description = "The toolset used to compile the release build (vs20xx or gcc)",
2717
}
2818

19+
newoption {
20+
trigger = "final-release",
21+
description = "Public release build."
22+
}
2923

3024
toolset = _OPTIONS["toolset"]
25+
final_flag = _OPTIONS["final-release"] and " --final-release" or ""
3126
action = (toolset == "gcc" and "gmake" or toolset)
3227
compiler = (toolset == "gcc" and "gcc" or "cl")
3328
build = (toolset == "gcc" and "make" or "msbuild")
3429

3530
function main()
3631

37-
local debugsymbols = _OPTIONS["debug-symbols"]
38-
3932
if not toolset then
4033
print("No toolset defined.\nAborting.")
4134
exit()
4235
end
4336

37+
if toolset ~= "gcc" and not toolset:match("^vs") then
38+
print("Unsupported toolset '" .. toolset .. "' (use a vs* premake action or gcc).\nAborting.")
39+
exit()
40+
end
41+
42+
require_tools()
43+
4444
local install = function()
4545
print "Making release directory tree..."
46-
execute("premake5 install ./release/")
47-
os.copyfile("./release/modloader/.data/Readme.md", "./release/Readme.txt")
48-
os.copyfile("./release/modloader/.data/Leia-me.md", "./release/Leia-me.txt")
49-
os.mkdir("./release/modloader/.profiles")
46+
execute("premake5 install ./release/binaries/")
47+
os.copyfile("./release/binaries/modloader/.data/Readme.md", "./release/binaries/Readme.txt")
48+
os.copyfile("./release/binaries/modloader/.data/Leia-me.md", "./release/binaries/Leia-me.txt")
49+
os.mkdir("./release/binaries/modloader/.profiles")
5050
end
5151

5252
print "Cleaning workspace..."
5353
execute("premake5 clean")
5454

5555
print "Generating build files..."
56-
if toolset == "gmake" then
57-
execute(string.format("premake5 %s --cc=%s --outdir=build_temp", action, compiler))
56+
if toolset == "gcc" then
57+
execute(string.format("premake5 %s --cc=%s --outdir=build_temp%s", action, compiler, final_flag))
5858
else
59-
execute(string.format("premake5 %s --outdir=build_temp", action))
59+
execute(string.format("premake5 %s --outdir=build_temp%s", action, final_flag))
6060
end
6161

6262
print "Building..."
6363
if build == "msbuild" then
64-
64+
6565
-- also use 'set CL=/MP' at release.bat
6666
execute("msbuild build_temp/modloader.sln /p:configuration=Release /p:platform=Win32 /m")
6767

68-
-- Install THEN move pdbs
6968
install()
70-
if debugsymbols then
71-
pdbmove()
72-
end
73-
69+
pdbpackage()
70+
7471
elseif compiler == "gcc" then
7572

7673
local cwd = os.getcwd()
@@ -81,9 +78,9 @@ function main()
8178
-- Strip binaries (ALWAYS)
8279
gccstrip()
8380
-- striping is not related to symbols, to have symbols send --export-all-symbols to the linker
84-
81+
8582
install()
86-
83+
8784
else
8885
print("Internal error")
8986
exit()
@@ -92,22 +89,21 @@ function main()
9289
os.rmdir("build_temp")
9390
end
9491

92+
function pdbpackage()
93+
print("Packaging stripped debug symbols (release/symbols/)...")
9594

95+
os.mkdir("release/symbols")
96+
os.mkdir("release/symbols/modloader/.data/plugins/gta3")
9697

98+
execute('pdbcopy "bin/modloader.pdb" "release/symbols/modloader.pdb" -p')
9799

98-
function pdbmove()
99-
print("Moving PDB files into release...")
100-
pdbcopy("bin", "release", false)
101-
pdbcopy("bin/plugins", "release/modloader/.data/plugins", true)
102-
end
103-
104-
function pdbcopy(src, dest, recursive)
105-
local cwd = os.getcwd()
106-
os.chdir(src)
107-
for i, file in ipairs(os.matchfiles(recursive and "**.pdb" or "*.pdb")) do
108-
execute(string.format([[pdbcopy "%s" "%s" -p]], file, cwd .. '/' .. dest .. '/' .. file))
100+
for i, file in ipairs(os.matchfiles("bin/plugins/gta3/*.pdb")) do
101+
local name = path.getname(file)
102+
execute(string.format(
103+
'pdbcopy "bin/plugins/gta3/%s" "release/symbols/modloader/.data/plugins/gta3/%s" -p',
104+
name, name
105+
))
109106
end
110-
os.chdir(cwd)
111107
end
112108

113109
function gccstrip()
@@ -124,16 +120,45 @@ function gccstrip()
124120
os.chdir(cwd)
125121
end
126122

123+
function require_tools()
124+
require_on_path("premake5",
125+
"Install Premake 5 and add it to PATH.")
127126

127+
if build == "msbuild" then
128+
require_on_path("msbuild",
129+
"Install Visual Studio with MSBuild, then run this from the x86 Native Tools Command Prompt.")
130+
require_on_path("pdbcopy",
131+
"Install the Debugging Tools for Windows component from the Windows SDK," ..
132+
" then add %ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x86 to PATH.")
133+
elseif compiler == "gcc" then
134+
require_on_path("mingw32-make",
135+
"Install MinGW and add mingw32-make to PATH.")
136+
end
137+
end
128138

129-
139+
function require_on_path(name, hint)
140+
if not os.ishost("windows") then
141+
return
142+
end
143+
local found = os.outputof("where " .. name .. " 2>nul")
144+
if not found or found == "" then
145+
print("Error: " .. name .. " is not on PATH.")
146+
if hint then
147+
print(hint)
148+
end
149+
exit()
150+
end
151+
end
130152

131153
function execute(command)
132-
os.execute(command)
154+
local result = os.execute(command)
155+
if result == 0 or result == true then
156+
return
157+
end
158+
print("Command failed: " .. command .. "\nAborting.")
159+
exit()
133160
end
134161

135162
function exit()
136163
os.exit()
137164
end
138-
139-

0 commit comments

Comments
 (0)