twilio-labs / serverless-toolkit

CLI tool to develop, debug and deploy Twilio Functions

Home Page:https://www.twilio.com/docs/labs/serverless-toolkit

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot deploy a new proejct

nathan-kinship opened this issue · comments

My problem seems related to this issue but is not directly addressed by any of the suggestions within it: twilio/twilio-cli#215

Versions are current: twilio-cli/5.3.3 darwin-arm64 node-v16.16.0

Following the documentation, I create a brand new project, correct the problems in its package.json which prevent it from compiling at all, and attempt to deploy it:

twilio serverless:init my-project --typescript
cd my-project
npm run build
twilio serverless:deploy                                                                                                       (:)

Deploying functions & assets to the Twilio Runtime

Username	SKf22618a36dfa62a811980e8a7d3f5871
Password	AkpA****************************
Service Name	my-project
Environment	dev
Root Directory	/Users/nate/dev/my-project
Dependencies	@twilio-labs/serverless-runtime-types, twilio, @twilio/runtime-handler
Env Variables	
Runtime		node16

✖ Failed Deployment

│ ERROR Failed API Request 20001
│ 
│ At least one Function Version or Asset Version is required for Build
│ 
│ More info: https://www.twilio.com/docs/errors/20001

Why does the deploy tool not perform the actions which are required to deploy anything?
What exactly do I have to do for the deploy tool in order to make it capable of deploying something?
Why does the documentation tell me that the deploy tool should be capable of deploying when it clearly is not?

Hey @nathan-kinship apologies for that inconsistency. The problem is that in the TypeScript project we modify the npm scripts to pass --functions-folder and --assets-folder but this doesn't translate to the twilio serverless:deploy command. The easiest solution here will be to modify the .twilioserverlessrc file to include the following configuration:

{
    "functionsFolder": "dist/functions",
    "assetsFolder": "dist/assets"
}

This option didn't exist when the TypeScript template was created and we didn't adjust this logic when it was introduced.

Once you do those config changes you should be able to run:

npm run build
twilio serverless:deploy

And it should deploy correctly. I'll make sure we do the necessary changes to set this configuration during project setup and also update docs accordingly.

Thanks, but there was absolutely no change in the behavior at all. Did you actually try this yourself?

My .twilioserverlessrc:

{
  "commands": {},
  "environments": {},
  "projects": {},
  // "assets": true 	/* Upload assets. Can be turned off with --no-assets */,
  "assetsFolder": "dist/assets" /* Specific folder name to be used for static assets */,
  // "buildSid": null 	/* An existing Build SID to deploy to the new environment */,
  // "createEnvironment": false 	/* Creates environment if it couldn't find it. */,
  // "cwd": null 	/* Sets the directory of your existing Serverless project. Defaults to current directory */,
  // "detailedLogs": false 	/* Toggles detailed request logging by showing request body and query params */,
  // "edge": null 	/* Twilio API Region */,
  // "env": null 	/* Path to .env file for environment variables that should be installed */,
  // "environment": "dev" 	/* The environment name (domain suffix) you want to use for your deployment. Alternatively you can specify an environment SID starting with ZE. */,
  // "extendedOutput": false 	/* Show an extended set of properties on the output */,
  // "force": false 	/* Will run deployment in force mode. Can be dangerous. */,
  // "forkProcess": true 	/* Disable forking function processes to emulate production environment */,
  // "functionSid": null 	/* Specific Function SID to retrieve logs for */,
  // "functions": true 	/* Upload functions. Can be turned off with --no-functions */,
  "functionsFolder": "dist/functions" /* Specific folder name to be used for static functions */,
  // "inspect": null 	/* Enables Node.js debugging protocol */,
  // "inspectBrk": null 	/* Enables Node.js debugging protocol, stops execution until debugger is attached */,
  // "legacyMode": false 	/* Enables legacy mode, it will prefix your asset paths with /assets */,
  // "live": true 	/* Always serve from the current functions (no caching) */,
  // "loadLocalEnv": false 	/* Includes the local environment variables */,
  // "loadSystemEnv": false 	/* Uses system environment variables as fallback for variables specified in your .env file. Needs to be used with --env explicitly specified. */,
  // "logCacheSize": null 	/* Tailing the log endpoint will cache previously seen entries to avoid duplicates. The cache is topped at a maximum of 1000 by default. This option can change that. */,
  // "logLevel": "info" 	/* Level of logging messages. */,
  // "logs": true 	/* Toggles request logging */,
  // "ngrok": null 	/* Uses ngrok to create a public url. Pass a string to set the subdomain (requires a paid-for ngrok account). */,
  // "outputFormat": "" 	/* Output the results in a different format */,
  // "overrideExistingProject": false 	/* Deploys Serverless project to existing service if a naming conflict has been found. */,
  // "port": "3000" 	/* Override default port of 3000 */,
  // "production": false 	/* Promote build to the production environment (no domain suffix). Overrides environment flag */,
  // "properties": null 	/* Specify the output properties you want to see. Works best on single types */,
  // "region": null 	/* Twilio API Region */,
  "runtime": "node16" /* The version of Node.js to deploy the build to. (node16) */
  // "serviceName": null 	/* Overrides the name of the Serverless project. Default: the name field in your package.json */,
  // "serviceSid": null 	/* SID of the Twilio Serverless Service to deploy to */,
  // "sourceEnvironment": null 	/* SID or suffix of an existing environment you want to deploy from. */,
  // "tail": false 	/* Continuously stream the logs */,
  // "template": null 	/* undefined */,
}

Screenshot 2023-02-07 at 11 32 40 PM

% twilio serverless:deploy --override-existing-project -l debug                                                                  
[DEBUG] Config File: /Users/nate/.twilio-cli/config.json
[DEBUG] Using profile: dev
  twilio-run:config:configLoader Load config +0ms
  twilio-run:config:configLoader Config found at /Users/nate/dev/my-project/.twilioserverlessrc +7ms
  twilio-run:config:credentials Using account credentials from Twilio CLI +0ms
  twilio-run:config:configLoader Load config +2ms
  twilio-run:config:configLoader Config cached in memory +0ms
  twilio-run:internal:utils Attempting to read serviceSid from a deployinfo file +0ms
  twilio-run:internal:utils Could not determine existing serviceSid +0ms
  twilio-run:internal:utils AC9080a3ff3df9007f9c8bbb21ebdf6c96:us1 +0ms
  twilio-run:deploy Deploy Config {
  twilio-run:deploy   cwd: '/Users/nate/dev/my-project',
  twilio-run:deploy   envPath: '/Users/nate/dev/my-project/.env',
  twilio-run:deploy   username: '[REDACTED]',
  twilio-run:deploy   password: '[REDACTED]',
  twilio-run:deploy   env: {},
  twilio-run:deploy   pkgJson: {
  twilio-run:deploy     name: '[REDACTED]',
  twilio-run:deploy     version: '[REDACTED]',
  twilio-run:deploy     private: '[REDACTED]',
  twilio-run:deploy     scripts: '[REDACTED]',
  twilio-run:deploy     dependencies: '[REDACTED]',
  twilio-run:deploy     devDependencies: '[REDACTED]',
  twilio-run:deploy     engines: '[REDACTED]'
  twilio-run:deploy   },
  twilio-run:deploy   overrideExistingService: true,
  twilio-run:deploy   force: false,
  twilio-run:deploy   serviceName: 'my-project',
  twilio-run:deploy   functionsEnv: 'dev',
  twilio-run:deploy   noAssets: false,
  twilio-run:deploy   noFunctions: false,
  twilio-run:deploy   runtime: 'node16',
  twilio-run:deploy   userAgentExtensions: [
  twilio-run:deploy     'twilio-run/3.5.3',
  twilio-run:deploy     '@twilio-labs/plugin-serverless/3.1.3',
  twilio-run:deploy     'twilio-run:deploy'
  twilio-run:deploy   ]
  twilio-run:deploy } +0ms

Deploying functions & assets to the Twilio Runtime

Username	SKf22618a36dfa62a811980e8a7d3f5871
Password	AkpA****************************
Service Name	my-project
Environment	dev
Root Directory	/Users/nate/dev/my-project
Dependencies	@twilio-labs/serverless-runtime-types, twilio, @twilio/runtime-handler
Env Variables	
Runtime		node16

⠋ Deploying Function  twilio-serverless-api:client Deploy config {
  twilio-serverless-api:client   cwd: '/Users/nate/dev/my-project',
  twilio-serverless-api:client   envPath: '/Users/nate/dev/my-project/.env',
  twilio-serverless-api:client   username: '[REDACTED]',
  twilio-serverless-api:client   password: '[REDACTED]',
  twilio-serverless-api:client   env: {},
  twilio-serverless-api:client   pkgJson: {
  twilio-serverless-api:client     name: '[REDACTED]',
  twilio-serverless-api:client     version: '[REDACTED]',
  twilio-serverless-api:client     private: '[REDACTED]',
  twilio-serverless-api:client     scripts: '[REDACTED]',
  twilio-serverless-api:client     dependencies: '[REDACTED]',
  twilio-serverless-api:client     devDependencies: '[REDACTED]',
  twilio-serverless-api:client     engines: '[REDACTED]'
  twilio-serverless-api:client   },
  twilio-serverless-api:client   overrideExistingService: true,
  twilio-serverless-api:client   force: false,
  twilio-serverless-api:client   serviceName: 'my-project',
  twilio-serverless-api:client   functionsEnv: 'dev',
  twilio-serverless-api:client   noAssets: false,
  twilio-serverless-api:client   noFunctions: false,
  twilio-serverless-api:client   runtime: 'node16',
  twilio-serverless-api:client   userAgentExtensions: [
  twilio-serverless-api:client     'twilio-run/3.5.3',
  twilio-serverless-api:client     '@twilio-labs/plugin-serverless/3.1.3',
  twilio-serverless-api:client     'twilio-run:deploy'
  twilio-serverless-api:client   ]
  twilio-serverless-api:client } +0ms
  twilio-serverless-api:fs Search for directory. Options: "functions,src" +0ms
  twilio-serverless-api:fs Found Functions Directory "/Users/nate/dev/my-project/src" +0ms
  twilio-serverless-api:fs Search for directory. Options: "assets,static" +0ms
  twilio-serverless-api:fs Found Assets Directory "undefined" +0ms
⠴ Creating Service
  twilio-serverless-api:services ClientApiError [TwilioApiError]: Service with this UniqueName already exists.
  twilio-serverless-api:services     at /Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/api/services.js:43:23
  twilio-serverless-api:services     at Generator.throw (<anonymous>)
  twilio-serverless-api:services     at rejected (/Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/api/services.js:7:65)
  twilio-serverless-api:services     at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  twilio-serverless-api:services   code: 20409,
  twilio-serverless-api:services   url: 'https://serverless.twilio.com/v1/Services',
  twilio-serverless-api:services   details: {
  twilio-serverless-api:services     code: 20409,
  twilio-serverless-api:services     message: 'Service with this UniqueName already exists.',
  twilio-serverless-api:services     more_info: 'https://www.twilio.com/docs/errors/20409',
  twilio-serverless-api:services     status: 409
  twilio-serverless-api:services   }
⠧ Waiting for deployment.
  twilio-serverless-api:builds ClientApiError [TwilioApiError]: At least one Function Version or Asset Version is required for Build
  twilio-serverless-api:builds     at /Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/api/builds.js:112:23
  twilio-serverless-api:builds     at Generator.throw (<anonymous>)
  twilio-serverless-api:builds     at rejected (/Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/api/builds.js:7:65)
  twilio-serverless-api:builds     at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  twilio-serverless-api:builds   code: 20001,
  twilio-serverless-api:builds   url: 'https://serverless.twilio.com/v1/Services/ZS1dc8ce4c593591676842caadc25d5257/Builds',
  twilio-serverless-api:builds   details: {
  twilio-serverless-api:builds     code: 20001,
  twilio-serverless-api:builds     message: 'At least one Function Version or Asset Version is required for Build',
  twilio-serverless-api:builds     more_info: 'https://www.twilio.com/docs/errors/20001',
  twilio-serverless-api:builds     status: 400
  twilio-serverless-api:builds   }
  twilio-serverless-api:builds } +0ms
  twilio-run:deploy ClientApiError [TwilioApiError]: At least one Function Version or Asset Version is required for Build
  twilio-run:deploy     at convertApiErrorsAndThrow (/Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/utils/error.js:33:15)
  twilio-run:deploy     at TwilioServerlessApiClient.<anonymous> (/Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/client.js:515:54)
  twilio-run:deploy     at Generator.throw (<anonymous>)
  twilio-run:deploy     at rejected (/Users/nate/.twilio-cli/node_modules/@twilio-labs/serverless-api/dist/client.js:7:65)
  twilio-run:deploy     at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  twilio-run:deploy   code: 20001,
  twilio-run:deploy   url: 'https://serverless.twilio.com/v1/Services/ZS1dc8ce4c593591676842caadc25d5257/Builds',
  twilio-run:deploy   details: {
  twilio-run:deploy     code: 20001,
  twilio-run:deploy     message: 'At least one Function Version or Asset Version is required for Build',
  twilio-run:deploy     more_info: 'https://www.twilio.com/docs/errors/20001',
  twilio-run:deploy     status: 400
  twilio-run:deploy   }
✖ Failed Deployment

│ ERROR Failed API Request 20001
│ 
│ At least one Function Version or Asset Version is required for Build
│ 
│ More info: https://www.twilio.com/docs/errors/20001

Hey @nathan-kinship apologies that you are still experiencing issues with the deployment and thanks from sharing the debug logs with me. From the debug logs it looks like the functionsFolder and assetsFolder configuration isn't found in /Users/nate/dev/my-project/.twilioserverlessrc. I did try this myself and didn't run into any issues. I also created a couple of new projects and asked several colleagues to verify the following series of commands which worked for them.

twilio serverless:init ts-example --typescript && cd ts-example && npm install -D typescript@latest && echo '{ "functionsFolder": "dist/functions", "assetsFolder": "dist/assets" }' > .twilioserverlessrc && npm run build && twilio serverless:deploy

If the configuration gets correctly picked up you should also see in the debug logs functionsFolderName and assetFolderName accordingly.

Screen Shot 2023-02-08 at 11 24 04 AM

Thanks; that sequence did indeed work.

Now how can I go about determining why the tool is ignoring my .twilioserverlessrc? My actual goal here is not to deploy a brand new project, but to update an older project to use the newer build tools so the fact that it's not being picked up consistently seems like a big issue.

I was able to do this successfully with another project which was not using TypeScript and it worked without a hitch.

Seems like it's in the right location with the right permissions and the right content.

% cd my-project                                                                                                                             (:)
[~/dev/my-project] nate@kin % ls                                                                                                                             (:)
total 752
drwxr-xr-x   12 nate  staff     384 Feb  7 09:39 .
drwxr-xr-x   20 nate  staff     640 Feb  8 12:51 ..
-rw-r--r--    1 nate  staff      58 Feb  7 09:38 .env
-rw-r--r--    1 nate  staff    2086 Feb  7 09:38 .gitignore
-rw-r--r--    1 nate  staff       2 Feb  7 09:38 .nvmrc
-rw-r--r--    1 nate  staff    3481 Feb  7 09:38 .twilioserverlessrc
drwxr-xr-x    4 nate  staff     128 Feb  7 09:39 dist
drwxr-xr-x  366 nate  staff   11712 Feb  7 09:56 node_modules
-rw-r--r--    1 nate  staff  357006 Feb  7 09:56 package-lock.json
-rw-r--r--    1 nate  staff     805 Feb  7 09:56 package.json
drwxr-xr-x    4 nate  staff     128 Feb  7 09:38 src
-rw-r--r--    1 nate  staff     218 Feb  7 09:38 tsconfig.json

Could you maybe point me to the spot in this repo where the file gets read in? Since I have the live test case it might be easier for me to debug now that we have established a root cause.

Interesting discovery... The way I was commenting and uncommenting individual lines in .twilioserverlessrc was making Prettier happy but they seemed to get parsed as though they weren't commented at all. I've just deleted every attribute I'm not actively using/testing and was able to deploy successfully with one lingering issue: the tool is not identifying the correct destination service and always wants to deploy to one called dialpad-functions.

This is a real service in my account and it is one that I want to continue deploying to, but it's not the actual destination for this code. I've wiped out .twiliodeployinfo and verified that the string dialpad-functions appears nowhere inside this project, but the CLI continues to decide that's where everything belongs. What exactly is it pulling this information from and how can I make it stop?

✔ Serverless project successfully deployed

Deployment Details
Domain: dialpad-functions-3099-dev.twil.io
Service:
   dialpad-functions (ZSb9f6bdb8158c4a4fdfa79ffd63861b1c)
Environment:
   dev (ZEd1a76bed8a0b468081cc2a79992245dc)
Build SID:
   ZB0b8a4a70281b47c3f03ecf50350dbd77

Without seeing your full project it's hard for me to tell where this is coming from but in general the logic is the following:

  1. Check if there is a specified serviceSid either passed in using --service-sid= or through the .twilioserverlessrc file (see Configuration docs on how to specify one either in general or per account SID). If that serviceSid can be found use that otherwise carry on
  2. Check if there is a .twiliodeployinfo and look up if the Account SID you are using to deploy has a corresponding serviceSid in it. If that's the case: use that one, otherwise carry on
  3. Try to create a service with the name specified in the .twilioserverlessrc if specified
  4. Try to create a service with the name in the package.json file

This is the full logic to determine it: https://github.com/twilio-labs/serverless-toolkit/blob/main/packages/twilio-run/src/config/deploy.ts#L92-L116

The debug logs should also include some pointers towards where it's coming. For example if it comes from the .twiliodeployinfo it should say something like:

 twilio-run:internal:utils Found service sid by region from deploy info, "ZS..."

Thanks; I think the remaining issues are on our side of the fence and do not belong in this discussion.

The takeaway for me is that an extremely generic exception handler is being relied upon to flag extremely specific problems in this tool and that is failing extremely predictably. Given the fact that the actual meaning of this mysterious error is "I don't like something about your build products" I believe this tool needs the following improvements:

  1. Ensure that new projects are configured in a working state as already discussed so that users can at least verify that the tool itself isn't fundamentally broken.
  2. Add integration testing to the release process to catch broken defaults before they go public.
  3. Add some new exception types and exit earlier with more relevant messages when an issue is discovered in a functions or assets directory. If it's empty, say it's empty and return. If it doesn't exist, say it doesn't exist and return. If it contains something undesirable, like a .dart file, say "Ignoring file XXXXXX.dart" and continue.

If these basic provisions were in place I more than likely could discovered the core issue myself, saving multiple weeks of my life exchanging frustrating emails with support reps who don't have any training with any of the tools they tell people to use beyond "copy and paste this over and over until they give up and go away."

I agree the error messages here were confusing and we'll make sure to address this. Sorry for the inconvenience.