From f5bd3e4a309a35a289a8e2d24da1d2b53d464691 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Fri, 31 Jul 2026 16:25:49 +0200 Subject: [PATCH] initial commit --- README.md | 41 +++++++++++++++++++++ example-export_presets.cfg | 43 ++++++++++++++++++++++ example-makefile.make | 74 ++++++++++++++++++++++++++++++++++++++ example-tasks.json | 35 ++++++++++++++++++ example-woodpecker.yaml | 35 ++++++++++++++++++ 5 files changed, 228 insertions(+) create mode 100644 README.md create mode 100644 example-export_presets.cfg create mode 100644 example-makefile.make create mode 100644 example-tasks.json create mode 100644 example-woodpecker.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..927085f --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# godot-tools + +CI/CD templates for [Godot](https://godotengine.org) (4.x) game +projects, in the same spirit as [ebitengine-tools](../ebitengine-tools) +and [tic80-tools](../tic80-tools). + +- `example-makefile.make` — project Makefile: local dev targets + (`build`, `run`, `web`, `export`, `watch`, `clean`) plus the + Woodpecker pipeline targets (`ci-version`, `ci-export`, `ci-upload`, + `ci-update`). +- `example-woodpecker.yaml` — Woodpecker pipeline: version → build + (headless web export in the `barichello/godot-ci` image) → upload + (scp to the droparea) → update (calls the teletypegames `/update` + endpoint with `platform=godot`). +- `example-export_presets.cfg` — minimal `export_presets.cfg` with the + **Web** preset the Makefile exports. Threads are disabled + (`variant/thread_support=false`, Godot 4.3+) so the build runs + without COOP/COEP (cross-origin isolation) headers. +- `example-tasks.json` — VS Code `.vscode/tasks.json` with the common + dev tasks: **Run** (`godot --path .`, default build task, + `Cmd+Shift+B`), **Edit**, **Export Web** and **Make build**. + +## Usage in a game repo + +1. Copy `example-makefile.make` to `Makefile` and set `PROJECT` + (the web build is packaged as `$(PROJECT)-$(VERSION).html.zip`). +2. Copy `example-export_presets.cfg` to `export_presets.cfg` (or merge + the `Web` preset into your existing presets). Keep the preset name + in sync with `EXPORT_PRESET` in the Makefile. +3. Copy `example-woodpecker.yaml` to `.woodpecker.yaml` and add the + `droparea_ssh_password` / `update_secret_key` secrets in Woodpecker. + Match the `barichello/godot-ci` image tag to the Godot version the + project is made with (e.g. `4.6`) — the image ships the matching + export templates. +4. Copy `example-tasks.json` to `.vscode/tasks.json`. + +The pipeline uploads `$(PROJECT)-$(VERSION).html.zip` to the droparea, +then triggers +`/update?platform=godot&name=$(PROJECT)&version=$(VERSION)`. + +Detailed documentation lives on the wiki: `/development/godot`. diff --git a/example-export_presets.cfg b/example-export_presets.cfg new file mode 100644 index 0000000..fa0c4f6 --- /dev/null +++ b/example-export_presets.cfg @@ -0,0 +1,43 @@ +; Copy to export_presets.cfg in the project root (or merge the preset +; into your existing file). The "Web" preset name is what the Makefile +; passes to `godot --headless --export-release`. +; +; `variant/thread_support=false` keeps the build runnable without +; COOP/COEP (cross-origin isolation) headers, which the game hosting +; does not send. Requires Godot 4.3+. + +[preset.0] + +name="Web" +platform="Web" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="dist/web/index.html" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +variant/extensions_support=false +variant/thread_support=false +vram_texture_compression/for_desktop=true +vram_texture_compression/for_mobile=false +html/export_icon=true +html/custom_html_shell="" +html/head_include="" +html/canvas_resize_policy=2 +html/focus_canvas_on_start=true +html/experimental_virtual_keyboard=false +progressive_web_app/enabled=false diff --git a/example-makefile.make b/example-makefile.make new file mode 100644 index 0000000..3476ac0 --- /dev/null +++ b/example-makefile.make @@ -0,0 +1,74 @@ +# ----------------------------------------- +# Makefile – Godot project builder +# ----------------------------------------- + +PROJECT = godotdemo + +GODOT ?= godot +EXPORT_PRESET = Web + +DIST_DIR = dist +WEB_DIR = $(DIST_DIR)/web +OUTPUT_ZIP = $(PROJECT)-$(VERSION).html.zip + +VERSION_FILE = .version + +all: build + +build: + $(GODOT) --headless --import + +run: + $(GODOT) --path . + +web: build + @mkdir -p $(WEB_DIR) + @echo "==> Exporting web build ($(EXPORT_PRESET) preset)" + $(GODOT) --headless --export-release "$(EXPORT_PRESET)" $(WEB_DIR)/index.html + +export: web + @if [ -z "$(VERSION)" ]; then \ + echo "ERROR: VERSION not set!"; exit 1; \ + fi + @echo "==> Packaging web build for $(VERSION)" + cd $(WEB_DIR) && zip -r ../../$(OUTPUT_ZIP) . + @echo "==> Cleaning temporary files" + rm -rf $(WEB_DIR) + +watch: + fswatch -o . --include="\.gd$$" --include="\.tscn$$" | while read; do make build; done + +clean: + rm -rf $(DIST_DIR) .godot + +ci-version: + @if [ -f metadata.json ]; then \ + VERSION=$$(jq -r '.version' metadata.json); \ + else \ + VERSION=$$(git rev-parse --short HEAD); \ + fi; \ + BRANCH=$$(git rev-parse --abbrev-ref HEAD); \ + if [ "$$BRANCH" != "main" ] && [ "$$BRANCH" != "master" ]; then \ + VERSION="dev-$$VERSION-$$BRANCH"; \ + fi; \ + echo $$VERSION > $(VERSION_FILE) + +ci-export: + @VERSION=$$(cat $(VERSION_FILE)); \ + $(MAKE) export VERSION=$$VERSION + +ci-upload: + @VERSION=$$(cat $(VERSION_FILE)); \ + FILE="$(PROJECT)-$$VERSION.html.zip"; \ + META_SRC="metadata.json"; \ + META_DST="$(PROJECT)-$$VERSION.metadata.json"; \ + cp $$META_SRC $$META_DST; \ + sshpass -p "$(DROPAREA_SSH_PASSWORD)" scp -o StrictHostKeyChecking=no -P $(DROPAREA_PORT) \ + $$FILE $$META_DST \ + $(DROPAREA_USER)@$(DROPAREA_HOST):$(DROPAREA_TARGET_PATH)/ + +ci-update: + @VERSION=$$(cat $(VERSION_FILE)); \ + curl "$(UPDATE_SERVER)/update?secret=$(UPDATE_SECRET)&name=$(PROJECT)&platform=godot&version=$$VERSION" + +.PHONY: all build run web export watch clean ci-version ci-export ci-upload ci-update diff --git a/example-tasks.json b/example-tasks.json new file mode 100644 index 0000000..1f50aba --- /dev/null +++ b/example-tasks.json @@ -0,0 +1,35 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + // Copy to .vscode/tasks.json. + "version": "2.0.0", + "tasks": [ + { + "label": "Run", + "type": "shell", + "command": "godot --path .", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Edit", + "type": "shell", + "command": "godot -e --path .", + "problemMatcher": [] + }, + { + "label": "Export Web", + "type": "shell", + "command": "make web", + "problemMatcher": [] + }, + { + "label": "Make build", + "type": "shell", + "command": "make build" + } + ] +} diff --git a/example-woodpecker.yaml b/example-woodpecker.yaml new file mode 100644 index 0000000..e2b959d --- /dev/null +++ b/example-woodpecker.yaml @@ -0,0 +1,35 @@ +steps: + - name: version + image: alpine + commands: + - apk add --no-cache git make jq + - make ci-version + + - name: build + image: barichello/godot-ci:4.6 + commands: + - apt-get update && apt-get install -y --no-install-recommends make zip + - make ci-export + + - name: artifact + image: alpine + environment: + DROPAREA_HOST: vps.teletype.hu + DROPAREA_PORT: 2223 + DROPAREA_TARGET_PATH: /home/drop + DROPAREA_USER: drop + DROPAREA_SSH_PASSWORD: + from_secret: droparea_ssh_password + commands: + - apk add --no-cache make openssh-client sshpass + - make ci-upload + + - name: update + image: alpine + environment: + UPDATE_SERVER: https://teletypegames.org + UPDATE_SECRET: + from_secret: update_secret_key + commands: + - apk add --no-cache make curl + - make ci-update