Skip to content

Fix: normalize packageManager "unknown" to "npm" before it hits PackageManagerEnum - #419

Open
giomartinsdev wants to merge 1 commit into
oblien:mainfrom
giomartinsdev:fix-packagemanager-unknown-400
Open

Fix: normalize packageManager "unknown" to "npm" before it hits PackageManagerEnum#419
giomartinsdev wants to merge 1 commit into
oblien:mainfrom
giomartinsdev:fix-packagemanager-unknown-400

Conversation

@giomartinsdev

Copy link
Copy Markdown

Closes #418

Summary

detectPackageManager() returns the internal sentinel "unknown" when no manifest is found anywhere in the scanned root — legitimate (applyWorkspaceContext already special-cases it), but not a real package manager, and PackageManagerEnum (derived from the STACKS registry) never accepted it as a literal.

Two builders echoed the raw value straight into API responses the dashboard persists verbatim into the next project-creation request, which validates against that strict enum and 400s with "Expected union value":

  • resolveProjectInfo in apps/api/src/modules/deployments/prepare.service.ts (single-root / declared-compose-path case)
  • toMonorepoApp in apps/api/src/lib/project-root-detector.ts (monorepo sub-app case)

Fixed both at the point the value is produced — "unknown""npm" — rather than patching every read site (the dashboard has a dozen-plus response.packageManager || "npm" fallbacks that all silently miss this because "unknown" is truthy).

Test plan

  • Added a regression test (prepare.service.test.ts) reproducing the exact repro: a docker-compose.yml in a subfolder with zero manifest files, scanned via a declared composePath. Verified it fails without the fix (expected 'unknown' to be 'npm') and passes with it.
  • bunx vitest run across the whole apps/api package — 171 test files, 1859 tests passing (15 pre-existing skips, unrelated), no regressions.
  • bunx tsc --noEmit in apps/api — clean.

…to the client

detectPackageManager() legitimately returns "unknown" when no manifest is
found anywhere in the scanned root (e.g. a docker-compose-only subfolder
in a monorepo, no package.json/go.mod/requirements.txt/etc). That's a
valid internal sentinel — applyWorkspaceContext already special-cases it
— but it isn't a real package manager, and PackageManagerEnum
(project.schema.ts, derived from the STACKS registry) never included it
as a literal.

Two builders echoed the raw value straight into API responses the
dashboard persists verbatim into subsequent project-creation requests:
ProjectInfo (prepare.service.ts, the single-root/declared-compose path)
and MonorepoApp (project-root-detector.ts, the monorepo sub-app path).
Either one 400s with "Expected union value" the moment a user deploys a
compose stack that lives in a subfolder with no manifest of its own —
which is the common case for a pure-infra monorepo (a repo of several
infra/<service>/docker-compose.yml folders, one Openship project per
folder).

Fixes both leak points by normalizing "unknown" to "npm" right where the
value is produced — the same default the dashboard's own `|| "npm"`
fallbacks already assume, now applied where it's actually needed instead
of scattered across every read site.

Added a regression test in prepare.service.test.ts reproducing the exact
shape that broke: a docker-compose.yml in a subfolder with zero manifest
files, scanned via a declared composePath. Confirmed it fails without the
fix ('unknown' !== 'npm') and passes with it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deploying a compose subfolder with no manifest 400s: "packageManager" "unknown" fails schema validation

1 participant