denoland / deployctl

Command line tool for Deno Deploy
https://deno.com/deploy
MIT License
352 stars 58 forks source link

[Bug]: deployctl deploy executes entrypoint before setting --env vars #311

Open h4l opened 6 months ago

h4l commented 6 months ago

Problem description

When creating a deployment from the CLI with deployctl deploy we can set environment variables with --env / --env-file. During deployment, Deno Deploy appears to execute the entrypoint module without the envars set.

Steps to reproduce

Create a module/app that requires environment variables to work:

// main.ts
const name = Deno.env.get("GREETING_NAME");
if (!name) throw new Error("GREETING_NAME is not set");

Deno.serve((): Response => {
  return new Response(`Hello ${name}\n`);
});

Deploy it with the environment variables set. Deployment fails due to the module being executed without the vars set:

$ deployctl deploy --include '*.ts' --env=GREETING_NAME=Foo --project=required-env 
ℹ Using config file '/workspaces/xxx/deploy_playground/deno.json'
✔ Deploying to project required-env.
✔ Entrypoint: /workspaces/xxx/deploy_playground/main.ts
ℹ Uploading all files from the current dir (/workspaces/xxx/deploy_playground)
✔ Found 2 assets.
✔ Uploaded 2 new assets.
✖ Deployment failed.
error: The deployment failed: UNCAUGHT_EXCEPTION

Error: GREETING_NAME is not set
    at file:///src/main.ts:2:18

If the throw is removed, deploy proceeds and shows ⠸ Setting environment variables... after the point that it failed previously.

Expected behavior

Environment variables provided should be set when the entrypoint is executed.

Environment

$ deployctl --version
deployctl 1.12.0
$ deno --version
deno 1.43.1 (release, aarch64-unknown-linux-gnu)
v8 12.4.254.12
typescript 5.4.3

Possible solution

If vars can't be set before executing the entrypoint, maybe provide a way for an app to know it's being executed during deployment as a test, so that it can avoid loading config & failing if it's not available?

Additional context

No response

h4l commented 6 months ago

I wonder if I'm misunderstanding the intention of deployment-level envars. Maybe they are not really intended for configuration? I notice that deployctl deployments show shows the names of env vars, but not their values. So it'd be hard to tell how a deployment was configured, if deploy-level env vars were used for config.

Also the example in the deployctl deploy --help output shows setting a metadata-like var DEPLOYMENT_TS — the kind of thing that would be optional:

You can set env variables for deployments to have access using Deno.env. You can use --env to set individual
environment variables, or --env-file to load one or more environment files. These options can be combined
and used multiple times:

    deployctl deploy --env-file --env-file=.other-env --env=DEPLOYMENT_TS=$(date +%s)

Be aware that the env variables set with --env and --env-file are merged with the env variables configured for the project.
If this does not suit your needs, please report your feedback at
https://github.com/denoland/deploy_feedback/issues/

And env vars set at the project level (e.g via the deploy website) are set during deploy.

magurotuna commented 6 months ago

Thanks for the report, this is indeed a bug (or rather current limitation with deployctl).

To be clear, there are two levels where we can configure env vars; one is project level and the other is deployment level. As you noticed, setting env vars in the settings page of the Deno Deploy dashboard is the project level configuration, whereas what deployctl deploy --env option is configuring is the deployment level. The final env vars that are applied to a particular deployment are the result of merging project-level and deployment-level config.

The current limitation we have with deployment-level env var configuration is as follows: what happens internally in deployctl deploy command is it first creates a deployment without any specified deployment-level env vars and then it will "redeploy" with the env vars. This is the limitation due to how the backend API works currently - we definitely could modify it so that we won't need to "redeploy" to apply the deployment-level env vars, but it's a little bit of a low priority as of now.

So for now, one possible workaround would be setting the required env vars as the project-level - that is, create a project (or you can reuse the empty project you got as a result of running deployctl deploy --env with failure), set the required env vars as project-level env vars in the settings tab of the dashboard (i.e. https://dash.deno.com/projects/<your-project-name>/settings), and then do deployctl deploy --env again.

h4l commented 6 months ago

Thanks for the explanation & workaround, that's helpful.