Skip to content

Commit 7f8f543

Browse files
committed
GitHub Actions: Test project exporting on CI
This allows finding issues in headless project export early on, including when exporting for a dedicated server. We also use this opportunity to check whether the audiovisual output between the project being run from its files and the exported PCK matches (it should always be a perfect match, assuming the same GPU is used for both runs). This can be used to catch audiovisual discrepancies, which could indicate a bug in the export process.
1 parent eb3d6d8 commit 7f8f543

File tree

114 files changed

+3000
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

114 files changed

+3000
-1
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Export Godot project
2+
description: Export a test Godot project.
3+
4+
inputs:
5+
bin:
6+
description: The path to the Godot executable
7+
required: true
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- name: Build test GDExtension
13+
shell: sh
14+
run: |
15+
cd misc/test_project/addons/test_extension/
16+
git clone --depth=1 https://github.com/godotengine/godot-cpp.git src/godot-cpp/
17+
scons target=template_debug
18+
scons target=template_release
19+
cd ../../../../
20+
21+
- name: Import resources and export project
22+
shell: bash
23+
run: |
24+
dotnet nuget add source "$PWD/bin/GodotSharp/Tools/nupkgs/" --name MyLocalNugetSource
25+
26+
echo "Importing resources"
27+
${{ inputs.bin }} --headless --path misc/test_project/ --import 2>&1 | tee log.txt || true
28+
# TODO: Try non-headless (also for export)?
29+
30+
echo "Exporting project for Linux (PCK)"
31+
${{ inputs.bin }} --headless --path misc/test_project/ --export-pack "Linux" /tmp/test_project.pck 2>&1 | tee log.txt || true
32+
misc/scripts/check_ci_log.py log.txt
33+
34+
# FIXME: Remove this once no longer needed.
35+
#shopt -s globstar nullglob
36+
#cat $HOME/.local/share/godot/mono/build_logs/**/*
37+
38+
echo "Exporting project for Linux (ZIP)"
39+
${{ inputs.bin }} --headless --path misc/test_project/ --export-pack "Linux" /tmp/test_project.zip 2>&1 | tee log.txt || true
40+
misc/scripts/check_ci_log.py log.txt
41+
42+
echo "Exporting project for Linux as dedicated server (PCK)"
43+
${{ inputs.bin }} --headless --path misc/test_project/ --export-pack "Linux Server" /tmp/test_project_server.pck 2>&1 | tee log.txt || true
44+
misc/scripts/check_ci_log.py log.txt
45+
46+
- name: Run project files from folder
47+
shell: sh
48+
run: |
49+
xvfb-run ${{ inputs.bin }} --path misc/test_project/ --language fr --audio-driver Dummy --resolution 64x64 --write-movie /tmp/test_project_folder.png --quit-after 9
50+
# FIXME: Not checked currently, as leaked resources on exit cause CI failures.
51+
# TODO: Check if above notice is still needed.
52+
misc/scripts/check_ci_log.py log.txt
53+
54+
# Wait several frames before quitting to ensure we don't quit while audio is still playing,
55+
# as this would cause an ObjectDB leaked instances warning, causing CI to fail (see GH-76745).
56+
${{ inputs.bin }} --headless --path misc/test_project/ --quit-after 9
57+
58+
- name: Run exported project PCK/ZIP
59+
shell: sh
60+
run: |
61+
xvfb-run ${{ inputs.bin }} --main-pack /tmp/test_project.pck --language fr --audio-driver Dummy --resolution 64x64 --write-movie /tmp/test_project_pck.png --quit-after 9
62+
# FIXME: Not checked currently, as leaked resources on exit cause CI failures.
63+
# TODO: Check if above notice is still needed.
64+
misc/scripts/check_ci_log.py log.txt
65+
66+
xvfb-run ${{ inputs.bin }} --main-pack /tmp/test_project.zip --language fr --audio-driver Dummy --resolution 64x64 --write-movie /tmp/test_project_zip.png --quit-after 9
67+
68+
# Headless mode is implied for dedicated server PCKs.
69+
# Wait several frames before quitting to ensure we don't quit while audio is still playing,
70+
# as this would cause an ObjectDB leaked instances warning, causing CI to fail (see GH-76745).
71+
${{ inputs.bin }} --main-pack /tmp/test_project_server.pck --quit-after 9
72+
73+
echo "Checking whether video output from project folder and exported project match..."
74+
md5sum /tmp/test_project*.png | md5sum --check
75+
76+
echo "Checking whether audio output from project folder and exported project match..."
77+
md5sum /tmp/test_project*.wav | md5sum --check

.github/workflows/linux_builds.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
build-mono: true
3535
doc-test: true
3636
proj-conv: true
37+
proj-export: true
3738
api-compat: true
3839
artifact: true
3940
# Validate godot-cpp compatibility on one arbitrary editor build.
@@ -117,7 +118,7 @@ jobs:
117118
run: |
118119
sudo apt-get update
119120
sudo apt-get install libwayland-bin # TODO: Figure out somehow how to embed this one.
120-
if [ "${{ matrix.proj-test }}" == "true" ]; then
121+
if [ "${{ matrix.proj-test }}" == "true" -o "${{ matrix.proj-export }}" == "true" ]; then
121122
sudo apt-get install mesa-vulkan-drivers
122123
fi
123124
@@ -249,6 +250,13 @@ jobs:
249250
with:
250251
bin: ${{ matrix.bin }}
251252

253+
# Test project export
254+
- name: Test project export
255+
uses: ./.github/actions/godot-project-export
256+
if: matrix.proj-export
257+
with:
258+
bin: ${{ matrix.bin }}
259+
252260
# Test the project converter
253261
- name: Test project converter
254262
uses: ./.github/actions/godot-converter-test

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ xcuserdata/
232232

233233
# Actual VS project files we don't use
234234
*.sln
235+
!misc/test_project/TestProject.sln
235236
*.vcxproj*
236237

237238
# User-specific files

misc/test_project/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.dblite
2+
3+
# Ignore the submodule so we don't add it to version control.
4+
# We clone it on CI when needed instead.
5+
addons/test_extension/src/godot-cpp

misc/test_project/LICENSE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# License for third-party files
2+
3+
## `polyhaven/*`
4+
5+
Copyright (c) Poly Haven
6+
7+
- Upstream: https://polyhaven.com
8+
- License: CC0-1.0
9+
10+
## `fonts/librequake_conchars.webp`
11+
12+
- Upstream: https://github.com/lavenderdotpet/LibreQuake
13+
- License: BSD-3-Clause

misc/test_project/SConstruct

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env python
2+
3+
# ruff: noqa: F821
4+
5+
# This file is for building as a Godot GDExtension.
6+
SConscript("addons/test_extension/SConstruct")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# GDExtension generated files
2+
*.gen.*
3+
.sconsign*.dblite
4+
bin/
5+
compile_commands.json
6+
src/gen/
7+
8+
# Compiled files
9+
*.bc
10+
*.creator
11+
*.creator.user
12+
*.dblite
13+
*.exp
14+
*.files
15+
*.idb
16+
*.includes
17+
*.lib
18+
*.o
19+
*.os
20+
*.pdb
21+
*.pyc
22+
*.so
23+
*.obj
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python
2+
3+
# ruff: noqa: F821
4+
5+
# This file is for building as a Godot GDExtension.
6+
7+
env = SConscript("src/godot-cpp/SConstruct")
8+
9+
# Add source files.
10+
env.Append(CPPPATH=["src/"])
11+
sources = Glob("src/*.cpp")
12+
13+
env.Append(CPPDEFINES=["GDEXTENSION"])
14+
15+
bin_path = "bin/"
16+
extension_name = "test_extension"
17+
debug_or_release = "release" if env["target"] == "template_release" else "debug"
18+
19+
if "arch_suffix" not in env:
20+
env["arch_suffix"] = env["arch"]
21+
22+
if env["target"] in ["editor", "template_debug"]:
23+
# GDExtension has editor classes available in debug templates, which allows editor code to compile.
24+
# If you don't want to compile editor stuff in templates, move these 2 lines to a separate "if" block.
25+
env.Append(CPPPATH=["src/editor/"])
26+
sources += Glob("src/editor/*.cpp")
27+
# Add documentation XML files as a generated cpp file. Only works in Godot 4.3+.
28+
doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
29+
sources.append(doc_data)
30+
31+
# Create the library target (e.g. libtest_extension.linux.debug.x86_64.so).
32+
if env["platform"] == "macos":
33+
library = env.SharedLibrary(
34+
"{0}/lib{1}.{2}.{3}.framework/{1}.{2}.{3}".format(
35+
bin_path,
36+
extension_name,
37+
env["platform"],
38+
debug_or_release,
39+
),
40+
source=sources,
41+
)
42+
else:
43+
library = env.SharedLibrary(
44+
"{}/{}{}.{}.{}.{}{}".format(
45+
bin_path,
46+
env.subst("$SHLIBPREFIX"),
47+
extension_name,
48+
env["platform"],
49+
debug_or_release,
50+
env["arch_suffix"],
51+
env["SHLIBSUFFIX"],
52+
),
53+
source=sources,
54+
)
55+
56+
Default(library)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="ExampleNode" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
3+
<brief_description>
4+
GDExtension example node.
5+
</brief_description>
6+
<description>
7+
An example node that demonstrates how to create a node in [GDExtension], which can be compiled and loaded by [GDExtensionManager]. This example node can also be compiled as an engine module, if that option was selected in the editor when creating the GDExtension.
8+
</description>
9+
<tutorials>
10+
<link title="GDExtension overview">$DOCS_URL/tutorials/scripting/gdextension/what_is_gdextension.html</link>
11+
<link title="GDExtension example in C++">$DOCS_URL/tutorials/scripting/gdextension/gdextension_cpp_example.html</link>
12+
</tutorials>
13+
<methods>
14+
<method name="print_hello" qualifiers="const">
15+
<return type="void" />
16+
<description>
17+
Prints either [code]"Hello, World! From GDExtension."[/code] if compiled as GDExtension or [code]"Hello, World! From a module."[/code] if compiled as a module, determined by the [code]#if[/code] directives in the C++ code.
18+
</description>
19+
</method>
20+
<method name="return_hello" qualifiers="const">
21+
<return type="String" />
22+
<description>
23+
Returns either [code]"Hello, World! From GDExtension."[/code] if compiled as GDExtension or [code]"Hello, World! From a module."[/code] if compiled as a module, determined by the [code]#if[/code] directives in the C++ code. If neither a module or extension, the code does not compile.
24+
</description>
25+
</method>
26+
</methods>
27+
</class>
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)