mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
ci: Drop support for Node.js 18 (#15146)
This commit is contained in:
committed by
GitHub
parent
40de4ed91c
commit
3bdbdfe6ce
2
.github/ISSUE_TEMPLATE/01-bug.yml
vendored
2
.github/ISSUE_TEMPLATE/01-bug.yml
vendored
@@ -53,7 +53,7 @@ body:
|
||||
id: nodejs-version
|
||||
attributes:
|
||||
label: Node.js Version
|
||||
placeholder: ex. 18.16.0
|
||||
placeholder: ex. 20.19.0
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
||||
2
.github/workflows/ci-master.yml
vendored
2
.github/workflows/ci-master.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
needs: install-and-build
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 22.4]
|
||||
node-version: [20.x, 22.x]
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
nodeVersion: ${{ matrix.node-version }}
|
||||
|
||||
1
.github/workflows/docker-base-image.yml
vendored
1
.github/workflows/docker-base-image.yml
vendored
@@ -9,7 +9,6 @@ on:
|
||||
required: true
|
||||
default: '20'
|
||||
options:
|
||||
- '18'
|
||||
- '20'
|
||||
- '22'
|
||||
|
||||
|
||||
2
.github/workflows/e2e-flaky.yml
vendored
2
.github/workflows/e2e-flaky.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: 20.x
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache build artifacts
|
||||
|
||||
20
.github/workflows/e2e-reusable.yml
vendored
20
.github/workflows/e2e-reusable.yml
vendored
@@ -76,7 +76,13 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.calculate_ref.outputs.value }}
|
||||
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20.x
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache build artifacts
|
||||
id: cache-build-artifacts
|
||||
@@ -94,7 +100,7 @@ jobs:
|
||||
|
||||
- name: Cypress build
|
||||
if: steps.cache-build-artifacts.outputs.cache-hit != 'true'
|
||||
uses: cypress-io/github-action@0ee1130f05f69098ab5c560bd198fecf5a14d75b # v6.9.0
|
||||
uses: cypress-io/github-action@be1bab96b388bbd9ce3887e397d373c8557e15af # v6.9.2
|
||||
with:
|
||||
# Disable running of tests within install job
|
||||
runTests: false
|
||||
@@ -120,7 +126,13 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.calculate_ref.outputs.value }}
|
||||
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20.x
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Restore cached pnpm modules
|
||||
id: cache-build-artifacts
|
||||
@@ -136,7 +148,7 @@ jobs:
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@0ee1130f05f69098ab5c560bd198fecf5a14d75b # v6.9.0
|
||||
uses: cypress-io/github-action@be1bab96b388bbd9ce3887e397d373c8557e15af # v6.9.2
|
||||
with:
|
||||
working-directory: cypress
|
||||
install: false
|
||||
|
||||
4
.github/workflows/e2e-tests-pr.yml
vendored
4
.github/workflows/e2e-tests-pr.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
is_pr_approved_by_maintainer: true
|
||||
|
||||
run-e2e-tests:
|
||||
name: E2E [Electron/Node 18]
|
||||
name: E2E
|
||||
uses: ./.github/workflows/e2e-reusable.yml
|
||||
needs: [eligibility_check]
|
||||
if: needs.eligibility_check.outputs.should_run == 'true'
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
|
||||
post-e2e-tests:
|
||||
name: E2E [Electron/Node 18] - Checks
|
||||
name: E2E - Checks
|
||||
runs-on: ubuntu-latest
|
||||
needs: [eligibility_check, run-e2e-tests]
|
||||
if: always() && needs.eligibility_check.result != 'skipped'
|
||||
|
||||
2
.github/workflows/e2e-tests.yml
vendored
2
.github/workflows/e2e-tests.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
run-e2e-tests:
|
||||
name: E2E [Electron/Node 18]
|
||||
name: E2E
|
||||
uses: ./.github/workflows/e2e-reusable.yml
|
||||
with:
|
||||
branch: ${{ github.event.inputs.branch || 'master' }}
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
"n8n-workflow": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ngneat/falso": "^7.2.0",
|
||||
"@ngneat/falso": "^7.3.0",
|
||||
"@sinonjs/fake-timers": "^13.0.2",
|
||||
"cypress": "^13.14.2",
|
||||
"cypress": "^14.4.0",
|
||||
"cypress-otp": "^1.0.3",
|
||||
"cypress-real-events": "^1.13.0",
|
||||
"cypress-real-events": "^1.14.0",
|
||||
"flatted": "catalog:",
|
||||
"lodash": "catalog:",
|
||||
"nanoid": "catalog:",
|
||||
|
||||
@@ -12,6 +12,18 @@ before(() => {
|
||||
Cypress.on('uncaught:exception', (error) => {
|
||||
return !error.message.includes('ResizeObserver');
|
||||
});
|
||||
|
||||
// Mock the clipboard API because in newer versions of cypress the clipboard API is flaky when the window is not focussed.
|
||||
Cypress.on('window:before:load', (win) => {
|
||||
let currentContent: string = '';
|
||||
Object.assign(win.navigator.clipboard, {
|
||||
writeText: async (text: string) => {
|
||||
currentContent = text;
|
||||
return await Promise.resolve();
|
||||
},
|
||||
readText: async () => await Promise.resolve(currentContent),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "1.97.0",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=20.15",
|
||||
"node": ">=22.16",
|
||||
"pnpm": ">=10.2.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.2.1",
|
||||
@@ -79,7 +79,7 @@
|
||||
],
|
||||
"overrides": {
|
||||
"@azure/identity": "^4.3.0",
|
||||
"@types/node": "^18.16.16",
|
||||
"@types/node": "^20.17.50",
|
||||
"chokidar": "^4.0.1",
|
||||
"esbuild": "^0.24.0",
|
||||
"pug": "^3.0.3",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/** @type {import('jest').Config} */
|
||||
module.exports = {
|
||||
...require('../../../jest.config'),
|
||||
setupFilesAfterEnv: ['n8n-workflow/test/setup.ts'],
|
||||
testTimeout: 10_000,
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"watch": "tsc-watch -p tsconfig.build.json --onCompilationComplete \"tsc-alias -p tsconfig.build.json\""
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.10"
|
||||
"node": ">=20.19"
|
||||
},
|
||||
"keywords": [
|
||||
"automate",
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
module.exports = {
|
||||
...require('../../../jest.config'),
|
||||
collectCoverageFrom: ['credentials/**/*.ts', 'nodes/**/*.ts', 'utils/**/*.ts'],
|
||||
setupFilesAfterEnv: ['jest-expect-message', 'n8n-workflow/test/setup.ts'],
|
||||
setupFilesAfterEnv: ['jest-expect-message'],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/** @type {import('jest').Config} */
|
||||
module.exports = {
|
||||
...require('../../../jest.config'),
|
||||
setupFilesAfterEnv: ['n8n-workflow/test/setup.ts'],
|
||||
testTimeout: 10_000,
|
||||
};
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// WebCrypto Polyfill for older versions of Node.js 18
|
||||
if (!globalThis.crypto?.getRandomValues) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
|
||||
globalThis.crypto = require('node:crypto').webcrypto;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import './polyfills';
|
||||
import { Container } from '@n8n/di';
|
||||
import { ensureError, setGlobalState } from 'n8n-workflow';
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@ If you've been ingesting route metrics from your n8n instance (version 1.81.0 an
|
||||
how the `last_activity` metric has affected your Prometheus instance and potentially clean up the old data. Future
|
||||
metrics will also be served in a different format, which needs to be taken into account.
|
||||
|
||||
### What changed?
|
||||
|
||||
The minimum Node.js version required for n8n is now v20.
|
||||
|
||||
### When is action necessary?
|
||||
|
||||
If you're using n8n via npm or PM2 or if you're contributing to n8n.
|
||||
|
||||
### How to upgrade:
|
||||
|
||||
Update the Node.js version to v20 or above.
|
||||
|
||||
## 1.83.0
|
||||
|
||||
### What changed?
|
||||
|
||||
@@ -65,11 +65,6 @@ if (process.env.NODEJS_PREFER_IPV4 === 'true') {
|
||||
// More details: https://github.com/nodejs/node/issues/48145
|
||||
require('net').setDefaultAutoSelectFamily?.(false);
|
||||
|
||||
// WebCrypto Polyfill for older versions of Node.js 18
|
||||
if (!globalThis.crypto?.getRandomValues) {
|
||||
globalThis.crypto = require('node:crypto').webcrypto;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const oclif = await import('@oclif/core');
|
||||
await oclif.execute({ dir: __dirname });
|
||||
|
||||
@@ -7,7 +7,6 @@ module.exports = {
|
||||
globalSetup: '<rootDir>/test/setup.ts',
|
||||
globalTeardown: '<rootDir>/test/teardown.ts',
|
||||
setupFilesAfterEnv: [
|
||||
'n8n-workflow/test/setup.ts',
|
||||
'<rootDir>/test/setup-test-folder.ts',
|
||||
'<rootDir>/test/setup-mocks.ts',
|
||||
'<rootDir>/test/extend-expect.ts',
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"workflow"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18.17 <= 22"
|
||||
"node": ">=20.19 <= 22.x"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
@@ -69,7 +69,7 @@
|
||||
"@types/psl": "^1.1.0",
|
||||
"@types/replacestream": "^4.0.1",
|
||||
"@types/shelljs": "^0.8.11",
|
||||
"@types/sshpk": "^1.17.1",
|
||||
"@types/sshpk": "^1.17.4",
|
||||
"@types/superagent": "^8.1.9",
|
||||
"@types/swagger-ui-express": "^4.1.8",
|
||||
"@types/syslog-client": "^1.1.2",
|
||||
@@ -170,7 +170,7 @@
|
||||
"simple-git": "3.17.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"sqlite3": "5.1.7",
|
||||
"sshpk": "1.17.0",
|
||||
"sshpk": "1.18.0",
|
||||
"swagger-ui-express": "5.0.1",
|
||||
"syslog-client": "1.1.1",
|
||||
"uuid": "catalog:",
|
||||
|
||||
@@ -21,7 +21,7 @@ type ConnectionState = {
|
||||
export class DbConnection {
|
||||
private dataSource: DataSource;
|
||||
|
||||
private pingTimer: NodeJS.Timer | undefined;
|
||||
private pingTimer: NodeJS.Timeout | undefined;
|
||||
|
||||
readonly connectionState: ConnectionState = {
|
||||
connected: false,
|
||||
|
||||
@@ -61,7 +61,7 @@ export class MessageEventBus extends EventEmitter {
|
||||
[key: string]: MessageEventBusDestination;
|
||||
} = {};
|
||||
|
||||
private pushIntervalTimer: NodeJS.Timer;
|
||||
private pushIntervalTimer: NodeJS.Timeout;
|
||||
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
|
||||
@@ -28,9 +28,9 @@ export class ExternalSecretsManager {
|
||||
|
||||
initialized = false;
|
||||
|
||||
updateInterval: NodeJS.Timer;
|
||||
updateInterval: NodeJS.Timeout;
|
||||
|
||||
initRetryTimeouts: Record<string, NodeJS.Timer> = {};
|
||||
initRetryTimeouts: Record<string, NodeJS.Timeout> = {};
|
||||
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
|
||||
@@ -230,7 +230,7 @@ export class VaultProvider extends SecretsProvider {
|
||||
|
||||
#http: AxiosInstance;
|
||||
|
||||
private refreshTimeout: NodeJS.Timer | null;
|
||||
private refreshTimeout: NodeJS.Timeout | null;
|
||||
|
||||
private refreshAbort = new AbortController();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { InsightsConfig } from './insights.config';
|
||||
*/
|
||||
@Service()
|
||||
export class InsightsCompactionService {
|
||||
private compactInsightsTimer: NodeJS.Timer | undefined;
|
||||
private compactInsightsTimer: NodeJS.Timeout | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly insightsByPeriodRepository: InsightsByPeriodRepository,
|
||||
|
||||
@@ -45,7 +45,7 @@ export class MultiMainSetup extends TypedEmitter<MultiMainEvents> {
|
||||
|
||||
private readonly leaderKeyTtl = this.globalConfig.multiMainSetup.ttl;
|
||||
|
||||
private leaderCheckInterval: NodeJS.Timer | undefined;
|
||||
private leaderCheckInterval: NodeJS.Timeout | undefined;
|
||||
|
||||
async init() {
|
||||
const prefix = config.getEnv('redis.prefix');
|
||||
|
||||
@@ -39,7 +39,7 @@ export class Subscriber {
|
||||
|
||||
const debouncedHandlerFn = debounce(handlerFn, 300);
|
||||
|
||||
this.client.on('message', (channel: PubSub.Channel, str) => {
|
||||
this.client.on('message', (channel: PubSub.Channel, str: string) => {
|
||||
const msg = this.parseMessage(str, channel);
|
||||
if (!msg) return;
|
||||
if (msg.debounce) debouncedHandlerFn(msg);
|
||||
|
||||
@@ -380,7 +380,7 @@ export class ScalingService {
|
||||
private readonly jobCounters = { completed: 0, failed: 0 };
|
||||
|
||||
/** Interval for collecting queue metrics to expose via Prometheus. */
|
||||
private queueMetricsInterval: NodeJS.Timer | undefined;
|
||||
private queueMetricsInterval: NodeJS.Timeout | undefined;
|
||||
|
||||
get isQueueMetricsEnabled() {
|
||||
return (
|
||||
|
||||
@@ -26,7 +26,7 @@ import { DbConnection } from '@/databases/db-connection';
|
||||
@Service()
|
||||
export class ExecutionsPruningService {
|
||||
/** Timer for soft-deleting executions on a rolling basis. */
|
||||
private softDeletionInterval: NodeJS.Timer | undefined;
|
||||
private softDeletionInterval: NodeJS.Timeout | undefined;
|
||||
|
||||
/** Timeout for next hard-deletion of soft-deleted executions. */
|
||||
private hardDeletionTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
@@ -53,7 +53,7 @@ export class RedisClientService extends TypedEmitter<RedisEventMap> {
|
||||
? this.createClusterClient(arg)
|
||||
: this.createRegularClient(arg);
|
||||
|
||||
client.on('error', (error) => {
|
||||
client.on('error', (error: Error) => {
|
||||
if ('code' in error && error.code === 'ECONNREFUSED') return; // handled by retryStrategy
|
||||
|
||||
this.logger.error(`[Redis client] ${error.message}`, { error });
|
||||
|
||||
@@ -31,7 +31,7 @@ type WsStatusCode = (typeof WsStatusCodes)[keyof typeof WsStatusCodes];
|
||||
export class TaskBrokerWsServer {
|
||||
runnerConnections: Map<TaskRunner['id'], WebSocket> = new Map();
|
||||
|
||||
private heartbeatTimer: NodeJS.Timer | undefined;
|
||||
private heartbeatTimer: NodeJS.Timeout | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
import 'reflect-metadata';
|
||||
|
||||
// WebCrypto Polyfill for older versions of Node.js 18
|
||||
if (!globalThis.crypto?.getRandomValues) {
|
||||
globalThis.crypto = require('node:crypto').webcrypto;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import WorkerChartsAccordion from './WorkerChartsAccordion.ee.vue';
|
||||
import { sortByProperty } from '@n8n/utils/sort/sortByProperty';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
|
||||
let interval: NodeJS.Timer;
|
||||
let interval: NodeJS.Timeout;
|
||||
|
||||
const orchestrationStore = useOrchestrationStore();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface IOrchestrationStoreState {
|
||||
[id: string]: IWorkerHistoryItem[];
|
||||
};
|
||||
workersLastUpdated: { [id: string]: number };
|
||||
statusInterval: NodeJS.Timer | null;
|
||||
statusInterval: NodeJS.Timeout | null;
|
||||
}
|
||||
|
||||
export interface IWorkerHistoryItem {
|
||||
|
||||
@@ -6,9 +6,5 @@ module.exports = {
|
||||
...require('../../jest.config'),
|
||||
collectCoverageFrom: ['credentials/**/*.ts', 'nodes/**/*.ts', 'utils/**/*.ts'],
|
||||
globalSetup: '<rootDir>/test/globalSetup.ts',
|
||||
setupFilesAfterEnv: [
|
||||
'jest-expect-message',
|
||||
'n8n-workflow/test/setup.ts',
|
||||
'<rootDir>/test/setup.ts',
|
||||
],
|
||||
setupFilesAfterEnv: ['jest-expect-message', '<rootDir>/test/setup.ts'],
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import { NodeOperationError, type IExecuteFunctions } from 'n8n-workflow';
|
||||
import { Wait } from '../Wait.node';
|
||||
|
||||
describe('Execute Wait Node', () => {
|
||||
let timer: NodeJS.Timer;
|
||||
let timer: NodeJS.Timeout;
|
||||
const { clearInterval, setInterval } = global;
|
||||
const nextDay = DateTime.now().startOf('day').plus({ days: 1 });
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/** @type {import('jest').Config} */
|
||||
module.exports = {
|
||||
...require('../../jest.config'),
|
||||
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
|
||||
};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { randomFillSync } from 'crypto';
|
||||
|
||||
Object.defineProperty(globalThis, 'crypto', {
|
||||
value: {
|
||||
getRandomValues: (buffer: NodeJS.ArrayBufferView) => randomFillSync(buffer),
|
||||
},
|
||||
});
|
||||
792
pnpm-lock.yaml
generated
792
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user