Skip to content

Commit

Permalink
Add migration ci check (twentyhq#8867)
Browse files Browse the repository at this point in the history
Fixes twentyhq#8865

---------

Co-authored-by: Félix Malfait <[email protected]>
  • Loading branch information
Weiko and FelixMalfait authored Dec 9, 2024
1 parent 310bba7 commit 23015de
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 46 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/ci-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,30 @@ jobs:
run: |
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
npx nx run twenty-server:database:init:prod
npx nx run twenty-server:database:migrate:prod
- name: Worker / Run
if: steps.changed-files.outputs.any_changed == 'true'
run: npx nx run twenty-server:worker:ci
- name: Server / Check for Pending Migrations
if: steps.changed-files.outputs.any_changed == 'true'
run: |
METADATA_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate metadata-migration-check -d src/database/typeorm/metadata/metadata.datasource.ts || true)
CORE_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate core-migration-check -d src/database/typeorm/core/core.datasource.ts || true)
METADATA_MIGRATION_FILE=$(ls packages/twenty-server/*metadata-migration-check.ts 2>/dev/null || echo "")
CORE_MIGRATION_FILE=$(ls packages/twenty-server/*core-migration-check.ts 2>/dev/null || echo "")
if [ -n "$METADATA_MIGRATION_FILE" ] || [ -n "$CORE_MIGRATION_FILE" ]; then
echo "::error::Unexpected migration files were generated. Please create a proper migration manually."
echo "$METADATA_MIGRATION_OUTPUT"
echo "$CORE_MIGRATION_OUTPUT"
rm -f packages/twenty-server/*metadata-migration-check.ts packages/twenty-server/*core-migration-check.ts
exit 1
fi
server-test:
timeout-minutes: 30
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ export const typeORMCoreModuleOptions: TypeOrmModuleOptions = {
type: 'postgres',
logging: ['error'],
schema: 'core',
entities: [
`${isJest ? '' : 'dist/'}src/engine/core-modules/**/*.entity{.ts,.js}`,
],
entities:
process.env.IS_BILLING_ENABLED === 'true'
? [`${isJest ? '' : 'dist/'}src/engine/core-modules/**/*.entity{.ts,.js}`]
: [
`${isJest ? '' : 'dist/'}src/engine/core-modules/**/!(billing-*).entity{.ts,.js}`,
],
synchronize: false,
migrationsRun: false,
migrationsTableName: '_typeorm_migrations',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class RemoveBillingFKWithCore1733753649142
implements MigrationInterface
{
name = 'RemoveBillingFKWithCore1733753649142';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."billingEntitlement" DROP CONSTRAINT "FK_599121a93d8177b5d713b941982"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscription" DROP CONSTRAINT "FK_4abfb70314c18da69e1bee1954d"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingCustomer" DROP CONSTRAINT "FK_53c2ef50e9611082f83d760897d"`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."billingCustomer" ADD CONSTRAINT "FK_53c2ef50e9611082f83d760897d" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscription" ADD CONSTRAINT "FK_4abfb70314c18da69e1bee1954d" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingEntitlement" ADD CONSTRAINT "FK_599121a93d8177b5d713b941982" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class SsoMissingMigration1733318043626 implements MigrationInterface {
name = 'SsoMissingMigration1733318043626';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_workspaceId"`,
);
await queryRunner.query(
`DROP INDEX "core"."apptoken_unique_invitation_by_user_workspace"`,
);
await queryRunner.query(
`DROP INDEX "core"."workspace_subdomain_unique_index"`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdIsNullWhenTypeIsInvitation"`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_OIDC"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_SAML"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" SET NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`,
);
await queryRunner.query(
`CREATE TYPE "core"."workspaceSSOIdentityProvider_status_enum" AS ENUM('Active', 'Inactive', 'Error')`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" "core"."workspaceSSOIdentityProvider_status_enum" NOT NULL DEFAULT 'Active'`,
);
await queryRunner.query(
`ALTER TYPE "core"."idp_type_enum" RENAME TO "idp_type_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "core"."workspaceSSOIdentityProvider_type_enum" AS ENUM('OIDC', 'SAML')`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."workspaceSSOIdentityProvider_type_enum" USING "type"::"text"::"core"."workspaceSSOIdentityProvider_type_enum"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`,
);
await queryRunner.query(`DROP TYPE "core"."idp_type_enum_old"`);
await queryRunner.query(
`ALTER TYPE "core"."workspace_activationStatus_enum" RENAME TO "workspace_activationStatus_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "core"."workspace_activationstatus_enum" AS ENUM('ONGOING_CREATION', 'PENDING_CREATION', 'ACTIVE', 'INACTIVE')`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationstatus_enum" USING "activationStatus"::"text"::"core"."workspace_activationstatus_enum"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`,
);
await queryRunner.query(
`DROP TYPE "core"."workspace_activationStatus_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" SET NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" SET NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" SET NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" DROP NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" DROP NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" DROP NOT NULL`,
);
await queryRunner.query(
`CREATE TYPE "core"."workspace_activationStatus_enum_old" AS ENUM('PENDING_CREATION', 'ONGOING_CREATION', 'ACTIVE', 'INACTIVE')`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationStatus_enum_old" USING "activationStatus"::"text"::"core"."workspace_activationStatus_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`,
);
await queryRunner.query(
`DROP TYPE "core"."workspace_activationstatus_enum"`,
);
await queryRunner.query(
`ALTER TYPE "core"."workspace_activationStatus_enum_old" RENAME TO "workspace_activationStatus_enum"`,
);
await queryRunner.query(
`CREATE TYPE "core"."idp_type_enum_old" AS ENUM('OIDC', 'SAML')`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."idp_type_enum_old" USING "type"::"text"::"core"."idp_type_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`,
);
await queryRunner.query(
`DROP TYPE "core"."workspaceSSOIdentityProvider_type_enum"`,
);
await queryRunner.query(
`ALTER TYPE "core"."idp_type_enum_old" RENAME TO "idp_type_enum"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`,
);
await queryRunner.query(
`DROP TYPE "core"."workspaceSSOIdentityProvider_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" character varying NOT NULL DEFAULT 'Active'`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" DROP NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_SAML" CHECK ((((type = 'SAML'::core.idp_type_enum) AND ("ssoURL" IS NOT NULL) AND (certificate IS NOT NULL)) OR (type = 'OIDC'::core.idp_type_enum)))`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_OIDC" CHECK ((((type = 'OIDC'::core.idp_type_enum) AND ("clientID" IS NOT NULL) AND ("clientSecret" IS NOT NULL)) OR (type = 'SAML'::core.idp_type_enum)))`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation" CHECK (((type = 'INVITATION_TOKEN'::text) OR ("userId" IS NOT NULL)))`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdIsNullWhenTypeIsInvitation" CHECK (((type <> 'INVITATION_TOKEN'::text) OR ("userId" IS NULL)))`,
);
await queryRunner.query(
`CREATE UNIQUE INDEX "workspace_subdomain_unique_index" ON "core"."workspace" ("subdomain") `,
);
await queryRunner.query(
`CREATE UNIQUE INDEX "apptoken_unique_invitation_by_user_workspace" ON "core"."appToken" ("workspaceId") WHERE (type = 'INVITATION_TOKEN'::text)`,
);
await queryRunner.query(
`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_workspaceId" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class MissingShortcutMigration1733318004066
implements MigrationInterface
{
name = 'MissingShortcutMigration1733318004066';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "metadata"."IDX_objectMetadata_shortcut_upper_workspace"`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_objectMetadata_shortcut_upper_workspace" ON "metadata"."objectMetadata" ("workspaceId") `,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
Column,
CreateDateColumn,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
Relation,
Expand All @@ -17,7 +15,6 @@ import {
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { BillingEntitlement } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';

@Entity({ name: 'billingCustomer', schema: 'core' })
@ObjectType('billingCustomer')
Expand All @@ -39,12 +36,6 @@ export class BillingCustomer {
@UpdateDateColumn({ type: 'timestamptz' })
updatedAt: Date;

@ManyToOne(() => Workspace, (workspace) => workspace.billingCustomers, {
onDelete: 'CASCADE',
})
@JoinColumn()
workspace: Relation<Workspace>;

@Column({ nullable: false, type: 'uuid' })
workspaceId: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.entity';
import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@Entity({ name: 'billingEntitlement', schema: 'core' })
@ObjectType('billingEntitlement')
@Unique('IndexOnFeatureKeyAndWorkspaceIdUnique', ['key', 'workspaceId'])
Expand All @@ -33,12 +32,6 @@ export class BillingEntitlement {
@Column({ nullable: false, type: 'uuid' })
workspaceId: string;

@ManyToOne(() => Workspace, (workspace) => workspace.billingEntitlements, {
onDelete: 'CASCADE',
})
@JoinColumn()
workspace: Relation<Workspace>;

@Column({ nullable: false })
stripeCustomerId: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entitie
import { BillingSubscriptionCollectionMethod } from 'src/engine/core-modules/billing/enums/billing-subscription-collection-method.enum';
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';

registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' });
registerEnumType(SubscriptionInterval, { name: 'SubscriptionInterval' });
Expand All @@ -41,12 +40,6 @@ export class BillingSubscription {
@UpdateDateColumn({ type: 'timestamptz' })
updatedAt: Date;

@ManyToOne(() => Workspace, (workspace) => workspace.billingSubscriptions, {
onDelete: 'CASCADE',
})
@JoinColumn()
workspace: Relation<Workspace>;

@Column({ nullable: false, type: 'uuid' })
workspaceId: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ export class KeyValuePair {
value: JSON;

@Field(() => String)
@Column({ nullable: false, type: 'text' })
textValueDeprecated: string;
@Column({ nullable: true, type: 'text' })
textValueDeprecated: string | null;

@Field(() => KeyValuePairType)
@Column({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,24 +119,6 @@ export class Workspace {
})
activationStatus: WorkspaceActivationStatus;

@OneToMany(
() => BillingSubscription,
(billingSubscription) => billingSubscription.workspace,
)
billingSubscriptions: Relation<BillingSubscription[]>;

@OneToMany(
() => BillingCustomer,
(billingCustomer) => billingCustomer.workspace,
)
billingCustomers: Relation<BillingCustomer[]>;

@OneToMany(
() => BillingEntitlement,
(billingEntitlement) => billingEntitlement.workspace,
)
billingEntitlements: Relation<BillingEntitlement[]>;

@OneToMany(
() => PostgresCredentials,
(postgresCredentials) => postgresCredentials.workspace,
Expand Down

0 comments on commit 23015de

Please sign in to comment.