fix(core): Send prod workflow succeeded for wfs in projects (#22223)

This commit is contained in:
Nikhil Kuriakose 2025-11-25 11:23:32 +01:00 committed by GitHub
parent 83809e62ad
commit 7068fe2510
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 62 additions and 10 deletions

View File

@ -1155,7 +1155,7 @@ describe('TelemetryEventRelay', () => {
});
describe('workflow execution events', () => {
it('should track on `first-production-workflow-succeeded` event', () => {
it('should track on `first-production-workflow-succeeded` event for personal project', () => {
const event: RelayEventMap['first-production-workflow-succeeded'] = {
projectId: 'project123',
workflowId: 'workflow123',
@ -1171,6 +1171,22 @@ describe('TelemetryEventRelay', () => {
});
});
it('should track on `first-production-workflow-succeeded` event for team project with null userId', () => {
const event: RelayEventMap['first-production-workflow-succeeded'] = {
projectId: 'project123',
workflowId: 'workflow123',
userId: null,
};
eventService.emit('first-production-workflow-succeeded', event);
expect(telemetry.track).toHaveBeenCalledWith('Workflow first prod success', {
project_id: 'project123',
workflow_id: 'workflow123',
user_id: undefined,
});
});
it('should track on `first-workflow-data-loaded` event', () => {
const event: RelayEventMap['first-workflow-data-loaded'] = {
userId: 'user123',

View File

@ -39,7 +39,7 @@ export type RelayEventMap = {
'first-production-workflow-succeeded': {
projectId: string;
workflowId: string;
userId: string;
userId: string | null;
};
'first-workflow-data-loaded': {

View File

@ -936,7 +936,7 @@ export class TelemetryEventRelay extends EventRelay {
this.telemetry.track('Workflow first prod success', {
project_id: projectId,
workflow_id: workflowId,
user_id: userId,
user_id: userId ?? undefined,
});
}

View File

@ -1,4 +1,10 @@
import { getPersonalProject, createWorkflow, testDb, mockInstance } from '@n8n/backend-test-utils';
import {
getPersonalProject,
createTeamProject,
createWorkflow,
testDb,
mockInstance,
} from '@n8n/backend-test-utils';
import { GlobalConfig } from '@n8n/config';
import type { IWorkflowDb, Project, WorkflowEntity, User } from '@n8n/db';
import { WorkflowStatisticsRepository } from '@n8n/db';
@ -243,6 +249,33 @@ describe('WorkflowStatisticsService', () => {
expect(updateSettingsSpy).not.toHaveBeenCalled();
expect(emitSpy).not.toHaveBeenCalled();
});
test('emits first-production-workflow-succeeded with null userId for team project', async () => {
// ARRANGE
const teamProject = await createTeamProject('Team Project');
const teamWorkflow = await createWorkflow({}, teamProject);
const runData: IRun = {
finished: true,
status: 'success',
data: createEmptyRunExecutionData(),
mode: 'internal',
startedAt: new Date(),
};
const emitSpy = jest.spyOn(Container.get(EventService), 'emit');
const updateSettingsSpy = jest.spyOn(userService, 'updateSettings');
// ACT
await workflowStatisticsService.workflowExecutionCompleted(teamWorkflow, runData);
// ASSERT
expect(updateSettingsSpy).not.toHaveBeenCalled();
expect(emitSpy).toHaveBeenCalledTimes(1);
expect(emitSpy).toHaveBeenCalledWith('first-production-workflow-succeeded', {
projectId: teamProject.id,
workflowId: teamWorkflow.id,
userId: null,
});
});
});
describe('nodeFetchedData', () => {

View File

@ -116,8 +116,11 @@ export class WorkflowStatisticsService extends TypedEmitter<WorkflowStatisticsEv
if (name === StatisticsNames.productionSuccess && upsertResult === 'insert') {
const project = await this.ownershipService.getWorkflowProjectCached(workflowId);
let userId: string | null = null;
if (project.type === 'personal') {
const owner = await this.ownershipService.getPersonalProjectOwnerCached(project.id);
userId = owner?.id ?? null;
if (owner && !owner.settings?.userActivated) {
await this.userService.updateSettings(owner.id, {
@ -126,13 +129,13 @@ export class WorkflowStatisticsService extends TypedEmitter<WorkflowStatisticsEv
userActivatedAt: runData.startedAt.getTime(),
});
}
this.eventService.emit('first-production-workflow-succeeded', {
projectId: project.id,
workflowId,
userId: owner!.id,
});
}
this.eventService.emit('first-production-workflow-succeeded', {
projectId: project.id,
workflowId,
userId,
});
}
} catch (error) {
this.logger.debug('Unable to fire first workflow success telemetry event');