Skip to content

Commit

Permalink
Merge pull request serverless#2505 from serverless/version-lock
Browse files Browse the repository at this point in the history
implement version check
  • Loading branch information
flomotlik authored Nov 1, 2016
2 parents a4353e3 + b790f5a commit f958ad6
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 1,096 deletions.
2 changes: 1 addition & 1 deletion docs/providers/aws/guide/v0_to_v1.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--
title: Serverless Framework - AWS Lambda Guide - Comparison Of Serverless Framework V.1 & V.0
menuText: V.0 & V.1
menuOrder: 14
menuOrder: 15
description: A comparison of Serverless Framework V.1 and Serverless Framework V.0
layout: Doc
-->
Expand Down
51 changes: 51 additions & 0 deletions docs/providers/aws/guide/version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!--
title: Serverless Framework - AWS Lambda Guide - Pinning the Serverless framework version
menuText: Version pinning
menuOrder: 14
description: How to pin a service to certain Serverless versions.
layout: Doc
-->

# Why?

The Serverless framework is usually installed globally via `npm install -g serverless`. This way you have the Serverless CLI available for all your services. Installing tools globally has the downside that the version can't be pinned inside package.json. This can lead to issues if you upgrade Serverless, but your colleagues or CI system don't. You can now use a new feature in your serverless.yaml which is available only in the latest version without worrying that your CI system will deploy with an old version of Serverless.

## Pinning a Version

To configure version pinning define a `frameworkVersion` property in your serverless.yaml. Whenever you run a Serverless command from the CLI it checks if your current Serverless version is matching the `frameworkVersion` range. The CLI uses [Semantic Versioning](http://semver.org/) so you can pin it to an exact version or provide a range. In general we recommend to pin to an exact version to ensure everybody in your team has the exact same setup and no unexpected problems happen.

## Examples

### Exact Version

```yml
# serverless.yml

frameworkVersion: "=1.0.3"

service: users

provider:
name: aws
runtime: nodejs4.3
memorySize: 512

```

### Version Range

```yml
# serverless.yml

frameworkVersion: ">=1.0.0 <2.0.0"

service: users

provider:
name: aws
runtime: nodejs4.3
memorySize: 512

```
10 changes: 10 additions & 0 deletions lib/classes/Service.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const SError = require('./Error').SError;
const path = require('path');
const _ = require('lodash');
const BbPromise = require('bluebird');
const semver = require('semver');

class Service {

Expand Down Expand Up @@ -52,6 +53,15 @@ class Service {
.then((serverlessFileParam) => {
const serverlessFile = serverlessFileParam;
// basic service level validation
const version = this.serverless.utils.getVersion();
const ymlVersion = serverlessFile.frameworkVersion;
if (ymlVersion && !semver.satisfies(version, ymlVersion)) {
const errorMessage = [
`The Serverless version (${version}) does not satisfy the`,
` "frameworkVersion" (${ymlVersion}) in serverless.yml`,
].join('');
throw new SError(errorMessage);
}
if (!serverlessFile.service) {
throw new SError('"service" property is missing in serverless.yml');
}
Expand Down
48 changes: 48 additions & 0 deletions lib/classes/Service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const path = require('path');
const YAML = require('js-yaml');
const expect = require('chai').expect;
const sinon = require('sinon');
const Service = require('../../lib/classes/Service');
const Utils = require('../../lib/classes/Utils');
const Serverless = require('../../lib/Serverless');
Expand Down Expand Up @@ -334,6 +335,53 @@ describe('Service', () => {
});
});

it('should throw error if frameworkVersion is not satisfied', () => {
const SUtils = new Utils();
const serverlessYml = {
service: 'service-name',
frameworkVersion: '=1.0.0',
provider: 'aws',
functions: {},
};
SUtils.writeFileSync(path.join(tmpDirPath, 'serverless.yml'),
YAML.dump(serverlessYml));

const serverless = new Serverless({ servicePath: tmpDirPath });
const getVersion = sinon.stub(serverless.utils, 'getVersion');
getVersion.returns('1.0.2');
serviceInstance = new Service(serverless);

return serviceInstance.load().then(() => {
// if we reach this, then no error was thrown as expected
// so make assertion fail intentionally to let us know something is wrong
expect(1).to.equal(2);
}).catch(e => {
expect(e.name).to.be.equal('ServerlessError');
});
});

it('should pass if frameworkVersion is satisfied', () => {
const SUtils = new Utils();
const serverlessYml = {
service: 'service-name',
frameworkVersion: '>=1.0.0',
provider: 'aws',
functions: {},
};
SUtils.writeFileSync(path.join(tmpDirPath, 'serverless.yml'),
YAML.dump(serverlessYml));

const serverless = new Serverless({ servicePath: tmpDirPath });
const getVersion = sinon.stub(serverless.utils, 'getVersion');
getVersion.returns('1.2.2');
serviceInstance = new Service(serverless);

return serviceInstance.load().then(() => {
// if this callbar is reached, then no error was thrown as expected
expect(1).to.equal(1);
});
});

it('should not throw error if functions property is missing', () => {
const SUtils = new Utils();
const serverlessYml = {
Expand Down
5 changes: 5 additions & 0 deletions lib/classes/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ const _ = require('lodash');
const fetch = require('node-fetch');
const uuid = require('uuid');
const os = require('os');
const version = require('../../package.json').version;

class Utils {
constructor(serverless) {
this.serverless = serverless;
}

getVersion() {
return version;
}

dirExistsSync(dirPath) {
try {
const stats = fse.statSync(dirPath);
Expand Down
4 changes: 4 additions & 0 deletions lib/plugins/create/templates/aws-java-gradle/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

service: aws-java-gradle # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
name: aws
runtime: java8
Expand Down
4 changes: 4 additions & 0 deletions lib/plugins/create/templates/aws-java-maven/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

service: aws-java-maven # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
name: aws
runtime: java8
Expand Down
4 changes: 4 additions & 0 deletions lib/plugins/create/templates/aws-nodejs/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

service: aws-nodejs # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
name: aws
runtime: nodejs4.3
Expand Down
4 changes: 4 additions & 0 deletions lib/plugins/create/templates/aws-python/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

service: aws-python # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
name: aws
runtime: python2.7
Expand Down
4 changes: 4 additions & 0 deletions lib/plugins/create/templates/aws-scala-sbt/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

service: aws-scala-sbt # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
name: aws
runtime: java8
Expand Down
Loading

0 comments on commit f958ad6

Please sign in to comment.