feat: add SENTRY_RELEASE env (#4912)
Add support for a new SENTRY_RELEASE and SENTRY_ENVIRONMENT env. It is optional and allows to init sentry with a Release version and an env (used internally at Twenty). Docker image have been updated do intergrate the new env as an Argument
This commit is contained in:
@ -19,12 +19,12 @@ jobs:
|
|||||||
echo "Patching docker-compose.yml..."
|
echo "Patching docker-compose.yml..."
|
||||||
# change image to localbuild using yq
|
# change image to localbuild using yq
|
||||||
yq eval 'del(.services.server.image)' -i docker-compose.yml
|
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.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i docker-compose.yml
|
||||||
yq eval '.services.server.restart = "no"' -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 '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
|
yq eval '.services.db.build.dockerfile = "./packages/twenty-docker/twenty-postgres/Dockerfile"' -i docker-compose.yml
|
||||||
|
|
||||||
echo "Setting up .env file..."
|
echo "Setting up .env file..."
|
||||||
@ -56,6 +56,4 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
done
|
|
||||||
working-directory: ./packages/twenty-docker/
|
working-directory: ./packages/twenty-docker/
|
||||||
|
|||||||
@ -57,6 +57,8 @@ WORKDIR /app/packages/twenty-server
|
|||||||
|
|
||||||
ARG REACT_APP_SERVER_BASE_URL
|
ARG REACT_APP_SERVER_BASE_URL
|
||||||
ENV REACT_APP_SERVER_BASE_URL $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 built applications from previous stages
|
||||||
COPY --chown=1000 --from=twenty-server-build /app /app
|
COPY --chown=1000 --from=twenty-server-build /app /app
|
||||||
|
|||||||
@ -9,4 +9,4 @@ rm -rf "./$BASE_FILENAME"
|
|||||||
echo "window._env_ = {"
|
echo "window._env_ = {"
|
||||||
echo " REACT_APP_SERVER_BASE_URL: \"$REACT_APP_SERVER_BASE_URL\","
|
echo " REACT_APP_SERVER_BASE_URL: \"$REACT_APP_SERVER_BASE_URL\","
|
||||||
echo "}"
|
echo "}"
|
||||||
} > "./$BASE_FILENAME"
|
} > "./$BASE_FILENAME"
|
||||||
|
|||||||
@ -803,6 +803,8 @@ export enum RemoteTableStatus {
|
|||||||
export type Sentry = {
|
export type Sentry = {
|
||||||
__typename?: 'Sentry';
|
__typename?: 'Sentry';
|
||||||
dsn?: Maybe<Scalars['String']['output']>;
|
dsn?: Maybe<Scalars['String']['output']>;
|
||||||
|
environment?: Maybe<Scalars['String']['output']>;
|
||||||
|
release?: Maybe<Scalars['String']['output']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SessionEntity = {
|
export type SessionEntity = {
|
||||||
|
|||||||
@ -575,6 +575,8 @@ export enum RemoteTableStatus {
|
|||||||
export type Sentry = {
|
export type Sentry = {
|
||||||
__typename?: 'Sentry';
|
__typename?: 'Sentry';
|
||||||
dsn?: Maybe<Scalars['String']>;
|
dsn?: Maybe<Scalars['String']>;
|
||||||
|
environment?: Maybe<Scalars['String']>;
|
||||||
|
release?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SessionEntity = {
|
export type SessionEntity = {
|
||||||
@ -1107,7 +1109,7 @@ export type UpdateBillingSubscriptionMutation = { __typename?: 'Mutation', updat
|
|||||||
export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>;
|
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<{
|
export type UploadFileMutationVariables = Exact<{
|
||||||
file: Scalars['Upload'];
|
file: Scalars['Upload'];
|
||||||
@ -2150,6 +2152,8 @@ export const GetClientConfigDocument = gql`
|
|||||||
}
|
}
|
||||||
sentry {
|
sentry {
|
||||||
dsn
|
dsn
|
||||||
|
environment
|
||||||
|
release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,8 @@ export const ClientConfigProviderEffect = () => {
|
|||||||
|
|
||||||
setSentryConfig({
|
setSentryConfig({
|
||||||
dsn: data?.clientConfig?.sentry?.dsn,
|
dsn: data?.clientConfig?.sentry?.dsn,
|
||||||
|
release: data?.clientConfig?.sentry?.release,
|
||||||
|
environment: data?.clientConfig?.sentry?.environment,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
|||||||
@ -25,6 +25,8 @@ export const GET_CLIENT_CONFIG = gql`
|
|||||||
}
|
}
|
||||||
sentry {
|
sentry {
|
||||||
dsn
|
dsn
|
||||||
|
environment
|
||||||
|
release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,8 @@ export const SentryInitEffect = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isNonEmptyString(sentryConfig?.dsn) && !isSentryInitialized) {
|
if (isNonEmptyString(sentryConfig?.dsn) && !isSentryInitialized) {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
|
environment: sentryConfig?.environment ?? undefined,
|
||||||
|
release: sentryConfig?.release ?? undefined,
|
||||||
dsn: sentryConfig?.dsn,
|
dsn: sentryConfig?.dsn,
|
||||||
integrations: [
|
integrations: [
|
||||||
new Sentry.BrowserTracing({
|
new Sentry.BrowserTracing({
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export default defineConfig(({ command, mode }) => {
|
|||||||
/*
|
/*
|
||||||
Using explicit env variables, there is no need to expose all of them (security).
|
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';
|
const isBuildCommand = command === 'build';
|
||||||
|
|
||||||
@ -62,6 +62,8 @@ export default defineConfig(({ command, mode }) => {
|
|||||||
define: {
|
define: {
|
||||||
'process.env': {
|
'process.env': {
|
||||||
REACT_APP_SERVER_BASE_URL,
|
REACT_APP_SERVER_BASE_URL,
|
||||||
|
SENTRY_RELEASE,
|
||||||
|
ENVIRONMENT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -44,6 +44,12 @@ class Support {
|
|||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
class Sentry {
|
class Sentry {
|
||||||
|
@Field(() => String, { nullable: true })
|
||||||
|
environment?: string;
|
||||||
|
|
||||||
|
@Field(() => String, { nullable: true })
|
||||||
|
release?: string;
|
||||||
|
|
||||||
@Field(() => String, { nullable: true })
|
@Field(() => String, { nullable: true })
|
||||||
dsn?: string;
|
dsn?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,9 @@ export class ClientConfigResolver {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
sentry: {
|
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'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -231,6 +231,26 @@ export class EnvironmentVariables {
|
|||||||
@IsString()
|
@IsString()
|
||||||
SENTRY_DSN: string;
|
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()
|
@IsDuration()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
PASSWORD_RESET_TOKEN_EXPIRES_IN: string = '5m';
|
PASSWORD_RESET_TOKEN_EXPIRES_IN: string = '5m';
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export class ExceptionHandlerSentryDriver
|
|||||||
{
|
{
|
||||||
constructor(options: ExceptionHandlerSentryDriverFactoryOptions['options']) {
|
constructor(options: ExceptionHandlerSentryDriverFactoryOptions['options']) {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
|
release: options.release,
|
||||||
dsn: options.dsn,
|
dsn: options.dsn,
|
||||||
integrations: [
|
integrations: [
|
||||||
new Sentry.Integrations.Http({ tracing: true }),
|
new Sentry.Integrations.Http({ tracing: true }),
|
||||||
|
|||||||
@ -25,6 +25,8 @@ export const exceptionHandlerModuleFactory = async (
|
|||||||
return {
|
return {
|
||||||
type: ExceptionHandlerDriver.Sentry,
|
type: ExceptionHandlerDriver.Sentry,
|
||||||
options: {
|
options: {
|
||||||
|
environment: environmentService.get('SENTRY_ENVIRONMENT'),
|
||||||
|
release: environmentService.get('SENTRY_RELEASE'),
|
||||||
dsn: environmentService.get('SENTRY_DSN') ?? '',
|
dsn: environmentService.get('SENTRY_DSN') ?? '',
|
||||||
serverInstance: adapterHost.httpAdapter?.getInstance(),
|
serverInstance: adapterHost.httpAdapter?.getInstance(),
|
||||||
debug: environmentService.get('DEBUG_MODE'),
|
debug: environmentService.get('DEBUG_MODE'),
|
||||||
|
|||||||
@ -8,6 +8,8 @@ export enum ExceptionHandlerDriver {
|
|||||||
export interface ExceptionHandlerSentryDriverFactoryOptions {
|
export interface ExceptionHandlerSentryDriverFactoryOptions {
|
||||||
type: ExceptionHandlerDriver.Sentry;
|
type: ExceptionHandlerDriver.Sentry;
|
||||||
options: {
|
options: {
|
||||||
|
environment?: string;
|
||||||
|
release?: string;
|
||||||
dsn: string;
|
dsn: string;
|
||||||
serverInstance?: Router;
|
serverInstance?: Router;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user