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
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:
@@ -0,0 +1,459 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import { projectRLC } from './common.descriptions';
|
||||
|
||||
export const actionOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new action for a project',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/actions',
|
||||
},
|
||||
},
|
||||
action: 'Create an action',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Archive an action (soft delete)',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'DELETE',
|
||||
url: '=/actions/{{$parameter["actionId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'set',
|
||||
properties: {
|
||||
value: '={{ { "success": true } }}',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Delete an action',
|
||||
},
|
||||
{
|
||||
name: 'Disable',
|
||||
value: 'disable',
|
||||
description: 'Deactivate an active action',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: '=/actions/{{$parameter["actionId"]}}/disable',
|
||||
},
|
||||
},
|
||||
action: 'Disable an action',
|
||||
},
|
||||
{
|
||||
name: 'Enable',
|
||||
value: 'enable',
|
||||
description: 'Reactivate a disabled action',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: '=/actions/{{$parameter["actionId"]}}/enable',
|
||||
},
|
||||
},
|
||||
action: 'Enable an action',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a single action by ID',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/actions/{{$parameter["actionId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get an action',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many actions for a project',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '/actions',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get many actions',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update an existing action',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: '=/actions/{{$parameter["actionId"]}}',
|
||||
},
|
||||
},
|
||||
action: 'Update an action',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const actionFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// action:get, delete, enable, disable, update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Action ID',
|
||||
name: 'actionId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['get', 'delete', 'enable', 'disable', 'update'],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the action',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// action:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'projectId',
|
||||
value: '={{ $value }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// action:create
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'projectId',
|
||||
value: '={{ $value }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// action:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Search',
|
||||
name: 'search',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'search',
|
||||
},
|
||||
},
|
||||
description: 'Search actions by name (max 100 characters)',
|
||||
},
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Active', value: 'active' },
|
||||
{ name: 'Archived', value: 'archived' },
|
||||
{ name: 'Disabled', value: 'disabled' },
|
||||
{ name: 'Expired', value: 'expired' },
|
||||
],
|
||||
default: [],
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'status',
|
||||
},
|
||||
},
|
||||
description: 'Filter by action status',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// action:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'name',
|
||||
},
|
||||
},
|
||||
description: 'The name of the action (1-255 characters)',
|
||||
},
|
||||
{
|
||||
displayName: 'Action Type',
|
||||
name: 'actionType',
|
||||
type: 'options',
|
||||
required: true,
|
||||
options: [
|
||||
{ name: 'Quarantine', value: 'quarantine', description: 'Quarantine matching tests' },
|
||||
{ name: 'Skip', value: 'skip', description: 'Skip matching tests' },
|
||||
{ name: 'Tag', value: 'tag', description: 'Add tags to matching tests' },
|
||||
],
|
||||
default: 'quarantine',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'action',
|
||||
value: '={{ [{ "op": $value }] }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'actionTags',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
actionType: ['tag'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'action',
|
||||
value:
|
||||
'={{ [{ "op": "tag", "details": { "tags": $value.split(",").map(t => t.trim()).filter(t => t) } }] }}',
|
||||
},
|
||||
},
|
||||
description: 'Comma-separated list of tags to apply',
|
||||
},
|
||||
{
|
||||
displayName: 'Matcher Type',
|
||||
name: 'matcherType',
|
||||
type: 'options',
|
||||
required: true,
|
||||
options: [
|
||||
{ name: 'Spec File Contains', value: 'specContains' },
|
||||
{ name: 'Spec File Equals', value: 'specEquals' },
|
||||
{ name: 'Test Signature', value: 'signature' },
|
||||
{ name: 'Test Title Contains', value: 'titleContains' },
|
||||
{ name: 'Test Title Equals', value: 'titleEquals' },
|
||||
],
|
||||
default: 'titleContains',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
// No routing - matcherValue will build the complete matcher object
|
||||
description: 'How to match tests for this action',
|
||||
},
|
||||
{
|
||||
displayName: 'Matcher Value',
|
||||
name: 'matcherValue',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'matcher',
|
||||
value:
|
||||
'={{ { "op": "AND", "cond": [{ "type": { "signature": "testId", "titleContains": "title", "titleEquals": "title", "specContains": "file", "specEquals": "file" }[$parameter.matcherType] || "title", "op": { "signature": "eq", "titleContains": "inc", "titleEquals": "eq", "specContains": "inc", "specEquals": "eq" }[$parameter.matcherType] || "inc", "value": $value }] } }}',
|
||||
},
|
||||
},
|
||||
description: 'The value to match against (test title, spec file path, or signature)',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'createOptions',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'description',
|
||||
},
|
||||
},
|
||||
description: 'A description for the action',
|
||||
},
|
||||
{
|
||||
displayName: 'Expires After',
|
||||
name: 'expiresAfter',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'expiresAfter',
|
||||
},
|
||||
},
|
||||
description: 'When the action should expire (ISO 8601 format)',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// action:update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['action'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'name',
|
||||
},
|
||||
},
|
||||
description: 'The name of the action (1-255 characters)',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'description',
|
||||
},
|
||||
},
|
||||
description: 'A description for the action',
|
||||
},
|
||||
{
|
||||
displayName: 'Expires After',
|
||||
name: 'expiresAfter',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'expiresAfter',
|
||||
},
|
||||
},
|
||||
description: 'When the action should expire (ISO 8601 format)',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const instanceOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['instance'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a spec file execution instance with full test results',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/instances/{{$parameter["instanceId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get an instance',
|
||||
},
|
||||
],
|
||||
default: 'get',
|
||||
},
|
||||
];
|
||||
|
||||
export const instanceFields: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Instance ID',
|
||||
name: 'instanceId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['instance'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the spec file execution instance',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,205 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
filterTagsOption,
|
||||
projectRLC,
|
||||
} from './common.descriptions';
|
||||
|
||||
export const projectOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['project'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a project by ID',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/projects/{{$parameter["projectId"]}}',
|
||||
},
|
||||
},
|
||||
action: 'Get a project',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many projects',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '/projects',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get many projects',
|
||||
},
|
||||
{
|
||||
name: 'Get Insights',
|
||||
value: 'getInsights',
|
||||
description: 'Get project insights and metrics',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/projects/{{$parameter["projectId"]}}/insights',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get project insights',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const projectFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// project:get
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['project'],
|
||||
operation: ['get', 'getInsights'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// project:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['project'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 50,
|
||||
},
|
||||
default: 10,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'limit',
|
||||
},
|
||||
},
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// project:getInsights
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Date Start',
|
||||
name: 'dateStart',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['project'],
|
||||
operation: ['getInsights'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_start',
|
||||
},
|
||||
},
|
||||
description: 'Start date for metrics (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Date End',
|
||||
name: 'dateEnd',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['project'],
|
||||
operation: ['getInsights'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_end',
|
||||
},
|
||||
},
|
||||
description: 'End date for metrics (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['project'],
|
||||
operation: ['getInsights'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
{
|
||||
displayName: 'Resolution',
|
||||
name: 'resolution',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: '1 Hour', value: '1h' },
|
||||
{ name: '1 Day', value: '1d' },
|
||||
{ name: '1 Week', value: '1w' },
|
||||
],
|
||||
default: '1d',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'resolution',
|
||||
},
|
||||
},
|
||||
description: 'Time resolution for metrics',
|
||||
},
|
||||
filterTagsOption,
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,549 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterTagsOption,
|
||||
projectRLC,
|
||||
} from './common.descriptions';
|
||||
|
||||
export const runOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Cancel',
|
||||
value: 'cancel',
|
||||
description: 'Cancel a run in progress',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: '=/runs/{{$parameter["runId"]}}/cancel',
|
||||
},
|
||||
},
|
||||
action: 'Cancel a run',
|
||||
},
|
||||
{
|
||||
name: 'Cancel by GitHub CI',
|
||||
value: 'cancelGithub',
|
||||
description: 'Cancel a run by GitHub Actions workflow run ID',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: '/runs/cancel-ci/github',
|
||||
},
|
||||
},
|
||||
action: 'Cancel a run by GitHub CI',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a run and all associated data',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'DELETE',
|
||||
url: '=/runs/{{$parameter["runId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'set',
|
||||
properties: {
|
||||
value: '={{ { "success": true } }}',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Delete a run',
|
||||
},
|
||||
{
|
||||
name: 'Find',
|
||||
value: 'find',
|
||||
description: 'Find a run by project and filters',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '/runs/find',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Find a run',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a run by ID',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/runs/{{$parameter["runId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get a run',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many runs for a project',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/projects/{{$parameter["projectId"]}}/runs',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get many runs',
|
||||
},
|
||||
{
|
||||
name: 'Reset',
|
||||
value: 'reset',
|
||||
description: 'Reset failed specs for re-execution on specified machines',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: '=/runs/{{$parameter["runId"]}}/reset',
|
||||
},
|
||||
},
|
||||
action: 'Reset a run',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const runFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// run:get, cancel, delete, reset
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Run ID',
|
||||
name: 'runId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['get', 'cancel', 'delete', 'reset'],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the run',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// run:reset
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Machine IDs',
|
||||
name: 'machineIds',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['reset'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'machineId',
|
||||
value: '={{ $value.split(",").map(id => id.trim()) }}',
|
||||
},
|
||||
},
|
||||
description: 'Comma-separated list of machine identifiers to reset (1-63 items)',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'resetOptions',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['reset'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Batched Orchestration',
|
||||
name: 'isBatchedOr8n',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'isBatchedOr8n',
|
||||
},
|
||||
},
|
||||
description: 'Whether to enable batched orchestration',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// run:cancelGithub
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'GitHub Run ID',
|
||||
name: 'githubRunId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['cancelGithub'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'githubRunId',
|
||||
},
|
||||
},
|
||||
description: 'The GitHub Actions workflow run ID',
|
||||
},
|
||||
{
|
||||
displayName: 'GitHub Run Attempt',
|
||||
name: 'githubRunAttempt',
|
||||
type: 'number',
|
||||
required: true,
|
||||
default: 1,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['cancelGithub'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'githubRunAttempt',
|
||||
},
|
||||
},
|
||||
description: 'The GitHub Actions workflow attempt number',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'cancelGithubOptions',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['cancelGithub'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Project ID',
|
||||
name: 'projectId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'projectId',
|
||||
},
|
||||
},
|
||||
description: 'Limit cancellation to a specific project',
|
||||
},
|
||||
{
|
||||
displayName: 'CI Build ID',
|
||||
name: 'ciBuildId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'ciBuildId',
|
||||
},
|
||||
},
|
||||
description: 'Limit cancellation to a specific CI build',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// run:find
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['find', 'getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'projectId',
|
||||
value: '={{ $value }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['find'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Branch',
|
||||
name: 'branch',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'branch',
|
||||
},
|
||||
},
|
||||
description: 'Filter by git branch name',
|
||||
},
|
||||
{
|
||||
displayName: 'CI Build ID',
|
||||
name: 'ciBuildId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'ciBuildId',
|
||||
},
|
||||
},
|
||||
description: 'Filter by CI build ID',
|
||||
},
|
||||
filterTagsOption,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// run:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 50,
|
||||
},
|
||||
default: 10,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'limit',
|
||||
},
|
||||
},
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
{
|
||||
displayName: 'Completion State',
|
||||
name: 'completionState',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Canceled', value: 'CANCELED' },
|
||||
{ name: 'Complete', value: 'COMPLETE' },
|
||||
{ name: 'In Progress', value: 'IN_PROGRESS' },
|
||||
{ name: 'Timeout', value: 'TIMEOUT' },
|
||||
],
|
||||
default: [],
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'completion_state',
|
||||
},
|
||||
},
|
||||
description: 'Filter by completion state',
|
||||
},
|
||||
{
|
||||
displayName: 'Date End',
|
||||
name: 'dateEnd',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_end',
|
||||
},
|
||||
},
|
||||
description: 'Filter runs created before this date',
|
||||
},
|
||||
{
|
||||
displayName: 'Date Start',
|
||||
name: 'dateStart',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_start',
|
||||
},
|
||||
},
|
||||
description: 'Filter runs created on or after this date',
|
||||
},
|
||||
{
|
||||
displayName: 'Search',
|
||||
name: 'search',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'search',
|
||||
},
|
||||
},
|
||||
description: 'Search by ciBuildId or commit message (max 200 characters)',
|
||||
},
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Failed', value: 'FAILED' },
|
||||
{ name: 'Failing', value: 'FAILING' },
|
||||
{ name: 'Passed', value: 'PASSED' },
|
||||
{ name: 'Running', value: 'RUNNING' },
|
||||
],
|
||||
default: [],
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'status',
|
||||
},
|
||||
},
|
||||
description: 'Filter by run status',
|
||||
},
|
||||
filterTagsOption,
|
||||
{
|
||||
displayName: 'Tag Operator',
|
||||
name: 'tagOperator',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'AND', value: 'AND', description: 'All tags must be present' },
|
||||
{ name: 'OR', value: 'OR', description: 'Any tag must be present' },
|
||||
],
|
||||
default: 'AND',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'tag_operator',
|
||||
},
|
||||
},
|
||||
description: 'Logical operator for tag filtering',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['run'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Starting After',
|
||||
name: 'startingAfter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'starting_after',
|
||||
},
|
||||
},
|
||||
description: 'Cursor for forward pagination (use cursor from previous response)',
|
||||
},
|
||||
{
|
||||
displayName: 'Ending Before',
|
||||
name: 'endingBefore',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'ending_before',
|
||||
},
|
||||
},
|
||||
description: 'Cursor for backward pagination (use cursor from previous response)',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,107 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import { projectRLC } from './common.descriptions';
|
||||
|
||||
export const signatureOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['signature'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Generate',
|
||||
value: 'generate',
|
||||
description: 'Generate a unique test signature',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/signature/test',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Generate a signature',
|
||||
},
|
||||
],
|
||||
default: 'generate',
|
||||
},
|
||||
];
|
||||
|
||||
export const signatureFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// signature:generate
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['signature'],
|
||||
operation: ['generate'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'projectId',
|
||||
value: '={{ $value }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Spec File Path',
|
||||
name: 'specFilePath',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['signature'],
|
||||
operation: ['generate'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'specFilePath',
|
||||
},
|
||||
},
|
||||
placeholder: 'e.g., tests/e2e/login.spec.ts',
|
||||
description: 'The complete path to the spec file',
|
||||
},
|
||||
{
|
||||
displayName: 'Test Title',
|
||||
name: 'testTitle',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['signature'],
|
||||
operation: ['generate'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'body',
|
||||
property: 'testTitle',
|
||||
},
|
||||
},
|
||||
placeholder: 'e.g., should login with valid credentials',
|
||||
description:
|
||||
'The test title. For nested describe blocks, use " > " as separator (e.g., "Login > should login with valid credentials").',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,244 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
filterTagsOption,
|
||||
projectRLC,
|
||||
} from './common.descriptions';
|
||||
|
||||
export const specFileOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get aggregated spec file metrics for a project',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/spec-files/{{$parameter["projectId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get many spec files',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const specFileFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// specFile:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Date Start',
|
||||
name: 'dateStart',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_start',
|
||||
},
|
||||
},
|
||||
description: 'Start date for metrics (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Date End',
|
||||
name: 'dateEnd',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_end',
|
||||
},
|
||||
},
|
||||
description: 'End date for metrics (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 50,
|
||||
},
|
||||
default: 50,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'limit',
|
||||
},
|
||||
},
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
{
|
||||
displayName: 'Spec Name',
|
||||
name: 'specNameFilter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'specNameFilter',
|
||||
},
|
||||
},
|
||||
description: 'Filter spec files by name (partial match)',
|
||||
},
|
||||
filterTagsOption,
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['specFile'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include Failed in Duration',
|
||||
name: 'includeFailedInDuration',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'includeFailedInDuration',
|
||||
},
|
||||
},
|
||||
description: 'Whether to include failed executions in duration calculation',
|
||||
},
|
||||
{
|
||||
displayName: 'Order By',
|
||||
name: 'order',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Average Duration', value: 'avgDuration' },
|
||||
{ name: 'Failed Executions', value: 'failedExecutions' },
|
||||
{ name: 'Failure Rate', value: 'failureRate' },
|
||||
{ name: 'Flake Rate', value: 'flakeRate' },
|
||||
{ name: 'Flaky Executions', value: 'flakyExecutions' },
|
||||
{ name: 'Fully Reported', value: 'fullyReported' },
|
||||
{ name: 'Overall Executions', value: 'overallExecutions' },
|
||||
{ name: 'Suite Size', value: 'suiteSize' },
|
||||
{ name: 'Timeout Executions', value: 'timeoutExecutions' },
|
||||
{ name: 'Timeout Rate', value: 'timeoutRate' },
|
||||
],
|
||||
default: 'avgDuration',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'order',
|
||||
},
|
||||
},
|
||||
description: 'The field to order results by',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Direction',
|
||||
name: 'dir',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Ascending', value: 'asc' },
|
||||
{ name: 'Descending', value: 'desc' },
|
||||
],
|
||||
default: 'desc',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'dir',
|
||||
},
|
||||
},
|
||||
description: 'The direction to sort results',
|
||||
},
|
||||
{
|
||||
displayName: 'Page',
|
||||
name: 'page',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'page',
|
||||
},
|
||||
},
|
||||
description: 'Page number (0-indexed)',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,296 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
filterTagsOption,
|
||||
projectRLC,
|
||||
} from './common.descriptions';
|
||||
|
||||
export const testOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get aggregated test metrics for a project',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/tests/{{$parameter["projectId"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get many tests',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const testFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// test:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
...projectRLC,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Date Start',
|
||||
name: 'dateStart',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_start',
|
||||
},
|
||||
},
|
||||
description: 'Start date for metrics (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Date End',
|
||||
name: 'dateEnd',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_end',
|
||||
},
|
||||
},
|
||||
description: 'End date for metrics (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 50,
|
||||
},
|
||||
default: 50,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'limit',
|
||||
},
|
||||
},
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
{
|
||||
displayName: 'Minimum Executions',
|
||||
name: 'minExecutions',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 1,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'min_executions',
|
||||
},
|
||||
},
|
||||
description: 'Minimum number of executions to include a test',
|
||||
},
|
||||
{
|
||||
displayName: 'Spec File',
|
||||
name: 'spec',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'spec',
|
||||
},
|
||||
},
|
||||
description: 'Filter tests by spec file name (partial match)',
|
||||
},
|
||||
filterTagsOption,
|
||||
{
|
||||
displayName: 'Test State',
|
||||
name: 'testState',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Failed', value: 'failed' },
|
||||
{ name: 'Passed', value: 'passed' },
|
||||
{ name: 'Pending', value: 'pending' },
|
||||
{ name: 'Skipped', value: 'skipped' },
|
||||
],
|
||||
default: [],
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'test_state[]',
|
||||
},
|
||||
},
|
||||
description: 'Filter by test state',
|
||||
},
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'title',
|
||||
},
|
||||
},
|
||||
description: 'Filter tests by title (partial match)',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['test'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Order By',
|
||||
name: 'order',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Duration', value: 'duration' },
|
||||
{ name: 'Duration Delta', value: 'durationDelta' },
|
||||
{ name: 'Duration Impact', value: 'durationXSamples' },
|
||||
{ name: 'Executions', value: 'executions' },
|
||||
{ name: 'Failure Impact', value: 'failRateXSamples' },
|
||||
{ name: 'Failure Rate Delta', value: 'failureRateDelta' },
|
||||
{ name: 'Failures', value: 'failures' },
|
||||
{ name: 'Flakiness', value: 'flakiness' },
|
||||
{ name: 'Flakiness Impact', value: 'flakinessXSamples' },
|
||||
{ name: 'Flakiness Rate Delta', value: 'flakinessRateDelta' },
|
||||
{ name: 'Passes', value: 'passes' },
|
||||
{ name: 'Title', value: 'title' },
|
||||
],
|
||||
default: 'title',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'order',
|
||||
},
|
||||
},
|
||||
description: 'The field to order results by',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Direction',
|
||||
name: 'dir',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Ascending', value: 'asc' },
|
||||
{ name: 'Descending', value: 'desc' },
|
||||
],
|
||||
default: 'desc',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'dir',
|
||||
},
|
||||
},
|
||||
description: 'The direction to sort results',
|
||||
},
|
||||
{
|
||||
displayName: 'Page',
|
||||
name: 'page',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'page',
|
||||
},
|
||||
},
|
||||
description: 'Page number (0-indexed)',
|
||||
},
|
||||
{
|
||||
displayName: 'Metric Settings',
|
||||
name: 'metric_settings',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'metric_settings',
|
||||
},
|
||||
},
|
||||
description:
|
||||
'Override which test statuses are included in metric calculations. JSON object with optional keys: executions, avgDuration, flakinessRate, failureRate. Each value is an array of status strings: passed, failed, pending, skipped. Example: {"executions":["failed","passed"],"failureRate":["failed"]}',
|
||||
placeholder: '{"executions":["failed","passed"],"failureRate":["failed"]}',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,213 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
filterAuthorsOption,
|
||||
filterBranchesOption,
|
||||
filterGroupsOption,
|
||||
filterTagsOption,
|
||||
} from './common.descriptions';
|
||||
|
||||
export const testResultOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get historical test execution results for a specific test signature',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '=/test-results/{{$parameter["signature"]}}',
|
||||
},
|
||||
output: {
|
||||
postReceive: [
|
||||
{
|
||||
type: 'rootProperty',
|
||||
properties: {
|
||||
property: 'data',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
action: 'Get test results',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const testResultFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// testResult:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Test Signature',
|
||||
name: 'signature',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
description:
|
||||
'The unique test signature. Use the Signature resource to generate this from project ID, spec file path, and test title.',
|
||||
},
|
||||
{
|
||||
displayName: 'Date Start',
|
||||
name: 'dateStart',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_start',
|
||||
},
|
||||
},
|
||||
description: 'Start date for results (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Date End',
|
||||
name: 'dateEnd',
|
||||
type: 'dateTime',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'date_end',
|
||||
},
|
||||
},
|
||||
description: 'End date for results (ISO 8601 format)',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 10,
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'limit',
|
||||
},
|
||||
},
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
filterBranchesOption,
|
||||
filterAuthorsOption,
|
||||
filterGroupsOption,
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Failed', value: 'failed' },
|
||||
{ name: 'Passed', value: 'passed' },
|
||||
{ name: 'Pending', value: 'pending' },
|
||||
{ name: 'Skipped', value: 'skipped' },
|
||||
],
|
||||
default: [],
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'status',
|
||||
},
|
||||
},
|
||||
description: 'Filter by test status',
|
||||
},
|
||||
{
|
||||
...filterTagsOption,
|
||||
description: 'Filter by run tags (multiple values supported)',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['testResult'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Starting After',
|
||||
name: 'startingAfter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'starting_after',
|
||||
},
|
||||
},
|
||||
description: 'Cursor for forward pagination',
|
||||
},
|
||||
{
|
||||
displayName: 'Ending Before',
|
||||
name: 'endingBefore',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'ending_before',
|
||||
},
|
||||
},
|
||||
description: 'Cursor for backward pagination',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,92 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const projectRLC: INodeProperties = {
|
||||
displayName: 'Project',
|
||||
name: 'projectId',
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
required: true,
|
||||
description: 'The Currents project',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'From List',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a project...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getProjects',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'By ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. abc123',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/** Expression: comma-separated string → array for brackets[] query serialization */
|
||||
const COMMA_TO_ARRAY_VALUE =
|
||||
"={{ $value && String($value).trim() ? String($value).split(',').map(v => v.trim()).filter(Boolean) : undefined }}";
|
||||
|
||||
export const filterAuthorsOption: INodeProperties = {
|
||||
displayName: 'Git Authors',
|
||||
name: 'authors',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'authors',
|
||||
value: COMMA_TO_ARRAY_VALUE,
|
||||
},
|
||||
},
|
||||
description: 'Filter by git authors (comma-separated for multiple)',
|
||||
};
|
||||
|
||||
export const filterBranchesOption: INodeProperties = {
|
||||
displayName: 'Branches',
|
||||
name: 'branches',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'branches',
|
||||
value: COMMA_TO_ARRAY_VALUE,
|
||||
},
|
||||
},
|
||||
description: 'Filter by branches (comma-separated for multiple)',
|
||||
};
|
||||
|
||||
export const filterGroupsOption: INodeProperties = {
|
||||
displayName: 'Groups',
|
||||
name: 'groups',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'groups',
|
||||
value: COMMA_TO_ARRAY_VALUE,
|
||||
},
|
||||
},
|
||||
description: 'Filter by groups (comma-separated for multiple)',
|
||||
};
|
||||
|
||||
export const filterTagsOption: INodeProperties = {
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
type: 'query',
|
||||
property: 'tags',
|
||||
value: COMMA_TO_ARRAY_VALUE,
|
||||
},
|
||||
},
|
||||
description: 'Filter by tags (comma-separated for multiple)',
|
||||
};
|
||||
Reference in New Issue
Block a user