devcontainers / devcontainers/cli
Proposal: pin `getProjectName` precedence behavior with tests
- Dominant language
- TypeScript
- Stars
- 3k
- Forks
- 457
- Avg merge
- 13h 17m
- Merged PRs (30d)
- 6
Description
Hi — I've been reading `getProjectName` in `src/spec-node/dockerCompose.ts` carefully while contributing to the Zed editor's dev container support ([zed-industries/zed][zed-repo]), which recently switched from shelling out to `@devcontainers/cli` to a native Rust implementation. (I'm an outside contributor doing small things there; the Zed team does the heavy lifting.)
The port mirrors this function's precedence ladder quite closely: `COMPOSE_PROJECT_NAME` env → workspace `.env` file → explicit top-level `name:` on the merged compose config → `${workspaceFolderBasename}_devcontainer` when the first compose file's directory is `/.devcontainer` → otherwise plain basename of that directory, all passed through `toProjectName`'s lowercase-and-strip-`[^-_a-z0-9]` sanitization — because divergence produces duplicate compose projects for the same folder when both tools touch it. The fix for this just landed in [Zed PR #54302][zed-pr] (tracking issue [#54255][zed-issue]).
The precedence is crisp in the code but mostly implied, rather than asserted by tests. The existing integration coverage in `cli.up.test.ts` pins three of the five rungs: explicit `name:` in a fragment, `name:` with `${env}` substitution (including the `CUSTOM_NAME=devcontainer` edge case that forces the raw-fragment rescan), and the `_devcontainer` suffix when the compose file sits under `.devcontainer/`. The remaining rungs — `COMPOSE_PROJECT_NAME` from the environment, the `.env` file lookup, and the "plain basename, no suffix" fallback for compose files outside `.devcontainer/` — don't appear to have direct tests. Same for`toProjectName`'s character class as a contract.
One related observation: the [spec on containers.dev][spec] is silent on compose project-name derivation — the Docker Compose section covers `dockerComposeFile`, `service`, and `runServices`, but nothing about how the project name is chosen, `COMPOSE_PROJECT_NAME`, or multi-tool interop around it. So `getProjectName` in this repo is the de facto contract that any other implementation has to match if the two are ever going to coexist on the same folder. That makes pinning it with tests a little more load-bearing than it might look from inside the CLI's own use.
**The question:** would you be open, in principle, to pinning this behavior with tests? I'd be happy to contribute them. Either:
- Unit tests alongside `dockerComposeUtils.test.ts` — possibly needs a small
refactor to pull the env/`.env`/config-name reasoning out of the
`cliHost`-dependent shell of `getProjectName`, or
- Integration tests with new fixtures for the three missing rungs, matching
the style of the existing `compose-with-name*` describe blocks in
`cli.up.test.ts`.
Or both, or a different shape — I'd rather ask than cold-drop a PR with the wrong approach. The motivation is durability: a CI-enforced invariant here is a nicer long-term mitigation than a doc comment in the Rust port saying "mirrors the reference CLI as of commit X".
No rush, and no problem if the answer is "not a priority / won't review" — in that case I'll close this and I figure Zed can keep on mirroring.
[zed-repo]: https://github.com/zed-industries/zed
[zed-pr]: https://github.com/zed-industries/zed/pull/54302
[zed-issue]: https://github.com/zed-industries/zed/issues/54255
[spec]: https://containers.dev/implementors/spec/
Contributor guide
Assessment
This issue has not been assessed yet.