fix(server): stabilize flaky app-install workspace-version gate test (#22851)

## What

The integration test
`failing-app-installation-workspace-version.integration-spec.ts` is
flaky depending on the shape of the upgrade sequence, especially right
after a version bump. It intermittently fails at upload time with:

```
App requires Twenty server >=2.21.0 but this server is 2.20.0.
(SERVER_VERSION_INCOMPATIBLE)
```

## Why

The test mixed two different version sources:

- The upload-time check (`validateServerCompatibility`) compares the
app's required version against the **instance** inferred version, i.e.
the last attempted instance command (`workspaceId IS NULL`, via
`getInferredVersion`).
- The test's `beforeAll` instead derived the required version from the
**workspace** cursor.

These agree most of the time but diverge right after a version bump
whose newest upgrade segment ends in workspace-scoped commands and adds
no new instance command. In that state the seeded workspace cursor sits
at the new version while the instance is still at the previous one. The
test then uploads an app requiring `>=newVersion`, which fails the
instance gate at upload time before the workspace gate under test is
ever reached.

## How

Derive the gate version in `beforeAll` from the last attempted instance
command, mirroring exactly what `getInferredVersion()` uses. The
required version is then always `>=` the instance's own version, so the
upload passes; injecting that same command as a failed workspace attempt
drops the workspace to the previous completed version, so the install
reliably hits the workspace gate and returns
`WORKSPACE_VERSION_INCOMPATIBLE` as the snapshot expects. This holds
regardless of whether the newest version's segment ends in an instance
or workspace command.

No production code changed; the fix is confined to test setup logic.


---
_Generated by [Claude
Code](https://claude.ai/code/session_01UtEpU7fF4q6pydGRaawfve)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22851?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
Paul Rastoin
2026-07-13 10:33:45 +02:00
committed by GitHub
parent bbe9886274
commit b94e38c2d9
@@ -76,29 +76,37 @@ describe('Install application is gated by the workspace completed upgrade versio
beforeAll(async () => {
jest.useRealTimers();
// The seeded workspace's cursor is the last step of the current version.
// Re-injecting it as a failed attempt makes the workspace resolve to the
// previous completed version — i.e. behind the instance.
const [workspaceCursor] = await global.testDataSource.query(
`SELECT name FROM core."upgradeMigration"
WHERE "workspaceId" = $1
ORDER BY "createdAt" DESC, attempt DESC
// Derive the gate version from the last attempted instance command, which
// is exactly what the upload-time server-compat check uses
// (getInferredVersion). The seeded workspace cursor can sit a version ahead
// of the instance right after a version bump whose newest segment ends in
// workspace-scoped commands with no new instance command: requiring
// >=workspaceVersion would then fail the instance gate at upload time,
// before the workspace gate under test is reached.
const [instanceCommand] = await global.testDataSource.query(
`SELECT migration.name AS name
FROM core."upgradeMigration" migration
WHERE migration."workspaceId" IS NULL
AND migration."isInitial" = false
AND migration.attempt = (
SELECT MAX(sub.attempt)
FROM core."upgradeMigration" sub
WHERE sub.name = migration.name
AND sub."workspaceId" IS NULL
)
ORDER BY migration."createdAt" DESC
LIMIT 1`,
[SEED_APPLE_WORKSPACE_ID],
);
if (!isDefined(workspaceCursor)) {
throw new Error(
`Expected a seeded upgrade cursor for workspace ${SEED_APPLE_WORKSPACE_ID}`,
);
if (!isDefined(instanceCommand)) {
throw new Error('Expected a seeded instance upgrade command');
}
currentVersionCommandName = workspaceCursor.name;
// Re-injecting this command as a failed workspace attempt makes the
// workspace resolve to the previous completed version (behind the
// instance), so the install reaches the workspace gate.
currentVersionCommandName = instanceCommand.name;
// Pin to the version the instance actually reached, not
// TWENTY_CURRENT_VERSION which can be bumped ahead of the latest instance
// command and trip the upload-time server-compat check before the
// workspace gate under test is reached.
const inferredServerVersion = extractVersionFromCommandName(
currentVersionCommandName,
);