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
This commit is contained in:
@@ -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 |
|
||||||
@@ -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 |
|
||||||
@@ -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) |
|
||||||
+15
-4
@@ -1,5 +1,6 @@
|
|||||||
# tinqs/ci/setup-aws — Tinqs Studio CI
|
# tinqs/ci/setup-aws — Tinqs Studio CI
|
||||||
# Installs AWS CLI and optionally logs into ECR.
|
# 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
|
# Credentials come from the runner environment (IAM task role on Fargate, instance
|
||||||
# profile on EC2/Lightsail) — no explicit key configuration needed.
|
# profile on EC2/Lightsail) — no explicit key configuration needed.
|
||||||
# Composite action — runs directly on the host.
|
# Composite action — runs directly on the host.
|
||||||
@@ -30,10 +31,20 @@ runs:
|
|||||||
# Install AWS CLI if missing
|
# Install AWS CLI if missing
|
||||||
if ! command -v aws &>/dev/null; then
|
if ! command -v aws &>/dev/null; then
|
||||||
echo "Installing AWS CLI..."
|
echo "Installing AWS CLI..."
|
||||||
curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip
|
if command -v apk &>/dev/null; then
|
||||||
unzip -q /tmp/awscli.zip -d /tmp/aws-install
|
# Alpine — use pip (AWS CLI v2 binary needs glibc)
|
||||||
/tmp/aws-install/aws/install
|
apk add --no-cache python3 py3-pip
|
||||||
rm -rf /tmp/awscli.zip /tmp/aws-install
|
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
|
fi
|
||||||
|
|
||||||
aws --version
|
aws --version
|
||||||
|
|||||||
@@ -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 |
|
||||||
+3
-2
@@ -1,11 +1,12 @@
|
|||||||
# tinqs/ci/setup-go — Tinqs Studio CI
|
# tinqs/ci/setup-go — Tinqs Studio CI
|
||||||
# Downloads Go from go.dev and adds it to PATH.
|
# 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).
|
# Skips install if the correct version is already present (pre-baked runner image).
|
||||||
# Composite action — runs directly on the host.
|
# Composite action — runs directly on the host.
|
||||||
# Author: Ozan + Claude Code — 2026-05-22
|
# Author: Ozan + Claude Code — 2026-05-22
|
||||||
|
|
||||||
name: 'Tinqs Setup Go'
|
name: 'Tinqs Setup Go'
|
||||||
description: 'Install Go and configure PATH (replaces actions/setup-go)'
|
description: 'Install Go and configure PATH'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
go-version:
|
go-version:
|
||||||
@@ -20,7 +21,7 @@ runs:
|
|||||||
|
|
||||||
# Skip if already installed at correct version
|
# Skip if already installed at correct version
|
||||||
if command -v go &>/dev/null; then
|
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
|
if [ "$CURRENT" = "$GO_VERSION" ]; then
|
||||||
echo "Go $GO_VERSION already installed"
|
echo "Go $GO_VERSION already installed"
|
||||||
go version
|
go version
|
||||||
|
|||||||
@@ -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 |
|
||||||
+18
-6
@@ -1,11 +1,12 @@
|
|||||||
# tinqs/ci/setup-node — Tinqs Studio CI
|
# 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).
|
# Skips install if the correct major version is already present (pre-baked runner image).
|
||||||
# Composite action — runs directly on the host.
|
# Composite action — runs directly on the host.
|
||||||
# Author: Ozan + Claude Code — 2026-05-22
|
# Author: Ozan + Claude Code — 2026-05-22
|
||||||
|
|
||||||
name: 'Tinqs Setup Node'
|
name: 'Tinqs Setup Node'
|
||||||
description: 'Install Node.js and pnpm (replaces actions/setup-node)'
|
description: 'Install Node.js and pnpm'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
node-version:
|
node-version:
|
||||||
@@ -24,17 +25,28 @@ runs:
|
|||||||
|
|
||||||
# Skip if already installed at correct major version
|
# Skip if already installed at correct major version
|
||||||
if command -v node &>/dev/null; then
|
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
|
if [ "$CURRENT" = "$NODE_VERSION" ]; then
|
||||||
echo "Node $NODE_VERSION already installed"
|
echo "Node $NODE_VERSION already installed"
|
||||||
node --version
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Installing Node.js $NODE_VERSION..."
|
echo "Installing Node.js $NODE_VERSION..."
|
||||||
curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash -
|
if command -v apk &>/dev/null; then
|
||||||
apt-get install -y nodejs
|
# 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
|
if [ "$INSTALL_PNPM" = "true" ]; then
|
||||||
npm install -g pnpm
|
npm install -g pnpm
|
||||||
|
|||||||
Reference in New Issue
Block a user