From e8d16a6269545917a07a89bf80db443ddd4d875d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=A4=96=20OpenCode=20for=20Michael=20Conrad?= Date: Mon, 9 Nov 2026 19:00:44 -0500 Subject: [PATCH] =?UTF-8?q?feat(#11):=20convert=20the=20deploy=20target=20?= =?UTF-8?q?to=20itch.io=20=E2=80=94=20repo-local=20push=20tooling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the BoundPronouns pattern, adapted to this repo's state: - itch-push.sh: conf presence + REPLACE_ME guards, butler resolution PATH -> vendored .tools/butler/, per-channel pushes (win-linux-mac, android) with status receipts; artifact paths come from itch.conf operator config (the existing APK/JAR deploy source — staged dist/ copies), not build-output globs; no version labels (butler auto-numbering stands). - itch.conf.example: binds the push target cherokee-language/cherokee-language-animals; artifact paths are REPLACE_ME placeholders, never hardcoded in tracked files. - .gitignore: /itch.conf and /.tools/butler/ (local-only state). --- .gitignore | 4 +++ itch-push.sh | 90 +++++++++++++++++++++++++++++++++++++++++++++++ itch.conf.example | 22 ++++++++++++ 3 files changed, 116 insertions(+) create mode 100755 itch-push.sh create mode 100644 itch.conf.example diff --git a/.gitignore b/.gitignore index 4ddd2303..8ffa8270 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,7 @@ build/ .import/ export_presets.cfg /.opencode/ + +## itch.io deployment tooling (itch-push.sh) — local-only +/itch.conf +/.tools/butler/ diff --git a/itch-push.sh b/itch-push.sh new file mode 100755 index 00000000..8108576c --- /dev/null +++ b/itch-push.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# itch-push.sh — push the published Cherokee Language Animals artifacts +# (the existing APK/JAR deploy source) to itch.io via butler. +# +# This repo builds nothing: the artifact paths come from itch.conf +# (operator config), pointing at the existing published artifacts — +# e.g. the staged dist/ copies — never at a build output. +# +# Prerequisites (all one-time, developer-side): +# 1. butler installed — either on PATH, or vendored at .tools/butler/butler. +# To vendor into the repo (gitignored), run one of: +# curl -L https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default -o butler.zip +# mkdir -p .tools/butler && unzip butler.zip -d .tools/butler && chmod +x .tools/butler/butler && rm butler.zip +# 2. `butler login` run once (opens a browser; writes butler's own credential store). +# 3. itch.conf filled with the real itch.io target (ITCH_USER, ITCH_GAME) +# and the artifact paths (ITCH_JAR, ITCH_APK) — see itch.conf.example. + +set -euo pipefail + +cd "$(dirname "$0")" + +# --- Load the itch.io target and artifact paths --------------------------- +if [ ! -f itch.conf ]; then + echo "ERROR: itch.conf not found — run: cp itch.conf.example itch.conf," >&2 + echo " then fill ITCH_USER, ITCH_GAME, ITCH_JAR and ITCH_APK with the" >&2 + echo " real target and the artifact paths." >&2 + exit 1 +fi + +# shellcheck disable=SC1091 +source itch.conf + +: "${ITCH_USER:?ERROR: itch.conf must define ITCH_USER}" +: "${ITCH_GAME:?ERROR: itch.conf must define ITCH_GAME}" +: "${ITCH_JAR:?ERROR: itch.conf must define ITCH_JAR}" +: "${ITCH_APK:?ERROR: itch.conf must define ITCH_APK}" + +if [ "${ITCH_USER}" = "REPLACE_ME" ] || [ "${ITCH_GAME}" = "REPLACE_ME" ] \ + || [ "${ITCH_JAR}" = "REPLACE_ME" ] || [ "${ITCH_APK}" = "REPLACE_ME" ]; then + echo "ERROR: itch.conf still carries REPLACE_ME placeholders — fill in the real itch.io target and artifact paths." >&2 + exit 1 +fi + +# --- Resolve butler: PATH first, then the vendored copy ------------------- +if ! command -v butler >/dev/null 2>&1; then + if [ -x .tools/butler/butler ]; then + BUTLER=".tools/butler/butler" + else + echo "ERROR: butler not found on PATH and .tools/butler/butler is missing." >&2 + echo " Vendor it (one-time):" >&2 + echo " curl -L https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default -o butler.zip" >&2 + echo " mkdir -p .tools/butler && unzip butler.zip -d .tools/butler && chmod +x .tools/butler/butler && rm butler.zip" >&2 + echo " Then authenticate (one-time): butler login" >&2 + exit 1 + fi +else + BUTLER="butler" +fi + +# --- Check the configured artifacts exist --------------------------------- +if [ ! -f "${ITCH_JAR}" ]; then + echo "ERROR: ITCH_JAR does not point at an existing file: ${ITCH_JAR}" >&2 + echo " Point it at the desktop jar in itch.conf (e.g. the staged dist/ copy)." >&2 + exit 1 +fi + +if [ ! -f "${ITCH_APK}" ]; then + echo "ERROR: ITCH_APK does not point at an existing file: ${ITCH_APK}" >&2 + echo " Point it at the release APK in itch.conf (e.g. the staged dist/ copy)." >&2 + exit 1 +fi + +JAR_CHANNEL="${ITCH_USER}/${ITCH_GAME}:win-linux-mac" +APK_CHANNEL="${ITCH_USER}/${ITCH_GAME}:android" + +# --- Push (idempotent patch pushes; first push creates the download) ------ +# No version label is passed: butler's auto-numbering stands. +echo "==> Pushing desktop (win-linux-mac): ${ITCH_JAR}" +"${BUTLER}" push "${ITCH_JAR}" "${JAR_CHANNEL}" + +echo "==> Pushing android: ${ITCH_APK}" +"${BUTLER}" push "${ITCH_APK}" "${APK_CHANNEL}" + +# --- Receipts ------------------------------------------------------------- +echo "==> butler receipt:" +"${BUTLER}" status "${JAR_CHANNEL}" +"${BUTLER}" status "${APK_CHANNEL}" + +echo "Done." diff --git a/itch.conf.example b/itch.conf.example new file mode 100644 index 00000000..07ef2fa1 --- /dev/null +++ b/itch.conf.example @@ -0,0 +1,22 @@ +# itch.io publish target for Cherokee Language Animals — used by itch-push.sh. +# Copy this file to itch.conf and fill in the REPLACE_ME paths; itch.conf is +# gitignored (local-only — do NOT commit it). Do NOT put any passwords or API +# keys here — butler keeps credentials in its own store (`butler login`). +# +# The push target below is the paired itch project +# (https://cherokee-language.itch.io/cherokee-language-animals). +# +# Artifact paths are operator config: point them at the existing published +# APK/JAR deploy source (the staged dist/ copies), not at any build output — +# this repo builds nothing. + +ITCH_USER=cherokee-language +ITCH_GAME=cherokee-language-animals + +# Path to the desktop jar (pushed to the win-linux-mac channel), +# e.g. the staged dist/ copy. +ITCH_JAR=REPLACE_ME + +# Path to the release APK (pushed to the android channel), +# e.g. the staged dist/ copy. +ITCH_APK=REPLACE_ME