From 6f51657ef8d8a1ddbd9180e1931bbc1b07ff9f74 Mon Sep 17 00:00:00 2001 From: ricardo Date: Tue, 30 Jun 2020 18:46:45 -0400 Subject: [PATCH 1/3] :sparkles: CircleCI-Node --- .../credentials/CircleCiApi.credentials.ts | 17 ++ .../nodes/CircleCi/CircleCi.node.ts | 137 +++++++++++ .../nodes/CircleCi/GenericFunctions.ts | 67 ++++++ .../nodes/CircleCi/PipelineDescription.ts | 222 ++++++++++++++++++ .../nodes-base/nodes/CircleCi/circleCi.png | Bin 0 -> 4787 bytes packages/nodes-base/package.json | 2 + 6 files changed, 445 insertions(+) create mode 100644 packages/nodes-base/credentials/CircleCiApi.credentials.ts create mode 100644 packages/nodes-base/nodes/CircleCi/CircleCi.node.ts create mode 100644 packages/nodes-base/nodes/CircleCi/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/CircleCi/PipelineDescription.ts create mode 100644 packages/nodes-base/nodes/CircleCi/circleCi.png diff --git a/packages/nodes-base/credentials/CircleCiApi.credentials.ts b/packages/nodes-base/credentials/CircleCiApi.credentials.ts new file mode 100644 index 0000000000..88ecdc4fe1 --- /dev/null +++ b/packages/nodes-base/credentials/CircleCiApi.credentials.ts @@ -0,0 +1,17 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class CircleCiApi implements ICredentialType { + name = 'circleCiApi'; + displayName = 'CircleCI API'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts b/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts new file mode 100644 index 0000000000..00eded6366 --- /dev/null +++ b/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts @@ -0,0 +1,137 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeTypeDescription, + INodeExecutionData, + INodeType, +} from 'n8n-workflow'; + +import { + pipelineFields, + pipelineOperations, +} from './PipelineDescription'; + +import { + circleciApiRequest, + circleciApiRequestAllItems, +} from './GenericFunctions'; + +export class CircleCi implements INodeType { + description: INodeTypeDescription = { + displayName: 'CircleCI', + name: 'circleCi', + icon: 'file:circleCi.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume CircleCI API', + defaults: { + name: 'CircleCI', + color: '#04AA51', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'circleCiApi', + required: true, + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: ' Pipeline', + value: 'pipeline', + }, + ], + default: 'pipeline', + description: 'Resource to consume.', + }, + ...pipelineOperations, + ...pipelineFields, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + const qs: IDataObject = {}; + let responseData; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + + for (let i = 0; i < length; i++) { + if (resource === 'pipeline') { + if (operation === 'get') { + let slug = this.getNodeParameter('projectSlug', i) as string; + const pipelineNumber = this.getNodeParameter('pipelineNumber', i) as number; + + slug = slug.replace(new RegExp(/\//g), '%2F'); + + const endpoint = `/project/${slug}/pipeline/${pipelineNumber}`; + + responseData = await circleciApiRequest.call(this, 'GET', endpoint, {}, qs); + } + if (operation === 'getAll') { + const filters = this.getNodeParameter('filters', i) as IDataObject; + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + let slug = this.getNodeParameter('projectSlug', i) as string; + + slug = slug.replace(new RegExp(/\//g), '%2F'); + + if (filters.branch) { + qs.branch = filters.branch; + } + + const endpoint = `/project/${slug}/pipeline`; + + if (returnAll === true) { + responseData = await circleciApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}, qs); + + } else { + qs.limit = this.getNodeParameter('limit', i) as number; + responseData = await circleciApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + responseData = responseData.splice(0, qs.limit); + } + } + + if (operation === 'trigger') { + let slug = this.getNodeParameter('projectSlug', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + slug = slug.replace(new RegExp(/\//g), '%2F'); + + const endpoint = `/project/${slug}/pipeline`; + + const body: IDataObject = {}; + + if (additionalFields.branch) { + body.branch = additionalFields.branch as string; + } + + if (additionalFields.tag) { + body.tag = additionalFields.tag as string; + } + + responseData = await circleciApiRequest.call(this, 'POST', endpoint, body, qs); + } + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts b/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts new file mode 100644 index 0000000000..fb30950a1a --- /dev/null +++ b/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts @@ -0,0 +1,67 @@ +import { + OptionsWithUri, +} from 'request'; + +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { + IDataObject, +} from 'n8n-workflow'; + +export async function circleciApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('circleCiApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + let options: OptionsWithUri = { + headers: { + 'Circle-Token': credentials.apiKey, + 'Accept': 'application/json', + }, + method, + qs, + body, + uri: uri ||`https://circleci.com/api/v2${resource}`, + json: true + }; + options = Object.assign({}, options, option); + if (Object.keys(options.body).length === 0) { + delete options.body; + } + try { + return await this.helpers.request!(options); + } catch (err) { + if (err.response && err.response.body && err.response.body.message) { + // Try to return the error prettier + throw new Error(`CircleCI error response [${err.statusCode}]: ${err.response.body.message}`); + } + + // If that data does not exist for some reason return the actual error + throw err; } +} + +/** + * Make an API request to paginated CircleCI endpoint + * and return all results + */ +export async function circleciApiRequestAllItems(this: IHookFunctions | IExecuteFunctions| ILoadOptionsFunctions, propertyName: string, method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + + do { + responseData = await circleciApiRequest.call(this, method, resource, body, query); + returnData.push.apply(returnData, responseData[propertyName]); + query['page-token'] = responseData.next_page_token; + } while ( + responseData.next_page_token !== undefined && + responseData.next_page_token !== null + ); + return returnData; +} diff --git a/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts b/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts new file mode 100644 index 0000000000..66b99f3eb3 --- /dev/null +++ b/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts @@ -0,0 +1,222 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const pipelineOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'pipeline', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Get a pipeline', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all pipelines', + }, + { + name: 'Trigger', + value: 'trigger', + description: 'Trigger a pipeline', + }, + ], + default: 'get', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const pipelineFields = [ + +/* -------------------------------------------------------------------------- */ +/* pipeline:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Project Slug', + name: 'projectSlug', + type: 'string', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: '', + description: 'Project slug in the form vcs-slug/org-name/repo-name', + }, + { + displayName: 'Pipeline Number', + name: 'pipelineNumber', + type: 'number', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: 0, + description: 'The number of the pipeline', + }, +/* -------------------------------------------------------------------------- */ +/* pipeline:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Project Slug', + name: 'projectSlug', + type: 'string', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: '', + description: 'Project slug in the form vcs-slug/org-name/repo-name', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'pipeline', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'pipeline', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Branch', + name: 'branch', + type: 'string', + default: '', + description: 'The name of a vcs branch.', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* pipeline:trigger */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Project Slug', + name: 'projectSlug', + type: 'string', + displayOptions: { + show: { + operation: [ + 'trigger', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: '', + description: 'Project slug in the form vcs-slug/org-name/repo-name', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'pipeline', + ], + operation: [ + 'trigger', + ], + }, + }, + options: [ + { + displayName: 'Branch', + name: 'branch', + type: 'string', + default: '', + description: `The branch where the pipeline ran.
+ The HEAD commit on this branch was used for the pipeline.
+ Note that branch and tag are mutually exclusive.`, + }, + { + displayName: 'Tag', + name: 'tag', + type: 'string', + default: '', + description: `The tag used by the pipeline.
+ The commit that this tag points to was used for the pipeline.
+ Note that branch and tag are mutually exclusive`, + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/CircleCi/circleCi.png b/packages/nodes-base/nodes/CircleCi/circleCi.png new file mode 100644 index 0000000000000000000000000000000000000000..1708a6a3dd604cd31db2718e9052fb312246e0eb GIT binary patch literal 4787 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 literal 0 HcmV?d00001 diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index c19d8e2349..a04293da42 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -37,6 +37,7 @@ "dist/credentials/BannerbearApi.credentials.js", "dist/credentials/BitbucketApi.credentials.js", "dist/credentials/BitlyApi.credentials.js", + "dist/credentials/CircleCiApi.credentials.js", "dist/credentials/ChargebeeApi.credentials.js", "dist/credentials/ClearbitApi.credentials.js", "dist/credentials/ClickUpApi.credentials.js", @@ -165,6 +166,7 @@ "dist/nodes/Bitbucket/BitbucketTrigger.node.js", "dist/nodes/Bitly/Bitly.node.js", "dist/nodes/Calendly/CalendlyTrigger.node.js", + "dist/nodes/CircleCi/CircleCi.node.js", "dist/nodes/Chargebee/Chargebee.node.js", "dist/nodes/Chargebee/ChargebeeTrigger.node.js", "dist/nodes/Clearbit/Clearbit.node.js", From c4332634eb2ef083842d64b6d715a407d7773b3b Mon Sep 17 00:00:00 2001 From: ricardo Date: Mon, 6 Jul 2020 12:18:36 -0400 Subject: [PATCH 2/3] :zap: Improvements --- .../credentials/CircleCiApi.credentials.ts | 2 +- .../nodes/CircleCi/CircleCi.node.ts | 9 +- .../nodes/CircleCi/PipelineDescription.ts | 92 ++++++++++++++++++- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/packages/nodes-base/credentials/CircleCiApi.credentials.ts b/packages/nodes-base/credentials/CircleCiApi.credentials.ts index 88ecdc4fe1..ef3104b5e6 100644 --- a/packages/nodes-base/credentials/CircleCiApi.credentials.ts +++ b/packages/nodes-base/credentials/CircleCiApi.credentials.ts @@ -8,7 +8,7 @@ export class CircleCiApi implements ICredentialType { displayName = 'CircleCI API'; properties = [ { - displayName: 'API Key', + displayName: 'Personal API Token', name: 'apiKey', type: 'string' as NodePropertyTypes, default: '', diff --git a/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts b/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts index 00eded6366..a15a9511e2 100644 --- a/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts +++ b/packages/nodes-base/nodes/CircleCi/CircleCi.node.ts @@ -71,16 +71,18 @@ export class CircleCi implements INodeType { for (let i = 0; i < length; i++) { if (resource === 'pipeline') { if (operation === 'get') { + const vcs = this.getNodeParameter('vcs', i) as string; let slug = this.getNodeParameter('projectSlug', i) as string; const pipelineNumber = this.getNodeParameter('pipelineNumber', i) as number; slug = slug.replace(new RegExp(/\//g), '%2F'); - const endpoint = `/project/${slug}/pipeline/${pipelineNumber}`; + const endpoint = `/project/${vcs}/${slug}/pipeline/${pipelineNumber}`; responseData = await circleciApiRequest.call(this, 'GET', endpoint, {}, qs); } if (operation === 'getAll') { + const vcs = this.getNodeParameter('vcs', i) as string; const filters = this.getNodeParameter('filters', i) as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; let slug = this.getNodeParameter('projectSlug', i) as string; @@ -91,7 +93,7 @@ export class CircleCi implements INodeType { qs.branch = filters.branch; } - const endpoint = `/project/${slug}/pipeline`; + const endpoint = `/project/${vcs}/${slug}/pipeline`; if (returnAll === true) { responseData = await circleciApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}, qs); @@ -105,13 +107,14 @@ export class CircleCi implements INodeType { } if (operation === 'trigger') { + const vcs = this.getNodeParameter('vcs', i) as string; let slug = this.getNodeParameter('projectSlug', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; slug = slug.replace(new RegExp(/\//g), '%2F'); - const endpoint = `/project/${slug}/pipeline`; + const endpoint = `/project/${vcs}/${slug}/pipeline`; const body: IDataObject = {}; diff --git a/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts b/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts index 66b99f3eb3..4ffd2183d6 100644 --- a/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts +++ b/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts @@ -41,6 +41,33 @@ export const pipelineFields = [ /* -------------------------------------------------------------------------- */ /* pipeline:get */ /* -------------------------------------------------------------------------- */ + { + displayName: 'VCS', + name: 'vcs', + type: 'options', + options: [ + { + name: 'Github', + value: 'github', + }, + { + name: 'Bitbucket', + value: 'bitbucket', + }, + ], + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: '', + description: 'Version control system', + }, { displayName: 'Project Slug', name: 'projectSlug', @@ -56,12 +83,15 @@ export const pipelineFields = [ }, }, default: '', - description: 'Project slug in the form vcs-slug/org-name/repo-name', + description: 'Project slug in the form org-name/repo-name', }, { displayName: 'Pipeline Number', name: 'pipelineNumber', type: 'number', + typeOptions: { + minValue: 1, + }, displayOptions: { show: { operation: [ @@ -72,12 +102,39 @@ export const pipelineFields = [ ], }, }, - default: 0, + default: 1, description: 'The number of the pipeline', }, /* -------------------------------------------------------------------------- */ /* pipeline:getAll */ /* -------------------------------------------------------------------------- */ + { + displayName: 'VCS', + name: 'vcs', + type: 'options', + options: [ + { + name: 'Github', + value: 'github', + }, + { + name: 'Bitbucket', + value: 'bitbucket', + }, + ], + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: '', + description: 'Version control system', + }, { displayName: 'Project Slug', name: 'projectSlug', @@ -93,7 +150,7 @@ export const pipelineFields = [ }, }, default: '', - description: 'Project slug in the form vcs-slug/org-name/repo-name', + description: 'Project slug in the form org-name/repo-name', }, { displayName: 'Return All', @@ -165,6 +222,33 @@ export const pipelineFields = [ /* -------------------------------------------------------------------------- */ /* pipeline:trigger */ /* -------------------------------------------------------------------------- */ + { + displayName: 'VCS', + name: 'vcs', + type: 'options', + options: [ + { + name: 'Github', + value: 'github', + }, + { + name: 'Bitbucket', + value: 'bitbucket', + }, + ], + displayOptions: { + show: { + operation: [ + 'trigger', + ], + resource: [ + 'pipeline', + ], + }, + }, + default: '', + description: 'Version control system', + }, { displayName: 'Project Slug', name: 'projectSlug', @@ -180,7 +264,7 @@ export const pipelineFields = [ }, }, default: '', - description: 'Project slug in the form vcs-slug/org-name/repo-name', + description: 'Project slug in the form org-name/repo-name', }, { displayName: 'Additional Fields', From 1b8e75dfadc42e0ca450dfb56ced53860acfc744 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Tue, 7 Jul 2020 11:10:01 +0200 Subject: [PATCH 3/3] :zap: Minor improvements to CircleCI-Node --- .../nodes/CircleCi/PipelineDescription.ts | 111 +++--------------- 1 file changed, 17 insertions(+), 94 deletions(-) diff --git a/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts b/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts index 4ffd2183d6..beb5e345fe 100644 --- a/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts +++ b/packages/nodes-base/nodes/CircleCi/PipelineDescription.ts @@ -39,26 +39,28 @@ export const pipelineOperations = [ export const pipelineFields = [ /* -------------------------------------------------------------------------- */ -/* pipeline:get */ +/* pipeline:shared */ /* -------------------------------------------------------------------------- */ { - displayName: 'VCS', + displayName: 'Provider', name: 'vcs', type: 'options', options: [ - { - name: 'Github', - value: 'github', - }, { name: 'Bitbucket', value: 'bitbucket', }, + { + name: 'Github', + value: 'github', + }, ], displayOptions: { show: { operation: [ 'get', + 'getAll', + 'trigger', ], resource: [ 'pipeline', @@ -76,6 +78,8 @@ export const pipelineFields = [ show: { operation: [ 'get', + 'getAll', + 'trigger', ], resource: [ 'pipeline', @@ -83,8 +87,13 @@ export const pipelineFields = [ }, }, default: '', + placeholder: 'n8n-io/n8n', description: 'Project slug in the form org-name/repo-name', }, + +/* -------------------------------------------------------------------------- */ +/* pipeline:get */ +/* -------------------------------------------------------------------------- */ { displayName: 'Pipeline Number', name: 'pipelineNumber', @@ -105,53 +114,10 @@ export const pipelineFields = [ default: 1, description: 'The number of the pipeline', }, + /* -------------------------------------------------------------------------- */ /* pipeline:getAll */ /* -------------------------------------------------------------------------- */ - { - displayName: 'VCS', - name: 'vcs', - type: 'options', - options: [ - { - name: 'Github', - value: 'github', - }, - { - name: 'Bitbucket', - value: 'bitbucket', - }, - ], - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'pipeline', - ], - }, - }, - default: '', - description: 'Version control system', - }, - { - displayName: 'Project Slug', - name: 'projectSlug', - type: 'string', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'pipeline', - ], - }, - }, - default: '', - description: 'Project slug in the form org-name/repo-name', - }, { displayName: 'Return All', name: 'returnAll', @@ -219,53 +185,10 @@ export const pipelineFields = [ }, ], }, + /* -------------------------------------------------------------------------- */ /* pipeline:trigger */ /* -------------------------------------------------------------------------- */ - { - displayName: 'VCS', - name: 'vcs', - type: 'options', - options: [ - { - name: 'Github', - value: 'github', - }, - { - name: 'Bitbucket', - value: 'bitbucket', - }, - ], - displayOptions: { - show: { - operation: [ - 'trigger', - ], - resource: [ - 'pipeline', - ], - }, - }, - default: '', - description: 'Version control system', - }, - { - displayName: 'Project Slug', - name: 'projectSlug', - type: 'string', - displayOptions: { - show: { - operation: [ - 'trigger', - ], - resource: [ - 'pipeline', - ], - }, - }, - default: '', - description: 'Project slug in the form org-name/repo-name', - }, { displayName: 'Additional Fields', name: 'additionalFields',