diff --git a/.github/workflows/ci-test-docker-compose.yaml b/.github/workflows/ci-test-docker-compose.yaml index 4b191e3be..1496425c8 100644 --- a/.github/workflows/ci-test-docker-compose.yaml +++ b/.github/workflows/ci-test-docker-compose.yaml @@ -19,12 +19,12 @@ jobs: echo "Patching docker-compose.yml..." # change image to localbuild using yq yq eval 'del(.services.server.image)' -i docker-compose.yml - yq eval '.services.server.build.context = "../../../"' -i docker-compose.yml + yq eval '.services.server.build.context = "../../"' -i docker-compose.yml yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i docker-compose.yml yq eval '.services.server.restart = "no"' -i docker-compose.yml yq eval 'del(.services.db.image)' -i docker-compose.yml - yq eval '.services.db.build.context = "../../../"' -i docker-compose.yml + yq eval '.services.db.build.context = "../../"' -i docker-compose.yml yq eval '.services.db.build.dockerfile = "./packages/twenty-docker/twenty-postgres/Dockerfile"' -i docker-compose.yml echo "Setting up .env file..." @@ -56,6 +56,4 @@ jobs: exit 1 fi done - - done working-directory: ./packages/twenty-docker/ diff --git a/packages/twenty-docker/twenty/Dockerfile b/packages/twenty-docker/twenty/Dockerfile index f55b581e0..33a872bf6 100644 --- a/packages/twenty-docker/twenty/Dockerfile +++ b/packages/twenty-docker/twenty/Dockerfile @@ -57,6 +57,8 @@ WORKDIR /app/packages/twenty-server ARG REACT_APP_SERVER_BASE_URL ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL +ARG SENTRY_RELEASE +ENV SENTRY_RELEASE $SENTRY_RELEASE # Copy built applications from previous stages COPY --chown=1000 --from=twenty-server-build /app /app diff --git a/packages/twenty-front/scripts/inject-runtime-env.sh b/packages/twenty-front/scripts/inject-runtime-env.sh index d561874a2..5b09e8b99 100755 --- a/packages/twenty-front/scripts/inject-runtime-env.sh +++ b/packages/twenty-front/scripts/inject-runtime-env.sh @@ -9,4 +9,4 @@ rm -rf "./$BASE_FILENAME" echo "window._env_ = {" echo " REACT_APP_SERVER_BASE_URL: \"$REACT_APP_SERVER_BASE_URL\"," echo "}" -} > "./$BASE_FILENAME" \ No newline at end of file +} > "./$BASE_FILENAME" diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 1ad5b50b4..e6ad38f71 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -803,6 +803,8 @@ export enum RemoteTableStatus { export type Sentry = { __typename?: 'Sentry'; dsn?: Maybe; + environment?: Maybe; + release?: Maybe; }; export type SessionEntity = { diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 0088c5535..620eaf377 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -575,6 +575,8 @@ export enum RemoteTableStatus { export type Sentry = { __typename?: 'Sentry'; dsn?: Maybe; + environment?: Maybe; + release?: Maybe; }; export type SessionEntity = { @@ -1107,7 +1109,7 @@ export type UpdateBillingSubscriptionMutation = { __typename?: 'Mutation', updat export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; -export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null } } }; +export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null } } }; export type UploadFileMutationVariables = Exact<{ file: Scalars['Upload']; @@ -2150,6 +2152,8 @@ export const GetClientConfigDocument = gql` } sentry { dsn + environment + release } } } diff --git a/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx b/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx index e8d57ee71..976921d40 100644 --- a/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx +++ b/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx @@ -51,6 +51,8 @@ export const ClientConfigProviderEffect = () => { setSentryConfig({ dsn: data?.clientConfig?.sentry?.dsn, + release: data?.clientConfig?.sentry?.release, + environment: data?.clientConfig?.sentry?.environment, }); } }, [ diff --git a/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts b/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts index aca84198a..b076a5445 100644 --- a/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts +++ b/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts @@ -25,6 +25,8 @@ export const GET_CLIENT_CONFIG = gql` } sentry { dsn + environment + release } } } diff --git a/packages/twenty-front/src/modules/error-handler/components/SentryInitiEffect.tsx b/packages/twenty-front/src/modules/error-handler/components/SentryInitiEffect.tsx index 463810674..16b1ed014 100644 --- a/packages/twenty-front/src/modules/error-handler/components/SentryInitiEffect.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/SentryInitiEffect.tsx @@ -22,6 +22,8 @@ export const SentryInitEffect = () => { useEffect(() => { if (isNonEmptyString(sentryConfig?.dsn) && !isSentryInitialized) { Sentry.init({ + environment: sentryConfig?.environment ?? undefined, + release: sentryConfig?.release ?? undefined, dsn: sentryConfig?.dsn, integrations: [ new Sentry.BrowserTracing({ diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index 388c50713..c5b59b84c 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -13,7 +13,7 @@ export default defineConfig(({ command, mode }) => { /* Using explicit env variables, there is no need to expose all of them (security). */ - const { REACT_APP_SERVER_BASE_URL } = env; + const { REACT_APP_SERVER_BASE_URL, SENTRY_RELEASE, ENVIRONMENT } = env; const isBuildCommand = command === 'build'; @@ -62,6 +62,8 @@ export default defineConfig(({ command, mode }) => { define: { 'process.env': { REACT_APP_SERVER_BASE_URL, + SENTRY_RELEASE, + ENVIRONMENT, }, }, }; diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts index 184c70047..368ba81ed 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts @@ -44,6 +44,12 @@ class Support { @ObjectType() class Sentry { + @Field(() => String, { nullable: true }) + environment?: string; + + @Field(() => String, { nullable: true }) + release?: string; + @Field(() => String, { nullable: true }) dsn?: string; } diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts index 0891de708..158c715a3 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts @@ -39,7 +39,9 @@ export class ClientConfigResolver { ), }, sentry: { - dsn: this.environmentService.get('SENTRY_DSN'), + environment: this.environmentService.get('SENTRY_ENVIRONMENT'), + release: this.environmentService.get('SENTRY_RELEASE'), + dsn: this.environmentService.get('SENTRY_DSN_FRONT'), }, }; diff --git a/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts b/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts index ed4d91e73..fce188010 100644 --- a/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts +++ b/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts @@ -231,6 +231,26 @@ export class EnvironmentVariables { @IsString() SENTRY_DSN: string; + @ValidateIf( + (env) => env.EXCEPTION_HANDLER_DRIVER === ExceptionHandlerDriver.Sentry, + ) + @IsString() + SENTRY_DSN_FRONT: string; + + @ValidateIf( + (env) => env.EXCEPTION_HANDLER_DRIVER === ExceptionHandlerDriver.Sentry, + ) + @IsString() + @IsOptional() + SENTRY_RELEASE: string; + + @ValidateIf( + (env) => env.EXCEPTION_HANDLER_DRIVER === ExceptionHandlerDriver.Sentry, + ) + @IsString() + @IsOptional() + SENTRY_ENVIRONMENT: string; + @IsDuration() @IsOptional() PASSWORD_RESET_TOKEN_EXPIRES_IN: string = '5m'; diff --git a/packages/twenty-server/src/engine/integrations/exception-handler/drivers/sentry.driver.ts b/packages/twenty-server/src/engine/integrations/exception-handler/drivers/sentry.driver.ts index fb8e1e2d6..302055bcb 100644 --- a/packages/twenty-server/src/engine/integrations/exception-handler/drivers/sentry.driver.ts +++ b/packages/twenty-server/src/engine/integrations/exception-handler/drivers/sentry.driver.ts @@ -14,6 +14,7 @@ export class ExceptionHandlerSentryDriver { constructor(options: ExceptionHandlerSentryDriverFactoryOptions['options']) { Sentry.init({ + release: options.release, dsn: options.dsn, integrations: [ new Sentry.Integrations.Http({ tracing: true }), diff --git a/packages/twenty-server/src/engine/integrations/exception-handler/exception-handler.module-factory.ts b/packages/twenty-server/src/engine/integrations/exception-handler/exception-handler.module-factory.ts index 70a4f4546..3b08ab93a 100644 --- a/packages/twenty-server/src/engine/integrations/exception-handler/exception-handler.module-factory.ts +++ b/packages/twenty-server/src/engine/integrations/exception-handler/exception-handler.module-factory.ts @@ -25,6 +25,8 @@ export const exceptionHandlerModuleFactory = async ( return { type: ExceptionHandlerDriver.Sentry, options: { + environment: environmentService.get('SENTRY_ENVIRONMENT'), + release: environmentService.get('SENTRY_RELEASE'), dsn: environmentService.get('SENTRY_DSN') ?? '', serverInstance: adapterHost.httpAdapter?.getInstance(), debug: environmentService.get('DEBUG_MODE'), diff --git a/packages/twenty-server/src/engine/integrations/exception-handler/interfaces/exception-handler.interface.ts b/packages/twenty-server/src/engine/integrations/exception-handler/interfaces/exception-handler.interface.ts index 9a38b1d67..431cbe4b9 100644 --- a/packages/twenty-server/src/engine/integrations/exception-handler/interfaces/exception-handler.interface.ts +++ b/packages/twenty-server/src/engine/integrations/exception-handler/interfaces/exception-handler.interface.ts @@ -8,6 +8,8 @@ export enum ExceptionHandlerDriver { export interface ExceptionHandlerSentryDriverFactoryOptions { type: ExceptionHandlerDriver.Sentry; options: { + environment?: string; + release?: string; dsn: string; serverInstance?: Router; debug?: boolean;