Skip to content

Commit

Permalink
Merge branch 'master' into N8N-5191-pinia-migration-part2
Browse files Browse the repository at this point in the history
* master:
  fix(editor): Showing string numbers and null properly in JSON view (#4513)
  fix(editor): Switch `CodeNodeEditor` linter parser to `esprima-next` (#4524)
  fix(API): Do not use names for typeorm connections (#4532)
  refactor(editor): Encapsulate canvas actions (#4416)
  fix: Database config should resolve entities and migrations folder relative to it's path (no-changelog) (#4527)
  feat(API): Set up error tracking using Sentry (#4394)
  fix(editor): Curb arg linting for `$input.first()` and `$input.last()` (#4526)
  fix(HTTP Request Node): use the data in "Put Output in Field" field (#4487)
  refactor: consolidate database configs (#4522)

# Conflicts:
#	packages/editor-ui/src/views/NodeView.vue
  • Loading branch information
MiloradFilipovic committed Nov 7, 2022
2 parents c761186 + f6b85f4 commit f65d5a1
Show file tree
Hide file tree
Showing 43 changed files with 2,385 additions and 1,759 deletions.
1 change: 1 addition & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
{
"name": "Launch n8n with debug",
"program": "${workspaceFolder}/packages/cli/bin/n8n",
"cwd": "${workspaceFolder}/packages/cli/bin",
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"type": "node",
Expand Down
1 change: 1 addition & 0 deletions docker/images/n8n-debian/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ARG N8N_VERSION

RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" ; exit 1; fi

ENV N8N_VERSION=${N8N_VERSION}
RUN \
apt-get update && \
apt-get -y install graphicsmagick gosu git
Expand Down
1 change: 1 addition & 0 deletions docker/images/n8n-rhel7/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ARG N8N_VERSION

RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" ; exit 1; fi

ENV N8N_VERSION=${N8N_VERSION}
RUN \
yum install -y gcc-c++ make

Expand Down
5 changes: 3 additions & 2 deletions docker/images/n8n/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ FROM n8nio/base:${NODE_VERSION}
ARG N8N_VERSION
RUN if [ -z "$N8N_VERSION" ] ; then echo "The N8N_VERSION argument is missing!" ; exit 1; fi

ENV N8N_VERSION=${N8N_VERSION}
ENV NODE_ENV=production
RUN set -eux; \
apkArch="$(apk --print-arch)"; \
case "$apkArch" in \
'armv7') apk --no-cache add --virtual build-dependencies python3 build-base;; \
'armv7') apk --no-cache add --virtual build-dependencies python3 build-base;; \
esac && \
npm install -g --omit=dev n8n@${N8N_VERSION} && \
case "$apkArch" in \
'armv7') apk del build-dependencies;; \
'armv7') apk del build-dependencies;; \
esac && \
find /usr/local/lib/node_modules/n8n -type f -name "*.ts" -o -name "*.js.map" -o -name "*.vue" | xargs rm && \
rm -rf /root/.npm
Expand Down
3,113 changes: 1,711 additions & 1,402 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions packages/cli/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ export const schema = {
},
},
sqlite: {
database: {
doc: 'SQLite Database file name',
format: String,
default: 'database.sqlite',
env: 'DB_SQLITE_DATABASE',
},
executeVacuumOnStartup: {
doc: 'Runs VACUUM operation on startup to rebuild the database. Reduces filesize and optimizes indexes. WARNING: This is a long running blocking operation. Will increase start-up time.',
format: Boolean,
Expand Down Expand Up @@ -942,6 +948,15 @@ export const schema = {
env: 'N8N_DIAGNOSTICS_POSTHOG_DISABLE_RECORDING',
},
},
sentry: {
dsn: {
doc: 'Data source name for error tracking on Sentry',
format: String,
default:
'https://[email protected]/4504016528408576',
env: 'N8N_SENTRY_DSN',
},
},
frontend: {
doc: 'Diagnostics config for frontend.',
format: String,
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
"@oclif/core": "^1.9.3",
"@oclif/errors": "^1.2.2",
"@rudderstack/rudder-sdk-node": "1.0.6",
"@sentry/node": "^7.17.3",
"@sentry/integrations": "^7.17.3",
"axios": "^0.21.1",
"basic-auth": "^2.0.1",
"bcryptjs": "^2.4.3",
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/ActiveWorkflowRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
WorkflowActivationError,
WorkflowExecuteMode,
LoggerProxy as Logger,
ErrorReporterProxy as ErrorReporter,
} from 'n8n-workflow';

import express from 'express';
Expand Down Expand Up @@ -121,6 +122,7 @@ export class ActiveWorkflowRunner {
});
console.log(` => Started`);
} catch (error) {
ErrorReporter.error(error);
console.log(
` => ERROR: Workflow could not be activated on first try, keep on trying`,
);
Expand Down Expand Up @@ -881,6 +883,7 @@ export class ActiveWorkflowRunner {
try {
await this.add(workflowId, activationMode, workflowData);
} catch (error) {
ErrorReporter.error(error);
let lastTimeout = this.queuedWorkflowActivations[workflowId].lastTimeout;
if (lastTimeout < WORKFLOW_REACTIVATE_MAX_TIMEOUT) {
lastTimeout = Math.min(lastTimeout * 2, WORKFLOW_REACTIVATE_MAX_TIMEOUT);
Expand Down Expand Up @@ -948,6 +951,7 @@ export class ActiveWorkflowRunner {
try {
await this.removeWorkflowWebhooks(workflowId);
} catch (error) {
ErrorReporter.error(error);
console.error(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Could not remove webhooks of workflow "${workflowId}" because of error: "${error.message}"`,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/CommunityNodes/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const executeCommand = async (
command: string,
options?: { doNotHandleError?: boolean },
): Promise<string> => {
const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const downloadFolder = UserSettings.getUserN8nFolderDownloadedNodesPath();

const execOptions = {
cwd: downloadFolder,
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/CredentialsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
WorkflowExecuteMode,
ITaskDataConnections,
LoggerProxy as Logger,
ErrorReporterProxy as ErrorReporter,
IHttpRequestHelper,
} from 'n8n-workflow';

Expand Down Expand Up @@ -672,6 +673,7 @@ export class CredentialsHelper extends ICredentialsHelper {
credentialsDecrypted,
);
} catch (error) {
ErrorReporter.error(error);
// Do not fail any requests to allow custom error messages and
// make logic easier
if (error.cause?.response) {
Expand Down
56 changes: 17 additions & 39 deletions packages/cli/src/Db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable no-case-declarations */
/* eslint-disable @typescript-eslint/naming-convention */
import { UserSettings } from 'n8n-core';
import {
Connection,
ConnectionOptions,
Expand All @@ -17,18 +16,20 @@ import {
Repository,
} from 'typeorm';
import { TlsOptions } from 'tls';
import path from 'path';
// eslint-disable-next-line import/no-cycle
import { DatabaseType, GenericHelpers, IDatabaseCollections } from '.';

import config from '../config';

// eslint-disable-next-line import/no-cycle
import { entities } from './databases/entities';

import { postgresMigrations } from './databases/migrations/postgresdb';
import { mysqlMigrations } from './databases/migrations/mysqldb';
import { sqliteMigrations } from './databases/migrations/sqlite';
import {
getMariaDBConnectionOptions,
getMysqlConnectionOptions,
getOptionOverrides,
getPostgresConnectionOptions,
getSqliteConnectionOptions,
} from './databases/config';

export let isInitialized = false;
export const collections = {} as IDatabaseCollections;
Expand All @@ -51,7 +52,6 @@ export async function init(
if (isInitialized) return collections;

const dbType = (await GenericHelpers.getConfigValue('database.type')) as DatabaseType;
const n8nFolder = UserSettings.getUserN8nFolderPath();

let connectionOptions: ConnectionOptions;

Expand Down Expand Up @@ -84,17 +84,8 @@ export async function init(
}

connectionOptions = {
type: 'postgres',
entityPrefix,
database: (await GenericHelpers.getConfigValue('database.postgresdb.database')) as string,
host: (await GenericHelpers.getConfigValue('database.postgresdb.host')) as string,
password: (await GenericHelpers.getConfigValue('database.postgresdb.password')) as string,
port: (await GenericHelpers.getConfigValue('database.postgresdb.port')) as number,
username: (await GenericHelpers.getConfigValue('database.postgresdb.user')) as string,
schema: config.getEnv('database.postgresdb.schema'),
migrations: postgresMigrations,
migrationsRun: true,
migrationsTableName: `${entityPrefix}migrations`,
...getPostgresConnectionOptions(),
...(await getOptionOverrides('postgresdb')),
ssl,
};

Expand All @@ -103,29 +94,14 @@ export async function init(
case 'mariadb':
case 'mysqldb':
connectionOptions = {
type: dbType === 'mysqldb' ? 'mysql' : 'mariadb',
database: (await GenericHelpers.getConfigValue('database.mysqldb.database')) as string,
entityPrefix,
host: (await GenericHelpers.getConfigValue('database.mysqldb.host')) as string,
password: (await GenericHelpers.getConfigValue('database.mysqldb.password')) as string,
port: (await GenericHelpers.getConfigValue('database.mysqldb.port')) as number,
username: (await GenericHelpers.getConfigValue('database.mysqldb.user')) as string,
migrations: mysqlMigrations,
migrationsRun: true,
migrationsTableName: `${entityPrefix}migrations`,
...(dbType === 'mysqldb' ? getMysqlConnectionOptions() : getMariaDBConnectionOptions()),
...(await getOptionOverrides('mysqldb')),
timezone: 'Z', // set UTC as default
};
break;

case 'sqlite':
connectionOptions = {
type: 'sqlite',
database: path.join(n8nFolder, 'database.sqlite'),
entityPrefix,
migrations: sqliteMigrations,
migrationsRun: false, // migrations for sqlite will be ran manually for now; see below
migrationsTableName: `${entityPrefix}migrations`,
};
connectionOptions = getSqliteConnectionOptions();
break;

default:
Expand All @@ -149,13 +125,15 @@ export async function init(
}
}

const maxQueryExecutionTime = (await GenericHelpers.getConfigValue(
'database.logging.maxQueryExecutionTime',
)) as string;

Object.assign(connectionOptions, {
entities: Object.values(entities),
synchronize: false,
logging: loggingOption,
maxQueryExecutionTime: (await GenericHelpers.getConfigValue(
'database.logging.maxQueryExecutionTime',
)) as string,
maxQueryExecutionTime,
});

connection = await createConnection(connectionOptions);
Expand Down
41 changes: 41 additions & 0 deletions packages/cli/src/ErrorReporting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as Sentry from '@sentry/node';
import { RewriteFrames } from '@sentry/integrations';
import type { Application } from 'express';
import config from '../config';
import { ErrorReporterProxy } from 'n8n-workflow';

let initialized = false;

export const initErrorHandling = (app?: Application) => {
if (initialized) return;

if (!config.getEnv('diagnostics.enabled')) {
initialized = true;
return;
}

const dsn = config.getEnv('diagnostics.config.sentry.dsn');
const { N8N_VERSION: release, ENVIRONMENT: environment } = process.env;

Sentry.init({
dsn,
release,
environment,
integrations: (integrations) => {
integrations.push(new RewriteFrames({ root: process.cwd() }));
return integrations;
},
});

if (app) {
const { requestHandler, errorHandler } = Sentry.Handlers;
app.use(requestHandler());
app.use(errorHandler());
}

ErrorReporterProxy.init({
report: (error, options) => Sentry.captureException(error, options),
});

initialized = true;
};
17 changes: 11 additions & 6 deletions packages/cli/src/LoadNodesAndCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
IVersionedNodeType,
LoggerProxy,
jsonParse,
ErrorReporterProxy as ErrorReporter,
} from 'n8n-workflow';

import {
Expand Down Expand Up @@ -125,19 +126,23 @@ class LoadNodesAndCredentialsClass {
const nodePackages = [];
try {
// Read downloaded nodes and credentials
const downloadedNodesFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const downloadedNodesFolder = UserSettings.getUserN8nFolderDownloadedNodesPath();
const downloadedNodesFolderModules = path.join(downloadedNodesFolder, 'node_modules');
await fsAccess(downloadedNodesFolderModules);
const downloadedPackages = await this.getN8nNodePackages(downloadedNodesFolderModules);
nodePackages.push(...downloadedPackages);
// eslint-disable-next-line no-empty
} catch (error) {}
} catch (error) {
// Folder does not exist so ignore and return
return;
}

for (const packagePath of nodePackages) {
try {
await this.loadDataFromPackage(packagePath);
// eslint-disable-next-line no-empty
} catch (error) {}
} catch (error) {
ErrorReporter.error(error);
}
}
}

Expand Down Expand Up @@ -231,7 +236,7 @@ class LoadNodesAndCredentialsClass {
}

async loadNpmModule(packageName: string, version?: string): Promise<InstalledPackages> {
const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const downloadFolder = UserSettings.getUserN8nFolderDownloadedNodesPath();
const command = `npm install ${packageName}${version ? `@${version}` : ''}`;

await executeCommand(command);
Expand Down Expand Up @@ -285,7 +290,7 @@ class LoadNodesAndCredentialsClass {
packageName: string,
installedPackage: InstalledPackages,
): Promise<InstalledPackages> {
const downloadFolder = UserSettings.getUserN8nFolderDowloadedNodesPath();
const downloadFolder = UserSettings.getUserN8nFolderDownloadedNodesPath();

const command = `npm i ${packageName}@latest`;

Expand Down
9 changes: 7 additions & 2 deletions packages/cli/src/ResponseHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Request, Response } from 'express';
import { parse, stringify } from 'flatted';
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';

// eslint-disable-next-line import/no-cycle
import {
Expand Down Expand Up @@ -154,8 +155,12 @@ export function send<T, R extends Request, S extends Response>(

sendSuccessResponse(res, data, raw);
} catch (error) {
if (error instanceof Error && isUniqueConstraintError(error)) {
error.message = 'There is already an entry with this name';
if (error instanceof Error) {
ErrorReporter.error(error);

if (isUniqueConstraintError(error)) {
error.message = 'There is already an entry with this name';
}
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
Expand Down
Loading

0 comments on commit f65d5a1

Please sign in to comment.