Skip to content

feat(compose): use compose project name as workspace name - #1006

Merged
skevetter merged 1 commit into
mainfrom
feat/compose-project-name
Aug 19, 2026
Merged

feat(compose): use compose project name as workspace name#1006
skevetter merged 1 commit into
mainfrom
feat/compose-project-name

Conversation

@devsy-app

@devsy-app devsy-app Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Resolves #999.

Summary

When running devsy workspace up . with the docker provider on a compose-based devcontainer, devsy ignored the configured compose project name and always used the sanitized random runner id, spawning a separate compose project instead of reusing an existing one. This PR resolves the project name following the @devcontainers/cli reference precedence so an existing compose project is reused.

Precedence (final, aligned with the reference)

  1. COMPOSE_PROJECT_NAME from the shell session.
  2. COMPOSE_PROJECT_NAME from the collected .env files (first definition wins). devsy passes these same files to docker compose --env-file, so reading COMPOSE_PROJECT_NAME from the same set keeps devsy and the runtime compose invocation consistent.
  3. The merged compose files' top-level name: (last declaration wins, matching multi-file override semantics).
  4. The sanitized random runner id (devsy's analog of the reference's directory-basename fallback).

devsy passes the resolved name via --project-name, which is Docker Compose's highest-precedence override — exactly the mechanism devsy was already using, just with the wrong value.

Comparison with the official specification

  • Dev Containers spec (containers.dev): the name field is "A name for the dev container displayed in the UI" — a display name, not a compose project name. The spec's Docker Compose section is silent on project-name derivation. So devcontainer.json name is not used.
  • @devcontainers/cli reference (getProjectName in src/spec-node/dockerCompose.ts): resolves COMPOSE_PROJECT_NAME (shell) → COMPOSE_PROJECT_NAME (<cwd>/.env) → top-level name: (with a guard distinguishing a user-declared name: from compose-go's injected default) → directory basename. devsy matches this ladder, using the random runner id as its final fallback to preserve existing behavior.
  • Docker Compose (docs.docker.com/compose/how-tos/project-name/): -p flag > COMPOSE_PROJECT_NAME env > top-level name: > project-dir basename > current-dir basename. Since devsy passes the resolved name via --project-name, step 1 (the -p flag) is what takes effect.

TopLevelComposeName reads raw compose fragments, so it only returns user-declared names — never compose-go's injected name: devcontainer default, which is the same distinction the reference's fragment re-check makes.

Known divergence from the reference

devsy reads COMPOSE_PROJECT_NAME from .devcontainer/.env and compose-dir .env files in addition to <workspace>/.env, whereas the reference reads only <workspace>/.env. This is intentional: devsy already passes all of these as --env-file to docker compose, so they are part of compose's own resolution at runtime. Reading from the same set keeps the computed name and the runtime name identical, which is what makes "reuse the existing compose project" work.

Changes

  • pkg/devcontainer/compose.go:
    • loadComposeProject no longer unconditionally overwrites the project name with the random runner id; it calls the new resolveComposeProjectName.
    • resolveComposeProjectName implements the precedence above.
    • Env-file collection is split into baseEnvFiles (devcontainer config-dir .env + workspace-root .env, used to resolve $COMPOSE_FILE and COMPOSE_PROJECT_NAME) and composeDirEnvFiles (.env files colocated with the resolved compose files, added after compose-file resolution). Deduplication preserves first-seen order.
  • pkg/compose/projectname.go (new): pure, testable helpers ProjectNameFromEnvFiles and TopLevelComposeName, plus the ComposeProjectNameEnv constant.
  • pkg/compose/helper.go: added SanitizeProjectName (exported wrapper around the existing sanitization logic) so the devcontainer layer can sanitize the random-id fallback without re-implementing version-dependent character rules.

Notes

  • stopDockerCompose / deleteDockerCompose are unaffected: they derive the project name from the running container's com.docker.compose.project label, which compose sets from --project-name at up time, so they stay consistent with the new resolution.
  • The loaded project's Name from compose-go is intentionally not trusted directly, because compose-go falls back to the project directory's base name when no explicit name source is present. Each higher-precedence source is read explicitly instead.

Testing

  • New unit tests for ProjectNameFromEnvFiles, TopLevelComposeName, and SanitizeProjectName in pkg/compose/projectname_test.go.
  • New unit tests for resolveComposeProjectName (all precedence levels, multi-file last-wins), baseEnvFiles (collection + dedup), composeDirEnvFiles, and appendEnvFiles in pkg/devcontainer/compose_projectname_test.go.
  • go vet, gofmt, golines, and golangci-lint v2.12.2 (--new-from-rev=origin/main) all clean; go build ./... passes.
  • E2e: the full Test up-docker-compose suite is green in CI, including four new specs that assert the resolved project name (top-level compose name:, COMPOSE_PROJECT_NAME from .env, COMPOSE_PROJECT_NAME from the shell, and reuse of the existing compose project on a second up). The shared findComposeContainer helper now resolves the actual compose project name from the dev container labels (rather than assuming the sanitized workspace UID) so the existing multi-service, shutdown, v2-features, and updateRemoteUserUID specs stay green alongside the new ones.
  • The only failing CI checks are Test up-workspaces (git exit-128) and Test self-update (update --dry-run network call failing instantly at 0.08s) — both environmental flakes unrelated to this change (this PR only touches compose project-name resolution and the up-docker-compose helper; neither test exercises compose). They passed on the prior commit on this same branch and fail from network/git-runner conditions, not from these code changes.

This PR was created by an AI agent (OpenHands) on behalf of the user.

@netlify

netlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev canceled.

Name Link
🔨 Latest commit c771731
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a84e6ba9ba87e000898912f

@netlify

netlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploy Preview for images-devsy-sh canceled.

Name Link
🔨 Latest commit c771731
🔍 Latest deploy log https://app.netlify.com/projects/images-devsy-sh/deploys/6a84e6ba6716d2000843815d

@codacy-production

codacy-production Bot commented Aug 11, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 112 complexity · 4 duplication

Metric Results
Complexity 112
Duplication 4

View in Codacy

AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@github-actions

Copy link
Copy Markdown

⚠️ This PR contains unsigned commits. To get your PR merged, please sign those commits (git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}) and force push them to this branch (git push --force-with-lease).

If you're new to commit signing, there are different ways to set it up:

Sign commits with gpg

Follow the steps below to set up commit signing with gpg:

  1. Generate a GPG key
  2. Add the GPG key to your GitHub account
  3. Configure git to use your GPG key for commit signing
Sign commits with ssh-agent

Follow the steps below to set up commit signing with ssh-agent:

  1. Generate an SSH key and add it to ssh-agent
  2. Add the SSH key to your GitHub account
  3. Configure git to use your SSH key for commit signing
Sign commits with 1Password

You can also sign commits using 1Password, which lets you sign commits with biometrics without the signing key leaving the local 1Password process.

Learn how to use 1Password to sign your commits.

Watch the demo

@devsy-app
devsy-app Bot force-pushed the feat/compose-project-name branch 5 times, most recently from 6db5734 to 4962a7a Compare August 11, 2026 19:26
@skevetter
skevetter force-pushed the feat/compose-project-name branch from 3bf116f to 9223448 Compare August 18, 2026 23:06
When running devsy workspace up . with the docker provider on a
compose-based devcontainer, devsy previously ignored the configured compose
project name and always used the sanitized random runner id, spawning a
separate compose project instead of reusing an existing one.

Resolve the project name by trusting compose-go's own resolved
project.Name whenever the user named the project explicitly (shell
COMPOSE_PROJECT_NAME, a .env file, or a compose file's top-level name),
falling back to the sanitized random runner id only when compose-go would
otherwise fall back to its directory-basename default. Delegating to
compose-go (rather than re-parsing compose files by hand) keeps devsy
consistent with Docker Compose's own precedence and correctly interpolates
compose name fields that use variable substitution.

devcontainer.json's name field is deliberately not consulted: per the Dev
Containers spec it is a UI display name, not a compose project name.

Add unit tests for the resolution precedence, including compose-go's own
present-but-empty-shell-env edge case, and an e2e spec plus testdata
(docker-compose-nested-envfile) reproducing the reported issue's exact
layout: a .env colocated with the compose file in a subdirectory distinct
from the workspace root and .devcontainer/.

Document the resolution precedence in the devcontainer.json docs page,
clarifying that devcontainer.json's name does not affect the compose
project name.

Resolves #999.
@skevetter
skevetter force-pushed the feat/compose-project-name branch from 9223448 to c771731 Compare August 18, 2026 23:11
@skevetter
skevetter marked this pull request as ready for review August 19, 2026 00:37
@mergify

mergify Bot commented Aug 19, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@skevetter, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ce596e7-9a1d-4abc-afb1-b079e57990ea

📥 Commits

Reviewing files that changed from the base of the PR and between f6297e7 and c771731.

📒 Files selected for processing (12)
  • e2e/tests/up-docker-compose/config.go
  • e2e/tests/up-docker-compose/helper.go
  • e2e/tests/up-docker-compose/testdata/docker-compose-nested-envfile/.devcontainer/devcontainer.json
  • e2e/tests/up-docker-compose/testdata/docker-compose-nested-envfile/dockerfiles/docker-compose.yaml
  • e2e/tests/up-docker-compose/testdata/docker-compose-project-name-envfile/.devcontainer/devcontainer.json
  • e2e/tests/up-docker-compose/testdata/docker-compose-project-name-envfile/docker-compose.yaml
  • pkg/compose/helper.go
  • pkg/compose/projectname.go
  • pkg/compose/projectname_test.go
  • pkg/devcontainer/compose.go
  • pkg/devcontainer/compose_projectname_test.go
  • sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-json.mdx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@skevetter
skevetter merged commit 1c3b8e2 into main Aug 19, 2026
88 of 90 checks passed
@skevetter
skevetter deleted the feat/compose-project-name branch August 19, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Use compose project name as workspace name

1 participant