tinqs/ci — composite actions + Lambda dispatcher for Spot CI runners

Actions: checkout, setup-go, setup-node, setup-aws
Dispatcher: Lambda → EC2 Spot (ephemeral, self-terminating)
Images: base, go, node, docker, deploy, godot

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 01:20:05 +01:00
commit 501953c636
21 changed files with 1722 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
# tinqs/ci base — shared foundation for all runner images
# Alpine + git + bash + curl + AWS CLI + ssh
# Every other image builds FROM this.
FROM alpine:3.23
RUN apk add --no-cache \
bash git curl wget unzip tar \
ca-certificates openssh-client \
tzdata
# AWS CLI (needed by almost every workflow)
RUN curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip && \
unzip -q /tmp/awscli.zip -d /tmp && \
/tmp/aws/install && \
rm -rf /tmp/awscli.zip /tmp/aws
RUN git --version && aws --version
WORKDIR /workspace
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
# Build all Tinqs CI runner images and push to ECR
set -euo pipefail
AWS_REGION="${AWS_REGION:-eu-west-1}"
ACCOUNT_ID="${ACCOUNT_ID:-149751500842}"
ECR_BASE="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
TAG="${1:-latest}"
echo "=== Logging into ECR ==="
aws ecr get-login-password --region "${AWS_REGION}" | \
docker login --username AWS --password-stdin "${ECR_BASE}"
# Ensure ECR repos exist
for NAME in tinqs-runner-base tinqs-runner-go tinqs-runner-node tinqs-runner-docker tinqs-runner-deploy tinqs-runner-godot; do
aws ecr describe-repositories --repository-names "$NAME" --region "$AWS_REGION" 2>/dev/null || \
aws ecr create-repository --repository-name "$NAME" --region "$AWS_REGION" --no-cli-pager
done
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# 1. Base (everything depends on this)
echo "=== Building base ==="
docker build -t "${ECR_BASE}/tinqs-runner-base:${TAG}" -t "${ECR_BASE}/tinqs-runner-base:latest" "$SCRIPT_DIR/base"
docker push "${ECR_BASE}/tinqs-runner-base:${TAG}"
docker push "${ECR_BASE}/tinqs-runner-base:latest"
BASE_ARG="--build-arg BASE_IMAGE=${ECR_BASE}/tinqs-runner-base:${TAG}"
# 2. All others in parallel (they only depend on base)
build_and_push() {
local name=$1
local dir=$2
local extra_args="${3:-}"
echo "=== Building ${name} ==="
docker build $extra_args -t "${ECR_BASE}/tinqs-runner-${name}:${TAG}" -t "${ECR_BASE}/tinqs-runner-${name}:latest" "$SCRIPT_DIR/$dir"
docker push "${ECR_BASE}/tinqs-runner-${name}:${TAG}"
docker push "${ECR_BASE}/tinqs-runner-${name}:latest"
echo "=== Done ${name} ==="
}
build_and_push "go" "go" "$BASE_ARG" &
build_and_push "node" "node" "$BASE_ARG" &
build_and_push "deploy" "deploy" "$BASE_ARG" &
build_and_push "docker" "docker" "" &
# godot is optional — uncomment when game CI is ready
# build_and_push "godot" "godot" "$BASE_ARG" &
wait
echo "=== All images built and pushed (tag: ${TAG}) ==="
+10
View File
@@ -0,0 +1,10 @@
# tinqs/ci deploy — lightweight deploy-only runner
# Used by: deploy-arikigame, release
# runs-on: deploy
# Smallest image — just AWS CLI + SSH for S3 sync, CloudFront invalidation, ECS updates.
ARG BASE_IMAGE=tinqs-runner-base:latest
FROM ${BASE_IMAGE}
# Nothing extra needed — base already has aws, git, ssh, curl
RUN aws --version && ssh -V
+27
View File
@@ -0,0 +1,27 @@
# tinqs/ci docker — Docker builds (platform image, bot image)
# Used by: build (platform), deploy-bot
# runs-on: docker
# Based on docker:dind for Docker-in-Docker support.
FROM docker:29-dind
RUN apk add --no-cache \
bash git curl wget unzip tar \
ca-certificates openssh-client \
build-base s6 tzdata
# AWS CLI
RUN curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip && \
unzip -q /tmp/awscli.zip -d /tmp && \
/tmp/aws/install && \
rm -rf /tmp/awscli.zip /tmp/aws
# Go (needed for platform Docker builds that compile inside container)
ARG GO_VERSION=1.26.2
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -C /usr/local -xz
ENV PATH="/usr/local/go/bin:/go/bin:${PATH}"
ENV GOPATH="/go"
RUN docker --version && aws --version && go version
WORKDIR /workspace
+15
View File
@@ -0,0 +1,15 @@
# tinqs/ci go — Go builds (platform, CLI, proxy)
# Used by: build-tstudio, deploy-proxy
# runs-on: go
ARG BASE_IMAGE=tinqs-runner-base:latest
FROM ${BASE_IMAGE}
ARG GO_VERSION=1.26.2
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -C /usr/local -xz
ENV PATH="/usr/local/go/bin:/go/bin:${PATH}"
ENV GOPATH="/go"
RUN go version
+27
View File
@@ -0,0 +1,27 @@
# tinqs/ci godot — headless Godot for game builds and export
# Used by: ariki-game build pipeline (future)
# runs-on: godot
# Headless Godot 4.6 + export templates for Windows/Linux/Web.
ARG BASE_IMAGE=tinqs-runner-base:latest
FROM ${BASE_IMAGE}
ARG GODOT_VERSION=4.6.2
# Headless Godot editor (for --headless --export-all)
RUN curl -fsSL "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
-o /tmp/godot.zip && \
unzip -q /tmp/godot.zip -d /tmp && \
mv /tmp/Godot_v${GODOT_VERSION}-stable_linux.x86_64 /usr/local/bin/godot && \
chmod +x /usr/local/bin/godot && \
rm -f /tmp/godot.zip
# Export templates
RUN mkdir -p /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable && \
curl -fsSL "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_export_templates.tpz" \
-o /tmp/templates.tpz && \
unzip -q /tmp/templates.tpz -d /tmp/templates && \
mv /tmp/templates/templates/* /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable/ && \
rm -rf /tmp/templates.tpz /tmp/templates
RUN godot --headless --version
+13
View File
@@ -0,0 +1,13 @@
# tinqs/ci node — Node.js builds (docs, frontend)
# Used by: deploy-docs
# runs-on: node
ARG BASE_IMAGE=tinqs-runner-base:latest
FROM ${BASE_IMAGE}
ARG NODE_VERSION=22
RUN apk add --no-cache nodejs npm && \
npm install -g pnpm
RUN node --version && pnpm --version