ce0bd2221c
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>
4.0 KiB
4.0 KiB
tinqs/ci
CI toolchain for Tinqs Studio — composite Gitea Actions and the Lambda dispatcher that orchestrates Spot runners.
Architecture
Push → Gitea webhook → Lambda (tinqs-ci-dispatch) → EC2 Spot instance → act_runner → job → self-terminate
Runners are ephemeral: one job per instance, self-terminates on completion. Actions are pre-cached on the runner to avoid repeated clones.
Actions
| Action | What it does |
|---|---|
tinqs/ci/checkout@v1 |
Clone a repo from tinqs.com (supports sparse checkout, depth control, token auth) |
tinqs/ci/setup-go@v1 |
Install Go (skips if pre-baked in AMI) |
tinqs/ci/setup-node@v1 |
Install Node.js + pnpm (skips if pre-baked) |
tinqs/ci/setup-aws@v1 |
Install AWS CLI + optional ECR login |
steps:
- uses: tinqs/ci/checkout@v1
with:
sparse: 'cmd/tstudio'
- uses: tinqs/ci/setup-go@v1
- uses: tinqs/ci/setup-aws@v1
with:
ecr-login: 'true'
Dispatcher (Lambda)
orchestrator/dispatch/main.go — receives Gitea webhooks, evaluates workflow triggers, launches Spot instances with the right label.
| Label | Instance | Use |
|---|---|---|
go |
t3.small | Go builds (tstudio, proxy, docgen) |
docker |
t3.medium | Docker image builds (platform, bot) |
deploy |
t3.micro | S3 sync, ECS update |
node |
t3.medium | Frontend builds |
godot |
t3.medium | Game exports (future) |
Runner Images
Dockerfiles in images/ — lean, purpose-built. Push to ECR with images/build-all.sh.
Deploying
The dispatcher Lambda can't CI itself — deploy manually:
cd orchestrator/dispatch
# Build
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bootstrap -ldflags "-s -w" .
# Zip (PowerShell on Windows, zip on Mac/Linux)
# Windows:
powershell -Command "Compress-Archive -Path bootstrap -DestinationPath function.zip -Force"
# Mac/Linux:
zip -j function.zip bootstrap
# Deploy
aws lambda update-function-code --region eu-west-1 \
--function-name tinqs-ci-dispatch \
--zip-file fileb://function.zip
# Verify
aws lambda invoke --region eu-west-1 --function-name tinqs-ci-dispatch \
--payload '{}' /dev/null --query 'StatusCode'
Lambda env vars (configured in AWS, not in code):
| Var | Purpose |
|---|---|
GITEA_URL |
https://tinqs.com |
GITEA_TOKEN |
API token for fetching workflows and runner git auth |
RUNNER_TOKEN |
act_runner registration token |
RUNNER_AMI |
Pre-baked AMI with Go, Node, Docker, act_runner |
SUBNET |
VPC subnet for Spot instances |
SECURITY_GROUP |
SG allowing outbound HTTPS |
DDB_TABLE |
DynamoDB table for run tracking |
INSTANCE_PROFILE |
IAM role for runner instances |
Contributing
This repo is private. Only Tinqs team members contribute.
Adding a new action
- Create
<action-name>/action.yml(composite, shell: bash) - Keep it simple — no Node.js runtime, just bash
- Add to the table in this README
- Push to main — actions are resolved via
@v1(main branch)
Modifying the dispatcher
- Edit
orchestrator/dispatch/main.go - Test locally:
go build . && echo '{}' | ./dispatch(dry run) - Deploy manually (see Deploying above)
- Verify: push a change to
tinqs/studioand check the pipeline
Runner images
- Edit
images/<name>/Dockerfile - Build:
cd images && ./build-all.sh v1 - Requires Docker + ECR login (
aws ecr get-login-password | docker login ...)
Monitoring
# Check for zombie runners (should be 0 except during active builds)
aws ec2 describe-instances --region eu-west-1 \
--filters "Name=tag:tinqs-ci,Values=true" "Name=instance-state-name,Values=running" \
--query 'Reservations[].Instances[].InstanceId'
# Lambda dispatch logs
MSYS_NO_PATHCONV=1 aws logs tail '/aws/lambda/tinqs-ci-dispatch' --region eu-west-1
# Build logs (via Gitea API)
curl -s "https://tinqs.com/api/v1/repos/tinqs/studio/actions/jobs/<ID>/logs" \
-H "Authorization: token $TOKEN"
Full debug guide: tinqs/docs/.cursor/skills/ci-pipeline-discipline/SKILL.md