From 0a69c6edbd322c1cbea50447a99ef15c0d3ffe84 Mon Sep 17 00:00:00 2001 From: "n8n-cat-bot[bot]" Date: Sat, 10 Oct 2026 06:15:33 +0000 Subject: [PATCH] chore: Resolve master-to-3.x sync conflicts --- .../@n8n/constants/src/community-nodes.ts | 6 +---- packages/cli/BREAKING-CHANGES.md | 24 +++++++++---------- .../n8n-packages/n8n-packages.service.ts | 8 ------- ...eprecated-nodes-inline-subworkflow.test.ts | 6 ++++- .../test/integration/shared/utils/index.ts | 15 ++++++++---- .../app/__tests__/modal-key-ratchet.test.ts | 5 ---- .../editor-ui/src/app/components/Modals.vue | 5 ---- .../src/app/stores/defaults/modals.ts | 5 ---- .../nodes/Function/Function.node.test.ts | 8 ------- .../FunctionItem/FunctionItem.node.test.ts | 8 ------- .../fixtures/community-packages/index.ts | 5 ++-- .../e2e/workflows/editor/ndv/ndv-core.spec.ts | 6 ----- .../playwright/workflows/Test_Template_2.json | 14 ----------- .../workflows/Test_workflow_ndv_version.json | 5 ---- 14 files changed, 31 insertions(+), 89 deletions(-) delete mode 100644 packages/nodes-base/nodes/Function/Function.node.test.ts delete mode 100644 packages/nodes-base/nodes/FunctionItem/FunctionItem.node.test.ts diff --git a/packages/@n8n/constants/src/community-nodes.ts b/packages/@n8n/constants/src/community-nodes.ts index b24ff81ac1f..e23ff4fb4d6 100644 --- a/packages/@n8n/constants/src/community-nodes.ts +++ b/packages/@n8n/constants/src/community-nodes.ts @@ -4,8 +4,4 @@ export const NPM_COMMUNITY_NODE_SEARCH_API_URL = 'https://api.npms.io/v2/'; * Node-authoring API level this runtime supports, and so the highest * `n8nNodesApiVersion` a node may declare to be installed. */ -<<<<<<< HEAD -export const N8N_NODES_API_VERSION = 3; -======= -export const N8N_NODES_API_VERSION = '1.0'; ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 +export const N8N_NODES_API_VERSION = '3.0'; diff --git a/packages/cli/BREAKING-CHANGES.md b/packages/cli/BREAKING-CHANGES.md index 97674e241b5..070414eaeca 100644 --- a/packages/cli/BREAKING-CHANGES.md +++ b/packages/cli/BREAKING-CHANGES.md @@ -2,7 +2,17 @@ This list shows all the versions which include breaking changes and how to upgrade. -<<<<<<< HEAD +# Unreleased + +## n8n Packages (preview) + +Package manifest requirements now use `usedBy: [{ "kind": "workflow", "id": "workflow-id" }]`. +The `usedByWorkflows` field is no longer supported. +Re-export packages after upgrading. +Regenerate existing Promotions snapshots. +Package import errors also use `usedBy` for resource consumers. +Update API clients to read each consumer's `kind` and `id`. + # 3.0.0 ### What changed? @@ -68,19 +78,7 @@ The `$evaluateExpression()` helper was removed from the Code node. A Code node t ### When is action necessary? If your Code nodes call `$evaluateExpression()`. Evaluate the expression in a node field instead, for example in an Edit Fields (Set) node before the Code node, and read the result from the input item. Code nodes on a secure-mode task runner, the default since 2.0, already failed on this call. -======= -# Unreleased -## n8n Packages (preview) - -Package manifest requirements now use `usedBy: [{ "kind": "workflow", "id": "workflow-id" }]`. -The `usedByWorkflows` field is no longer supported. -Re-export packages after upgrading. -Regenerate existing Promotions snapshots. -Package import errors also use `usedBy` for resource consumers. -Update API clients to read each consumer's `kind` and `id`. - ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 # 2.0.0 ### What changed? diff --git a/packages/cli/src/modules/n8n-packages/n8n-packages.service.ts b/packages/cli/src/modules/n8n-packages/n8n-packages.service.ts index dd8d6798aaa..e1cb036bbc7 100644 --- a/packages/cli/src/modules/n8n-packages/n8n-packages.service.ts +++ b/packages/cli/src/modules/n8n-packages/n8n-packages.service.ts @@ -196,16 +196,8 @@ export class N8nPackagesService { const dependencyPolicy = request.dependencyPolicy ?? ExportDependencyPolicy.Fail; const isReferenceOnly = dependencyPolicy === ExportDependencyPolicy.ReferenceOnly; -<<<<<<< HEAD - const workflowIds = request.workflowIds ?? []; - const folderIds = request.folderIds ?? []; - const projectIds = request.projectIds ?? []; const includeTags = request.includeTags ?? true; - const workflowVersionPolicy = request.workflowVersionPolicy ?? WorkflowVersionPolicy.Latest; -======= - const includeTags = (request.includeTags ?? true) && !this.globalConfig.tags.disabled; const versionPolicy = request.versionPolicy ?? ExportVersionPolicy.Latest; ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 const credentialExportPolicy = request.credentialExportPolicy ?? CredentialExportPolicy.ExpressionValuesOnly; const includeArchivedWorkflows = request.includeArchivedWorkflows ?? false; diff --git a/packages/cli/test/integration/deprecated-nodes-inline-subworkflow.test.ts b/packages/cli/test/integration/deprecated-nodes-inline-subworkflow.test.ts index fe438a175bc..f86c6628b1c 100644 --- a/packages/cli/test/integration/deprecated-nodes-inline-subworkflow.test.ts +++ b/packages/cli/test/integration/deprecated-nodes-inline-subworkflow.test.ts @@ -27,8 +27,12 @@ describe('inline sub-workflow with a deprecated node', () => { 'n8n-nodes-base.manualTrigger', 'n8n-nodes-base.executeWorkflow', 'n8n-nodes-base.executeWorkflowTrigger', - 'n8n-nodes-base.function', ]); + const deprecatedNode = utils.createDeprecatedNodeType('n8n-nodes-base.function'); + deprecatedNode.description.inputs = [NodeConnectionTypes.Main]; + deprecatedNode.description.outputs = [NodeConnectionTypes.Main]; + deprecatedNode.execute = async () => [[{ json: { ran: 'function' } }]]; + nodeTypes['n8n-nodes-base.function'] = { type: deprecatedNode, sourcePath: '' }; await utils.initNodeTypes(nodeTypes); await utils.initBinaryDataService(); diff --git a/packages/cli/test/integration/shared/utils/index.ts b/packages/cli/test/integration/shared/utils/index.ts index 002431466d5..9bd83bb2d05 100644 --- a/packages/cli/test/integration/shared/utils/index.ts +++ b/packages/cli/test/integration/shared/utils/index.ts @@ -16,8 +16,6 @@ import { HttpBasicAuth } from 'n8n-nodes-base/credentials/HttpBasicAuth.credenti import { HttpHeaderAuth } from 'n8n-nodes-base/credentials/HttpHeaderAuth.credentials'; import { OpenAiApi } from 'n8n-nodes-base/credentials/OpenAiApi.credentials'; import { FormTrigger } from 'n8n-nodes-base/nodes/Form/FormTrigger.node'; -import { Function as FunctionNode } from 'n8n-nodes-base/nodes/Function/Function.node'; -import { FunctionItem } from 'n8n-nodes-base/nodes/FunctionItem/FunctionItem.node'; import { ManualTrigger } from 'n8n-nodes-base/nodes/ManualTrigger/ManualTrigger.node'; import { ScheduleTrigger } from 'n8n-nodes-base/nodes/Schedule/ScheduleTrigger.node'; import { Set } from 'n8n-nodes-base/nodes/Set/Set.node'; @@ -114,6 +112,15 @@ function minimalNodeType(name: string, properties: INodeProperties[] = []): INod }; } +// Test-only definitions keep deprecation coverage after 3.x removes the legacy nodes. +export function createDeprecatedNodeType(name: string): INodeType { + const { type } = minimalNodeType(name, [ + { displayName: 'Code', name: 'functionCode', type: 'string', default: '' }, + ]); + type.description.deprecated = true; + return type as INodeType; +} + function buildDefaultNodes(): INodeTypeData { ScheduleTrigger.prototype.trigger = async () => ({}); return { @@ -140,11 +147,11 @@ function buildDefaultNodes(): INodeTypeData { sourcePath: '', }, 'n8n-nodes-base.function': { - type: new FunctionNode(), + type: createDeprecatedNodeType('n8n-nodes-base.function'), sourcePath: '', }, 'n8n-nodes-base.functionItem': { - type: new FunctionItem(), + type: createDeprecatedNodeType('n8n-nodes-base.functionItem'), sourcePath: '', }, // Minimal mocks for node types the package-import fixtures reference at typeVersion 1. diff --git a/packages/frontend/editor-ui/src/app/__tests__/modal-key-ratchet.test.ts b/packages/frontend/editor-ui/src/app/__tests__/modal-key-ratchet.test.ts index b619c7f0615..4dd435fb19d 100644 --- a/packages/frontend/editor-ui/src/app/__tests__/modal-key-ratchet.test.ts +++ b/packages/frontend/editor-ui/src/app/__tests__/modal-key-ratchet.test.ts @@ -33,11 +33,6 @@ const ALLOWED_KEY_EXPORTS = [ 'EXTERNAL_SECRETS_PROVIDER_MODAL_KEY', 'FROM_AI_PARAMETERS_MODAL_KEY', 'IMPORT_CURL_MODAL_KEY', -<<<<<<< HEAD - 'LOG_STREAM_MODAL_KEY', -======= - 'IMPORT_WORKFLOW_URL_MODAL_KEY', ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 'MIGRATE_WORKFLOW_MODAL_KEY', 'NEW_ASSISTANT_SESSION_MODAL', 'NPS_SURVEY_MODAL_KEY', diff --git a/packages/frontend/editor-ui/src/app/components/Modals.vue b/packages/frontend/editor-ui/src/app/components/Modals.vue index 9a759996797..c78a3eeb6f4 100644 --- a/packages/frontend/editor-ui/src/app/components/Modals.vue +++ b/packages/frontend/editor-ui/src/app/components/Modals.vue @@ -9,11 +9,6 @@ import { DELETE_SECRETS_PROVIDER_MODAL_KEY, FROM_AI_PARAMETERS_MODAL_KEY, IMPORT_CURL_MODAL_KEY, -<<<<<<< HEAD - LOG_STREAM_MODAL_KEY, -======= - IMPORT_WORKFLOW_URL_MODAL_KEY, ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 VERSIONS_MODAL_KEY, NEW_ASSISTANT_SESSION_MODAL, NPS_SURVEY_MODAL_KEY, diff --git a/packages/frontend/editor-ui/src/app/stores/defaults/modals.ts b/packages/frontend/editor-ui/src/app/stores/defaults/modals.ts index 29722f71300..ba0ad90389d 100644 --- a/packages/frontend/editor-ui/src/app/stores/defaults/modals.ts +++ b/packages/frontend/editor-ui/src/app/stores/defaults/modals.ts @@ -12,11 +12,6 @@ import { EXTERNAL_SECRETS_PROVIDER_MODAL_KEY, FROM_AI_PARAMETERS_MODAL_KEY, IMPORT_CURL_MODAL_KEY, -<<<<<<< HEAD - LOG_STREAM_MODAL_KEY, -======= - IMPORT_WORKFLOW_URL_MODAL_KEY, ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 MIGRATE_WORKFLOW_MODAL_KEY, NEW_ASSISTANT_SESSION_MODAL, NPS_SURVEY_MODAL_KEY, diff --git a/packages/nodes-base/nodes/Function/Function.node.test.ts b/packages/nodes-base/nodes/Function/Function.node.test.ts deleted file mode 100644 index d701d5954fc..00000000000 --- a/packages/nodes-base/nodes/Function/Function.node.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Function } from './Function.node'; - -describe('Function Node', () => { - it('is marked deprecated so the backend refuses new instances', () => { - const node = new Function(); - expect(node.description.deprecated).toBe(true); - }); -}); diff --git a/packages/nodes-base/nodes/FunctionItem/FunctionItem.node.test.ts b/packages/nodes-base/nodes/FunctionItem/FunctionItem.node.test.ts deleted file mode 100644 index 659e6631950..00000000000 --- a/packages/nodes-base/nodes/FunctionItem/FunctionItem.node.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { FunctionItem } from './FunctionItem.node'; - -describe('FunctionItem Node', () => { - it('is marked deprecated so the backend refuses new instances', () => { - const node = new FunctionItem(); - expect(node.description.deprecated).toBe(true); - }); -}); diff --git a/packages/quality/testing/playwright/fixtures/community-packages/index.ts b/packages/quality/testing/playwright/fixtures/community-packages/index.ts index 2a79b7dbc7b..55d6c1e4305 100644 --- a/packages/quality/testing/playwright/fixtures/community-packages/index.ts +++ b/packages/quality/testing/playwright/fixtures/community-packages/index.ts @@ -1,4 +1,5 @@ import { N8N_NODES_API_VERSION } from '@n8n/constants'; +import { parseNodesApiLevel } from 'n8n-workflow'; import { test as base } from '../base'; import { IMPORT_MARKER_DIR, PUBLISHED_PACKAGES, type FixturePackage } from './fixture-packages'; @@ -20,7 +21,7 @@ export interface PackageDisk { type Fixtures = { /** Publishes every fixture package into the stack's registry, once per worker, before any test runs. */ publishedPackages: readonly FixturePackage[]; - /** Node API level the instance supports: 2.x runs level 1, 3.x runs level 3. */ + /** Major node API level for fixtures that require integer levels. */ supportedNodesApiVersion: number; /** What the package left on the instance's disk; follows the main container across a restart. */ packageDisk: PackageDisk; @@ -44,7 +45,7 @@ export const test = base.extend< ], supportedNodesApiVersion: async ({ api: _api }, use) => { - await use(N8N_NODES_API_VERSION); + await use(parseNodesApiLevel(N8N_NODES_API_VERSION)!.major); }, packageDisk: async ({ n8nContainer }, use) => { diff --git a/packages/quality/testing/playwright/tests/e2e/workflows/editor/ndv/ndv-core.spec.ts b/packages/quality/testing/playwright/tests/e2e/workflows/editor/ndv/ndv-core.spec.ts index cd72b42b46f..3f2a70ea1c7 100644 --- a/packages/quality/testing/playwright/tests/e2e/workflows/editor/ndv/ndv-core.spec.ts +++ b/packages/quality/testing/playwright/tests/e2e/workflows/editor/ndv/ndv-core.spec.ts @@ -164,15 +164,9 @@ test.describe( await expect(n8n.ndv.getNodeVersion()).toContainText('Latest'); await n8n.ndv.close(); -<<<<<<< HEAD await n8n.canvas.openNode('Read Spreadsheet File'); await n8n.ndv.openSettings(); await expect(n8n.ndv.getNodeVersion()).toContainText('Spreadsheet File node version 1'); -======= - await n8n.canvas.openNode('Cron'); - await n8n.ndv.openSettings(); - await expect(n8n.ndv.getNodeVersion()).toContainText('Cron node version 1'); ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 await expect(n8n.ndv.getNodeVersion()).toContainText('Deprecated'); await n8n.ndv.close(); }); diff --git a/packages/quality/testing/playwright/workflows/Test_Template_2.json b/packages/quality/testing/playwright/workflows/Test_Template_2.json index 9e1b4ef9036..df84b33bed6 100644 --- a/packages/quality/testing/playwright/workflows/Test_Template_2.json +++ b/packages/quality/testing/playwright/workflows/Test_Template_2.json @@ -38,12 +38,8 @@ "type": "n8n-nodes-base.code", "position": [620, 420], "parameters": { -<<<<<<< HEAD "mode": "runOnceForAllItems", "jsCode": "const _ = require('lodash')\n\nconst sanitize = str => _.chain(str)\n .replace(/[^A-Za-z0-9&.-]/g, '-') // sanitise via whitelist of characters\n .replace(/-(?=-)/g, '') // remove repeated dashes - https://regexr.com/6ag8h\n .trim('-') // trim any leading/trailing dashes\n .truncate({\n length: 60,\n omission: '-' // when the string ends with '-', you'll know it was truncated\n })\n .value()\n\nconst result = _.flatMap($input.all().map(item => {\n //console.log({item})\n\n // Maps each attachment to a separate item\n return _.values(item.binary).map(file => {\n console.log(\"Saving attachement:\", file.fileName, 'from:', ...item.json.from.value)\n \n // sanitize filename but exclude extension\n const filename_parts = file.fileName.split('.')\n const ext = _.slice(filename_parts, filename_parts.length-1)\n const filename_main = _.join(_.dropRight(filename_parts), '.')\n file.fileName = sanitize(filename_main) + '.' + ext\n \n return {\n json: {\n from: sanitize(item.json.from.value[0].name),\n date: sanitize(new Date(item.json.date).toISOString().split(\"T\")[0]) // get date part \"2020-01-01\"\n }, \n binary: { file }\n }\n })\n}))\n\n//console.log(result)\nreturn result" -======= - "jsCode": "const _ = require('lodash')\n\nconst sanitize = str => _.chain(str)\n .replace(/[^A-Za-z0-9&.-]/g, '-') // sanitise via whitelist of characters\n .replace(/-(?=-)/g, '') // remove repeated dashes - https://regexr.com/6ag8h\n .trim('-') // trim any leading/trailing dashes\n .truncate({\n length: 60,\n omission: '-' // when the string ends with '-', you'll know it was truncated\n })\n .value()\n\nconst result = _.flatMap(items.map(item => {\n //console.log({item})\n\n // Maps each attachment to a separate item\n return _.values(item.binary).map(file => {\n console.log(\"Saving attachement:\", file.fileName, 'from:', ...item.json.from.value)\n \n // sanitize filename but exclude extension\n const filename_parts = file.fileName.split('.')\n const ext = _.slice(filename_parts, filename_parts.length-1)\n const filename_main = _.join(_.dropRight(filename_parts), '.')\n file.fileName = sanitize(filename_main) + '.' + ext\n \n return {\n json: {\n from: sanitize(item.json.from.value[0].name),\n date: sanitize(new Date(item.json.date).toISOString().split(\"T\")[0]) // get date part \"2020-01-01\"\n }, \n binary: { file }\n }\n })\n}))\n\n//console.log(result)\nreturn result" ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 }, "typeVersion": 2 } @@ -77,12 +73,6 @@ "workflowInfo": { "nodeCount": 3, "nodeTypes": { -<<<<<<< HEAD -======= - "n8n-nodes-base.code": { - "count": 1 - }, ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 "n8n-nodes-base.nextCloud": { "count": 1 }, @@ -125,11 +115,7 @@ }, { "id": 14, -<<<<<<< HEAD "icon": "node:code", -======= - "icon": "fa:code", ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 "name": "n8n-nodes-base.code", "defaults": { "name": "Code" diff --git a/packages/quality/testing/playwright/workflows/Test_workflow_ndv_version.json b/packages/quality/testing/playwright/workflows/Test_workflow_ndv_version.json index d2c576cdd83..1afc59221a5 100644 --- a/packages/quality/testing/playwright/workflows/Test_workflow_ndv_version.json +++ b/packages/quality/testing/playwright/workflows/Test_workflow_ndv_version.json @@ -10,13 +10,8 @@ }, { "id": "1ea0a87c-3395-4bd9-84fb-cf8b0f769cc4", -<<<<<<< HEAD "name": "Read Spreadsheet File", "type": "n8n-nodes-base.spreadsheetFile", -======= - "name": "Cron", - "type": "n8n-nodes-base.cron", ->>>>>>> 7424f0ca0452f9dc9fe4cf6627ecbf0b315ed1e3 "typeVersion": 1, "position": [960, 460], "parameters": {}