commit fd760dc061fef36b70bfc35e6385a7798ab490d4 Author: Zsolt Tasnadi Date: Thu Jul 16 16:58:37 2026 +0200 initial commit: C64 (acme+VICE) Makefile, woodpecker, metadata and vscode tasks templates Co-Authored-By: Claude Fable 5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..299560f --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# c64-tools + +CI/CD templates for Commodore 64 (ACME + VICE) game projects, in the same +spirit as [tic80-tools](../tic80-tools). + +- `example-makefile.make` — project Makefile: local dev targets + (`deps`, `build`, `run`, `clear`, `rebuild`, `rebuildrun`) plus the + Woodpecker pipeline targets (`ci-version`, `ci-build`, `ci-artifact`, + `ci-update`). +- `example-woodpecker.yaml` — Woodpecker pipeline: version → build + (Debian, `apt install acme`) → artifact (scp to the droparea) → + update (calls the teletypegames `/update` endpoint with + `platform=c64`). +- `example-metadata.json` — catalog metadata; the `version` field drives + `ci-version`, the rest (`name`, `title`, `author`, `desc`, `site`, + `license`) is what `SoftwareUpdater::C64Service` writes into the DB. +- `example-tasks.json` — VS Code `.vscode/tasks.json` wrapping the local + make targets. + +## Usage in a game repo + +1. Copy `example-makefile.make` to `Makefile`, set `PROJECT` (and + `TARGET` if the .prg name differs from `$(PROJECT).prg`). +2. Copy `example-metadata.json` to `metadata.json` and fill it in; + `name` must match `PROJECT`. +3. Copy `example-woodpecker.yaml` to `.woodpecker.yaml` and add the + `droparea_ssh_password` / `update_secret_key` secrets in Woodpecker. +4. Copy `example-tasks.json` to `.vscode/tasks.json`. + +The pipeline uploads `$(PROJECT)-$(VERSION).prg` and +`$(PROJECT)-$(VERSION).metadata.json` to the droparea, then triggers +`/update?platform=c64&name=$(PROJECT)&version=$(VERSION)`, which +creates/updates the Software row and a Release with `cartridge_path`. diff --git a/example-makefile.make b/example-makefile.make new file mode 100644 index 0000000..686d1e9 --- /dev/null +++ b/example-makefile.make @@ -0,0 +1,91 @@ +# ----------------------------------------- +# Makefile – C64 project builder (ACME + VICE) +# ----------------------------------------- + +PROJECT = example + +ASM = acme +EMU = x64sc +SRC = main.asm +SRCS = $(wildcard *.asm) +TARGET ?= $(PROJECT).prg + +METADATA = metadata.json + +UNAME_S := $(shell uname -s) + +# CI/CD variables +VERSION_FILE = .version +DROPAREA_HOST ?= vps.teletype.hu +DROPAREA_PORT ?= 2223 +DROPAREA_TARGET_PATH ?= /home/drop +DROPAREA_USER ?= drop +UPDATE_SERVER ?= https://games.vps.teletype.hu + +all: build + +deps: +ifeq ($(UNAME_S),Darwin) + @command -v brew >/dev/null 2>&1 || { echo "Homebrew kell ehhez. Telepitsd: https://brew.sh"; exit 1; } + brew install acme vice +else + @echo "A 'deps' target csak macOS-en (Darwin) automatikus. Detektalt OS: $(UNAME_S)" + @echo "Telepitsd kezzel: acme assembler + VICE emulator (x64sc)." + @exit 1 +endif + +build: $(TARGET) + +$(TARGET): $(SRCS) + $(ASM) -f cbm -o $(TARGET) $(SRC) + +run: build + $(EMU) $(TARGET) + +clear: + rm -f $(TARGET) $(PROJECT)-*.prg $(PROJECT)-*.metadata.json $(VERSION_FILE) + +rebuild: clear build + +rebuildrun: clear build run + +# ----------------------------------------- +# CI/CD Pipeline targets +# ----------------------------------------- + +ci-version: + @VERSION=$$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' $(METADATA) | head -n 1); \ + if [ -z "$$VERSION" ]; then \ + echo "ERROR: no \"version\" field in $(METADATA)!"; \ + exit 1; \ + fi; \ + BRANCH=$${CI_COMMIT_BRANCH:-$${WOODPECKER_BRANCH}}; \ + BRANCH=$$(echo "$$BRANCH" | tr '/' '-'); \ + if [ "$$BRANCH" != "main" ] && [ "$$BRANCH" != "master" ] && [ -n "$$BRANCH" ]; then \ + VERSION=dev-$$VERSION-$$BRANCH; \ + fi; \ + echo "VERSION is: $$VERSION"; \ + echo $$VERSION > $(VERSION_FILE) + +ci-build: build + @VERSION=$$(cat $(VERSION_FILE)); \ + echo "==> Creating versioned files for $$VERSION"; \ + cp $(TARGET) $(PROJECT)-$$VERSION.prg; \ + cp $(METADATA) $(PROJECT)-$$VERSION.metadata.json; \ + ls -lh $(PROJECT)-$$VERSION.* + +ci-artifact: + @VERSION=$$(cat $(VERSION_FILE)); \ + echo "==> Uploading artifacts for version $$VERSION"; \ + SCP_TARGET="$(DROPAREA_USER)@$(DROPAREA_HOST):$(DROPAREA_TARGET_PATH)/"; \ + sshpass -p "$(DROPAREA_SSH_PASSWORD)" scp -o StrictHostKeyChecking=no -P $(DROPAREA_PORT) \ + $(PROJECT)-$$VERSION.prg \ + $(PROJECT)-$$VERSION.metadata.json \ + $$SCP_TARGET + +ci-update: + @VERSION=$$(cat $(VERSION_FILE)); \ + echo "==> Triggering update for version $$VERSION"; \ + curl "$(UPDATE_SERVER)/update?secret=$(UPDATE_SECRET)&name=$(PROJECT)&platform=c64&version=$$VERSION" + +.PHONY: all deps build run clear rebuild rebuildrun ci-version ci-build ci-artifact ci-update diff --git a/example-metadata.json b/example-metadata.json new file mode 100644 index 0000000..0d482b0 --- /dev/null +++ b/example-metadata.json @@ -0,0 +1,9 @@ +{ + "name": "example", + "title": "Example C64 Game", + "author": "Teletype Games", + "desc": "Short description of the game.", + "site": "https://git.teletype.hu/games/example", + "license": "MIT", + "version": "1.0.0" +} diff --git a/example-tasks.json b/example-tasks.json new file mode 100644 index 0000000..9de1d66 --- /dev/null +++ b/example-tasks.json @@ -0,0 +1,45 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "deps", + "type": "shell", + "command": "make deps", + "problemMatcher": [] + }, + { + "label": "build", + "type": "shell", + "command": "make build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [] + }, + { + "label": "run", + "type": "shell", + "command": "make run", + "problemMatcher": [] + }, + { + "label": "clear", + "type": "shell", + "command": "make clear", + "problemMatcher": [] + }, + { + "label": "rebuild", + "type": "shell", + "command": "make rebuild", + "problemMatcher": [] + }, + { + "label": "rebuildrun", + "type": "shell", + "command": "make rebuildrun", + "problemMatcher": [] + } + ] +} diff --git a/example-woodpecker.yaml b/example-woodpecker.yaml new file mode 100644 index 0000000..a51c43f --- /dev/null +++ b/example-woodpecker.yaml @@ -0,0 +1,35 @@ +steps: + - name: version + image: alpine + commands: + - 'apk add --no-cache make' + - 'make ci-version' + + - name: build + image: debian:stable-slim + commands: + - 'apt-get update && apt-get install -y --no-install-recommends make acme' + - 'make ci-build' + + - 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-artifact' + + - name: update + image: alpine + environment: + UPDATE_SERVER: https://games.vps.teletype.hu + UPDATE_SECRET: + from_secret: update_secret_key + commands: + - 'apk add --no-cache make curl' + - 'make ci-update'