109 Commits

Author SHA1 Message Date
exoego
f434009c45 Move stage name validation to Service#validate.
Since validation should be performed after service.functions are resolved.
2019-01-16 16:39:09 +09:00
Daniel Schep
96906c1c70
Merge pull request #5686 from exoego/validation-after-var-resolution
AWS: Fix stage name validation timing and allow hyphen
2019-01-13 20:25:53 -05:00
exoego
fe6cb01302 Fix error message. 2019-01-12 17:33:38 +09:00
exoego
ef591b2677 Add test case when the populated variable is valid. 2019-01-12 17:23:45 +09:00
exoego
df780c36e3 Allow underscore too. 2019-01-12 17:17:40 +09:00
exoego
a12bb5bf71 Allow hyphen which is valid for API Gateway now. 2019-01-12 08:53:29 +09:00
exoego
5ca31157b7 Add test case to increase coverage. 2019-01-12 08:33:50 +09:00
exoego
6e0d7a86d1 Implement after-variable-resolution stage name validation for AWS. 2019-01-12 08:11:50 +09:00
Daniel Schep
0896f311b1
Merge pull request #5312 from Limess/4496/handle-scoped-packages
Handle scoped npm packages in ${file()} variables
2019-01-07 10:56:25 -05:00
Daniel Schep
e99e71d215 lint 2018-12-13 09:32:46 -05:00
Daniel Schep
63fb1309d3 restore support for variable refs with spaces in them 2018-12-13 09:16:57 -05:00
horike37
4336340aa4 Merge remote-tracking branch 'root/master' into cf-ref-region 2018-12-10 12:01:41 +09:00
exoego
e90e293c71 Add region suffix support to CloudFormation reference syntax 2018-12-08 20:44:16 +09:00
exoego
1a9cdf356b Remove whitespace-celaning that seems unnecessary. 2018-12-06 21:36:00 +09:00
Charlie Briggs
8f8c27ae7e Handle scoped packages in ${file()} variables
Currently @ is not a valid variable character, so it doesn't get parsed
as one.
When it does get parsed, @ is not considered valid as part of a file path
- we add a blacklist as per https://github.com/serverless/serverless/pull/4528 to
handle this case.
2018-09-19 17:26:50 +01:00
Erik Erikson
2ebc65fe97 Fix Embedded Deep Variable in Variable String, within Override bug
If an override comes back as a variable containing a deep variable (e.g. `''${self:custom.${deep:1}, "fallback"}''`) or really any variable at all, it needs to be made a deep variable and paused for next iteration.  Do this generally rather than only in the case of deep variables.  See the test case for a circumstance that the prior fix didn't resolve.  This more generalized handling improves the fix and solves a remaining issue we found locally.
2018-08-17 17:50:58 -07:00
Erik Erikson
73ebe0f66b Fix #5205
Use the variable string from which the overwrite parameters were extracted as the replacement target (in the case of deep variable discovery) rather than the context property which represents the entire original value that the replacement is being waited upon.  That context property can contain far more content than the overwrite string itself.
2018-08-16 18:35:53 -07:00
Takahiro Horike
659df3651c
Merge pull request #5119 from gcphost/master
#5110 null error on undefined AWS SSM variables
2018-08-06 21:31:57 +09:00
Erik Erikson
42d1749c36 When evaluating overwrite values, identify deep values and pause population.
This avoids taking a deep value as a valid term within an overwrite 
(defaulting) variable statement that will later resolve to undefined 
but, as a deep variable string, is valid in immediate evaluation.

Fixes #5027
2018-07-24 14:42:21 -07:00
William
0f1c8047da Use statusCode for comparison, update tests to provide correct statusCode. 2018-07-16 21:51:02 -07:00
Erik Erikson
534dda6285 Fix #4973
Do a better job of extracting the current variable syntax for use in deep variable generation.
2018-05-18 00:04:37 -07:00
Erik Erikson
63045fd206 Fix #4946
Use the variable syntax present in the given variable string, extracting it from the given string that may contain embedded custom variables (i.e. `${{self:var.${{self:var.foo}}.bar}}`).
2018-05-02 11:52:24 -07:00
Erik Erikson
71c6db9687 Re-write self:service.[...] to self:serviceObject.[...]
Handle `self:service.[...]` references properly.  The prior represents what the user typed into their configuration.  In service, we move all this from `service` to `serviceObject`, therefore, by rewriting `self:service.[...]` to `self:serviceObject.[...]` user's will get the result they expect.
Use else if, given exclusivity of conditions
2018-03-27 15:34:34 -07:00
Frank Schmid
5a4d00c9ad
Merge pull request #4800 from bsdkurt/master
Continue recursion for #4687
2018-03-06 11:35:17 +01:00
Erik Erikson
8f32a59c7f add test that fails prior to the fix in #4800 and succeeds after 2018-03-05 13:33:18 -08:00
Erik Erikson
0ee0a1e239 Only disable and restore dependent service resolution methods once. Otherwise, subsequent removals may cache the previous replacements. If they restore last then they will restore with the replacements, breaking standard usage.
Add tests for this guarantee.
2018-02-24 09:34:50 -08:00
Erik Erikson
bf5a8c9fd4 Fix 4744 and associated
The framework's Service class modifies a user's service, mutating a given `service: { name: 'string' }` to `service: 'string'` but doesn't account for this in the variables system.  This is the basis for #4744.

While working this area, I discovered that the Service class also does this to the provider, accepting `provider: 'aws'` and replacing it with `provider: { name: 'aws' }`, causing the natural `${self:provider}` to fail.

Catching either 'self:service.name' or 'self:provider' and replacing them with the mutated reference solves this user confusion.
2018-02-22 17:17:55 -08:00
Erik Erikson
dc3a4aa6af Fix print, clean pre-population, fix cyclic bug
Fix `print`
The print command is highly linked to the `Variables` and `Service` codebases, keep those in sync and leave reminders about the link.  Made these explicit and separately implemented to avoid complexity.
Additionally, the print command re-populates an object with the *very similar* content as the previously pre-populated service (just not augmented as just mentioned).  This can lead to cross contamination between the two.  As such, all caches must be cleared per unique invocation of service/object/property population.
Add tests for some expected but previously unverified behaviors.

Clean pre-population
The previous implementation worked okay but was unnecessary and would have been a maintenance problem.  Instead, just knock out the population of variables depending on those config dependent services and use the standard means of resolution.

Fix cyclic bug (resulting from running print against a self-referencing serverless.yml)
The caching of values could lead to a cyclic object remaining in the caches for variable population.  This causes crashes and pain.  Solved by the cache cleaning logic.
2018-02-22 16:30:04 -08:00
Erik Erikson
8c7db120ae Add cases for all dependent services, and a variety of deep variable (DV) cases
Solve for these cases.  The bug was that DVs can render to DVs when a value is being obtained from them (i.e. they are being de-referenced in getValueFromDeep).  This is particularly problematic in the case that the original DV being rendered has a deep reference into the rendered DV.  In that case the DV returned by rendering must be replaced by yet another DV.

While accomplishing the above, various bits of cleanup were implemented and I added some commentary around getDeeperValue for future engineers.

This case is particularly relevant if you have:

`serverless.yml`:
```
service: serverless-hello-world

provider:
  name: aws
  runtime: nodejs6.10
  stage: dev
  environment:
    SECRET: ${self:custom.secrets.SECRET}

functions:
  helloWorld:
    handler: handler.helloWorld
    events:
      - http:
          path: hello-world
          method: get
          cors: true

custom:
  stage: ${opt:stage, self:provider.stage}
  secrets: ${file(secrets.${self:custom.stage}.yml)}
```
AND
`secrets.dev.yml`:
```
SECRETS: secrets
```

Populating this service should result in the following sequence of rendering phases:

#########################
# PHASE 1
#
# ${self:custom.secrets.SECRET}
#   <- ${deep:0.SECRET}
#   deep[0] = ${file(secrets.${self:custom.stage}.yml)}
#
# ${opt:stage, self:provider.stage}
#   <- 'dev'
#
# ${file(secrets.${self:custom.stage}.yml)}
#   <- ${file(secrets.${deep:1}.yml)}
#   deep[1] = ${opt:stage, self:provider.stage}
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: ${deep:0.SECRET}
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets: ${file(secrets.${deep:1}.yml)}
#########################

#########################
# PHASE 2
#
# ${deep:0.SECRET}
#   <- this.populateValue('${file(secrets.${self:custom.stage}.yml)}') => '${file(secrets.${deep:1}.yml)}' => '${deep:2}' => '${deep:2.SECRET}'
#   deep[2] = ${file(secrets.${deep:1}.yml)}
#
# ${file(secrets.${deep:1}.yml)}
#   <- this.populateValue('${file(secrets.${deep:1}.yml)}') => '${file(secrets.dev.yml)}' => '${deep:3}'
#   deep[3] = ${file(secrets.dev.yml)}
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: ${deep:2.SECRET}
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets: ${deep:3}
#########################

#########################
# PHASE 3
#
# ${deep:2.SECRET}
#   <- this.populateValue('${file(secrets.${deep:1}.yml)}') => '${file(secrets.dev.yml)}' => '${deep:3}' => '${deep:3.SECRET}'
#   deep[3] is already set to ${file(secrets.dev.yml)}
#
# ${deep:3}
#   <- this.populateValue('${file(secrets.dev.yml)}') => { SECRET: 'secret' }
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: ${deep:3.SECRET}
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets:
#     SECRET: secret
#########################

#########################
# PHASE 4
#
# ${deep:3}
#   <- this.populateValue('${file(secrets.dev.yml)}') => this.getDeeperValue(['SECRET'], { SECRET: 'secret' }) => 'secret'
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: secret
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets:
#     SECRET: secret
#########################
2018-02-20 20:57:24 -08:00
Erik Erikson
a35bcc01cd Deep values can be overwrites too! Fix issue reported by @laardee (thank you!)
Simple oversight that deep variables can reference overwrites too.  This fix acknowledges this oversight by using the standard logic for using overwrite instead of getValueFromSource in this case.
2018-02-20 12:21:26 -08:00
Erik Erikson
4400ffc9e4 fix #4311 & #4734, separate PromiseTracker, minutiae
#4311
  see prepopulateService - attempts to pre-populate the region and stage settings necessary for making a request to AWS, rejecting and dependencies thereon it runs into during that process
  see the `deep` variable work.  this was a knock-on effect of providing pre-population.  it actually represents an obscure class of bugs where the recursive population previously in getDeepValue caused the caller not to be in charge of population choices (thus fixing for pre-population) but also caused potential deadlocks resulting from getDeepValue creating circular dependencies.

#4734
  see splitByComma - a regex to do the splitting but ignore quoted commas was getting very deep and involved.  Instead, identify quoted string boundaries, then identify commas (including white space around them) and take those commas not contained by quotes as the locations for splitting the given string.  Trim the string as well (removing leading and trailing white space).
  add sophistication to the overwrite syntax, allowing for whitespace and repetitions (for robustness)
  add sophistication to the string ref syntax, allowing for use in identifying multiple quoted strings in a variable (i.e. for overwrites)

#NotCreated
  fix a bug I created earlier in the branch that caused reporting to be less informative (see renderMatches)

separate PromiseTracker
  move this class into its own file for the purpose of increasing testability and offering reuse

minutiae
  filter the properties given to populateVariables so as to avoid attempting resolution on non-variables.  Efficiency and noise reduction change.  Also cleans up the code (e.g. see populateObject and its use)
  cleaning of overwrite as a side effect
  offer variable cleaning as a idiom
  reorder the Variables.js `require`s to be in alphabetical order
2018-02-16 17:13:03 -08:00
Erik Erikson
8f69678a88 remove .only from describe for Variables tests
add expected rejection message
2018-02-03 13:14:11 -08:00
Erik Erikson
c18eb70a28 Eliminate Deadlocks, Report Hung Promises (#4687)
Add a "PromiseTracker" to the Variables class.  It provides tracking and reporting of pending variable resolutions during service populations.
Decompose populateObject and populateProperty into smaller pieces that are easier to understand.
Additionally, remove the immediate recursive resolution of variables, recursing only at the Object or Property entry point (when changes have been made).  This avoids a problem where the resolved value, prior to being replaced in the containing object or value refers to itself and thereby is waiting on its own resolution before it will resolve itself.
Return the given value in warnIfNotFound so that it can chain.
2018-02-02 19:29:19 -08:00
Frank Schmid
81c896bc12
Removed reintroduction of stage+region in request. Added options.
Delete bucket was still using them

Hopefully all :)

Further test fixes.

.... worked too long yesterday

Fixed Variable tests

Remove not used parameters from request() and add options with warning
2017-12-11 12:33:35 +01:00
Erik Erikson
df5dc28961 add tests to get to 100% line coverage
1. add tests that validate string value defaults in overrides.
2. add test of behavior when a javascript's export does not contain the attribute declared in the variable.
3. add tests of behavior when an SSM parameter is not found and the request to the SSM service fails.

add returns to tests that weren't returning their promises (and were thereby risking false positives.
2017-12-08 00:53:58 -08:00
Erik Erikson
32e660d94c add tests to validate that nested variables inside overwrites are resolved 2017-12-07 12:49:09 -08:00
Erik Erikson
6a0784ce2f add now passing "populate once" tests, use populate over render 2017-12-06 16:48:54 -08:00
Erik Erikson
c8ebe25968 fix build by adding `'use strict'; to generated 'async.load.js' 2017-12-06 16:38:51 -08:00
Erik Erikson
d6abd689b6 fix migrated tests 2017-12-06 16:20:17 -08:00
Erik Erikson
8c1fe6dfcc Refactor, simplify, correct, add tests
Increase name consistency
Improve names to be-what-they-are
Reduce cyclomatic complexity
Include overrides population fix
Add variable methods documentation
Add more tests around significant variable patterns/risky cases
2017-12-06 15:59:07 -08:00
Frank Schmid
8f70c13a9c
Merge branch 'master' into circular-vars 2017-12-07 00:22:55 +01:00
Frank Schmid
2e09606f13
Merge remote-tracking branch 'remotes/upstream/master' into circular-vars 2017-12-06 13:20:51 +01:00
Frank Schmid
8ff661835e
Merge branch 'master' into populate-default-objects 2017-12-06 12:34:50 +01:00
Erik Erikson
dea94bc310 Add significant variable usage corner cases 2017-12-05 14:31:00 -08:00
Frank Schmid
5526802a1b
Added request cache and queue to AWS provider
Make sure that requests are throttled. Use a queue for the requests.

Added new expected parameter to request() call in variables test

Added request cache tests
Check that request is indeed called 1000 times

Cache promises, not values

Use request cache for AWS variable requests

Use fromCallback instead of "new Promise" anti-pattern.

Added request cache to AWS provider
2017-12-05 12:39:39 +01:00
Frank Schmid
37340467ed
Populate objects if default syntax targets an object 2017-12-04 18:08:39 +01:00
Benjamin Forster
fae0ccb1d7 update variable name in test to be more descriptive 2017-12-01 10:40:23 +11:00
Benjamin Forster
6e6fea3fa2 update ssm cache to generic variable cache. 2017-12-01 10:33:30 +11:00
Benjamin Forster
382f6900e0 update test to show that cache is working 2017-11-30 10:08:23 +11:00
Benjamin Forster
33b666c431 add test 2017-11-29 17:49:52 +11:00