Skip to content
This repository was archived by the owner on May 1, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,90 @@
# Template

This component is used behind the scenes to deploy your YAML templates. It is loaded by the serverless CLI and executed just as any other component.
However, there's a lot you can do with this component programmatically. See the sections below for some examples.

### Programmatic usage and custom environments

To deploy to multiple environments you must utilize the programmatic API, via `serverless.js` file.

`serverless.js`

```js
const { Component } = require('@serverless/core')

class Deploy extends Component {
async default(inputs = {}) {
const { env } = inputs

const template = await this.load('@serverless/template', env)
return await template({ template: __dirname + '/serverless.yml' })
}

async remove(inputs = {}) {
const { env } = inputs

const template = await this.load('@serverless/template', env)
await template.remove(inputs)
}
}

module.exports = Deploy
```

`serverless.yml`

```yml
name: test

lambda:
component: '@serverless/function'
inputs:
name: my-function
description: My Serverless Function
memory: 128
timeout: 20
code: './code'
hanlder": 'handler.handler'
region: us-east-1
runtime: nodejs10.x
```

Invoking `sls --env=dev` will result in state files in `.serverless/` being prefixed with the value of your `env`:
`Deploy.dev.json`, etc. That way you can deploy unlimited environments, add pre/post processing, load whatever `.env` you need, etc.

### Running custom methods on a template

A template itself does not contain any methods so custom methods are executed on the specific template aliases.

`sls install --component lambda` will load the `lambda` alias from your template, instantiate the corresponding component, and execute the `install` method passing in the inputs you specify via CLI parameters.
Inputs from the template itself are not passed as they can not be interpreted/resolved without running the entire template.

You can pass as many `--component` parameters as you need.

### Running custom methods programmatically

`serverless.js`

```js
const { Component } = require('@serverless/core')

class Deploy extends Component {
/* ...skipped default method for brevity ... */

async install(inputs = {}) {
const template = await this.load('@serverless/template')
await template.install({ template: __dirname + '/serverless.yml', ...inputs })
}
}

module.exports = Deploy
```

When invoking methods on a `template` instance, you always need to pass in a path to the template file or a template object.

Running `sls install --component lambda --debug` - this will load the template, find the `lambda` alias, and invoke the `install` method on the instance of the component.

### Couldn't find what you were looking for?

Visit our github and file an issue with as much info as possible about your problem.
If you think you've found a bug - please do post a complete reproduction repo. It will help us and our contributors to help you much faster.
5 changes: 5 additions & 0 deletions serverless.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ class Template extends Component {

return new Proxy(defaultFunction, {
get: (obj, prop) => {
// This handles the weird case when `then` is called on the `defaultFunction`
if (prop === 'then') {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this happening? I would suspect that properties from a promise are bleeding through here. However guarding against then does not guarantee that other things may also cause trouble. I suggest that createCustomMethodHandler should be renamed tryCreateCustomMethodHandler and if a component cannot be found, instead of creating an error, rather just return obj[prop]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately that is not possible, since you're passing template path at method invocation and not Template component construction.

return obj[prop]
}

if (obj.hasOwnProperty(prop)) {
return obj[prop]
}
Expand Down
6 changes: 5 additions & 1 deletion utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,12 @@ const createCustomMethodHandler = (instance, method) => {
instance.context.debug(
`Attempting to run method "${method}" on template aliases: ${components.join(', ')}`
)

// Make sure the template is an object
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it important to make sure the template is an object? Can this be explained in this comment?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On line 349 above, is it prudent to throw an Error? Perhaps if there was a proper testing framework that would guarantee the behavior of this, however since there is no framework and this is a core part of serverless components, I suggest not throwing an error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

template input of Template component can accept both string (path to file) and an object, which you can prepare in advance and simply pass for execution.

const templateObject = await getTemplate({ template })

// Load template components
const templateComponents = await getAllComponents(template)
const templateComponents = await getAllComponents(templateObject)

// Get only the requested components ("component" input)
const componentsToRun = Object.keys(templateComponents)
Expand Down