mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
ci: Configure eslint for benchmark cli (#10480)
This commit is contained in:
parent
dd0c098b86
commit
8403f4aa11
30
packages/@n8n/benchmark/.eslintrc.js
Normal file
30
packages/@n8n/benchmark/.eslintrc.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
const sharedOptions = require('@n8n_io/eslint-config/shared');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
extends: ['@n8n_io/eslint-config/node'],
|
||||||
|
|
||||||
|
...sharedOptions(__dirname),
|
||||||
|
|
||||||
|
parserOptions: {
|
||||||
|
project: './tsconfig.json',
|
||||||
|
},
|
||||||
|
|
||||||
|
ignorePatterns: ['scenarios/**'],
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'n8n-local-rules/no-plain-errors': 'off',
|
||||||
|
complexity: 'error',
|
||||||
|
},
|
||||||
|
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['./src/commands/*.ts'],
|
||||||
|
rules: {
|
||||||
|
'import/no-default-export': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -5,6 +5,8 @@
|
||||||
"main": "dist/index",
|
"main": "dist/index",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lintfix": "eslint . --fix",
|
||||||
"start": "./bin/n8n-benchmark",
|
"start": "./bin/n8n-benchmark",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { strict as assert } from 'node:assert';
|
import { strict as assert } from 'node:assert';
|
||||||
|
import type { AxiosRequestConfig } from 'axios';
|
||||||
import { N8nApiClient } from './n8nApiClient';
|
import { N8nApiClient } from './n8nApiClient';
|
||||||
import { AxiosRequestConfig } from 'axios';
|
|
||||||
|
|
||||||
export class AuthenticatedN8nApiClient extends N8nApiClient {
|
export class AuthenticatedN8nApiClient extends N8nApiClient {
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import axios, { AxiosError, AxiosRequestConfig } from 'axios';
|
import type { AxiosError, AxiosRequestConfig } from 'axios';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export class N8nApiClient {
|
export class N8nApiClient {
|
||||||
constructor(public readonly apiBaseUrl: string) {}
|
constructor(public readonly apiBaseUrl: string) {}
|
||||||
|
@ -11,7 +12,7 @@ export class N8nApiClient {
|
||||||
|
|
||||||
while (Date.now() - START_TIME < TIMEOUT_MS) {
|
while (Date.now() - START_TIME < TIMEOUT_MS) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.request({
|
const response = await axios.request<{ status: 'ok' }>({
|
||||||
url: `${this.apiBaseUrl}/${HEALTH_ENDPOINT}`,
|
url: `${this.apiBaseUrl}/${HEALTH_ENDPOINT}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
@ -72,7 +73,7 @@ export class N8nApiClient {
|
||||||
return `${this.apiBaseUrl}/rest${endpoint}`;
|
return `${this.apiBaseUrl}/rest${endpoint}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private delay(ms: number): Promise<void> {
|
private async delay(ms: number): Promise<void> {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return await new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Workflow } from '@/n8nApiClient/n8nApiClient.types';
|
import type { AuthenticatedN8nApiClient } from './authenticatedN8nApiClient';
|
||||||
import { AuthenticatedN8nApiClient } from './authenticatedN8nApiClient';
|
import type { Workflow } from '@/n8nApiClient/n8nApiClient.types';
|
||||||
|
|
||||||
export class WorkflowApiClient {
|
export class WorkflowApiClient {
|
||||||
constructor(private readonly apiClient: AuthenticatedN8nApiClient) {}
|
constructor(private readonly apiClient: AuthenticatedN8nApiClient) {}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { Scenario } from '@/types/scenario';
|
import type { Scenario } from '@/types/scenario';
|
||||||
import { Workflow } from '@/n8nApiClient/n8nApiClient.types';
|
import type { Workflow } from '@/n8nApiClient/n8nApiClient.types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads scenario data files from FS
|
* Loads scenario data files from FS
|
||||||
|
@ -25,11 +25,10 @@ export class ScenarioDataFileLoader {
|
||||||
const fileContent = fs.readFileSync(workflowFilePath, 'utf8');
|
const fileContent = fs.readFileSync(workflowFilePath, 'utf8');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return JSON.parse(fileContent);
|
return JSON.parse(fileContent) as Workflow;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(
|
const e = error as Error;
|
||||||
`Failed to parse workflow file ${workflowFilePath}: ${error instanceof Error ? error.message : error}`,
|
throw new Error(`Failed to parse workflow file ${workflowFilePath}: ${e.message}`);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,11 @@ export class ScenarioLoader {
|
||||||
private loadAndValidateScenarioManifest(
|
private loadAndValidateScenarioManifest(
|
||||||
scenarioManifestPath: string,
|
scenarioManifestPath: string,
|
||||||
): [ScenarioManifest, null] | [null, string[]] {
|
): [ScenarioManifest, null] | [null, string[]] {
|
||||||
const scenario = JSON.parse(fs.readFileSync(scenarioManifestPath, 'utf8'));
|
const [scenario, error] = this.loadScenarioManifest(scenarioManifestPath);
|
||||||
|
if (!scenario) {
|
||||||
|
return [null, [error]];
|
||||||
|
}
|
||||||
|
|
||||||
const validationErrors: string[] = [];
|
const validationErrors: string[] = [];
|
||||||
|
|
||||||
if (!scenario.name) {
|
if (!scenario.name) {
|
||||||
|
@ -61,6 +65,21 @@ export class ScenarioLoader {
|
||||||
return validationErrors.length === 0 ? [scenario, null] : [null, validationErrors];
|
return validationErrors.length === 0 ? [scenario, null] : [null, validationErrors];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private loadScenarioManifest(
|
||||||
|
scenarioManifestPath: string,
|
||||||
|
): [ScenarioManifest, null] | [null, string] {
|
||||||
|
try {
|
||||||
|
const scenario = JSON.parse(
|
||||||
|
fs.readFileSync(scenarioManifestPath, 'utf8'),
|
||||||
|
) as ScenarioManifest;
|
||||||
|
|
||||||
|
return [scenario, null];
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
||||||
|
return [null, `Failed to parse manifest ${scenarioManifestPath}: ${message}`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private formScenarioId(scenarioPath: string): string {
|
private formScenarioId(scenarioPath: string): string {
|
||||||
return createHash('sha256').update(scenarioPath).digest('hex');
|
return createHash('sha256').update(scenarioPath).digest('hex');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { $, which } from 'zx';
|
import { $, which } from 'zx';
|
||||||
import { Scenario } from '@/types/scenario';
|
import type { Scenario } from '@/types/scenario';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes test scenarios using k6
|
* Executes test scenarios using k6
|
||||||
|
@ -24,7 +24,7 @@ export class K6Executor {
|
||||||
})`${k6ExecutablePath} run --quiet --stage ${stage} ${scenario.scriptPath}`;
|
})`${k6ExecutablePath} run --quiet --stage ${stage} ${scenario.scriptPath}`;
|
||||||
|
|
||||||
for await (const chunk of processPromise.stdout) {
|
for await (const chunk of processPromise.stdout) {
|
||||||
console.log(chunk.toString());
|
console.log((chunk as Buffer).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AuthenticatedN8nApiClient } from '@/n8nApiClient/authenticatedN8nApiClient';
|
import type { AuthenticatedN8nApiClient } from '@/n8nApiClient/authenticatedN8nApiClient';
|
||||||
import { Workflow } from '@/n8nApiClient/n8nApiClient.types';
|
import type { Workflow } from '@/n8nApiClient/n8nApiClient.types';
|
||||||
import { WorkflowApiClient } from '@/n8nApiClient/workflowsApiClient';
|
import { WorkflowApiClient } from '@/n8nApiClient/workflowsApiClient';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Scenario } from '@/types/scenario';
|
import type { K6Executor } from './k6Executor';
|
||||||
import { N8nApiClient } from '@/n8nApiClient/n8nApiClient';
|
import type { Scenario } from '@/types/scenario';
|
||||||
import { ScenarioDataFileLoader } from '@/scenario/scenarioDataLoader';
|
import type { N8nApiClient } from '@/n8nApiClient/n8nApiClient';
|
||||||
import { K6Executor } from './k6Executor';
|
import type { ScenarioDataFileLoader } from '@/scenario/scenarioDataLoader';
|
||||||
import { ScenarioDataImporter } from '@/testExecution/scenarioDataImporter';
|
import { ScenarioDataImporter } from '@/testExecution/scenarioDataImporter';
|
||||||
import { AuthenticatedN8nApiClient } from '@/n8nApiClient/authenticatedN8nApiClient';
|
import { AuthenticatedN8nApiClient } from '@/n8nApiClient/authenticatedN8nApiClient';
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue