Skip to content

fix: aio app deploy fails when packages: {} is declared#233

Merged
riddhi2910 merged 5 commits into
adobe:masterfrom
iivvaannxx:fix/deploy-empty-packages
Jun 11, 2026
Merged

fix: aio app deploy fails when packages: {} is declared#233
riddhi2910 merged 5 commits into
adobe:masterfrom
iivvaannxx:fix/deploy-empty-packages

Conversation

@iivvaannxx

@iivvaannxx iivvaannxx commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • When a manifest declares packages: {} (empty packages), the build step produces no output so the dist directory is never created. The deploy command was throwing a spurious "missing files in dist/…, maybe you forgot to build your actions?" error.
  • A secondary issue in replacePackagePlaceHolder silently set ow.package = undefined when packages was empty, causing syncProject to search the runtime server for a project named undefined.

Changes

src/deploy-actions.js
Gate the dist-existence check behind hasAnyActions — only validate the build directory when at least one package actually declares actions. Removed the redundant || {} fallback (packages is always an object at this point) and the dead pkg && guard (null-valued packages already fail elsewhere in the pipeline).

src/utils.js (replacePackagePlaceHolder)
Guard the packageNames[0] assignment so an empty packages object no longer clobbers ow.package with undefined.

Note

Deploying with packages: {} is effectively a no-op — no package, action, trigger, rule, or API is created on Adobe I/O Runtime. If the project was previously deployed with actual entities, the runtime's sync mechanism will treat the empty manifest as the desired state and undeploy them. This is consistent with how the full-sync model works in general, though it may be unexpected if packages: {} is used as a placeholder during development.

When a manifest declares `packages: {}` the build step produces no
output so the dist directory is never created. The existing dist check
was throwing "missing files in dist/…, maybe you forgot to build your
actions?" even though there was nothing to build.

* deploy-actions.js: gate the dist check on `hasAnyActions` — only
  validate the build directory when at least one package actually
  defines actions. Two tests cover both branches of `pkg.actions || {}`
  (empty packages and package with no actions key), keeping 100%
  branch coverage on deploy-actions.js.
* utils.js (replacePackagePlaceHolder): guard the `packageNames[0]`
  assignment so an empty packages object no longer clobbers `ow.package`
  with `undefined`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Comment thread src/deploy-actions.js
iivvaannxx and others added 2 commits June 11, 2026 12:05
The dist-existence check had an operator-precedence bug:
`!fs.readdirSync(dist).length === 0` parses as `(!length) === 0`,
which is always false, so the empty-build-directory branch never
fired. Correct it to `fs.readdirSync(dist).length === 0` so a dist
directory that exists but contains no built actions now raises the
"missing files" error as intended. Adds a test covering that branch.
@pru55e11

Copy link
Copy Markdown
Contributor

Thanks for this @iivvaannxx, really useful fix, and the ow.package guard was a nice catch.

One thing came up in review that I'd like to sort before we ship. As written, when packages: {} is declared the deploy no longer aborts. It falls through to the full sync (deleteOldEntities = true), so syncProject treats the empty manifest as the desired state and undeploys all previously-deployed actions/triggers/rules for the project, with just a log warning. Before this PR the missing files error blocked that. So an accidental empty or commented-out packages block (like the config slip you mentioned in the original thread) would silently wipe a live deployment, and that path fires for any project, not just the DB auto-provision case.

Proposal: when no actions are declared, skip the sync entirely (early return) instead of proceeding to the delete. That keeps your fix's intent, so no more spurious missing files error for the auto-provision or empty case, but makes it a true no-op that never deletes anything. aio app undeploy already covers intentional "remove everything".

When the manifest declares `packages: {}` (e.g. only to trigger database
auto-provisioning), deployActions previously fell through to a full sync
against an empty manifest, which undeploys every previously-deployed
entity for the project. Return early instead so an empty manifest is a
true no-op that leaves existing entities untouched. `aio app undeploy`
remains the explicit way to remove everything.
@iivvaannxx

iivvaannxx commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@pru55e11 I agree with that, it may be unexpected such a change in behavior. I am good with early returning. Seems you already did that in f87a478, thanks!

Not exactly sure how you were able to push a commit since this is a personal fork, but whatever 🤣

@pru55e11

Copy link
Copy Markdown
Contributor

Thanks @iivvaannxx! "Allow edits by maintainers" was enabled on the PR so it made it easy to add a commit

@pru55e11 pru55e11 requested review from mgar and riddhi2910 June 11, 2026 16:53
@riddhi2910 riddhi2910 merged commit fd00eb1 into adobe:master Jun 11, 2026
11 checks passed
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.

5 participants