mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
Merge pull request #5299 from weeniearms/master
Added possibility to specify custom S3 key prefix instead of the stan…
This commit is contained in:
commit
bf2ee2e56b
@ -68,6 +68,9 @@ The Serverless Framework translates all syntax in `serverless.yml` to a single A
|
||||
* You can specify your own S3 bucket which should be used to store all the deployment artifacts.
|
||||
The `deploymentBucket` config which is nested under `provider` lets you e.g. set the `name` or the `serverSideEncryption` method for this bucket
|
||||
|
||||
* You can specify your own S3 prefix which should be used to store all the deployment artifacts.
|
||||
The `deploymentPrefix` config which is nested under `provider` lets you set the prefix under which the deployment artifacts will be stored. If not specified, defaults to `serverless`.
|
||||
|
||||
* You can make uploading to S3 faster by adding `--aws-s3-accelerate`
|
||||
|
||||
Check out the [deploy command docs](../cli-reference/deploy.md) for all details and options.
|
||||
|
||||
@ -37,6 +37,7 @@ provider:
|
||||
deploymentBucket:
|
||||
name: com.serverless.${self:provider.region}.deploys # Deployment bucket name. Default is generated by the framework
|
||||
serverSideEncryption: AES256 # when using server-side encryption
|
||||
deploymentPrefix: serverless # The S3 prefix under which deployed artifacts should be stored. Default is serverless
|
||||
role: arn:aws:iam::XXXXXX:role/role # Overwrite the default IAM role which is used for all functions
|
||||
cfnRole: arn:aws:iam::XXXXXX:role/role # ARN of an IAM role for CloudFormation service. If specified, CloudFormation uses the role's credentials
|
||||
versionFunctions: false # Optional function versioning
|
||||
|
||||
@ -107,6 +107,7 @@ provider:
|
||||
deploymentBucket:
|
||||
name: com.serverless.${self:provider.region}.deploys # Overwrite the default deployment bucket
|
||||
serverSideEncryption: AES256 # when using server-side encryption
|
||||
deploymentPrefix: serverless # Overwrite the default S3 prefix under which deployed artifacts should be stored. Default is serverless
|
||||
versionFunctions: false # Optional function versioning
|
||||
stackTags: # Optional CF stack tags
|
||||
key: value
|
||||
|
||||
@ -27,7 +27,7 @@ module.exports = {
|
||||
|
||||
const params = {
|
||||
Bucket: this.bucketName,
|
||||
Prefix: `serverless/${service}/${this.provider.getStage()}`,
|
||||
Prefix: `${this.provider.getDeploymentPrefix()}/${service}/${this.provider.getStage()}`,
|
||||
};
|
||||
|
||||
return this.provider.request('S3',
|
||||
|
||||
@ -10,18 +10,19 @@ module.exports = {
|
||||
const stacksToKeepCount = 5;
|
||||
const service = this.serverless.service.service;
|
||||
const stage = this.provider.getStage();
|
||||
const prefix = this.provider.getDeploymentPrefix();
|
||||
|
||||
return this.provider.request('S3',
|
||||
'listObjectsV2',
|
||||
{
|
||||
Bucket: this.bucketName,
|
||||
Prefix: `serverless/${service}/${stage}`,
|
||||
Prefix: `${prefix}/${service}/${stage}`,
|
||||
})
|
||||
.then((response) => {
|
||||
const stacks = findAndGroupDeployments(response, service, stage);
|
||||
const stacks = findAndGroupDeployments(response, prefix, service, stage);
|
||||
const stacksToKeep = _.takeRight(stacks, stacksToKeepCount);
|
||||
const stacksToRemove = _.pullAllWith(stacks, stacksToKeep, _.isEqual);
|
||||
const objectsToRemove = getS3ObjectsFromStacks(stacksToRemove, service, stage);
|
||||
const objectsToRemove = getS3ObjectsFromStacks(stacksToRemove, prefix, service, stage);
|
||||
|
||||
if (objectsToRemove.length) {
|
||||
return BbPromise.resolve(objectsToRemove);
|
||||
|
||||
@ -29,7 +29,8 @@ describe('cleanupS3Bucket', () => {
|
||||
provider = new AwsProvider(serverless, options);
|
||||
serverless.setProvider('aws', provider);
|
||||
serverless.service.service = 'cleanupS3Bucket';
|
||||
s3Key = `serverless/${serverless.service.service}/${provider.getStage()}`;
|
||||
const prefix = provider.getDeploymentPrefix();
|
||||
s3Key = `${prefix}/${serverless.service.service}/${provider.getStage()}`;
|
||||
awsDeploy = new AwsDeploy(serverless, options);
|
||||
awsDeploy.bucketName = 'deployment-bucket';
|
||||
awsDeploy.serverless.cli = new serverless.classes.CLI();
|
||||
|
||||
@ -35,17 +35,18 @@ class AwsDeployList {
|
||||
listDeployments() {
|
||||
const service = this.serverless.service.service;
|
||||
const stage = this.provider.getStage();
|
||||
const prefix = this.provider.getDeploymentPrefix();
|
||||
|
||||
return this.provider.request('S3',
|
||||
'listObjectsV2',
|
||||
{
|
||||
Bucket: this.bucketName,
|
||||
Prefix: `serverless/${service}/${stage}`,
|
||||
Prefix: `${prefix}/${service}/${stage}`,
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
const directoryRegex = new RegExp('(.+)-(.+-.+-.+)');
|
||||
const deployments = findAndGroupDeployments(response, service, stage);
|
||||
const deployments = findAndGroupDeployments(response, prefix, service, stage);
|
||||
|
||||
if (deployments.length === 0) {
|
||||
this.serverless.cli.log('Couldn\'t find any existing deployments.');
|
||||
|
||||
@ -21,7 +21,8 @@ describe('AwsDeployList', () => {
|
||||
provider = new AwsProvider(serverless, options);
|
||||
serverless.setProvider('aws', provider);
|
||||
serverless.service.service = 'listDeployments';
|
||||
s3Key = `serverless/${serverless.service.service}/${provider.getStage()}`;
|
||||
const prefix = provider.getDeploymentPrefix();
|
||||
s3Key = `${prefix}/${serverless.service.service}/${provider.getStage()}`;
|
||||
awsDeployList = new AwsDeployList(serverless, options);
|
||||
awsDeployList.bucketName = 'deployment-bucket';
|
||||
awsDeployList.serverless.cli = {
|
||||
|
||||
@ -7,8 +7,9 @@ module.exports = {
|
||||
const date = new Date();
|
||||
const serviceStage = `${this.serverless.service.service}/${this.provider.getStage()}`;
|
||||
const dateString = `${date.getTime().toString()}-${date.toISOString()}`;
|
||||
const prefix = this.provider.getDeploymentPrefix();
|
||||
this.serverless.service.package
|
||||
.artifactDirectoryName = `serverless/${serviceStage}/${dateString}`;
|
||||
.artifactDirectoryName = `${prefix}/${serviceStage}/${dateString}`;
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
|
||||
@ -266,6 +266,7 @@ class AwsProvider {
|
||||
{ providerError: _.assign({}, err, { retryable: false }) }
|
||||
));
|
||||
}
|
||||
|
||||
return BbPromise.reject(Object.assign(
|
||||
new this.serverless.classes.Error(message, err.statusCode),
|
||||
{ providerError: err }
|
||||
@ -390,6 +391,10 @@ class AwsProvider {
|
||||
).then((result) => result.StackResourceDetail.PhysicalResourceId);
|
||||
}
|
||||
|
||||
getDeploymentPrefix() {
|
||||
return this.serverless.service.provider.deploymentPrefix || 'serverless';
|
||||
}
|
||||
|
||||
getStageSourceValue() {
|
||||
const values = this.getValues(this, [
|
||||
['options', 'stage'],
|
||||
|
||||
@ -911,6 +911,21 @@ describe('AwsProvider', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getDeploymentPrefix()', () => {
|
||||
it('should return custom deployment prefix if defined', () => {
|
||||
serverless.service.provider.deploymentPrefix = 'providerPrefix';
|
||||
|
||||
expect(awsProvider.getDeploymentPrefix())
|
||||
.to.equal(serverless.service.provider.deploymentPrefix);
|
||||
});
|
||||
|
||||
it('should use the default serverless if not defined', () => {
|
||||
serverless.service.provider.deploymentPrefix = undefined;
|
||||
|
||||
expect(awsProvider.getDeploymentPrefix()).to.equal('serverless');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getStage()', () => {
|
||||
it('should prefer options over config or provider', () => {
|
||||
const newOptions = {
|
||||
|
||||
@ -18,7 +18,7 @@ module.exports = {
|
||||
|
||||
return this.provider.request('S3', 'listObjectsV2', {
|
||||
Bucket: this.bucketName,
|
||||
Prefix: `serverless/${serviceStage}`,
|
||||
Prefix: `${this.provider.getDeploymentPrefix()}/${serviceStage}`,
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
result.Contents.forEach((object) => {
|
||||
|
||||
@ -42,6 +42,9 @@ describe('emptyS3Bucket', () => {
|
||||
const listObjectsStub = sinon.stub(awsRemove.provider, 'request')
|
||||
.resolves();
|
||||
|
||||
const stage = awsRemove.provider.getStage();
|
||||
const prefix = awsRemove.provider.getDeploymentPrefix();
|
||||
|
||||
return awsRemove.listObjects().then(() => {
|
||||
expect(listObjectsStub.calledOnce).to.be.equal(true);
|
||||
expect(listObjectsStub.calledWithExactly(
|
||||
@ -49,7 +52,7 @@ describe('emptyS3Bucket', () => {
|
||||
'listObjectsV2',
|
||||
{
|
||||
Bucket: awsRemove.bucketName,
|
||||
Prefix: `serverless/${serverless.service.service}/${awsRemove.provider.getStage()}`,
|
||||
Prefix: `${prefix}/${serverless.service.service}/${stage}`,
|
||||
}
|
||||
)).to.be.equal(true);
|
||||
expect(awsRemove.objectsInBucket.length).to.equal(0);
|
||||
@ -66,6 +69,9 @@ describe('emptyS3Bucket', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const stage = awsRemove.provider.getStage();
|
||||
const prefix = awsRemove.provider.getDeploymentPrefix();
|
||||
|
||||
return awsRemove.listObjects().then(() => {
|
||||
expect(listObjectsStub.calledOnce).to.be.equal(true);
|
||||
expect(listObjectsStub.calledWithExactly(
|
||||
@ -73,7 +79,7 @@ describe('emptyS3Bucket', () => {
|
||||
'listObjectsV2',
|
||||
{
|
||||
Bucket: awsRemove.bucketName,
|
||||
Prefix: `serverless/${serverless.service.service}/${awsRemove.provider.getStage()}`,
|
||||
Prefix: `${prefix}/${serverless.service.service}/${stage}`,
|
||||
}
|
||||
)).to.be.equal(true);
|
||||
expect(awsRemove.objectsInBucket[0]).to.deep.equal({ Key: 'object1' });
|
||||
|
||||
@ -47,7 +47,8 @@ class AwsRollback {
|
||||
const service = this.serverless.service;
|
||||
const serviceName = this.serverless.service.service;
|
||||
const stage = this.provider.getStage();
|
||||
const prefix = `serverless/${serviceName}/${stage}`;
|
||||
const deploymentPrefix = this.provider.getDeploymentPrefix();
|
||||
const prefix = `${deploymentPrefix}/${serviceName}/${stage}`;
|
||||
|
||||
return this.provider.request('S3',
|
||||
'listObjectsV2',
|
||||
@ -56,7 +57,7 @@ class AwsRollback {
|
||||
Prefix: prefix,
|
||||
})
|
||||
.then((response) => {
|
||||
const deployments = findAndGroupDeployments(response, serviceName, stage);
|
||||
const deployments = findAndGroupDeployments(response, deploymentPrefix, serviceName, stage);
|
||||
|
||||
if (deployments.length === 0) {
|
||||
const msg = 'Couldn\'t find any existing deployments.';
|
||||
|
||||
@ -27,7 +27,8 @@ describe('AwsRollback', () => {
|
||||
spawnStub = sinon.stub(serverless.pluginManager, 'spawn');
|
||||
awsRollback = new AwsRollback(serverless, options);
|
||||
awsRollback.serverless.cli = new serverless.classes.CLI();
|
||||
s3Key = `serverless/${serverless.service.service}/${provider.getStage()}`;
|
||||
const prefix = provider.getDeploymentPrefix();
|
||||
s3Key = `${prefix}/${serverless.service.service}/${provider.getStage()}`;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = (s3Response, service, stage) => {
|
||||
module.exports = (s3Response, prefix, service, stage) => {
|
||||
if (s3Response.Contents.length) {
|
||||
const regex = new RegExp(`serverless/${service}/${stage}/(.+-.+-.+-.+)/(.+)`);
|
||||
const regex = new RegExp(`${prefix}/${service}/${stage}/(.+-.+-.+-.+)/(.+)`);
|
||||
const s3Objects = s3Response.Contents.filter((s3Object) => s3Object.Key.match(regex));
|
||||
const names = s3Objects.map((s3Object) => {
|
||||
const match = s3Object.Key.match(regex);
|
||||
|
||||
@ -9,7 +9,7 @@ describe('#findAndGroupDeployments()', () => {
|
||||
Contents: [],
|
||||
};
|
||||
|
||||
expect(findAndGroupDeployments(s3Response, 'test', 'dev')).to.deep.equal([]);
|
||||
expect(findAndGroupDeployments(s3Response, 'serverless', 'test', 'dev')).to.deep.equal([]);
|
||||
});
|
||||
|
||||
it('should group stacks', () => {
|
||||
@ -73,6 +73,7 @@ describe('#findAndGroupDeployments()', () => {
|
||||
],
|
||||
];
|
||||
|
||||
expect(findAndGroupDeployments(s3Response, 'test', 'dev')).to.deep.equal(expected);
|
||||
expect(findAndGroupDeployments(s3Response, 'serverless', 'test', 'dev'))
|
||||
.to.deep.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = (stacks, service, stage) => (
|
||||
module.exports = (stacks, prefix, service, stage) => (
|
||||
_.flatten(stacks).map((entry) => (
|
||||
{ Key: `serverless/${service}/${stage}/${entry.directory}/${entry.file}` })
|
||||
{ Key: `${prefix}/${service}/${stage}/${entry.directory}/${entry.file}` })
|
||||
)
|
||||
);
|
||||
|
||||
@ -5,7 +5,7 @@ const getS3ObjectsFromStacks = require('./getS3ObjectsFromStacks');
|
||||
|
||||
describe('#getS3ObjectsFromStacks()', () => {
|
||||
it('should return an empty result in case no stacks are provided', () => {
|
||||
expect(getS3ObjectsFromStacks([], 'test', 'dev')).to.deep.equal([]);
|
||||
expect(getS3ObjectsFromStacks([], 'serverless', 'test', 'dev')).to.deep.equal([]);
|
||||
});
|
||||
|
||||
it('should return an empty result in case no stacks are provided', () => {
|
||||
@ -41,6 +41,6 @@ describe('#getS3ObjectsFromStacks()', () => {
|
||||
{ Key: 'serverless/test/dev/1476779278222-2016-10-18T08:27:58.222Z/test.zip' },
|
||||
];
|
||||
|
||||
expect(getS3ObjectsFromStacks(stacks, 'test', 'dev')).to.deep.equal(expected);
|
||||
expect(getS3ObjectsFromStacks(stacks, 'serverless', 'test', 'dev')).to.deep.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user