Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Container } from '@n8n/di';
import fsPromises from 'fs/promises';
import { mock } from 'jest-mock-extended';
import type {
Expression,
Expand Down Expand Up @@ -404,4 +405,42 @@ describe('NodeExecutionContext', () => {
);
});
});

describe('getN8nVersion', () => {
it('should return the version of the n8n', async () => {
const spy = jest.spyOn(fsPromises, 'readFile');
spy.mockResolvedValue('{ "version": "1.114.0" }');

const result = await testContext.getN8nVersion();

expect(result).toBe('1.114.0');
});

it('should return 0.0.0 when the package.json file is not found', async () => {
const spy = jest.spyOn(fsPromises, 'readFile');
spy.mockRejectedValue(new Error('File not found'));

const result = await testContext.getN8nVersion();

expect(result).toBe('0.0.0');
});

it('should return 0.0.0 when the package.json file is not valid', async () => {
const spy = jest.spyOn(fsPromises, 'readFile');
spy.mockResolvedValue('invalid');

const result = await testContext.getN8nVersion();

expect(result).toBe('0.0.0');
});

it('should return 0.0.0 when the package.json file does not contain the version', async () => {
const spy = jest.spyOn(fsPromises, 'readFile');
spy.mockResolvedValue('{ "foo": "bar" }');

const result = await testContext.getN8nVersion();

expect(result).toBe('0.0.0');
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Logger } from '@n8n/backend-common';
import { Memoized } from '@n8n/decorators';
import { Container } from '@n8n/di';
import { readFile } from 'fs/promises';
import get from 'lodash/get';
import type {
FunctionsBase,
Expand Down Expand Up @@ -28,10 +29,12 @@ import {
CHAT_TRIGGER_NODE_TYPE,
deepCopy,
ExpressionError,
jsonParse,
NodeHelpers,
NodeOperationError,
UnexpectedError,
} from 'n8n-workflow';
import { join, resolve } from 'path';

import {
HTTP_REQUEST_AS_TOOL_NODE_TYPE,
Expand Down Expand Up @@ -214,6 +217,18 @@ export abstract class NodeExecutionContext implements Omit<FunctionsBase, 'getCr
return this.instanceSettings.instanceId;
}

async getN8nVersion() {
const fallbackValue = '0.0.0';
try {
const rootDir = resolve(__dirname, '..', '..', '..', '..', '..');
const packageJsonPath = join(rootDir, 'package.json');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work, once published, n8n-core will not have access to the parent folder. Docker build might run into a similar issue where the path is different at runtime.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering if we could read the version at build time and inject it either as a constant or an env variable

const packageJson = jsonParse<{ version: string }>(await readFile(packageJsonPath, 'utf8'));
return packageJson?.version ?? fallbackValue;
} catch {
return fallbackValue;
}
}

setSignatureValidationRequired() {
if (this.runExecutionData) this.runExecutionData.validateSignature = true;
}
Expand Down
1 change: 1 addition & 0 deletions packages/workflow/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,7 @@ export interface FunctionsBase {
getRestApiUrl(): string;
getInstanceBaseUrl(): string;
getInstanceId(): string;
getN8nVersion(): Promise<string>;
/** Get the waiting resume url signed with the signature token */
getSignedResumeUrl(parameters?: Record<string, string>): string;
/** Set requirement in the execution for signature token validation */
Expand Down