diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d839026..c34a9f0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,9 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +// README at: https://github.com/devcontainers/templates/tree/main/src/debian { - "name": "Ubuntu", + "name": "Debian Trixie", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/base:noble", + "image": "mcr.microsoft.com/devcontainers/base:trixie", "features": { "ghcr.io/devcontainers/features/docker-in-docker:4": {}, "ghcr.io/pablozaiden/devcontainers-features/bun": {} diff --git a/README.md b/README.md index 1463c10..e296ffc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It does not modify the original `devcontainer.json`. Instead, it generates a der ## What it does -- Discovers `.devcontainer/devcontainer.json` or `.devcontainer.json` in the current directory, can target `.devcontainer//devcontainer.json` with a flag, and falls back to the built-in `ubuntu` template when no repo devcontainer is present. +- Discovers `.devcontainer/devcontainer.json` or `.devcontainer.json` in the current directory, can target `.devcontainer//devcontainer.json` with a flag, and falls back to the built-in Debian Trixie template when no repo devcontainer is present. - Reuses or creates the devcontainer with Docker + Dev Container CLI. - Names the managed container as `devbox--`. - Publishes the same TCP port on host and container. @@ -109,9 +109,9 @@ When you run `devbox up`, the port precedence is: When you run `devbox rebuild`, omitting the port reuses the last stored port for the current workspace. -If no repo devcontainer is found and no previous template source is stored, `devbox up` automatically starts from the built-in `ubuntu` template. `devbox rebuild ` does the same when there is enough information to create the devbox but no prior workspace state exists. Devbox prints a message when this automatic fallback is used. +If no repo devcontainer is found and no previous template source is stored, `devbox up` automatically starts from the built-in Debian Trixie template. `devbox rebuild ` does the same when there is enough information to create the devbox but no prior workspace state exists. Devbox prints a message when this automatic fallback is used. -`devbox rebuild` reuses the previously selected source for the workspace. If the workspace was started from `--template` or the automatic Ubuntu fallback, rebuild uses that saved template again. `rebuild --template ...` is intentionally not supported. +`devbox rebuild` reuses the previously selected source for the workspace. If the workspace was started from `--template` or the automatic Debian Trixie fallback, rebuild uses that saved template again. `rebuild --template ...` is intentionally not supported. GitHub CLI authentication for `GH_TOKEN` injection can be pinned per workspace with `--gh-user ` and optional `--gh-host `. Devbox stores only the selected account metadata in `.devbox/state.json` as `githubAuth`; it does not store the token. Later `up`, `rebuild`, and `arise` runs reuse that account by calling `gh auth token --hostname --user `. The selection precedence is: explicit flags, `DEVBOX_GH_USER` / `DEVBOX_GH_HOST`, saved `.devbox/state.json`, then the currently active `gh` account. @@ -123,7 +123,7 @@ GitHub CLI authentication for `GH_TOKEN` injection can be pinned per workspace w Built-in templates: -- `ubuntu` +- `ubuntu` (Debian Trixie base) - `dotnet` - `typescript` - `python` @@ -216,7 +216,7 @@ The complex example uses several devcontainer features, so the first `up` or `re - `.devbox/` contains all devbox-owned local state (`state.json`, `user-data/`, template generated configs, and `ssh/`) and should stay ignored by version control. - `.devbox/state.json` may include `githubAuth: { "host": "...", "user": "..." }` so tools can detect or preserve the GitHub CLI account devbox will use for future `GH_TOKEN` injection. - `--devcontainer-subpath services/api` tells `devbox` to use `.devcontainer/services/api/devcontainer.json`. -- `--template ` explicitly chooses a built-in template, even if the repo already has a devcontainer definition. If no repo devcontainer exists and no template was previously saved, omitting `--template` falls back to `ubuntu`. +- `--template ` explicitly chooses a built-in template, even if the repo already has a devcontainer definition. If no repo devcontainer exists and no template was previously saved, omitting `--template` falls back to the `ubuntu` template identifier, which uses the Debian Trixie base. - `--gh-user ` and `--gh-host ` select the GitHub CLI account used for `GH_TOKEN` injection without changing the globally active `gh` account. - `devbox shell` opens an interactive shell inside the running managed container for the current workspace. - `devbox status` reports live container state when available and falls back to saved workspace state in `.devbox/state.json` plus the persisted `.devbox/ssh/credentials` password file and `.devbox/ssh/metadata.json` metadata when the container is stopped or Docker is unavailable. diff --git a/examples/complex-workspace/.devcontainer/devcontainer.json b/examples/complex-workspace/.devcontainer/devcontainer.json index 1427e2b..0ebb45f 100644 --- a/examples/complex-workspace/.devcontainer/devcontainer.json +++ b/examples/complex-workspace/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ // Feature-heavy sample workspace used to exercise slower first-time container setup. { "name": "devbox-complex-workspace", - "image": "mcr.microsoft.com/devcontainers/base:noble", + "image": "mcr.microsoft.com/devcontainers/base:trixie", "features": { "ghcr.io/devcontainers/features/azure-cli:1": {}, "ghcr.io/devcontainers/features/docker-in-docker:4": {}, diff --git a/examples/smoke-workspace/.devcontainer/devcontainer.json b/examples/smoke-workspace/.devcontainer/devcontainer.json index 73d14c0..c4d499b 100644 --- a/examples/smoke-workspace/.devcontainer/devcontainer.json +++ b/examples/smoke-workspace/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "devbox-smoke-workspace", - "image": "mcr.microsoft.com/devcontainers/base:noble", + "image": "mcr.microsoft.com/devcontainers/base:trixie", "features": { "ghcr.io/devcontainers/features/docker-in-docker:4": {} } diff --git a/src/cli.ts b/src/cli.ts index aa5837f..884e36e 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -180,7 +180,7 @@ async function handleUpLike( preferStateSource: command === "rebuild", }); if (resolvedConfig.templateSelection === "fallback") { - console.log("No devcontainer definition found; using built-in ubuntu template."); + console.log("No devcontainer definition found; using built-in Debian Trixie template."); } const generatedConfigPath = resolvedConfig.generatedConfigPath; const userDataDir = getWorkspaceUserDataDir(workspacePath); diff --git a/src/core.ts b/src/core.ts index 67f73fa..5824e83 100644 --- a/src/core.ts +++ b/src/core.ts @@ -156,8 +156,8 @@ export function helpText(): string { ` ${CLI_NAME} --help`, "", "Commands:", - " up Start or reuse the managed devcontainer; falls back to the ubuntu template when none is found.", - " rebuild Recreate the managed devcontainer; falls back to the ubuntu template when no repo devcontainer or prior state exists.", + " up Start or reuse the managed devcontainer; falls back to the built-in Debian Trixie template when none is found.", + " rebuild Recreate the managed devcontainer; falls back to the built-in Debian Trixie template when no repo devcontainer or prior state exists.", " shell Open an interactive shell in the running managed container.", " status Print JSON describing the managed devbox for this workspace.", " templates Print JSON describing the built-in templates.", diff --git a/src/templates.ts b/src/templates.ts index 868820f..8c65c73 100644 --- a/src/templates.ts +++ b/src/templates.ts @@ -26,8 +26,8 @@ export interface DevboxTemplateSummary { runnerCompatible: boolean; } -const BASE_IMAGE = "mcr.microsoft.com/devcontainers/base:noble"; -const BASE_NAME = "noble"; +const BASE_IMAGE = "mcr.microsoft.com/devcontainers/base:trixie"; +const BASE_NAME = "trixie"; const DOCKER_IN_DOCKER_FEATURE = "ghcr.io/devcontainers/features/docker-in-docker:4"; const DOTNET_FEATURE = "ghcr.io/devcontainers/features/dotnet:2"; const GO_FEATURE = "ghcr.io/devcontainers/features/go:1"; @@ -40,48 +40,48 @@ const UV_FEATURE = "ghcr.io/devcontainers-extra/features/uv:1"; const TEMPLATE_DEFINITIONS: Record = { ubuntu: createTemplateDefinition({ name: "ubuntu", - description: "Ubuntu noble base image with Docker-in-Docker preinstalled.", - runtimeVersion: "Ubuntu noble", + description: "Debian Trixie base image with Docker-in-Docker preinstalled.", + runtimeVersion: "Debian Trixie", languages: [], }), dotnet: createTemplateDefinition({ name: "dotnet", - description: ".NET SDK on Ubuntu noble via the official devcontainer feature.", + description: ".NET SDK on Debian Trixie via the official devcontainer feature.", runtimeVersion: ".NET SDK", languages: ["dotnet", "csharp", "fsharp"], features: [DOTNET_FEATURE], }), typescript: createTemplateDefinition({ name: "typescript", - description: "Node.js and Bun on Ubuntu noble via devcontainer features.", + description: "Node.js and Bun on Debian Trixie via devcontainer features.", runtimeVersion: "Node.js + Bun", languages: ["node", "bun", "typescript", "javascript"], features: [NODE_FEATURE, BUN_FEATURE], }), python: createTemplateDefinition({ name: "python", - description: "Python workflows on Ubuntu noble via the uv feature.", + description: "Python workflows on Debian Trixie via the uv feature.", runtimeVersion: "Python via uv", languages: ["python"], features: [UV_FEATURE], }), go: createTemplateDefinition({ name: "go", - description: "Go on Ubuntu noble via the official devcontainer feature.", + description: "Go on Debian Trixie via the official devcontainer feature.", runtimeVersion: "Go", languages: ["go"], features: [GO_FEATURE], }), rust: createTemplateDefinition({ name: "rust", - description: "Rust on Ubuntu noble via the official devcontainer feature.", + description: "Rust on Debian Trixie via the official devcontainer feature.", runtimeVersion: "Rust", languages: ["rust"], features: [RUST_FEATURE], }), java: createTemplateDefinition({ name: "java", - description: "Java on Ubuntu noble via the official devcontainer feature.", + description: "Java on Debian Trixie via the official devcontainer feature.", runtimeVersion: "Java", languages: ["java"], features: [JAVA_FEATURE], diff --git a/tests/core.test.ts b/tests/core.test.ts index 8818df1..693af1a 100644 --- a/tests/core.test.ts +++ b/tests/core.test.ts @@ -263,13 +263,13 @@ describe("helpText", () => { expect(text).toContain("help"); }); - test("mentions ubuntu fallback for up and rebuild", () => { + test("mentions the Debian Trixie fallback for up and rebuild", () => { const text = helpText(); expect(text).toContain( - "\n up Start or reuse the managed devcontainer; falls back to the ubuntu template when none is found.", + "\n up Start or reuse the managed devcontainer; falls back to the built-in Debian Trixie template when none is found.", ); expect(text).toContain( - "\n rebuild Recreate the managed devcontainer; falls back to the ubuntu template when no repo devcontainer or prior state exists.", + "\n rebuild Recreate the managed devcontainer; falls back to the built-in Debian Trixie template when no repo devcontainer or prior state exists.", ); }); }); @@ -574,7 +574,7 @@ describe("resolveWorkspaceConfig", () => { expect(rebuildStyleResolution.template?.name).toBe("python"); expect(rebuildStyleResolution.templateSelection).toBe("state"); expect(rebuildStyleResolution.config).toEqual({ - image: "mcr.microsoft.com/devcontainers/base:noble", + image: "mcr.microsoft.com/devcontainers/base:trixie", features: { "ghcr.io/devcontainers/features/docker-in-docker:4": {}, "ghcr.io/devcontainers-extra/features/uv:1": {}, diff --git a/tests/examples.live.test.ts b/tests/examples.live.test.ts index 12f7c9c..c3da365 100644 --- a/tests/examples.live.test.ts +++ b/tests/examples.live.test.ts @@ -88,13 +88,13 @@ afterEach(async () => { describe("example workspaces (real devcontainers)", () => { liveTest( - "template workspace falls back to the ubuntu template without a repo devcontainer", + "template workspace falls back to the Debian Trixie template without a repo devcontainer", async () => { const fixture = await setupLiveFixture("template-workspace"); const up = runCli(fixture, ["up", "--allow-missing-ssh"]); expect(up.exitCode).toBe(0); - expect(up.stdout).toContain("No devcontainer definition found; using built-in ubuntu template."); + expect(up.stdout).toContain("No devcontainer definition found; using built-in Debian Trixie template."); expect(up.stdout).toContain("Devcontainer is ready"); expect(up.stdout).toContain("SSH server:"); expect(up.stdout).toContain("Ready."); diff --git a/tests/examples.test.ts b/tests/examples.test.ts index 52a7bfc..ef7be5b 100644 --- a/tests/examples.test.ts +++ b/tests/examples.test.ts @@ -386,7 +386,7 @@ describe("example workspaces (simulated host tools)", () => { expect(await readFile(String(fixture.sourceConfigPath), "utf8")).toBe(sourceBefore); const generatedConfig = await readJson(fixture.generatedConfigPath); - expect(generatedConfig.image).toBe("mcr.microsoft.com/devcontainers/base:noble"); + expect(generatedConfig.image).toBe("mcr.microsoft.com/devcontainers/base:trixie"); expect(generatedConfig.features).toEqual({ "ghcr.io/devcontainers/features/docker-in-docker:4": {}, }); @@ -527,7 +527,7 @@ describe("example workspaces (simulated host tools)", () => { expect(commandsAfterDown.filter((entry) => entry.tool === "docker" && entry.args[0] === "rm").length).toBeGreaterThanOrEqual(2); }); - test("template-backed workspace lists templates, falls back to ubuntu, and rebuilds from saved state", async () => { + test("template-backed workspace lists templates, falls back to the default template, and rebuilds from saved state", async () => { const fixture = await setupExampleFixture("template-workspace"); const templates = runCli(fixture, ["templates"]); @@ -539,11 +539,11 @@ describe("example workspaces (simulated host tools)", () => { const up = runCli(fixture, ["up", "--allow-missing-ssh"]); expect(up.exitCode).toBe(0); expect(up.stdout).toContain("Using port 5001."); - expect(up.stdout).toContain("No devcontainer definition found; using built-in ubuntu template."); + expect(up.stdout).toContain("No devcontainer definition found; using built-in Debian Trixie template."); expect(existsSync(fixture.generatedConfigPath)).toBe(true); const generatedConfig = await readJson(fixture.generatedConfigPath); - expect(generatedConfig.image).toBe("mcr.microsoft.com/devcontainers/base:noble"); + expect(generatedConfig.image).toBe("mcr.microsoft.com/devcontainers/base:trixie"); expect(generatedConfig.features).toEqual({ "ghcr.io/devcontainers/features/docker-in-docker:4": {}, }); @@ -553,11 +553,11 @@ describe("example workspaces (simulated host tools)", () => { expect(state.configSource).toBe("template"); expect(state.sourceConfigPath).toBeNull(); expect(state.template.name).toBe("ubuntu"); - expect(state.template.image).toBe("mcr.microsoft.com/devcontainers/base:noble"); + expect(state.template.image).toBe("mcr.microsoft.com/devcontainers/base:trixie"); expect(state.template.pinnedReference).toBe( - "mcr.microsoft.com/devcontainers/base:noble + ghcr.io/devcontainers/features/docker-in-docker:4", + "mcr.microsoft.com/devcontainers/base:trixie + ghcr.io/devcontainers/features/docker-in-docker:4", ); - expect(state.template.runtimeVersion).toBe("Ubuntu noble"); + expect(state.template.runtimeVersion).toBe("Debian Trixie"); const statusWhileRunning = runCli(fixture, ["status"]); expect(statusWhileRunning.exitCode).toBe(0); @@ -568,7 +568,7 @@ describe("example workspaces (simulated host tools)", () => { const rebuild = runCli(fixture, ["rebuild", "--allow-missing-ssh"]); expect(rebuild.exitCode).toBe(0); expect(rebuild.stdout).toContain("Using port 5001."); - expect(rebuild.stdout).not.toContain("No devcontainer definition found; using built-in ubuntu template."); + expect(rebuild.stdout).not.toContain("No devcontainer definition found; using built-in Debian Trixie template."); expect(rebuild.stdout).toContain("Ready."); const rebuildWithTemplate = runCli(fixture, ["rebuild", "--template", "python"]); @@ -588,13 +588,13 @@ describe("example workspaces (simulated host tools)", () => { expect(stoppedStatus.templateName).toBe("ubuntu"); }); - test("rebuild without prior state falls back to ubuntu when a port is provided", async () => { + test("rebuild without prior state falls back to the default template when a port is provided", async () => { const fixture = await setupExampleFixture("template-workspace"); const rebuild = runCli(fixture, ["rebuild", "5010", "--allow-missing-ssh"]); expect(rebuild.exitCode).toBe(0); expect(rebuild.stdout).toContain("Using port 5010."); - expect(rebuild.stdout).toContain("No devcontainer definition found; using built-in ubuntu template."); + expect(rebuild.stdout).toContain("No devcontainer definition found; using built-in Debian Trixie template."); expect(existsSync(fixture.generatedConfigPath)).toBe(true); const state = await readJson(fixture.statePath); @@ -604,19 +604,19 @@ describe("example workspaces (simulated host tools)", () => { expect(state.template.name).toBe("ubuntu"); }); - test("workspace without a repo devcontainer reuses a saved non-ubuntu template", async () => { + test("workspace without a repo devcontainer reuses a saved non-default template", async () => { const fixture = await setupExampleFixture("template-workspace"); const explicitTemplateUp = runCli(fixture, ["up", "--template", "python", "--allow-missing-ssh"]); expect(explicitTemplateUp.exitCode).toBe(0); - expect(explicitTemplateUp.stdout).not.toContain("No devcontainer definition found; using built-in ubuntu template."); + expect(explicitTemplateUp.stdout).not.toContain("No devcontainer definition found; using built-in Debian Trixie template."); const down = runCli(fixture, ["down"]); expect(down.exitCode).toBe(0); const upFromState = runCli(fixture, ["up", "--allow-missing-ssh"]); expect(upFromState.exitCode).toBe(0); - expect(upFromState.stdout).not.toContain("No devcontainer definition found; using built-in ubuntu template."); + expect(upFromState.stdout).not.toContain("No devcontainer definition found; using built-in Debian Trixie template."); const state = await readJson(fixture.statePath); expect(state.configSource).toBe("template"); diff --git a/tests/templates.test.ts b/tests/templates.test.ts index 3e33fa7..1286c3f 100644 --- a/tests/templates.test.ts +++ b/tests/templates.test.ts @@ -2,14 +2,14 @@ import { describe, expect, test } from "bun:test"; import { getTemplateDefinition, listTemplateDefinitions, listTemplateSummaries } from "../src/templates"; describe("built-in templates", () => { - test("standardizes every template on the noble base image with docker-in-docker", () => { + test("standardizes every template on the Trixie base image with docker-in-docker", () => { for (const template of listTemplateDefinitions()) { - expect(template.base).toBe("noble"); - expect(template.image).toBe("mcr.microsoft.com/devcontainers/base:noble"); - expect(template.pinnedReference).toContain("mcr.microsoft.com/devcontainers/base:noble"); + expect(template.base).toBe("trixie"); + expect(template.image).toBe("mcr.microsoft.com/devcontainers/base:trixie"); + expect(template.pinnedReference).toContain("mcr.microsoft.com/devcontainers/base:trixie"); expect(template.config).toEqual( expect.objectContaining({ - image: "mcr.microsoft.com/devcontainers/base:noble", + image: "mcr.microsoft.com/devcontainers/base:trixie", features: expect.objectContaining({ "ghcr.io/devcontainers/features/docker-in-docker:4": {}, }), @@ -25,15 +25,15 @@ describe("built-in templates", () => { throw new Error("Expected the built-in typescript template to exist."); } - expect(template.description).toBe("Node.js and Bun on Ubuntu noble via devcontainer features."); - expect(template.base).toBe("noble"); - expect(template.image).toBe("mcr.microsoft.com/devcontainers/base:noble"); + expect(template.description).toBe("Node.js and Bun on Debian Trixie via devcontainer features."); + expect(template.base).toBe("trixie"); + expect(template.image).toBe("mcr.microsoft.com/devcontainers/base:trixie"); expect(template.pinnedReference).toBe( - "mcr.microsoft.com/devcontainers/base:noble + ghcr.io/devcontainers/features/docker-in-docker:4 + ghcr.io/devcontainers/features/node:2 + ghcr.io/devcontainers-extra/features/bun:1", + "mcr.microsoft.com/devcontainers/base:trixie + ghcr.io/devcontainers/features/docker-in-docker:4 + ghcr.io/devcontainers/features/node:2 + ghcr.io/devcontainers-extra/features/bun:1", ); expect(template.runnerCompatible).toBe(true); expect(template.config).toEqual({ - image: "mcr.microsoft.com/devcontainers/base:noble", + image: "mcr.microsoft.com/devcontainers/base:trixie", features: { "ghcr.io/devcontainers/features/docker-in-docker:4": {}, "ghcr.io/devcontainers/features/node:2": {}, @@ -46,12 +46,12 @@ describe("built-in templates", () => { const typescriptTemplate = listTemplateSummaries().find((template) => template.name === "typescript"); expect(typescriptTemplate).toEqual({ name: "typescript", - description: "Node.js and Bun on Ubuntu noble via devcontainer features.", + description: "Node.js and Bun on Debian Trixie via devcontainer features.", source: "built-in", - base: "noble", - image: "mcr.microsoft.com/devcontainers/base:noble", + base: "trixie", + image: "mcr.microsoft.com/devcontainers/base:trixie", pinnedReference: - "mcr.microsoft.com/devcontainers/base:noble + ghcr.io/devcontainers/features/docker-in-docker:4 + ghcr.io/devcontainers/features/node:2 + ghcr.io/devcontainers-extra/features/bun:1", + "mcr.microsoft.com/devcontainers/base:trixie + ghcr.io/devcontainers/features/docker-in-docker:4 + ghcr.io/devcontainers/features/node:2 + ghcr.io/devcontainers-extra/features/bun:1", runtimeVersion: "Node.js + Bun", languages: ["node", "bun", "typescript", "javascript"], runnerCompatible: true,