From 90f2b8282e6b0aae2e1ec5f311fcd823871d569b Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 20:25:05 -0700 Subject: [PATCH 01/21] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 23149bf11..5362bb078 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ artifacts/main_menu.png v8_coverage_*.json tests/refactor/__pycache__/ report.html +scan_project.py \ No newline at end of file From 85d572eeadd7ffe50d83d7a34fe2451be9c34e0e Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 20:25:18 -0700 Subject: [PATCH 02/21] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5362bb078..29d9f51b5 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,5 @@ artifacts/main_menu.png v8_coverage_*.json tests/refactor/__pycache__/ report.html -scan_project.py \ No newline at end of file +scan_project.py +project_structure.txt From 0365ec9078bcb03fd83548260663be350f19d023 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 20:57:12 -0700 Subject: [PATCH 03/21] Update run_pipeline.sh --- run_pipeline.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index 0f214237b..49cb2f458 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -47,11 +47,17 @@ echo "Running GDUnit4 Tests..." godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --verbose --ignoreHeadlessMode --add res://test check_exit "GDUnit4 Tests" +# 5. GUT Unit Tests +# Added from run_gut_unit_tests.sh +echo "Running GUT Unit Tests..." +godot --headless --verbose --path $PROJECT_DIR -s res://addons/gut/gut_cmdln.gd -gconfig=res://.gutconfig.json -gdir=res://test -ginclude_subdirs=true -gexit +check_exit "GUT Unit Tests" + # Upload reports (simulate artifact upload by copying to a reports dir) mkdir -p $PROJECT_DIR/reports cp -r reports/** $PROJECT_DIR/reports || true -# 5. Browser Functional Tests +# 6. Browser Functional Tests echo "Exporting Godot Project to Web..." mkdir -p $EXPORT_DIR @@ -108,4 +114,4 @@ cp $PROJECT_DIR/report.xml $PROJECT_DIR/artifacts/ || true cp main_menu.png $PROJECT_DIR/artifacts/ || true # If screenshot exists cp -r $PROJECT_DIR/reports $PROJECT_DIR/artifacts/gdunit-reports || true -echo "Pipeline completed successfully!" +echo "Pipeline completed successfully!" \ No newline at end of file From 371d6bccc0eed4e0aee9a68e73642a68c46248f6 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:21:43 -0700 Subject: [PATCH 04/21] README updates --- README.md | 10 +++++--- files/docs/Development_Guide.md | 10 ++++---- .../Platforms_for_Web_Deployment_Guide.md | 23 ++++++++++--------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index dc3f0ad90..d0af7d3dd 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ source code to users. For closed-source commercial alternatives without these GPL requirements, a separate license is available upon request. ### Key Terms + - **Open Source**: You can view, modify, and distribute the code freely, as long as derivatives remain under GPLv3. - **Commercial Use**: Allowed under GPLv3 (with source code obligations @@ -253,18 +254,21 @@ Milestone 12 focused on making the game more navigable and responsive to user input devices: ### Input Remapping + - Conflict detection dialog when assigning existing bindings - Per-device last input selection persists between sessions - Critical control warnings if actions are unbound - Remap menu accessible from all relevant UI paths ### Menu Navigation + - Keyboard + gamepad (D-Pad) support for all menu flows - Guaranteed core navigation actions remain bound - Focus restoration when leaving submenus (Audio → Options → Main) - Modifier key respect (Ctrl/Shift/Alt/Meta) in remapping UI ### Audio Settings Controls + - Use keyboard/gamepad accept action for sliders and toggles - Focus highlighting for better visual feedback - Unified UI interactions without relying on the mouse @@ -273,18 +277,18 @@ to user input devices: synchronization. ### Godot Resource Migration + - Replaced hard-coded globals with a `GameSettingsResource` - Easier inspector-based editing and persistence - Safer loading with fallback on corrupted configs ### Known Limitations -* Some complex menu flows may still rely on the mouse until additional +- Some complex menu flows may still rely on the mouse until additional focus neighbors are defined. -* Modifier-aware remapping requires explicit key+modifier press for +- Modifier-aware remapping requires explicit key+modifier press for unique bindings. - Track progress via [Milestones](https://github.com/ikostan/SkyLockAssault/milestones). --- diff --git a/files/docs/Development_Guide.md b/files/docs/Development_Guide.md index 0b0946ea5..82821a3ab 100644 --- a/files/docs/Development_Guide.md +++ b/files/docs/Development_Guide.md @@ -98,7 +98,7 @@ When adding a new setting: 4. No Manual Saves: Do not call save functions directly from the UI; changing the resource value is sufficient to trigger a save. -#### The technical documentation for the "Working with Game Settings" section. +#### The technical documentation for the "Working with Game Settings" section This documentation explicitly defines the signal signature and the specific files responsible for the **Observer Pattern** architecture. @@ -112,10 +112,10 @@ and a centralized observer handles persistence and logging. When connecting a UI element or a new system to the settings resource, use the following signature: -* **Signal Name**: `setting_changed` -* **Parameters**: - * `setting_name`: **String** (The name of the property that changed, e.g., "difficulty") - * `new_value`: **Variant** (The newly assigned, clamped value) +- **Signal Name**: `setting_changed` +- **Parameters**: + - `setting_name`: **String** (The name of the property that changed, e.g., "difficulty") + - `new_value`: **Variant** (The newly assigned, clamped value) #### 2. Core Files Reference diff --git a/files/docs/Platforms_for_Web_Deployment_Guide.md b/files/docs/Platforms_for_Web_Deployment_Guide.md index 349dd8769..e19f37ab0 100644 --- a/files/docs/Platforms_for_Web_Deployment_Guide.md +++ b/files/docs/Platforms_for_Web_Deployment_Guide.md @@ -8,6 +8,7 @@ We're building **SkyLockAssault** — a totally free-to-play browser game in **Godot v4.5** on **Windows 10 64-bit**. This is our learning journey into game dev, so we're keeping everything practical, low-friction, and focused on **automatic deploys** via GitHub Actions + + CI/CD where possible. This `.md` file is your living playbook. Update it as you go (e.g. mark @@ -19,11 +20,11 @@ new platforms as "Deployed: ✅ Yes"). ## Why Web Platforms for a Free F2P Godot Game? -- **Zero cost to publish** (no Steam $100 fee) -- **Instant browser play** (Godot WebGL export = one ZIP) -- **High traffic** for casual games like SkyLockAssault -- **Ad revenue or donations** without forcing monetization -- **GitHub Actions** = push → auto-deploy (your dream workflow) ++ **Zero cost to publish** (no Steam $100 fee) ++ **Instant browser play** (Godot WebGL export = one ZIP) ++ **High traffic** for casual games like SkyLockAssault ++ **Ad revenue or donations** without forcing monetization ++ **GitHub Actions** = push → auto-deploy (your dream workflow) --- @@ -75,9 +76,9 @@ but it's maintenance work. ## Automation Strategy -- 100% Auto: itch.io, Poki, Viverse, Game Jolt -- Playwright Auto: iDev.games, GameMonetize (easiest) -- Manual + Occasional: CrazyGames, Y8, GameDistribution, GamePix, Newgrounds, ++ 100% Auto: itch.io, Poki, Viverse, Game Jolt ++ Playwright Auto: iDev.games, GameMonetize (easiest) ++ Manual + Occasional: CrazyGames, Y8, GameDistribution, GamePix, Newgrounds, SoftGames --- @@ -92,12 +93,12 @@ but it's maintenance work. ### Phase 2: Semi-Auto Bonus (Playwright) -- **iDev.games** + **GameMonetize** (easiest forms) -- Update every 2–4 weeks via one shared script ++ **iDev.games** + **GameMonetize** (easiest forms) ++ Update every 2–4 weeks via one shared script ### Phase 3: Manual Once + Occasional Updates -- CrazyGames, Y8, GameDistribution, GamePix, Newgrounds, SoftGames, Game Jolt ++ CrazyGames, Y8, GameDistribution, GamePix, Newgrounds, SoftGames, Game Jolt **Goal:** Push to `main` → 10+ platforms updated automatically. From c3b3b09ccedfe0ac5435e60db2cab17c879b69d0 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:21:54 -0700 Subject: [PATCH 05/21] Update run_pipeline.sh --- run_pipeline.sh | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index 49cb2f458..2d7a0dcf4 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -6,7 +6,7 @@ PROJECT_DIR="/project" EXPORT_DIR="$PROJECT_DIR/export/web_thread_off" SERVER_PORT=8080 -PW_TIMEOUT=10000 # Default timeout in ms; adjustable +PW_TIMEOUT=10000 # Function to check if a step failed check_exit() { @@ -27,7 +27,9 @@ check_exit "GDScript Lint" # 2. Markdown Lint echo "Running Markdown Lint..." -markdownlint-cli2 "**/*.md" --config .markdownlint-cli2.yaml --fix +# --yes: skips the interactive install prompt +# !venv/**: prevents the linter from scanning your virtual environment +npx --yes markdownlint-cli2@0.12.1 "**/*.md" "!venv/**" --config .markdownlint-cli2.yaml --fix check_exit "Markdown Lint" # 3. YAML Lint @@ -36,8 +38,8 @@ yamllint -c .yamllint.yaml .github/workflows/*.yml check_exit "YAML Lint" # 4. Godot Unit Tests (GDUnit4 v6) -echo "Downloading GDUnit4 if needed (already in image, but ensure project addons)..." -cp -r /project/addons/gdUnit4 $PROJECT_DIR/addons/ || true # Copy if not present +echo "Ensuring GDUnit4 addons are present..." +cp -r /project/addons/gdUnit4 $PROJECT_DIR/addons/ || true echo "Importing Resources..." godot --headless --path $PROJECT_DIR --import --quit @@ -48,28 +50,22 @@ godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.g check_exit "GDUnit4 Tests" # 5. GUT Unit Tests -# Added from run_gut_unit_tests.sh echo "Running GUT Unit Tests..." godot --headless --verbose --path $PROJECT_DIR -s res://addons/gut/gut_cmdln.gd -gconfig=res://.gutconfig.json -gdir=res://test -ginclude_subdirs=true -gexit check_exit "GUT Unit Tests" -# Upload reports (simulate artifact upload by copying to a reports dir) mkdir -p $PROJECT_DIR/reports cp -r reports/** $PROJECT_DIR/reports || true # 6. Browser Functional Tests echo "Exporting Godot Project to Web..." mkdir -p $EXPORT_DIR - -# Simulate firebelley/godot-export action: Run Godot export to HTML5 godot --headless --path $PROJECT_DIR --export-release "Web_thread_off" $EXPORT_DIR/index.html check_exit "Godot Web Export" -# Start web server in background python3 -m http.server $SERVER_PORT --directory $EXPORT_DIR & SERVER_PID=$! -# Wait for server to be ready for i in {1..20}; do if curl -f http://localhost:$SERVER_PORT/index.html >/dev/null 2>&1; then echo "Web server ready" @@ -77,18 +73,17 @@ for i in {1..20}; do fi sleep 1 done + if [ $i -eq 20 ]; then echo "Web server failed to start" kill $SERVER_PID exit 1 fi -# Run Playwright tests echo "Running Playwright Browser Tests..." pytest tests/ --ignore=tests/refactor -v --junitxml=$PROJECT_DIR/report.xml check_exit "Playwright Tests" -# Generate test report summary if [ -f $PROJECT_DIR/report.xml ]; then total=$(xmllint --xpath 'count(//testcase)' $PROJECT_DIR/report.xml) failures=$(xmllint --xpath 'count(//testcase/failure)' $PROJECT_DIR/report.xml) @@ -101,17 +96,13 @@ if [ -f $PROJECT_DIR/report.xml ]; then echo "- Failed: $failures" echo "- Errors: $errors" echo "- Skipped: $skipped" -else - echo "No report.xml found—tests may not have run." fi -# Cleanup: Stop server kill $SERVER_PID -# Simulate artifact uploads (copy to host via mounted volume) mkdir -p $PROJECT_DIR/artifacts cp $PROJECT_DIR/report.xml $PROJECT_DIR/artifacts/ || true -cp main_menu.png $PROJECT_DIR/artifacts/ || true # If screenshot exists +cp main_menu.png $PROJECT_DIR/artifacts/ || true cp -r $PROJECT_DIR/reports $PROJECT_DIR/artifacts/gdunit-reports || true echo "Pipeline completed successfully!" \ No newline at end of file From 25e21bf9b6088a463de638f52f5f1be997359fcb Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:25:49 -0700 Subject: [PATCH 06/21] Update run_gdunit4_unit_tests.sh --- run_unit_tests.sh => run_gdunit4_unit_tests.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename run_unit_tests.sh => run_gdunit4_unit_tests.sh (100%) diff --git a/run_unit_tests.sh b/run_gdunit4_unit_tests.sh similarity index 100% rename from run_unit_tests.sh rename to run_gdunit4_unit_tests.sh From aff443fe39363934d3853401b0eb7abaa784c58a Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:38:47 -0700 Subject: [PATCH 07/21] Refactor Phase 3: Migrate Core and Manager scripts #526 Move the high-level game state and manager scripts out of the root folder into core/ and managers/. --- project.godot | 4 ++-- scenes/main_scene.tscn | 2 +- scripts/{ => core}/globals.gd | 0 scripts/{ => core}/globals.gd.uid | 0 scripts/{ => core}/main_scene.gd | 0 scripts/{ => core}/main_scene.gd.uid | 0 scripts/{ => core}/settings.gd | 0 scripts/{ => core}/settings.gd.uid | 0 test/gdunit4/test_globals.gd | 2 +- 9 files changed, 4 insertions(+), 4 deletions(-) rename scripts/{ => core}/globals.gd (100%) rename scripts/{ => core}/globals.gd.uid (100%) rename scripts/{ => core}/main_scene.gd (100%) rename scripts/{ => core}/main_scene.gd.uid (100%) rename scripts/{ => core}/settings.gd (100%) rename scripts/{ => core}/settings.gd.uid (100%) diff --git a/project.godot b/project.godot index 7e2836aac..7d5751742 100644 --- a/project.godot +++ b/project.godot @@ -24,8 +24,8 @@ general/default_playback_type.web=0 [autoload] -Globals="*res://scripts/globals.gd" -Settings="*res://scripts/settings.gd" +Globals="*res://scripts/core/globals.gd" +Settings="*res://scripts/core/settings.gd" AudioConstants="*res://scripts/audio_constants.gd" AudioManager="*res://scripts/audio_manager.gd" AudioWebBridge="*res://scripts/audio_web_bridge.gd" diff --git a/scenes/main_scene.tscn b/scenes/main_scene.tscn index 888ca363d..7179b3508 100644 --- a/scenes/main_scene.tscn +++ b/scenes/main_scene.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=83 format=3 uid="uid://nnnc0qhx07i8"] -[ext_resource type="Script" uid="uid://ctm7qg12s2swt" path="res://scripts/main_scene.gd" id="1_7ykc4"] +[ext_resource type="Script" uid="uid://ctm7qg12s2swt" path="res://scripts/core/main_scene.gd" id="1_7ykc4"] [ext_resource type="PackedScene" uid="uid://cb4n4cqkuddqg" path="res://scenes/pause_menu.tscn" id="1_w2twt"] [ext_resource type="Texture2D" uid="uid://ce63ga8f5mua7" path="res://files/trees/tree_01.png" id="2_fm3ay"] [ext_resource type="FontFile" uid="uid://borwvgqdgawbj" path="res://files/fonts/EMPIREST.TTF" id="2_pu3yx"] diff --git a/scripts/globals.gd b/scripts/core/globals.gd similarity index 100% rename from scripts/globals.gd rename to scripts/core/globals.gd diff --git a/scripts/globals.gd.uid b/scripts/core/globals.gd.uid similarity index 100% rename from scripts/globals.gd.uid rename to scripts/core/globals.gd.uid diff --git a/scripts/main_scene.gd b/scripts/core/main_scene.gd similarity index 100% rename from scripts/main_scene.gd rename to scripts/core/main_scene.gd diff --git a/scripts/main_scene.gd.uid b/scripts/core/main_scene.gd.uid similarity index 100% rename from scripts/main_scene.gd.uid rename to scripts/core/main_scene.gd.uid diff --git a/scripts/settings.gd b/scripts/core/settings.gd similarity index 100% rename from scripts/settings.gd rename to scripts/core/settings.gd diff --git a/scripts/settings.gd.uid b/scripts/core/settings.gd.uid similarity index 100% rename from scripts/settings.gd.uid rename to scripts/core/settings.gd.uid diff --git a/test/gdunit4/test_globals.gd b/test/gdunit4/test_globals.gd index f6f3b2563..47d126f13 100644 --- a/test/gdunit4/test_globals.gd +++ b/test/gdunit4/test_globals.gd @@ -13,7 +13,7 @@ var test_path: String = "user://test_globals.cfg" # Temp for isolation func before_test() -> void: # Instantiate the script - globals = auto_free(load("res://scripts/globals.gd").new()) + globals = auto_free(load("res://scripts/core/globals.gd").new()) # FIX: Manually initialize the settings resource # because _ready() hasn't run yet. From 1995f5ae62449a9afbae6fa61e89b0a78d64f3a7 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:52:41 -0700 Subject: [PATCH 08/21] Install GUT before running it and use the configured test directory. The command assumes addons/gut/ already exists, but run_pipeline.sh does not install it. The existing run_gut_unit_tests.sh and .github/workflows/gut_tests.yml both include GUT installation logic that run_pipeline.sh lacks. Additionally, passing -gdir=res://test broadens test discovery beyond .gutconfig.json's configured res://test/gut/, so GUT may attempt to load unintended test suites (e.g., GDUnit4 tests under res://test/gdunit4/). --- run_pipeline.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/run_pipeline.sh b/run_pipeline.sh index 2d7a0dcf4..dc6ea64a1 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -50,6 +50,14 @@ godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.g check_exit "GDUnit4 Tests" # 5. GUT Unit Tests +# Install GUT v9.5.0 +RUN mkdir -p /project/addons \ + && wget https://github.com/bitwes/Gut/archive/refs/tags/v9.5.0.zip \ + && unzip v9.5.0.zip -d /project/addons \ + && mv /project/addons/Gut-9.5.0/addons/gut /project/addons/gut \ + && rm -rf /project/addons/Gut-9.5.0 v9.5.0.zip \ + && chown -R godotuser:godotuser /project + echo "Running GUT Unit Tests..." godot --headless --verbose --path $PROJECT_DIR -s res://addons/gut/gut_cmdln.gd -gconfig=res://.gutconfig.json -gdir=res://test -ginclude_subdirs=true -gexit check_exit "GUT Unit Tests" From f9e5307efa60a5dc33c370ccd25d8c506a671416 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:55:49 -0700 Subject: [PATCH 09/21] Refactor Phase 3: Migrate Core and Manager scripts #526 Move to managers/: audio_manager.gd, resource_preloader.gd. --- project.godot | 2 +- scenes/main_scene.tscn | 2 +- scripts/{ => managers}/audio_manager.gd | 0 scripts/{ => managers}/audio_manager.gd.uid | 0 scripts/{ => managers}/resource_preloader.gd | 0 scripts/{ => managers}/resource_preloader.gd.uid | 0 6 files changed, 2 insertions(+), 2 deletions(-) rename scripts/{ => managers}/audio_manager.gd (100%) rename scripts/{ => managers}/audio_manager.gd.uid (100%) rename scripts/{ => managers}/resource_preloader.gd (100%) rename scripts/{ => managers}/resource_preloader.gd.uid (100%) diff --git a/project.godot b/project.godot index 7d5751742..b701295a4 100644 --- a/project.godot +++ b/project.godot @@ -27,7 +27,7 @@ general/default_playback_type.web=0 Globals="*res://scripts/core/globals.gd" Settings="*res://scripts/core/settings.gd" AudioConstants="*res://scripts/audio_constants.gd" -AudioManager="*res://scripts/audio_manager.gd" +AudioManager="*res://scripts/managers/audio_manager.gd" AudioWebBridge="*res://scripts/audio_web_bridge.gd" [debug] diff --git a/scenes/main_scene.tscn b/scenes/main_scene.tscn index 7179b3508..d3831c25f 100644 --- a/scenes/main_scene.tscn +++ b/scenes/main_scene.tscn @@ -5,7 +5,7 @@ [ext_resource type="Texture2D" uid="uid://ce63ga8f5mua7" path="res://files/trees/tree_01.png" id="2_fm3ay"] [ext_resource type="FontFile" uid="uid://borwvgqdgawbj" path="res://files/fonts/EMPIREST.TTF" id="2_pu3yx"] [ext_resource type="PackedScene" uid="uid://37rarq1yywmc" path="res://scenes/Player.tscn" id="2_pw63i"] -[ext_resource type="Script" uid="uid://csdce7ynrpivs" path="res://scripts/resource_preloader.gd" id="3_c1pb6"] +[ext_resource type="Script" uid="uid://csdce7ynrpivs" path="res://scripts/managers/resource_preloader.gd" id="3_c1pb6"] [ext_resource type="Texture2D" uid="uid://bsmbcgovcph7p" path="res://files/trees/tree_02.png" id="3_sgkfd"] [ext_resource type="Texture2D" uid="uid://syw5eae1ebna" path="res://files/trees/tree_11.png" id="4_qj6t7"] [ext_resource type="Texture2D" uid="uid://grifp8c6vrgt" path="res://files/trees/tree_12.png" id="5_k78mq"] diff --git a/scripts/audio_manager.gd b/scripts/managers/audio_manager.gd similarity index 100% rename from scripts/audio_manager.gd rename to scripts/managers/audio_manager.gd diff --git a/scripts/audio_manager.gd.uid b/scripts/managers/audio_manager.gd.uid similarity index 100% rename from scripts/audio_manager.gd.uid rename to scripts/managers/audio_manager.gd.uid diff --git a/scripts/resource_preloader.gd b/scripts/managers/resource_preloader.gd similarity index 100% rename from scripts/resource_preloader.gd rename to scripts/managers/resource_preloader.gd diff --git a/scripts/resource_preloader.gd.uid b/scripts/managers/resource_preloader.gd.uid similarity index 100% rename from scripts/resource_preloader.gd.uid rename to scripts/managers/resource_preloader.gd.uid From 9364109db56a8b429790e8bb5184aebd2c2c8e07 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 21:59:41 -0700 Subject: [PATCH 10/21] =?UTF-8?q?1.=20Invalid=20RUN=20keyword=20(Line=2054?= =?UTF-8?q?)=20=E2=80=94=20Dockerfile=20syntax=20in=20a=20bash=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RUN is a Dockerfile instruction and is not valid bash. Running this will cause a command not found error. It should be replaced with a conditional install bloc --- run_pipeline.sh | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index dc6ea64a1..c76911819 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -27,8 +27,6 @@ check_exit "GDScript Lint" # 2. Markdown Lint echo "Running Markdown Lint..." -# --yes: skips the interactive install prompt -# !venv/**: prevents the linter from scanning your virtual environment npx --yes markdownlint-cli2@0.12.1 "**/*.md" "!venv/**" --config .markdownlint-cli2.yaml --fix check_exit "Markdown Lint" @@ -46,20 +44,29 @@ godot --headless --path $PROJECT_DIR --import --quit check_exit "Resource Import" echo "Running GDUnit4 Tests..." -godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --verbose --ignoreHeadlessMode --add res://test +# Specific directory to avoid GUT conflicts +godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --verbose --ignoreHeadlessMode --add res://test/gdunit4 check_exit "GDUnit4 Tests" # 5. GUT Unit Tests -# Install GUT v9.5.0 -RUN mkdir -p /project/addons \ - && wget https://github.com/bitwes/Gut/archive/refs/tags/v9.5.0.zip \ - && unzip v9.5.0.zip -d /project/addons \ - && mv /project/addons/Gut-9.5.0/addons/gut /project/addons/gut \ - && rm -rf /project/addons/Gut-9.5.0 v9.5.0.zip \ - && chown -R godotuser:godotuser /project +# FIXED: Replaced RUN instruction with proper bash conditional +echo "Ensuring GUT is installed in addons/..." +if [ ! -d "$PROJECT_DIR/addons/gut" ]; then + mkdir -p "$PROJECT_DIR/addons" + wget https://github.com/bitwes/Gut/archive/refs/tags/v9.5.0.zip + unzip v9.5.0.zip -d "$PROJECT_DIR/addons" + mv "$PROJECT_DIR/addons/Gut-9.5.0/addons/gut" "$PROJECT_DIR/addons/gut" + rm -rf "$PROJECT_DIR/addons/Gut-9.5.0" v9.5.0.zip +fi echo "Running GUT Unit Tests..." -godot --headless --verbose --path $PROJECT_DIR -s res://addons/gut/gut_cmdln.gd -gconfig=res://.gutconfig.json -gdir=res://test -ginclude_subdirs=true -gexit +# FIXED: Isolated to res://test/gut to prevent discovery of GDUnit tests +godot --headless --verbose --path $PROJECT_DIR \ + -s res://addons/gut/gut_cmdln.gd \ + -gconfig=res://.gutconfig.json \ + -gdir=res://test/gut \ + -ginclude_subdirs=true \ + -gexit check_exit "GUT Unit Tests" mkdir -p $PROJECT_DIR/reports From 464db5cfd5e6131a3132927f930b4250d7c7bc85 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 22:01:29 -0700 Subject: [PATCH 11/21] 2. -gdir=res://test -ginclude_subdirs=true still present (Line 62) This overrides the directory configured in .gutconfig.json (which points to res://test/gut/) and causes GUT to scan all subdirectories under res://test/, including GDUnit4 tests. These flags should be removed so -gconfig alone governs test discovery: --- run_pipeline.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index c76911819..1ce7e7a24 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -49,7 +49,6 @@ godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.g check_exit "GDUnit4 Tests" # 5. GUT Unit Tests -# FIXED: Replaced RUN instruction with proper bash conditional echo "Ensuring GUT is installed in addons/..." if [ ! -d "$PROJECT_DIR/addons/gut" ]; then mkdir -p "$PROJECT_DIR/addons" @@ -60,12 +59,10 @@ if [ ! -d "$PROJECT_DIR/addons/gut" ]; then fi echo "Running GUT Unit Tests..." -# FIXED: Isolated to res://test/gut to prevent discovery of GDUnit tests +# FIXED: Removed -gdir and -ginclude_subdirs to let .gutconfig.json govern discovery godot --headless --verbose --path $PROJECT_DIR \ -s res://addons/gut/gut_cmdln.gd \ -gconfig=res://.gutconfig.json \ - -gdir=res://test/gut \ - -ginclude_subdirs=true \ -gexit check_exit "GUT Unit Tests" From 49fa33cc2ce2ec33df262b6b6d2a28e5f9505908 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 18 Apr 2026 22:14:17 -0700 Subject: [PATCH 12/21] Update test_audio_manager.gd --- test/gdunit4/test_audio_manager.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gdunit4/test_audio_manager.gd b/test/gdunit4/test_audio_manager.gd index 3d9f1bd22..e441349e1 100644 --- a/test/gdunit4/test_audio_manager.gd +++ b/test/gdunit4/test_audio_manager.gd @@ -16,7 +16,7 @@ var test_path: String = "user://test_audio.cfg" # Temp for isolation ## Per-test setup: Instantiate manager and init defaults. ## :rtype: void func before_test() -> void: - manager = auto_free(load("res://scripts/audio_manager.gd").new()) + manager = auto_free(load("res://scripts/managers/audio_manager.gd").new()) manager._init_to_defaults() # Manually set defaults (since _ready() not called in isolation) From bb191771d068ca8a1805bacd5c5fcaaa24f246b0 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 18:38:13 -0700 Subject: [PATCH 13/21] Update run_pipeline.sh In run_pipeline.sh, removing the report.xml existence warning means a missing or failed pytest run will now fail silently; consider restoring a clear message or explicit failure if the report is absent to make pipeline debugging easier. --- run_pipeline.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index 1ce7e7a24..e63868540 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -27,6 +27,7 @@ check_exit "GDScript Lint" # 2. Markdown Lint echo "Running Markdown Lint..." +# --yes: skips interactive prompt | !venv/**: excludes virtual environment npx --yes markdownlint-cli2@0.12.1 "**/*.md" "!venv/**" --config .markdownlint-cli2.yaml --fix check_exit "Markdown Lint" @@ -44,7 +45,6 @@ godot --headless --path $PROJECT_DIR --import --quit check_exit "Resource Import" echo "Running GDUnit4 Tests..." -# Specific directory to avoid GUT conflicts godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --verbose --ignoreHeadlessMode --add res://test/gdunit4 check_exit "GDUnit4 Tests" @@ -59,7 +59,7 @@ if [ ! -d "$PROJECT_DIR/addons/gut" ]; then fi echo "Running GUT Unit Tests..." -# FIXED: Removed -gdir and -ginclude_subdirs to let .gutconfig.json govern discovery +# Let .gutconfig.json govern discovery; removed -gdir overrides godot --headless --verbose --path $PROJECT_DIR \ -s res://addons/gut/gut_cmdln.gd \ -gconfig=res://.gutconfig.json \ @@ -96,18 +96,24 @@ echo "Running Playwright Browser Tests..." pytest tests/ --ignore=tests/refactor -v --junitxml=$PROJECT_DIR/report.xml check_exit "Playwright Tests" +# 7. Report Summary & Failure Check if [ -f $PROJECT_DIR/report.xml ]; then total=$(xmllint --xpath 'count(//testcase)' $PROJECT_DIR/report.xml) failures=$(xmllint --xpath 'count(//testcase/failure)' $PROJECT_DIR/report.xml) errors=$(xmllint --xpath 'count(//testcase/error)' $PROJECT_DIR/report.xml) skipped=$(xmllint --xpath 'count(//testcase/skipped)' $PROJECT_DIR/report.xml) passed=$((total - failures - errors - skipped)) + echo "Test Report Summary:" echo "- Total tests: $total" echo "- Passed: $passed" echo "- Failed: $failures" echo "- Errors: $errors" echo "- Skipped: $skipped" +else + echo "CRITICAL ERROR: report.xml not found! Playwright tests failed to generate results." + kill $SERVER_PID + exit 1 fi kill $SERVER_PID From ea06ea7db7320774269c16f771d4b90bc5d263d9 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 18:44:25 -0700 Subject: [PATCH 14/21] install the tool during the Docker build stage so it is "baked in" to the environment The npx --yes markdownlint-cli2@0.12.1 invocation couples the pipeline to an on-demand network install of a specific version on every run; consider using a locally installed tool (or caching) and/or moving the version pin to a central config so CI remains faster and less dependent on external availability. --- Dockerfile | 2 +- run_pipeline.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2688cadf1..2e485e50f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ RUN pip install yamllint RUN pip install pytest-html pytest-timeout # Install markdownlint-cli2 via npm (Node.js tool) -RUN npm install -g markdownlint-cli2 +RUN npm install -g markdownlint-cli2@0.12.1 # Download Godot v4.5 binary and export templates RUN wget https://github.com/godotengine/godot/releases/download/4.5-stable/Godot_v4.5-stable_linux.x86_64.zip \ diff --git a/run_pipeline.sh b/run_pipeline.sh index e63868540..381e97a0f 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -27,8 +27,8 @@ check_exit "GDScript Lint" # 2. Markdown Lint echo "Running Markdown Lint..." -# --yes: skips interactive prompt | !venv/**: excludes virtual environment -npx --yes markdownlint-cli2@0.12.1 "**/*.md" "!venv/**" --config .markdownlint-cli2.yaml --fix +# Now using the version pre-installed in the Docker image +markdownlint-cli2 "**/*.md" "!venv/**" --config .markdownlint-cli2.yaml --fix check_exit "Markdown Lint" # 3. YAML Lint From 171e27d71f2d871a4630f439009156e71cf4ddf0 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:45:25 -0700 Subject: [PATCH 15/21] Update run_pipeline.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- run_pipeline.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index 381e97a0f..ddb82c61f 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -38,7 +38,10 @@ check_exit "YAML Lint" # 4. Godot Unit Tests (GDUnit4 v6) echo "Ensuring GDUnit4 addons are present..." -cp -r /project/addons/gdUnit4 $PROJECT_DIR/addons/ || true +if [ ! -d "$PROJECT_DIR/addons/gdUnit4" ]; then + echo "GDUnit4 addon missing at $PROJECT_DIR/addons/gdUnit4" + exit 1 +fi echo "Importing Resources..." godot --headless --path $PROJECT_DIR --import --quit From 67535c900c549642b82b9e6b639226d57120e1b3 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:46:29 -0700 Subject: [PATCH 16/21] Update run_pipeline.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- run_pipeline.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index ddb82c61f..192091a7c 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -81,15 +81,17 @@ check_exit "Godot Web Export" python3 -m http.server $SERVER_PORT --directory $EXPORT_DIR & SERVER_PID=$! +server_ready=false for i in {1..20}; do if curl -f http://localhost:$SERVER_PORT/index.html >/dev/null 2>&1; then echo "Web server ready" + server_ready=true break fi sleep 1 done -if [ $i -eq 20 ]; then +if [ "$server_ready" != true ]; then echo "Web server failed to start" kill $SERVER_PID exit 1 From 41c04bce75b56447ed23fceffe69cc3dc67f791c Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 18:53:34 -0700 Subject: [PATCH 17/21] Remove or wire PW_TIMEOUT into the pytest command. 9-9: Remove or wire PW_TIMEOUT into the pytest command. Line 9 defines PW_TIMEOUT=10000, but the pytest command on line 96 doesn't use the --timeout parameter, so the variable has no effect. Either add --timeout=$PW_TIMEOUT to the pytest invocation or remove the unused variable. --- run_pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index 192091a7c..9a1f21a03 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -98,7 +98,7 @@ if [ "$server_ready" != true ]; then fi echo "Running Playwright Browser Tests..." -pytest tests/ --ignore=tests/refactor -v --junitxml=$PROJECT_DIR/report.xml +pytest tests/ --ignore=tests/refactor -v --timeout=$PW_TIMEOUT --junitxml=$PROJECT_DIR/report.xml check_exit "Playwright Tests" # 7. Report Summary & Failure Check From c8e2cc64e36821a426075ec33e6bfbe8e6cb6a4d Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 18:57:08 -0700 Subject: [PATCH 18/21] Update Platforms_for_Web_Deployment_Guide.md Line 12 now renders as a standalone + bullet, which breaks the paragraph flow. --- files/docs/Platforms_for_Web_Deployment_Guide.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/docs/Platforms_for_Web_Deployment_Guide.md b/files/docs/Platforms_for_Web_Deployment_Guide.md index e19f37ab0..372b77839 100644 --- a/files/docs/Platforms_for_Web_Deployment_Guide.md +++ b/files/docs/Platforms_for_Web_Deployment_Guide.md @@ -4,17 +4,17 @@ ## Project Context -We're building **SkyLockAssault** — a totally free-to-play browser +- We're building **SkyLockAssault** — a totally free-to-play browser game in **Godot v4.5** on **Windows 10 64-bit**. This is our learning journey into game dev, so we're keeping everything practical, low-friction, and focused on **automatic deploys** via GitHub Actions -+ CI/CD where possible. +- CI/CD where possible. -This `.md` file is your living playbook. Update it as you go (e.g. mark +- This `.md` file is your living playbook. Update it as you go (e.g. mark new platforms as "Deployed: ✅ Yes"). -**Target**: Automatic GitHub Actions deploys where possible. +- **Target**: Automatic GitHub Actions deploys where possible. --- From 983955a921086a7e72240e289be199171923acdb Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 18:58:18 -0700 Subject: [PATCH 19/21] Update Platforms_for_Web_Deployment_Guide.md Remove Game Jolt from the manual phase or reclassify it consistently. The guide lists Game Jolt as 100% Auto on Line 79, but also includes it in the manual/occasional Phase 3 list on Line 101. --- files/docs/Platforms_for_Web_Deployment_Guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/docs/Platforms_for_Web_Deployment_Guide.md b/files/docs/Platforms_for_Web_Deployment_Guide.md index 372b77839..0df701256 100644 --- a/files/docs/Platforms_for_Web_Deployment_Guide.md +++ b/files/docs/Platforms_for_Web_Deployment_Guide.md @@ -98,7 +98,7 @@ but it's maintenance work. ### Phase 3: Manual Once + Occasional Updates -+ CrazyGames, Y8, GameDistribution, GamePix, Newgrounds, SoftGames, Game Jolt ++ CrazyGames, Y8, GameDistribution, GamePix, Newgrounds, SoftGames **Goal:** Push to `main` → 10+ platforms updated automatically. From 8228fbd9179b75f5cfc49b28b46318f398f26538 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 19:05:34 -0700 Subject: [PATCH 20/21] issue (bug_risk): Clarify timeout units to match pytest-timeout expectations issue (bug_risk): Clarify timeout units to match pytest-timeout expectations This value is now passed directly to pytest via --timeout=$PW_TIMEOUT, and pytest-timeout interprets it as seconds, not milliseconds. As written, 10000 is ~2.8 hours, not 10 seconds. Please either change the value to the intended number of seconds or clearly document that this timeout is in seconds to avoid accidental misconfiguration. --- run_pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_pipeline.sh b/run_pipeline.sh index 9a1f21a03..4086c2a4d 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -6,7 +6,7 @@ PROJECT_DIR="/project" EXPORT_DIR="$PROJECT_DIR/export/web_thread_off" SERVER_PORT=8080 -PW_TIMEOUT=10000 +PW_TIMEOUT=10 # Value is in SECONDS for pytest-timeout compatibility # Function to check if a step failed check_exit() { From 0aa098b63e2e82e84070c33668d3ee5d9484965d Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Mon, 20 Apr 2026 19:15:18 -0700 Subject: [PATCH 21/21] suggestion (performance): Avoid downloading and unpacking GUT on every pipeline run for performance and reliability This step makes every CI run download and unzip GUT, adding avoidable network and I/O overhead and introducing a runtime dependency on GitHub being available. If GUT is a stable dependency, consider installing it in the Docker image (or caching it via a shared volume) so the pipeline avoids repeated downloads and file moves. To fully implement the suggestion: Update your Dockerfile (or base image build) to clone/unpack GUT into $PROJECT_DIR/addons/gut at image build time, so it is available for the pipeline without network access. If you are using a cache/volume approach instead, ensure that the cache populates $PROJECT_DIR/addons/gut before run_pipeline.sh executes. If there is (or will be) a command that actually runs the GUT tests (e.g. godot --headless ...), place it immediately after this existence check and wrap it with check_exit as done for the other steps. --- Dockerfile | 8 ++++++++ run_pipeline.sh | 13 ++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2e485e50f..565344042 100644 --- a/Dockerfile +++ b/Dockerfile @@ -62,6 +62,14 @@ RUN mkdir -p /project/addons \ && rm -rf /project/addons/gdUnit4-6.0.0 v6.0.0.zip \ && chown -R godotuser:godotuser /project # Make project dir accessible +# Install GUT v9.5.0 +RUN mkdir -p /project/addons \ + && wget https://github.com/bitwes/Gut/archive/refs/tags/v9.5.0.zip \ + && unzip v9.5.0.zip -d /project/addons \ + && mv /project/addons/Gut-9.5.0/addons/gut /project/addons/gut \ + && rm -rf /project/addons/Gut-9.5.0 v9.5.0.zip \ + && chown -R godotuser:godotuser /project + # Install Playwright Python packages and system deps (as root) RUN pip install playwright pytest-playwright pytest-asyncio \ && playwright install-deps \ diff --git a/run_pipeline.sh b/run_pipeline.sh index 4086c2a4d..72f264c0d 100644 --- a/run_pipeline.sh +++ b/run_pipeline.sh @@ -52,17 +52,16 @@ godot --headless --path $PROJECT_DIR -s res://addons/gdUnit4/bin/GdUnitCmdTool.g check_exit "GDUnit4 Tests" # 5. GUT Unit Tests -echo "Ensuring GUT is installed in addons/..." +# FIXED: Replaced download/unpack logic with existence check +echo "Checking for GUT installation..." if [ ! -d "$PROJECT_DIR/addons/gut" ]; then - mkdir -p "$PROJECT_DIR/addons" - wget https://github.com/bitwes/Gut/archive/refs/tags/v9.5.0.zip - unzip v9.5.0.zip -d "$PROJECT_DIR/addons" - mv "$PROJECT_DIR/addons/Gut-9.5.0/addons/gut" "$PROJECT_DIR/addons/gut" - rm -rf "$PROJECT_DIR/addons/Gut-9.5.0" v9.5.0.zip + echo "GUT not found at '$PROJECT_DIR/addons/gut'." + echo "CRITICAL: GUT must be pre-installed in the Docker image or cached volume." + exit 1 fi echo "Running GUT Unit Tests..." -# Let .gutconfig.json govern discovery; removed -gdir overrides +# Let .gutconfig.json govern discovery godot --headless --verbose --path $PROJECT_DIR \ -s res://addons/gut/gut_cmdln.gd \ -gconfig=res://.gutconfig.json \