From 1564c61acc0b84c663d4266361c6fe173a9a9195 Mon Sep 17 00:00:00 2001 From: tinqs-limited Date: Fri, 22 May 2026 18:06:11 +0100 Subject: [PATCH] fix: Alpine compatibility + READMEs + roadmap - setup-node: detect Alpine/Debian, use apk or NodeSource - setup-aws: use pip on Alpine (musl), binary on Debian (glibc) - setup-go: fix version parsing for Alpine (no grep -P) - README per action with usage examples and input docs - PLAN.md: roadmap for runner images, labels, Lambda dispatch --- PLAN.md | 57 +++++++++++++++++++++++++++++++++++++++++++ checkout/README.md | 33 +++++++++++++++++++++++++ setup-aws/README.md | 28 +++++++++++++++++++++ setup-aws/action.yml | 19 ++++++++++++--- setup-go/README.md | 25 +++++++++++++++++++ setup-go/action.yml | 5 ++-- setup-node/README.md | 27 ++++++++++++++++++++ setup-node/action.yml | 24 +++++++++++++----- 8 files changed, 206 insertions(+), 12 deletions(-) create mode 100644 PLAN.md create mode 100644 checkout/README.md create mode 100644 setup-aws/README.md create mode 100644 setup-go/README.md create mode 100644 setup-node/README.md diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..85440cf --- /dev/null +++ b/PLAN.md @@ -0,0 +1,57 @@ +# tinqs/ci — Roadmap + +## Done (2026-05-22) + +- [x] Create `tinqs/ci` repo on tinqs.com +- [x] Composite actions: checkout, setup-go, setup-node, setup-aws +- [x] Wire all 6 studio workflows to `tinqs/ci/*@v1` +- [x] Alpine + Debian compatibility in all actions +- [x] Runner image Dockerfiles: base, go, node, docker, deploy, godot +- [x] Architecture doc: `tinqs/internal/architecture/ci-runner-architecture.md` + +## Next: Runner Images + +Build and push purpose-built images to ECR. Each workflow type gets a lean image. + +| Image | ECR name | Contents | Priority | +|-------|----------|----------|----------| +| base | tinqs-runner-base | Alpine + git + AWS CLI + SSH | High | +| go | tinqs-runner-go | base + Go 1.26 | High | +| node | tinqs-runner-node | base + Node 22 + pnpm | High | +| docker | tinqs-runner-docker | dind + Go + AWS CLI | High | +| deploy | tinqs-runner-deploy | base only | Medium | +| godot | tinqs-runner-godot | base + headless Godot 4.6 | Low (future) | + +**Blocker:** No Docker on Forge, Lightsail unreachable. Options: +1. AWS CodeBuild project to build images from this repo +2. SSH to Lightsail when back online +3. Self-build: add a workflow here that builds images on the current runner + +## Next: Label Routing + +Once images exist: +1. Update ECS task definitions — one per image +2. Register runners with matching labels: `go`, `node`, `docker`, `deploy` +3. Update studio workflows: `runs-on: host` → specific labels +4. Lambda dispatcher (future): webhook → Fargate task with correct image + +## Future: Lambda Dispatch + Cancel + +Lambda code already exists in `tinqs-ltd/docs/lambda/` (ci-dispatch + ci-exec). +Move to `tinqs/studio/deploy/lambda/`, deploy with SAM. + +- DynamoDB table for run tracking (`tinqs-ci-runs`) +- Cancel via `ecs:StopTask` on webhook or timeout +- EventBridge cron for stale task cleanup +- Deploy-only jobs run directly in Lambda (no Fargate needed) + +See: `tinqs/internal/architecture/ci-runner-architecture.md` + +## Future: More Actions + +| Action | Purpose | +|--------|---------| +| `tinqs/ci/setup-python` | Python + pip/uv for ML pipelines | +| `tinqs/ci/deploy-ecs` | ECS update-service wrapper with wait | +| `tinqs/ci/deploy-s3` | S3 sync + CloudFront invalidation | +| `tinqs/ci/notify` | Post build status to Lobster GChat | diff --git a/checkout/README.md b/checkout/README.md new file mode 100644 index 0000000..bba9723 --- /dev/null +++ b/checkout/README.md @@ -0,0 +1,33 @@ +# tinqs/ci/checkout + +Clones a repository from tinqs.com (self-hosted Gitea) using plain `git clone`. + +Works on any runner with git installed — Alpine, Debian, or pre-baked images. No Node.js runtime, no GitHub API dependency. + +## Usage + +```yaml +- uses: tinqs/ci/checkout@v1 +``` + +### With options + +```yaml +- uses: tinqs/ci/checkout@v1 + with: + repository: 'tinqs/engine' # default: current repo + ref: 'tinqs/main' # default: current branch + depth: '0' # default: 1 (shallow) + token: ${{ secrets.TOKEN }} # default: none (public clone) + path: 'engine' # default: . (current dir) +``` + +## Inputs + +| Input | Default | Description | +|-------|---------|-------------| +| `repository` | `${{ github.repository }}` | Repository in `owner/repo` format | +| `ref` | `${{ github.ref_name }}` | Branch or tag | +| `depth` | `1` | Clone depth (0 = full history) | +| `path` | `.` | Directory to clone into | +| `token` | `` | Gitea access token for private repos | diff --git a/setup-aws/README.md b/setup-aws/README.md new file mode 100644 index 0000000..78278cb --- /dev/null +++ b/setup-aws/README.md @@ -0,0 +1,28 @@ +# tinqs/ci/setup-aws + +Installs AWS CLI and optionally logs into ECR. + +Detects Alpine (musl) vs Debian (glibc) and uses the right install method — pip on Alpine, official binary on Debian. Credentials come from the runner environment (IAM task role on Fargate, instance profile on EC2). + +## Usage + +```yaml +- uses: tinqs/ci/setup-aws@v1 +``` + +### With ECR login + +```yaml +- uses: tinqs/ci/setup-aws@v1 + with: + ecr-login: 'true' + ecr-repo: '149751500842.dkr.ecr.eu-west-1.amazonaws.com/tinqs-git' +``` + +## Inputs + +| Input | Default | Description | +|-------|---------|-------------| +| `region` | `eu-west-1` | AWS region | +| `ecr-login` | `false` | Login to ECR after install | +| `ecr-repo` | `` | ECR repository URL (required when ecr-login is true) | diff --git a/setup-aws/action.yml b/setup-aws/action.yml index 8cdb7fd..2c65283 100644 --- a/setup-aws/action.yml +++ b/setup-aws/action.yml @@ -1,5 +1,6 @@ # tinqs/ci/setup-aws — Tinqs Studio CI # Installs AWS CLI and optionally logs into ECR. +# Detects Alpine (musl) vs Debian (glibc) and uses the right install method. # Credentials come from the runner environment (IAM task role on Fargate, instance # profile on EC2/Lightsail) — no explicit key configuration needed. # Composite action — runs directly on the host. @@ -30,10 +31,20 @@ runs: # Install AWS CLI if missing if ! command -v aws &>/dev/null; then echo "Installing AWS CLI..." - curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip - unzip -q /tmp/awscli.zip -d /tmp/aws-install - /tmp/aws-install/aws/install - rm -rf /tmp/awscli.zip /tmp/aws-install + if command -v apk &>/dev/null; then + # Alpine — use pip (AWS CLI v2 binary needs glibc) + apk add --no-cache python3 py3-pip + pip3 install --break-system-packages awscli 2>/dev/null || pip3 install awscli + elif command -v apt-get &>/dev/null; then + # Debian/Ubuntu — use official installer + apt-get update && apt-get install -y unzip curl + curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip + unzip -q /tmp/awscli.zip -d /tmp/aws-install + /tmp/aws-install/aws/install + rm -rf /tmp/awscli.zip /tmp/aws-install + else + echo "ERROR: unsupported package manager" && exit 1 + fi fi aws --version diff --git a/setup-go/README.md b/setup-go/README.md new file mode 100644 index 0000000..9ece09a --- /dev/null +++ b/setup-go/README.md @@ -0,0 +1,25 @@ +# tinqs/ci/setup-go + +Installs Go from go.dev and adds it to PATH. + +Downloads the official tarball — works on any Linux (Alpine, Debian, etc.). Skips installation if the correct version is already present in the runner image. + +## Usage + +```yaml +- uses: tinqs/ci/setup-go@v1 +``` + +### Specific version + +```yaml +- uses: tinqs/ci/setup-go@v1 + with: + go-version: '1.26.2' +``` + +## Inputs + +| Input | Default | Description | +|-------|---------|-------------| +| `go-version` | `1.26.2` | Go version to install | diff --git a/setup-go/action.yml b/setup-go/action.yml index 76fc85f..0db817e 100644 --- a/setup-go/action.yml +++ b/setup-go/action.yml @@ -1,11 +1,12 @@ # tinqs/ci/setup-go — Tinqs Studio CI # Downloads Go from go.dev and adds it to PATH. +# Works on any Linux (Alpine, Debian, etc.) — just a tarball extract. # Skips install if the correct version is already present (pre-baked runner image). # Composite action — runs directly on the host. # Author: Ozan + Claude Code — 2026-05-22 name: 'Tinqs Setup Go' -description: 'Install Go and configure PATH (replaces actions/setup-go)' +description: 'Install Go and configure PATH' inputs: go-version: @@ -20,7 +21,7 @@ runs: # Skip if already installed at correct version if command -v go &>/dev/null; then - CURRENT=$(go version | grep -oP '\d+\.\d+\.\d+' || true) + CURRENT=$(go version | sed 's/.*go//' | cut -d' ' -f1) if [ "$CURRENT" = "$GO_VERSION" ]; then echo "Go $GO_VERSION already installed" go version diff --git a/setup-node/README.md b/setup-node/README.md new file mode 100644 index 0000000..37bf867 --- /dev/null +++ b/setup-node/README.md @@ -0,0 +1,27 @@ +# tinqs/ci/setup-node + +Installs Node.js and optionally pnpm. + +Detects Alpine vs Debian and uses the right package manager (`apk` or NodeSource). Skips installation if the correct major version is already present in the runner image. + +## Usage + +```yaml +- uses: tinqs/ci/setup-node@v1 +``` + +### Options + +```yaml +- uses: tinqs/ci/setup-node@v1 + with: + node-version: '22' # default: 22 + pnpm: 'true' # default: true +``` + +## Inputs + +| Input | Default | Description | +|-------|---------|-------------| +| `node-version` | `22` | Node.js major version | +| `pnpm` | `true` | Install pnpm globally | diff --git a/setup-node/action.yml b/setup-node/action.yml index 173f630..d08c1b4 100644 --- a/setup-node/action.yml +++ b/setup-node/action.yml @@ -1,11 +1,12 @@ # tinqs/ci/setup-node — Tinqs Studio CI -# Installs Node.js via NodeSource and optionally pnpm. +# Installs Node.js and optionally pnpm. +# Detects Alpine vs Debian and uses the right package manager. # Skips install if the correct major version is already present (pre-baked runner image). # Composite action — runs directly on the host. # Author: Ozan + Claude Code — 2026-05-22 name: 'Tinqs Setup Node' -description: 'Install Node.js and pnpm (replaces actions/setup-node)' +description: 'Install Node.js and pnpm' inputs: node-version: @@ -24,17 +25,28 @@ runs: # Skip if already installed at correct major version if command -v node &>/dev/null; then - CURRENT=$(node --version | grep -oP '\d+' | head -1) + CURRENT=$(node --version | sed 's/v//' | cut -d. -f1) if [ "$CURRENT" = "$NODE_VERSION" ]; then echo "Node $NODE_VERSION already installed" node --version - [ "$INSTALL_PNPM" = "true" ] && command -v pnpm &>/dev/null && pnpm --version && exit 0 + if [ "$INSTALL_PNPM" = "true" ] && command -v pnpm &>/dev/null; then + pnpm --version + exit 0 + fi fi fi echo "Installing Node.js $NODE_VERSION..." - curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash - - apt-get install -y nodejs + if command -v apk &>/dev/null; then + # Alpine + apk add --no-cache nodejs npm + elif command -v apt-get &>/dev/null; then + # Debian/Ubuntu + curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash - + apt-get install -y nodejs + else + echo "ERROR: unsupported package manager" && exit 1 + fi if [ "$INSTALL_PNPM" = "true" ]; then npm install -g pnpm