diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml new file mode 100644 index 0000000000..0ce6406657 --- /dev/null +++ b/.github/workflows/containers.yml @@ -0,0 +1,38 @@ +name: containers + +on: + push: + branches: + - dev + paths: + - packages/containers/** + - .github/workflows/containers.yml + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + build: + runs-on: blacksmith-4vcpu-ubuntu-2404 + env: + REGISTRY: ghcr.io/${{ github.repository_owner }} + TAG: "24.04" + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/setup-bun + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push containers + run: bun ./packages/containers/script/build.ts --push + env: + REGISTRY: ${{ env.REGISTRY }} + TAG: ${{ env.TAG }} diff --git a/packages/containers/README.md b/packages/containers/README.md new file mode 100644 index 0000000000..42190f0ba6 --- /dev/null +++ b/packages/containers/README.md @@ -0,0 +1,36 @@ +# CI containers + +Prebuilt images intended to speed up GitHub Actions jobs by baking in +large, slow-to-install dependencies. These are designed for Linux jobs +that can use `job.container` in workflows. + +Images + +- `base`: Ubuntu 24.04 with common build tools and utilities +- `bun-node`: `base` plus Bun and Node.js 24 +- `rust`: `bun-node` plus Rust (stable, minimal profile) +- `tauri-linux`: `rust` plus Tauri Linux build dependencies +- `publish`: `bun-node` plus Docker CLI and AUR tooling + +Build + +``` +REGISTRY=ghcr.io/anomalyco TAG=24.04 bun ./packages/containers/script/build.ts +``` + +Workflow usage + +``` +jobs: + build-cli: + runs-on: ubuntu-latest + container: + image: ghcr.io/anomalyco/build/bun-node:24.04 +``` + +Notes + +- These images only help Linux jobs. macOS and Windows jobs cannot run + inside Linux containers. +- If a job uses Docker Buildx, the container needs access to the host + Docker daemon (or `docker-in-docker` with privileged mode). diff --git a/packages/containers/base/Dockerfile b/packages/containers/base/Dockerfile new file mode 100644 index 0000000000..a81f4baa22 --- /dev/null +++ b/packages/containers/base/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + ca-certificates \ + curl \ + git \ + jq \ + openssh-client \ + pkg-config \ + python3 \ + unzip \ + xz-utils \ + zip \ + && rm -rf /var/lib/apt/lists/* diff --git a/packages/containers/bun-node/Dockerfile b/packages/containers/bun-node/Dockerfile new file mode 100644 index 0000000000..69c7803964 --- /dev/null +++ b/packages/containers/bun-node/Dockerfile @@ -0,0 +1,22 @@ +ARG REGISTRY=ghcr.io/anomalyco +FROM ${REGISTRY}/build/base:24.04 + +ARG NODE_VERSION=24.4.0 +ARG BUN_VERSION=1.2.4 + +ENV BUN_INSTALL=/opt/bun +ENV PATH=/opt/bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN set -euo pipefail; \ + arch=$(uname -m); \ + node_arch=x64; \ + if [ "$arch" = "aarch64" ]; then node_arch=arm64; fi; \ + curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz" \ + | tar -xJf - -C /usr/local --strip-components=1; \ + corepack enable + +RUN set -euo pipefail; \ + curl -fsSL https://bun.sh/install | bash -s -- "bun-v${BUN_VERSION}"; \ + bun --version; \ + node --version; \ + npm --version diff --git a/packages/containers/publish/Dockerfile b/packages/containers/publish/Dockerfile new file mode 100644 index 0000000000..4780d22740 --- /dev/null +++ b/packages/containers/publish/Dockerfile @@ -0,0 +1,10 @@ +ARG REGISTRY=ghcr.io/anomalyco +FROM ${REGISTRY}/build/bun-node:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + docker.io \ + pacman-package-manager \ + && rm -rf /var/lib/apt/lists/* diff --git a/packages/containers/rust/Dockerfile b/packages/containers/rust/Dockerfile new file mode 100644 index 0000000000..533f348be7 --- /dev/null +++ b/packages/containers/rust/Dockerfile @@ -0,0 +1,13 @@ +ARG REGISTRY=ghcr.io/anomalyco +FROM ${REGISTRY}/build/bun-node:24.04 + +ARG RUST_TOOLCHAIN=stable + +ENV CARGO_HOME=/opt/cargo +ENV RUSTUP_HOME=/opt/rustup +ENV PATH=/opt/cargo/bin:/opt/bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN set -euo pipefail; \ + curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain "${RUST_TOOLCHAIN}"; \ + rustc --version; \ + cargo --version diff --git a/packages/containers/script/build.ts b/packages/containers/script/build.ts new file mode 100644 index 0000000000..18ae328e1c --- /dev/null +++ b/packages/containers/script/build.ts @@ -0,0 +1,25 @@ +#!/usr/bin/env bun + +import { $ } from "bun" + +const dir = new URL("..", import.meta.url).pathname +process.chdir(dir) + +const reg = process.env.REGISTRY ?? "ghcr.io/anomalyco" +const tag = process.env.TAG ?? "24.04" +const push = process.argv.includes("--push") || process.env.PUSH === "1" + +const images = ["base", "bun-node", "rust", "tauri-linux", "publish"] + +for (const name of images) { + const image = `${reg}/build/${name}:${tag}` + const file = `packages/containers/${name}/Dockerfile` + const arg = name === "base" ? "" : `--build-arg REGISTRY=${reg}` + const cmd = `docker build -f ${file} -t ${image} ${arg} .` + console.log(cmd) + await $`${cmd}` + + if (push) { + await $`docker push ${image}` + } +} diff --git a/packages/containers/tauri-linux/Dockerfile b/packages/containers/tauri-linux/Dockerfile new file mode 100644 index 0000000000..9f67a28049 --- /dev/null +++ b/packages/containers/tauri-linux/Dockerfile @@ -0,0 +1,12 @@ +ARG REGISTRY=ghcr.io/anomalyco +FROM ${REGISTRY}/build/rust:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + libappindicator3-dev \ + libwebkit2gtk-4.1-dev \ + librsvg2-dev \ + patchelf \ + && rm -rf /var/lib/apt/lists/* diff --git a/packages/containers/tsconfig.json b/packages/containers/tsconfig.json new file mode 100644 index 0000000000..00ef125468 --- /dev/null +++ b/packages/containers/tsconfig.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@tsconfig/bun/tsconfig.json", + "compilerOptions": { + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "noUncheckedIndexedAccess": false + } +}