Merge runner image: Java 21, .NET 8, Ruby 3.3
7 files+239−180/7 viewed
| 229 | 229 | macOS and Windows, on x64 and arm64. | |
| 230 | 230 | - **Status.** Not scheduled. | |
| 231 | 231 | ||
| 232 | + | ### No `gh` command in jobs | |
| 233 | + | ||
| 234 | + | The runner does not include the `gh` command, and pointing it at g1t | |
| 235 | + | (`GH_HOST=g1t.sh`) does not work. | |
| 236 | + | ||
| 237 | + | - **Why.** Most of `gh`'s commands use a GraphQL API, and the rest expect | |
| 238 | + | the REST API under `/api/v3` on the same host. g1t's API is REST, at | |
| 239 | + | `api.g1t.sh`. | |
| 240 | + | - **Instead.** Call the API with `curl` and the job's token. See | |
| 241 | + | [calling g1t's API from a job](/guides/actions/#calling-g1ts-api-from-a-job). | |
| 242 | + | - **Status.** Not scheduled. | |
| 243 | + | ||
| 244 | + | ### One Ruby for `ruby/setup-ruby` | |
| 245 | + | ||
| 246 | + | On g1t's machines, `ruby/setup-ruby` finds Ruby 3.3, which the runner | |
| 247 | + | includes, and fails for any other version. | |
| 248 | + | ||
| 249 | + | - **Why.** Its prebuilt Rubies are for other Linux systems, so on Debian it | |
| 250 | + | uses only the Rubies already in `RUNNER_TOOL_CACHE`. | |
| 251 | + | - **Instead.** Use 3.3, run the job in a `container:` with the Ruby you | |
| 252 | + | need (such as `ruby:3.4`), or build it in a step with `ruby-build`. See | |
| 253 | + | [languages and their setup actions](/guides/actions/#languages-and-their-setup-actions). | |
| 254 | + | - **Status.** Not scheduled. | |
| 255 | + | ||
| 232 | 256 | ### Machine sizes, time and storage | |
| 233 | 257 | ||
| 234 | 258 | | Limit | Value | |
| 189 | 189 | ## The runner | |
| 190 | 190 | ||
| 191 | 191 | Jobs run in a fresh sandbox each: Debian with Node 24, Python 3, Go, Rust, | |
| 192 | − | `build-essential`, `git`, `curl`, `jq`, Docker (with Buildx and Compose) | |
| 193 | − | and passwordless `sudo`, in GitHub's layout (`/home/runner/work`, | |
| 194 | − | `RUNNER_TEMP`, `RUNNER_TOOL_CACHE`). | |
| 192 | + | Java 21, .NET 8, Ruby 3.3, `build-essential`, `git`, `curl`, `jq`, Docker | |
| 193 | + | (with Buildx and Compose) and passwordless `sudo`, in GitHub's layout | |
| 194 | + | (`/home/runner/work`, `RUNNER_TEMP`, `RUNNER_TOOL_CACHE`). | |
| 195 | 195 | `runner.os` is `Linux`. `ubuntu-latest`, `ubuntu-24.04` and other Linux | |
| 196 | 196 | labels all run here. A job whose `runs-on` names `self-hosted` waits for one | |
| 197 | 197 | of your [self-hosted runners](/guides/self-hosted-runners/) instead. Setup actions such as | |
| 198 | 198 | `actions/setup-node` and `actions/setup-python` install other versions as | |
| 199 | 199 | they do on GitHub. | |
| 200 | 200 | ||
| 201 | + | ### Languages and their setup actions | |
| 202 | + | ||
| 203 | + | Each language below is on `PATH` from the job's first step, so a workflow | |
| 204 | + | that only runs `java`, `dotnet` or `ruby` needs no setup step. When it has | |
| 205 | + | one, the setup action finds the version that is already there and | |
| 206 | + | downloads nothing. | |
| 207 | + | ||
| 208 | + | | Language | Version | Where | Setup action | | |
| 209 | + | | --- | --- | --- | --- | | |
| 210 | + | | Java | Eclipse Temurin 21 (LTS), JDK | `JAVA_HOME` (also `JAVA_HOME_21_X64`), in `RUNNER_TOOL_CACHE` | `actions/setup-java` with `distribution: temurin` and `java-version: 21` uses it. Other versions and distributions are downloaded. | | |
| 211 | + | | .NET | SDK 8 (LTS) | `DOTNET_ROOT`, `/usr/share/dotnet` | `actions/setup-dotnet` with `dotnet-version: 8.0.x` keeps it when it is the newest 8.0 SDK, and installs other SDKs beside it. | | |
| 212 | + | | Ruby | 3.3, with Bundler | in `RUNNER_TOOL_CACHE` | `ruby/setup-ruby` with `ruby-version: '3.3'` (or a `.ruby-version` naming 3.3) uses it. | | |
| 213 | + | | Node | 24 | `/usr/local/bin` | `actions/setup-node` installs other versions. | | |
| 214 | + | | Python | 3.11 | `/usr/bin/python3` | `actions/setup-python` installs other versions. | | |
| 215 | + | | Go | 1.27 | `/usr/local/go` | `actions/setup-go` installs other versions. | | |
| 216 | + | | Rust | stable, with `rustfmt`, `clippy` and the `wasm32-unknown-unknown` target | `~/.cargo/bin` | `rustup` is there to add toolchains and targets. | | |
| 217 | + | ||
| 218 | + | ```yaml | |
| 219 | + | steps: | |
| 220 | + | - uses: actions/checkout@v5 | |
| 221 | + | - uses: actions/setup-java@v5 | |
| 222 | + | with: | |
| 223 | + | distribution: temurin | |
| 224 | + | java-version: 21 | |
| 225 | + | - run: ./gradlew build | |
| 226 | + | ``` | |
| 227 | + | ||
| 228 | + | Because the sandbox runs Debian, `ruby/setup-ruby` treats it as a | |
| 229 | + | self-hosted runner and uses only the Rubies in `RUNNER_TOOL_CACHE`. A version other than 3.3 fails at that step; install | |
| 230 | + | it in a `run` step instead (for example with `ruby-build`) or run the job | |
| 231 | + | in a `container:` with the Ruby you need, such as `ruby:3.4`. | |
| 232 | + | ||
| 233 | + | The headers that gems and .NET need to build native code (`libyaml`, | |
| 234 | + | `libffi`, `zlib`, OpenSSL, ICU) are installed too. | |
| 235 | + | ||
| 236 | + | ### Calling g1t's API from a job | |
| 237 | + | ||
| 238 | + | The `gh` command is not installed: it needs a GraphQL API, and g1t's API | |
| 239 | + | is REST. Call it with `curl`, using the job's token and the API's address, | |
| 240 | + | which every job has as `GITHUB_API_URL`: | |
| 241 | + | ||
| 242 | + | ```yaml | |
| 243 | + | - name: Comment on the pull request | |
| 244 | + | env: | |
| 245 | + | TOKEN: ${{ github.token }} | |
| 246 | + | run: | | |
| 247 | + | curl -fsS -X POST "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/issues/${{ github.event.number }}/comments" \ | |
| 248 | + | -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ | |
| 249 | + | -d '{"body": "Built."}' | |
| 250 | + | ``` | |
| 251 | + | ||
| 252 | + | The token reaches this repository and does what the job's `permissions:` | |
| 253 | + | say; see [the job's token](#the-jobs-token). The | |
| 254 | + | [API reference](/reference/api/) lists every endpoint. | |
| 255 | + | ||
| 201 | 256 | ### Machine sizes | |
| 202 | 257 | ||
| 203 | 258 | A job runs on the standard machine unless its `runs-on` names a larger |
| 221 | 221 | builds the runner's image on it. `npm run test:deploy` fails while the | |
| 222 | 222 | folder and the file disagree, so a change to the base's Dockerfile cannot | |
| 223 | 223 | merge without the base it describes. Layers go from what changes least to | |
| 224 | − | most (system packages, Go, Rust, the Claude Code CLI), and the apt and npm | |
| 225 | − | caches stay in BuildKit's cache, out of the image. | |
| 224 | + | most (system packages, Go, Rust, Java, .NET and Ruby, the Claude Code | |
| 225 | + | CLI), and the apt and npm caches stay in BuildKit's cache, out of the | |
| 226 | + | image. Ruby is compiled from source in a single step (a few minutes on a | |
| 227 | + | cold cache) that removes its source tree before the layer is written. | |
| 226 | 228 | ||
| 227 | 229 | The base's build cache is the base itself: it is built with | |
| 228 | 230 | `BUILDKIT_INLINE_CACHE`, which records in the image how each layer was | |
| ⋯ | |||
| 444 | 446 | ### What the sandbox has | |
| 445 | 447 | ||
| 446 | 448 | The base image (`services/runner/base/Dockerfile`) has Node 24, npm, git, | |
| 447 | − | Go, zstd, Docker, musl-tools, and Rust stable for the `node` user with | |
| 448 | − | rustfmt, clippy and the `wasm32-unknown-unknown` target, but not | |
| 449 | − | worker-build. The workflow's `rustup target add wasm32-unknown-unknown` is | |
| 449 | + | Go, zstd, Docker, musl-tools, Rust stable for the `node` user with | |
| 450 | + | rustfmt, clippy and the `wasm32-unknown-unknown` target, Java (Temurin 21), | |
| 451 | + | the .NET 8 SDK and Ruby 3.3, but not worker-build or `gh`. Java and Ruby | |
| 452 | + | sit in the tool cache (`/home/runner/_tool/Java_Temurin-Hotspot_jdk/<semver | |
| 453 | + | with + as ->/x64` and `/home/runner/_tool/Ruby/<version>/x64`, each with | |
| 454 | + | an `x64.complete` marker), which is where `actions/setup-java` and | |
| 455 | + | `ruby/setup-ruby` look; .NET is in `/usr/share/dotnet`, owned by `node`, | |
| 456 | + | which is where `actions/setup-dotnet` installs. Bumping one means changing | |
| 457 | + | its version and checksum `ARG`s together (Java's tool cache name is | |
| 458 | + | Adoptium's `version_data.semver`; .NET's SHA-512 is in its release | |
| 459 | + | metadata; Ruby's SHA-256 is in `cache.ruby-lang.org/pub/ruby/index.txt`). | |
| 460 | + | The user docs list what jobs get in | |
| 461 | + | `apps/docs/src/content/docs/guides/actions.md` (The runner). The workflow's `rustup target add wasm32-unknown-unknown` is | |
| 450 | 462 | then a no-op, and worker-build is restored from the cache, installed on a | |
| 451 | 463 | miss. The image job adds `x86_64-unknown-linux-musl` (about 30 MB from | |
| 452 | 464 | `static.rust-lang.org`) and keeps its Cargo target in the cache. worker-build | |
| 813 | 813 | - Not yet: re-running one combination of a matrix alone; signals into a | |
| 814 | 814 | job container's processes on cancel (they reach `docker exec` only). | |
| 815 | 815 | ||
| 816 | + | ### Runner image: Java, .NET and Ruby (built 2026-10-08) | |
| 817 | + | ||
| 818 | + | The base (`services/runner/base/Dockerfile`) adds Temurin 21, the .NET 8 | |
| 819 | + | SDK and Ruby 3.3, placed where the setup actions look so common workflows | |
| 820 | + | run unmodified and download nothing: | |
| 821 | + | ||
| 822 | + | - **Java** in `RUNNER_TOOL_CACHE/Java_Temurin-Hotspot_jdk/<semver, + as | |
| 823 | + | ->/x64` with `x64.complete`; `JAVA_HOME`, `JAVA_HOME_21_X64` and `PATH` | |
| 824 | + | set. `actions/setup-java` (`temurin`, `21`) resolves it from the cache. | |
| 825 | + | - **.NET** in `/usr/share/dotnet` (setup-dotnet's Linux install dir), | |
| 826 | + | owned by `node`; `DOTNET_ROOT` set, telemetry off. `setup-dotnet` with | |
| 827 | + | `8.0.x` keeps it while it is the newest 8.0 SDK, else installs beside it. | |
| 828 | + | - **Ruby** built from source into `RUNNER_TOOL_CACHE/Ruby/<v>/x64` with | |
| 829 | + | `x64.complete`, on `PATH`. On Debian, `ruby/setup-ruby` counts as | |
| 830 | + | self-hosted and uses only the tool cache, so any version but 3.3 fails | |
| 831 | + | (documented in limitations). | |
| 832 | + | ||
| 833 | + | **`gh`: not installed.** With `GH_HOST=g1t.sh`, `gh` treats g1t as | |
| 834 | + | GitHub Enterprise Server: REST under `https://g1t.sh/api/v3` and GraphQL at | |
| 835 | + | `https://g1t.sh/api/graphql`. Both are 404 today (the API is REST at | |
| 836 | + | `api.g1t.sh`, and `GITHUB_GRAPHQL_URL` is empty), and `pr`, `issue`, `repo` | |
| 837 | + | and `run` are GraphQL-first, so even `gh api` alone would need the | |
| 838 | + | `/api/v3` prefix. Jobs call the API with `curl` and `$GITHUB_API_URL` | |
| 839 | + | (documented in the Actions guide). | |
| 840 | + | ||
| 841 | + | **Later:** to make `gh` useful, `g1t.sh/api/v3/*` proxying to the REST API | |
| 842 | + | (enough for `gh api` and `gh auth status`), then a GraphQL subset for the | |
| 843 | + | `pr`/`issue` read paths. Ship `gh` in the base only once those exist. | |
| 844 | + | More preinstalled Rubies (3.2, 3.4) if workflows ask, at roughly 75 MB | |
| 845 | + | each. `setup-dotnet@v5` first installs the current LTS .NET runtime (10, | |
| 846 | + | a 36 MB download) every run before finding SDK 8 already there; | |
| 847 | + | preinstalling that runtime would skip it. | |
| 848 | + | ||
| 849 | + | **Size:** the base went from 3.18 GB to 4.52 GB as `docker image inspect` | |
| 850 | + | reports it (813 MB to about 1.2 GB compressed): Temurin 308 MB (without | |
| 851 | + | `src.zip`), .NET 512 MB (without the SDK's translations), Ruby 74 MB, | |
| 852 | + | headers and ICU 44 MB. | |
| 853 | + | ||
| 816 | 854 | ## A repository that maintains itself | |
| 817 | 855 | ||
| 818 | 856 | > **2026-10-04:** the user asked for Dependabot, GitHub Advanced Security and |
| 213 | 213 | 'echo "python=$(python3 --version | cut -d" " -f2)"', | |
| 214 | 214 | 'echo "go=$(go version | cut -d" " -f3)"', | |
| 215 | 215 | 'echo "rust=$(rustc --version | cut -d" " -f2)"', | |
| 216 | + | 'echo "java=$(java --version | head -n1 | cut -d" " -f2)"', | |
| 217 | + | 'echo "dotnet=$(dotnet --version)"', | |
| 218 | + | 'echo "ruby=$(ruby --version | cut -d" " -f2)"', | |
| 216 | 219 | 'echo "git=$(git --version | cut -d" " -f3)"', | |
| 217 | 220 | 'echo "claude_code=$(claude --version | cut -d" " -f1)"', | |
| 218 | 221 | 'echo "docker=$(dockerd --version | cut -d" " -f3 | tr -d ,)"', |
| 1 | 1 | { | |
| 2 | − | "image": "registry.cloudflare.com/1e6f2cffa3f445920836e8ebe446bb58/g1t-runner:base-20261008-072528b93a0f", | |
| 3 | − | "digest": "sha256:4353ff9d0c113297d487e807b7b4c5d87a475f222345fbf5eb097271553311f5", | |
| 4 | − | "pushed": true, | |
| 5 | − | "inputs": "072528b93a0f6468ab876770e0f4a4a9b10969e6fc49b4cbe9264e1824244914", | |
| 6 | − | "built_at": "2026-10-08T08:13:38.448Z", | |
| 7 | − | "size_bytes": 3175486075, | |
| 2 | + | "image": "registry.cloudflare.com/1e6f2cffa3f445920836e8ebe446bb58/g1t-runner:base-20261008-a314499af03b", | |
| 3 | + | "digest": null, | |
| 4 | + | "pushed": false, | |
| 5 | + | "inputs": "a314499af03bda6a12f906332827ba1b2c23ea781c32e69599050762e5c2ce05", | |
| 6 | + | "built_at": "2026-10-08T19:12:40.565Z", | |
| 7 | + | "size_bytes": 4521302378, | |
| 8 | 8 | "versions": { | |
| 9 | 9 | "node": "v24.21.0", | |
| 10 | 10 | "npm": "11.19.0", | |
| 11 | 11 | "python": "3.11.2", | |
| 12 | 12 | "go": "go1.27.1", | |
| 13 | 13 | "rust": "1.99.0", | |
| 14 | + | "java": "21.0.12.1", | |
| 15 | + | "dotnet": "8.0.425", | |
| 16 | + | "ruby": "3.3.12", | |
| 14 | 17 | "git": "2.39.5", | |
| 15 | 18 | "claude_code": "2.1.291", | |
| 16 | 19 | "docker": "29.8.2", |
| 3 | 3 | # g1t-runner-base: everything a g1t sandbox has apart from the g1t runner | |
| 4 | 4 | # itself. Agents, checks, the merge queue, workflow jobs and g1t.page | |
| 5 | 5 | # builds all run in it: git, Node, Python, Go, Rust (with the formatter, | |
| 6 | − | # the linter, and the wasm32 and musl targets), the usual build tools, | |
| 7 | − | # Docker (Engine, Buildx, Compose), and the Claude Code CLI. | |
| 6 | + | # the linter, and the wasm32 and musl targets), Java (Temurin 21), .NET | |
| 7 | + | # (SDK 8), Ruby (3.3), the usual build tools, Docker (Engine, Buildx, | |
| 8 | + | # Compose), and the Claude Code CLI. | |
| 8 | 9 | # | |
| 9 | 10 | # Built and pushed by `node scripts/deploy.mjs build-base` (by hand, or by | |
| 10 | 11 | # .g1t/workflows/runner-base.yml), which records what it pushed in | |
| ⋯ | |||
| 13 | 14 | # runner builds in seconds. docs/DEPLOYING.md explains the two. | |
| 14 | 15 | # | |
| 15 | 16 | # Layers go from what changes least to what changes most: the system's | |
| 16 | − | # packages, Docker, then Go, then Rust, then the Claude Code CLI on top, so | |
| 17 | − | # a new CLI version rebuilds and pushes one layer. | |
| 17 | + | # packages, Docker, then Go, then Rust, then Java, .NET and Ruby, then the | |
| 18 | + | # Claude Code CLI on top, so a new CLI version rebuilds and pushes one | |
| 19 | + | # layer. | |
| 20 | + | # | |
| 21 | + | # Java and Ruby live in the runner's tool cache (RUNNER_TOOL_CACHE, | |
| 22 | + | # /home/runner/_tool), laid out as the setup actions look for them, so | |
| 23 | + | # `actions/setup-java` (temurin, 21) and `ruby/setup-ruby` (3.3) find them | |
| 24 | + | # there instead of downloading. .NET is in /usr/share/dotnet, where | |
| 25 | + | # `actions/setup-dotnet` installs, so it finds the SDK already there. | |
| 18 | 26 | # | |
| 19 | 27 | # Build context: this folder (nothing is copied from it). | |
| 20 | 28 | ||
| ⋯ | |||
| 108 | 116 | /home/node/.rustup/toolchains/*/share/doc \ | |
| 109 | 117 | /home/node/.rustup/toolchains/*/share/man | |
| 110 | 118 | ||
| 119 | + | USER root | |
| 120 | + | ||
| 121 | + | # What Java, .NET and Ruby need from the system: ICU for .NET, and the | |
| 122 | + | # headers that gems with native extensions compile against (Ruby's own | |
| 123 | + | # were built with them). | |
| 124 | + | RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ | |
| 125 | + | --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ | |
| 126 | + | apt-get update \ | |
| 127 | + | && apt-get install -y --no-install-recommends -o Dpkg::Options::=--force-unsafe-io \ | |
| 128 | + | libicu72 libyaml-dev libffi-dev zlib1g-dev libgmp-dev libreadline-dev \ | |
| 129 | + | && rm -rf /var/log/apt /var/log/dpkg.log /var/cache/debconf/*-old | |
| 130 | + | ||
| 131 | + | # Java: Eclipse Temurin 21 (LTS), from Adoptium, in the tool cache under | |
| 132 | + | # the name `actions/setup-java` gives it (Adoptium's semver with `+` | |
| 133 | + | # written as `-`), with the `x64.complete` marker it checks for. The JDK's | |
| 134 | + | # source archive is left out. | |
| 135 | + | ARG TEMURIN_RELEASE=jdk-21.0.12.1+1 | |
| 136 | + | ARG TEMURIN_TOOLCACHE_VERSION=21.0.12-101.0.LTS | |
| 137 | + | ARG TEMURIN_SHA256=ce79869e1307ed8ee1e2baa86a412b1eb5b75d10a01006d788a6f968bcfaee94 | |
| 138 | + | RUN file="$(echo "${TEMURIN_RELEASE#jdk-}" | tr + _)" \ | |
| 139 | + | && tag="$(echo "${TEMURIN_RELEASE}" | sed 's/+/%2B/')" \ | |
| 140 | + | && curl -fsSLo /tmp/jdk.tgz "https://github.com/adoptium/temurin21-binaries/releases/download/${tag}/OpenJDK21U-jdk_x64_linux_hotspot_${file}.tar.gz" \ | |
| 141 | + | && echo "${TEMURIN_SHA256} /tmp/jdk.tgz" | sha256sum -c - \ | |
| 142 | + | && dir="/home/runner/_tool/Java_Temurin-Hotspot_jdk/${TEMURIN_TOOLCACHE_VERSION}" \ | |
| 143 | + | && mkdir -p "$dir/x64" \ | |
| 144 | + | && tar -C "$dir/x64" --strip-components=1 -xzf /tmp/jdk.tgz \ | |
| 145 | + | && rm -f /tmp/jdk.tgz "$dir/x64/lib/src.zip" \ | |
| 146 | + | && touch "$dir/x64.complete" \ | |
| 147 | + | && chown -R node:node /home/runner/_tool | |
| 148 | + | ENV JAVA_HOME=/home/runner/_tool/Java_Temurin-Hotspot_jdk/${TEMURIN_TOOLCACHE_VERSION}/x64 | |
| 149 | + | ENV JAVA_HOME_21_X64=${JAVA_HOME} | |
| 150 | + | ||
| 151 | + | # .NET: the SDK 8 (LTS), from Microsoft's builds, checked against the | |
| 152 | + | # SHA-512 in its release metadata. In /usr/share/dotnet, owned by the | |
| 153 | + | # job's user, so `actions/setup-dotnet` can add other SDKs beside it. The | |
| 154 | + | # SDK's translated messages (about 100 MB) are left out: it speaks English. | |
| 155 | + | ARG DOTNET_SDK_VERSION=8.0.425 | |
| 156 | + | ARG DOTNET_SDK_SHA512=934b8060a7190e5909ad1fd0785db542f487b3bbf6cdd14826b02095fdd0d0394298b1634085eff302928fccc33f7c1a7253e9b87df555fc36fce819bcd2e798 | |
| 157 | + | RUN curl -fsSLo /tmp/dotnet.tgz "https://builds.dotnet.microsoft.com/dotnet/Sdk/${DOTNET_SDK_VERSION}/dotnet-sdk-${DOTNET_SDK_VERSION}-linux-x64.tar.gz" \ | |
| 158 | + | && echo "${DOTNET_SDK_SHA512} /tmp/dotnet.tgz" | sha512sum -c - \ | |
| 159 | + | && mkdir -p /usr/share/dotnet \ | |
| 160 | + | && tar -C /usr/share/dotnet -xzf /tmp/dotnet.tgz \ | |
| 161 | + | && rm /tmp/dotnet.tgz \ | |
| 162 | + | && find /usr/share/dotnet/sdk -type d \( -name cs -o -name de -o -name es -o -name fr -o -name it \ | |
| 163 | + | -o -name ja -o -name ko -o -name pl -o -name pt-BR -o -name ru -o -name tr -o -name zh-Hans -o -name zh-Hant \) \ | |
| 164 | + | -prune -exec rm -rf {} + \ | |
| 165 | + | && chown -R node:node /usr/share/dotnet \ | |
| 166 | + | && ln -s /usr/share/dotnet/dotnet /usr/local/bin/dotnet | |
| 167 | + | ENV DOTNET_ROOT=/usr/share/dotnet \ | |
| 168 | + | DOTNET_NOLOGO=1 \ | |
| 169 | + | DOTNET_CLI_TELEMETRY_OPTOUT=1 \ | |
| 170 | + | DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 \ | |
| 171 | + | DOTNET_MULTILEVEL_LOOKUP=0 | |
| 172 | + | ||
| 173 | + | # Ruby 3.3, built from ruby-lang.org's source in the tool cache, where | |
| 174 | + | # `ruby/setup-ruby` looks on a Debian machine (its prebuilt Rubies are for | |
| 175 | + | # other systems), with the `x64.complete` marker it checks for. The prefix | |
| 176 | + | # is fixed when Ruby is built, so it is built in place. One step, so the | |
| 177 | + | # source and objects never reach a layer, and the previous base's inline | |
| 178 | + | # cache covers it. | |
| 179 | + | ARG RUBY_VERSION=3.3.12 | |
| 180 | + | ARG RUBY_SHA256=b06d63beae271933033e27f0a389bc582a009e7845357d44365c39de525a051b | |
| 181 | + | RUN prefix="/home/runner/_tool/Ruby/${RUBY_VERSION}/x64" \ | |
| 182 | + | && curl -fsSLo /tmp/ruby.tgz "https://cache.ruby-lang.org/pub/ruby/${RUBY_VERSION%.*}/ruby-${RUBY_VERSION}.tar.gz" \ | |
| 183 | + | && echo "${RUBY_SHA256} /tmp/ruby.tgz" | sha256sum -c - \ | |
| 184 | + | && mkdir /tmp/ruby && tar -C /tmp/ruby --strip-components=1 -xzf /tmp/ruby.tgz \ | |
| 185 | + | && cd /tmp/ruby \ | |
| 186 | + | && ./configure --prefix="$prefix" --enable-shared --disable-install-doc \ | |
| 187 | + | && make -j"$(nproc)" \ | |
| 188 | + | && make install \ | |
| 189 | + | && cd / && rm -rf /tmp/ruby /tmp/ruby.tgz \ | |
| 190 | + | && "$prefix/bin/ruby" -ropenssl -rpsych -rzlib -rfiddle -e 'puts RUBY_DESCRIPTION' \ | |
| 191 | + | && touch "$prefix.complete" \ | |
| 192 | + | && chown -R node:node "/home/runner/_tool/Ruby" | |
| 193 | + | ENV PATH=${JAVA_HOME}/bin:/home/runner/_tool/Ruby/${RUBY_VERSION}/x64/bin:$PATH | |
| 194 | + | ||
| 195 | + | USER node | |
| 196 | + | ||
| 111 | 197 | # Commits are the g1t agent's; the harness does not sign them as its own. | |
| 112 | 198 | RUN mkdir -p /home/node/.claude \ | |
| 113 | 199 | && echo '{"includeCoAuthoredBy": false}' > /home/node/.claude/settings.json | |