Fix sdk-e2e-test: ensure DB is ready before server starts (#19583)
## Summary
- The `sdk-e2e-test` CI job has been failing since at least April 9th
because the nx dependency graph runs `database:reset` and
`start:ci-if-needed` in **parallel** — neither depends on the other. The
server starts before the DB tables are created, crashes with `relation
"core.keyValuePair" does not exist`, and `wait-on` times out after 10
minutes.
- Replace the `nx-affected` orchestration for e2e with explicit
**sequential** CI steps: build → create DB → reset DB → start server →
wait for health → run tests.
- Add server log dump on failure for easier future debugging.
## Root cause
In `packages/twenty-sdk/project.json`, the `test:e2e` target has:
```json
"dependsOn": [
"build",
{ "target": "database:reset", "projects": "twenty-server" },
{ "target": "start:ci-if-needed", "projects": "twenty-server" }
]
```
Since `database:reset` and `start:ci-if-needed` don't depend on each
other, nx can (and does) run them concurrently. `start:ci-if-needed`
fires `nohup nest start &` and immediately completes. The server process
tries to query `core.keyValuePair` before `database:reset` creates it →
crash → wait-on timeout → job failure.
This commit is contained in:
@@ -2,15 +2,15 @@ import path from 'path';
|
||||
import { OUTPUT_DIR, type Manifest } from 'twenty-shared/application';
|
||||
|
||||
import { ApiService } from '@/cli/utilities/api/api-service';
|
||||
import {
|
||||
ensureAppAccessTokenIsValidOrRefresh,
|
||||
ensureAppRegistration,
|
||||
} from '@/cli/utilities/auth';
|
||||
import { buildApplication } from '@/cli/utilities/build/common/build-application';
|
||||
import { runTypecheck } from '@/cli/utilities/build/common/typecheck-plugin';
|
||||
import { buildAndValidateManifest } from '@/cli/utilities/build/manifest/build-and-validate-manifest';
|
||||
import { manifestUpdateChecksums } from '@/cli/utilities/build/manifest/manifest-update-checksums';
|
||||
import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer';
|
||||
import {
|
||||
ensureValidAppAccessTokenOrRefresh,
|
||||
exchangeCredentialsForTokens,
|
||||
} from '@/cli/utilities/auth/resolve-app-access-token';
|
||||
import { ClientService } from '@/cli/utilities/client/client-service';
|
||||
import { ConfigService } from '@/cli/utilities/config/config-service';
|
||||
import { formatSyncErrorEvents } from '@/cli/utilities/dev/orchestrator/steps/format-sync-error-events';
|
||||
@@ -124,37 +124,14 @@ const innerAppDevOnce = async (
|
||||
|
||||
const configService = new ConfigService();
|
||||
|
||||
const appAccessToken =
|
||||
await ensureValidAppAccessTokenOrRefresh(configService);
|
||||
|
||||
if (!appAccessToken) {
|
||||
const createResult = await apiService.createApplicationRegistration({
|
||||
const { clientId, clientSecret } = await ensureAppRegistration(
|
||||
apiService,
|
||||
configService,
|
||||
{
|
||||
name: manifest.application.displayName,
|
||||
universalIdentifier: manifest.application.universalIdentifier,
|
||||
});
|
||||
|
||||
if (!createResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: APP_ERROR_CODES.SYNC_FAILED,
|
||||
message: `Failed to create app registration: ${serializeError(createResult.error)}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const { applicationRegistration, clientSecret } = createResult.data;
|
||||
|
||||
await configService.setConfig({
|
||||
appRegistrationId: applicationRegistration.id,
|
||||
appRegistrationClientId: applicationRegistration.oAuthClientId,
|
||||
});
|
||||
|
||||
await exchangeCredentialsForTokens(configService, {
|
||||
clientId: applicationRegistration.oAuthClientId,
|
||||
clientSecret,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const createDevAppResult = await apiService.createDevelopmentApplication({
|
||||
universalIdentifier: manifest.application.universalIdentifier,
|
||||
@@ -166,7 +143,7 @@ const innerAppDevOnce = async (
|
||||
success: false,
|
||||
error: {
|
||||
code: APP_ERROR_CODES.SYNC_FAILED,
|
||||
message: `Failed to create development application: ${serializeError(createDevAppResult.error)}`,
|
||||
message: `Failed to install development application: ${serializeError(createDevAppResult.error)}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -235,13 +212,14 @@ const innerAppDevOnce = async (
|
||||
};
|
||||
}
|
||||
|
||||
// Generate the CoreApiClient using an APPLICATION_ACCESS token so the
|
||||
// server returns the app-scoped schema (objects defined by this app).
|
||||
onProgress?.('Generating API client...');
|
||||
|
||||
try {
|
||||
const appAccessToken =
|
||||
await ensureValidAppAccessTokenOrRefresh(configService);
|
||||
const appAccessToken = await ensureAppAccessTokenIsValidOrRefresh(
|
||||
configService,
|
||||
{ clientId, clientSecret },
|
||||
);
|
||||
|
||||
const clientService = new ClientService();
|
||||
|
||||
await clientService.generateCoreClient({
|
||||
|
||||
Reference in New Issue
Block a user