Skip to content

Commit

Permalink
feat: Add create and remove template tag routes
Browse files Browse the repository at this point in the history
  • Loading branch information
d2lam committed Jul 18, 2017
1 parent 369d20b commit e936260
Show file tree
Hide file tree
Showing 7 changed files with 356 additions and 20 deletions.
4 changes: 4 additions & 0 deletions bin/server
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ const Models = require('screwdriver-models');
const templateFactory = Models.TemplateFactory.getInstance({
datastore
});
const templateTagFactory = Models.TemplateTagFactory.getInstance({
datastore
});
const pipelineFactory = Models.PipelineFactory.getInstance({
datastore,
scm
Expand Down Expand Up @@ -117,6 +120,7 @@ datastore.setup()
notifications: notificationConfig,
ecosystem,
templateFactory,
templateTagFactory,
pipelineFactory,
jobFactory,
userFactory,
Expand Down
1 change: 1 addition & 0 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ module.exports = (config) => {
// Instantiating the server with the factories will apply a shallow copy
server.app = {
templateFactory: config.templateFactory,
templateTagFactory: config.templateTagFactory,
pipelineFactory: config.pipelineFactory,
jobFactory: config.jobFactory,
userFactory: config.userFactory,
Expand Down
29 changes: 26 additions & 3 deletions plugins/templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ server.register({

`GET /templates?page={pageNumber}&count={countNumber}`

#### Get single template
#### Get a single template

`GET /templates/{id}`

#### Create a template
Create a template will store the template data (`config`, `name`, `version`, `description`, `maintainer`, `labels`) into the datastore.
Creating a template will store the template data (`config`, `name`, `version`, `description`, `maintainer`, `labels`) into the datastore.

If the exact template and version already exist, the only thing that can be changed is `labels`.

If the template already exists but not the version, the new version will be stored provided that the build has correct permissions.

This endpoint is only accessible in `build` scope.
*Note: This endpoint is only accessible in `build` scope and the permission is tied to the pipeline that first creates the template.*

`POST /templates`

Expand Down Expand Up @@ -73,3 +73,26 @@ Example payload:
}
}
```

#### Create/Update a tag for a template version

Tagging a template version allows fetching on template version by tag. For example, tag `[email protected]` as `stable`.

*Note: This endpoint is only accessible in `build` scope and the permission is tied to the pipeline that creates the template.*

`POST /templates/tags` with the following payload

* `name` - Name of the template (ex: `mytemplate`)
* `version` - Version of the template (ex: `1.1.0`)
* `tag` - Name of the tag (ex: `stable`)

#### Delete a template tag

Delete the template tag. This does not delete the template itself.

*Note: This endpoint is only accessible in `build` scope and the permission is tied to the pipeline that creates the template.*

`DELETE /templates/tags` with the following payload

* `name` - Name of the template (ex: `mytemplate`)
* `tag` - Name of the tag (ex: `stable`)
79 changes: 79 additions & 0 deletions plugins/templates/createTag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use strict';

const boom = require('boom');
const schema = require('screwdriver-data-schema');
const urlLib = require('url');

/* Currently, only build scope is allowed to tag template due to security reasons.
* The same pipeline that publishes the template has the permission to tag it.
*/
module.exports = () => ({
method: 'PUT',
path: '/templates/tags',
config: {
description: 'Add or update a template tag',
notes: 'Add or update a specific template',
tags: ['api', 'templates'],
auth: {
strategies: ['token', 'session'],
scope: ['build']
},
plugins: {
'hapi-swagger': {
security: [{ token: [] }]
}
},
handler: (request, reply) => {
const pipelineFactory = request.server.app.pipelineFactory;
const templateFactory = request.server.app.templateFactory;
const templateTagFactory = request.server.app.templateTagFactory;
const pipelineId = request.auth.credentials.pipelineId;
const config = request.payload;

return Promise.all([
pipelineFactory.get(pipelineId),
templateFactory.get({
name: config.name,
version: config.version
}),
templateTagFactory.get({
name: config.name,
tag: config.tag
})
]).then(([pipeline, template, templateTag]) => {
// If template doesn't exist, throw error
if (!template) {
throw boom.notFound(`Template ${config.name}@${config.version} not found`);
}

// If template exists, but this build's pipelineId is not the same as template's pipelineId
// Then this build does not have permission to tag the template
if (pipeline.id !== template.pipelineId) {
throw boom.unauthorized('Not allowed to tag this template');
}

// If template tag exists, then the only thing it can update is the version
if (templateTag) {
templateTag.version = config.version;

return templateTag.update().then(tag => reply(tag.toJson()).code(200));
}

// If template exists, then create the tag
return templateTagFactory.create(config).then((tag) => {
const location = urlLib.format({
host: request.headers.host,
port: request.headers.port,
protocol: request.server.info.protocol,
pathname: `${request.path}/${tag.id}`
});

return reply(tag.toJson()).header('Location', location).code(201);
});
}).catch(err => reply(boom.wrap(err)));
},
validate: {
payload: schema.models.templateTag.create
}
}
});
6 changes: 5 additions & 1 deletion plugins/templates/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
'use strict';

const createRoute = require('./create');
const createTagRoute = require('./createTag');
const getRoute = require('./get');
const listRoute = require('./list');
const listVersionsRoute = require('./listVersions');
const removeTagRoute = require('./removeTag');

/**
* Template API Plugin
Expand All @@ -15,9 +17,11 @@ const listVersionsRoute = require('./listVersions');
exports.register = (server, options, next) => {
server.route([
createRoute(),
createTagRoute(),
getRoute(),
listRoute(),
listVersionsRoute()
listVersionsRoute(),
removeTagRoute()
]);

next();
Expand Down
65 changes: 65 additions & 0 deletions plugins/templates/removeTag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

const boom = require('boom');
const schema = require('screwdriver-data-schema');

/* Currently, only build scope is allowed to tag template due to security reasons.
* The same pipeline that publishes the template has the permission to tag it.
*/
module.exports = () => ({
method: 'DELETE',
path: '/templates/tags',
config: {
description: 'Delete a template tag',
notes: 'Delete a specific template',
tags: ['api', 'templates'],
auth: {
strategies: ['token', 'session'],
scope: ['build']
},
plugins: {
'hapi-swagger': {
security: [{ token: [] }]
}
},
handler: (request, reply) => {
const pipelineFactory = request.server.app.pipelineFactory;
const templateFactory = request.server.app.templateFactory;
const templateTagFactory = request.server.app.templateTagFactory;
const pipelineId = request.auth.credentials.pipelineId;
const config = request.payload;

return templateTagFactory.get({
name: config.name,
tag: config.tag
})
.then((templateTag) => {
if (!templateTag) {
throw boom.notFound('Template tag does not exist');
}

return Promise.all([
pipelineFactory.get(pipelineId),
templateFactory.get({
name: config.name,
version: templateTag.version
})
])
.then(([pipeline, template]) => {
// Check for permission
if (pipeline.id !== template.pipelineId) {
throw boom.unauthorized('Not allowed to delete this template tag');
}

// Remove the template tag, not the template
return templateTag.remove();
});
})
.then(() => reply().code(204))
.catch(err => reply(boom.wrap(err)));
},
validate: {
payload: schema.models.templateTag.remove
}
}
});
Loading

0 comments on commit e936260

Please sign in to comment.