Skip to content

Commit

Permalink
feat(2135): Add new commands to validate and publish pipeline level t…
Browse files Browse the repository at this point in the history
…emplate (#38)
  • Loading branch information
aishwaryanair04 authored Aug 11, 2023
1 parent fe87d2b commit eb2ff58
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 37 deletions.
5 changes: 5 additions & 0 deletions bin/pipelineTemplatePublish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node

'use strict';

require('../commands').run('publishPipelineTemplate');
5 changes: 5 additions & 0 deletions bin/pipelineTemplateValidate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node

'use strict';

require('../commands').run('validatePipelineTemplate');
66 changes: 57 additions & 9 deletions commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const index = require('./index');
const path = process.env.SD_TEMPLATE_PATH || './sd-template.yaml';

const operations = {
/* Publish template */
/* Publish job template */
publish: {
opts: {
json: { abbr: 'j', flag: true, help: 'Output result as json' },
Expand All @@ -14,7 +14,7 @@ const operations = {
exec(opts) {
return index
.loadYaml(path)
.then(config => index.publishTemplate(config))
.then(config => index.publishJobTemplate(config))
.then(publishResult =>
index.tagTemplate({
name: publishResult.name,
Expand All @@ -40,15 +40,15 @@ const operations = {
help: 'publish template'
},

/* Validate template */
/* Validate job template */
validate: {
opts: {
json: { abbr: 'j', flag: true, help: 'Output result as json' }
},
exec(opts) {
return index
.loadYaml(path)
.then(config => index.validateTemplate(config))
.then(config => index.validateJobTemplate(config))
.then(result => {
if (!opts.json) {
console.log('Template is valid');
Expand All @@ -64,7 +64,7 @@ const operations = {
help: 'validate template'
},

/* Add tag for template */
/* Add tag for job template */
tag: {
opts: {
name: { required: true, abbr: 'n', help: 'Template name' },
Expand Down Expand Up @@ -96,7 +96,7 @@ const operations = {
help: 'add tag'
},

/* Remove tag for template */
/* Remove tag for job template */
remove_tag: {
opts: {
name: { required: true, abbr: 'n', help: 'Template name' },
Expand Down Expand Up @@ -125,7 +125,7 @@ const operations = {
help: 'remove tag'
},

/* Remove template version */
/* Remove job template version */
remove_version: {
opts: {
name: { required: true, abbr: 'n', help: 'Template name' },
Expand Down Expand Up @@ -154,7 +154,7 @@ const operations = {
help: 'remove version'
},

/* remove a template */
/* remove a job template */
remove_template: {
opts: {
name: { required: true, abbr: 'n', help: 'Template name' },
Expand All @@ -179,7 +179,7 @@ const operations = {
help: 'remove template'
},

/* get version number from tag */
/* get job template version number from tag */
get_version_from_tag: {
opts: {
name: { required: true, abbr: 'n', help: 'Template name' },
Expand All @@ -201,6 +201,54 @@ const operations = {
});
},
help: 'get version from tag'
},

/* Validate pipeline template */
validatePipelineTemplate: {
opts: {
json: { abbr: 'j', flag: true, help: 'Output result as json' }
},
exec(opts) {
return index
.loadYaml(path)
.then(config => index.validatePipelineTemplate(config))
.then(result => {
if (!opts.json) {
console.log('Template is valid');
} else {
console.log(JSON.stringify(result));
}
})
.catch(err => {
console.error(err);
process.exit(1);
});
},
help: 'validate pipeline template'
},

/* Publish pipeline template */
publishPipelineTemplate: {
opts: {
json: { abbr: 'j', flag: true, help: 'Output result as json' }
},
exec(opts) {
return index
.loadYaml(path)
.then(config => index.publishPipelineTemplate(config))
.then(result => {
if (!opts.json) {
console.log(`Pipeline template ${result.name}@${result.version} was successfully published`);
} else {
console.log(JSON.stringify(result));
}
})
.catch(err => {
console.error(err);
process.exit(1);
});
},
help: 'publish pipeline template'
}
};

Expand Down
83 changes: 64 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';

const request = require('screwdriver-request');
const fs = require('fs');
const URL = require('url');
const request = require('screwdriver-request');
const Yaml = require('js-yaml');

/**
Expand All @@ -18,14 +18,15 @@ function loadYaml(path) {
}

/**
* Validates the template yaml
* Validates the jobs and pipeline template yaml by posting to the endpoint
* @method validateTemplate
* @param {Object} config Template config
* @return {Promise} Resolves when template is valid/rejects when error or invalid
* @param {Object} config Template config
* @param {String} apiURL endpoint API
* @return {Promise} Resolves if validates successfully
*/
function validateTemplate(config) {
function validateTemplate(config, apiURL) {
const hostname = process.env.SD_API_URL || 'https://api.screwdriver.cd/v4/';
const url = URL.resolve(hostname, 'validator/template');
const url = URL.resolve(hostname, apiURL);

return request({
method: 'POST',
Expand All @@ -43,9 +44,7 @@ function validateTemplate(config) {
let errorMessage = 'Template is not valid for the following reasons:';

body.errors.forEach(err => {
/* eslint-disable prefer-template */
errorMessage += `\n${JSON.stringify(err, null, 4)},`;
/* eslint-enable prefer-template */
});

throw new Error(errorMessage);
Expand All @@ -58,14 +57,35 @@ function validateTemplate(config) {
}

/**
* Publishes the template yaml by posting to the SDAPI /templates endpoint
* Validates the job template yaml by using the validateTemplate method and passing the API endpoint
* @method validateJobTemplate
* @param {Object} config Template config
* @return {Promise} Resolves if validates successfully
*/
function validateJobTemplate(config) {
return validateTemplate(config, 'validator/template');
}

/**
* Validates the pipeline template yaml by using the validateTemplate method and passing the API endpoint
* @method validatePipelineTemplate
* @param {Object} config Template config
* @return {Promise} Resolves if validates successfully
*/
function validatePipelineTemplate(config) {
return validateTemplate(config, 'validator/pipelineTemplate');
}

/**
* Publishes the jobs and pipeline template yaml by posting to the endpoint
* @method publishTemplate
* @param {Object} config Template config
* @return {Promise} Resolves if publish successfully
* @param {String} apiURL endpoint API
* @return {Promise} Resolves if publishes successfully
*/
function publishTemplate(config) {
function publishTemplate(config, apiURL) {
const hostname = process.env.SD_API_URL || 'https://api.screwdriver.cd/v4/';
const url = URL.resolve(hostname, 'templates');
const url = URL.resolve(hostname, apiURL);

return request({
method: 'POST',
Expand All @@ -83,20 +103,42 @@ function publishTemplate(config) {
throw new Error(`Error publishing template. ${response.statusCode} (${body.error}): ${body.message}`);
}

let fullTemplateName = body.name;
return body;
});
}

/**
* Publishes the job template yaml by using the publishTemplate method and passing the API endpoint
* @method publishJobTemplate
* @param {Object} config Template config
* @return {Promise} Resolves if publishes successfully
*/
function publishJobTemplate(config) {
return publishTemplate(config, 'templates').then(template => {
let fullTemplateName = template.name;

// Figure out template name
if (body.namespace && body.namespace !== 'default') {
fullTemplateName = `${body.namespace}/${body.name}`;
if (template.namespace && template.namespace !== 'default') {
fullTemplateName = `${template.namespace}/${template.name}`;
}

return {
name: fullTemplateName,
version: body.version
version: template.version
};
});
}

/**
* Publishes the pipeline template yaml by using the publishTemplate method and passing the API endpoint
* @method publishPipelineTemplate
* @param {Object} config Template config
* @return {Promise} Resolves if publishes successfully
*/
function publishPipelineTemplate(config) {
return publishTemplate(config, 'pipeline/template/publish');
}

/**
* Removes all versions of a template by sending a delete request to the SDAPI /templates/{name} endpoint
* @method removeTemplate
Expand Down Expand Up @@ -292,13 +334,16 @@ function removeTag({ name, tag }) {
};
});
}

module.exports = {
loadYaml,
validateTemplate,
publishTemplate,
validateJobTemplate,
publishJobTemplate,
removeTemplate,
removeVersion,
tagTemplate,
removeTag,
getVersionFromTag
getVersionFromTag,
validatePipelineTemplate,
publishPipelineTemplate
};
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"template-tag": "./bin/tag.js",
"template-remove-tag": "./bin/removeTag.js",
"template-remove-version": "./bin/removeVersion.js",
"template-get-version-from-tag": "./bin/getVersionFromTag.js"
"template-get-version-from-tag": "./bin/getVersionFromTag.js",
"pipeline-template-validate": "./bin/pipelineTemplateValidate.js",
"pipeline-template-publish": "./bin/pipelineTemplatePublish.js"
},
"repository": {
"type": "git",
Expand Down
16 changes: 8 additions & 8 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe('index', () => {
requestMock.rejects(new Error('error'));

return index
.validateTemplate(templateConfig)
.validateJobTemplate(templateConfig)
.then(() => assert.fail('should not get here'))
.catch(err => {
assert.equal(err.message, 'error');
Expand All @@ -99,7 +99,7 @@ describe('index', () => {
requestMock.resolves(responseFake);

return index
.validateTemplate(templateConfig)
.validateJobTemplate(templateConfig)
.then(() => assert.fail('should not get here'))
.catch(err => {
// eslint-disable-next-line max-len
Expand All @@ -124,7 +124,7 @@ describe('index', () => {

requestMock.resolves(responseFake);

return index.validateTemplate(templateConfig).then(result =>
return index.validateJobTemplate(templateConfig).then(result =>
assert.deepEqual(result, {
valid: true
})
Expand All @@ -137,7 +137,7 @@ describe('index', () => {
requestMock.rejects(new Error('error'));

return index
.publishTemplate(templateConfig)
.publishJobTemplate(templateConfig)
.then(() => assert.fail('should not get here'))
.catch(err => {
assert.equal(err.message, 'error');
Expand All @@ -157,7 +157,7 @@ describe('index', () => {
requestMock.resolves(responseFake);

return index
.publishTemplate(templateConfig)
.publishJobTemplate(templateConfig)
.then(() => assert.fail('should not get here'))
.catch(err => {
assert.equal(err.message, 'Error publishing template. 403 (Forbidden): Fake forbidden message');
Expand All @@ -172,7 +172,7 @@ describe('index', () => {

requestMock.resolves(responseFake);

return index.publishTemplate(templateConfig).then(result =>
return index.publishJobTemplate(templateConfig).then(result =>
assert.deepEqual(result, {
name: templateConfig.name,
version: templateConfig.version
Expand All @@ -189,7 +189,7 @@ describe('index', () => {
templateConfig.namespace = 'meow';
requestMock.resolves(responseFake);

return index.publishTemplate(templateConfig).then(result =>
return index.publishJobTemplate(templateConfig).then(result =>
assert.deepEqual(result, {
name: `${templateConfig.namespace}/${templateConfig.name}`,
version: templateConfig.version
Expand All @@ -206,7 +206,7 @@ describe('index', () => {
templateConfig.namespace = 'default';
requestMock.resolves(responseFake);

return index.publishTemplate(templateConfig).then(result =>
return index.publishJobTemplate(templateConfig).then(result =>
assert.deepEqual(result, {
name: templateConfig.name,
version: templateConfig.version
Expand Down

0 comments on commit eb2ff58

Please sign in to comment.