first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,25 @@
{
"node": "n8n-nodes-base.circleCi",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Development"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/circleci/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.circleci/"
}
],
"generic": [
{
"label": "How to set up a no-code CI/CD pipeline with GitHub and TravisCI",
"icon": "🎡",
"url": "https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/"
}
]
}
}
@@ -0,0 +1,155 @@
import type {
IExecuteFunctions,
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { circleciApiRequest, circleciApiRequestAllItems } from './GenericFunctions';
import { pipelineFields, pipelineOperations } from './PipelineDescription';
export class CircleCi implements INodeType {
description: INodeTypeDescription = {
displayName: 'CircleCI',
name: 'circleCi',
icon: { light: 'file:circleCi.svg', dark: 'file:circleCi.dark.svg' },
group: ['output'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume CircleCI API',
defaults: {
name: 'CircleCI',
},
usableAsTool: true,
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'circleCiApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Pipeline',
value: 'pipeline',
},
],
default: 'pipeline',
},
...pipelineOperations,
...pipelineFields,
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
const length = items.length;
const qs: IDataObject = {};
let responseData;
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
for (let i = 0; i < length; i++) {
try {
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/${vcs}/${slug}/pipeline/${pipelineNumber}`;
responseData = await circleciApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
}
if (operation === 'getAll') {
const vcs = this.getNodeParameter('vcs', i) as string;
const filters = this.getNodeParameter('filters', i);
const returnAll = this.getNodeParameter('returnAll', i);
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/${vcs}/${slug}/pipeline`;
if (returnAll) {
responseData = await circleciApiRequestAllItems.call(
this,
'items',
'GET',
endpoint,
{},
qs,
);
} else {
qs.limit = this.getNodeParameter('limit', i);
responseData = await circleciApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = responseData.items;
responseData = responseData.splice(0, qs.limit);
}
responseData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
}
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);
slug = slug.replace(new RegExp(/\//g), '%2F');
const endpoint = `/project/${vcs}/${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);
responseData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
}
}
returnData.push(...(responseData as INodeExecutionData[]));
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message, json: {}, itemIndex: i });
continue;
}
throw error;
}
}
return [returnData];
}
}
@@ -0,0 +1,68 @@
import type {
IDataObject,
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
JsonObject,
IRequestOptions,
IHttpRequestMethods,
} from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';
export async function circleciApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
resource: string,
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
): Promise<any> {
const credentials = await this.getCredentials('circleCiApi');
let options: IRequestOptions = {
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 as IDataObject).length === 0) {
delete options.body;
}
try {
return await this.helpers.request(options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
/**
* Make an API request to paginated CircleCI endpoint
* and return all results
*/
export async function circleciApiRequestAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: IHttpRequestMethods,
resource: string,
body: any = {},
query: IDataObject = {},
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
do {
responseData = await circleciApiRequest.call(this, method, resource, body, query);
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
query['page-token'] = responseData.next_page_token;
} while (responseData.next_page_token !== undefined && responseData.next_page_token !== null);
return returnData;
}
@@ -0,0 +1,191 @@
import type { INodeProperties } from 'n8n-workflow';
export const pipelineOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['pipeline'],
},
},
options: [
{
name: 'Get',
value: 'get',
description: 'Get a pipeline',
action: 'Get a pipeline',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many pipelines',
action: 'Get many pipelines',
},
{
name: 'Trigger',
value: 'trigger',
description: 'Trigger a pipeline',
action: 'Trigger a pipeline',
},
],
default: 'get',
},
];
export const pipelineFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* pipeline:shared */
/* -------------------------------------------------------------------------- */
{
displayName: 'Provider',
name: 'vcs',
type: 'options',
options: [
{
name: 'Bitbucket',
value: 'bitbucket',
},
{
name: 'GitHub',
value: 'github',
},
],
displayOptions: {
show: {
operation: ['get', 'getAll', 'trigger'],
resource: ['pipeline'],
},
},
default: '',
description: 'Source control system',
},
{
displayName: 'Project Slug',
name: 'projectSlug',
type: 'string',
displayOptions: {
show: {
operation: ['get', 'getAll', 'trigger'],
resource: ['pipeline'],
},
},
default: '',
placeholder: 'n8n-io/n8n',
description: 'Project slug in the form org-name/repo-name',
},
/* -------------------------------------------------------------------------- */
/* pipeline:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Pipeline Number',
name: 'pipelineNumber',
type: 'number',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
operation: ['get'],
resource: ['pipeline'],
},
},
default: 1,
description: 'The number of the pipeline',
},
/* -------------------------------------------------------------------------- */
/* pipeline:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
operation: ['getAll'],
resource: ['pipeline'],
},
},
default: false,
description: 'Whether to return all results 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: 'Max number of 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: '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',
},
],
},
];
@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6768 20C14.6768 17.3764 16.8061 15.2471 19.4297 15.2471C22.0532 15.2471 24.1825 17.3764 24.1825 20C24.1825 22.6236 22.0532 24.7529 19.4297 24.7529C16.8061 24.7909 14.6768 22.6236 14.6768 20ZM19.4297 0C10.076 0 2.24335 6.38783 0.0380228 15.057C0.0380228 15.1331 0 15.1711 0 15.2471C0 15.7795 0.418251 16.1977 0.95057 16.1977H9.01141C9.39164 16.1977 9.73384 15.9696 9.88593 15.6274C11.5589 12.0152 15.1711 9.5057 19.4297 9.5057C25.2091 9.5057 29.924 14.2205 29.924 20C29.924 25.7795 25.2091 30.4943 19.4297 30.4943C15.2091 30.4943 11.5589 27.9848 9.88593 24.3726C9.73384 24.0304 9.39164 23.8023 9.01141 23.8023H0.95057C0.418251 23.8023 0 24.2205 0 24.7529C0 24.8289 0 24.8669 0.0380228 24.943C2.24335 33.6122 10.076 40 19.4297 40C30.4943 40 39.4677 31.0266 39.4677 19.962C39.4677 8.93536 30.4943 0 19.4297 0Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 939 B

@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6768 20C14.6768 17.3764 16.8061 15.2471 19.4297 15.2471C22.0532 15.2471 24.1825 17.3764 24.1825 20C24.1825 22.6236 22.0532 24.7529 19.4297 24.7529C16.8061 24.7909 14.6768 22.6236 14.6768 20ZM19.4297 0C10.076 0 2.24335 6.38783 0.0380228 15.057C0.0380228 15.1331 0 15.1711 0 15.2471C0 15.7795 0.418251 16.1977 0.95057 16.1977H9.01141C9.39164 16.1977 9.73384 15.9696 9.88593 15.6274C11.5589 12.0152 15.1711 9.5057 19.4297 9.5057C25.2091 9.5057 29.924 14.2205 29.924 20C29.924 25.7795 25.2091 30.4943 19.4297 30.4943C15.2091 30.4943 11.5589 27.9848 9.88593 24.3726C9.73384 24.0304 9.39164 23.8023 9.01141 23.8023H0.95057C0.418251 23.8023 0 24.2205 0 24.7529C0 24.8289 0 24.8669 0.0380228 24.943C2.24335 33.6122 10.076 40 19.4297 40C30.4943 40 39.4677 31.0266 39.4677 19.962C39.4677 8.93536 30.4943 0 19.4297 0Z" fill="#343434"/>
</svg>

After

Width:  |  Height:  |  Size: 941 B