Twenty sdk cli oauth (#18638)
<img width="1418" height="804" alt="image" src="https://github.com/user-attachments/assets/de6c8222-6496-4a71-bc21-7e5e1269d5cb" /> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { vi } from 'vitest';
|
||||
|
||||
import { appBuild } from '@/cli/public-operations/app-build';
|
||||
import { appUninstall } from '@/cli/public-operations/app-uninstall';
|
||||
import { functionExecute } from '@/cli/public-operations/function-execute';
|
||||
import { appBuild } from '@/cli/operations/build';
|
||||
import { appUninstall } from '@/cli/operations/uninstall';
|
||||
import { functionExecute } from '@/cli/operations/execute';
|
||||
import { FUNCTION_EXECUTE_APP_PATH } from '@/cli/__tests__/apps/fixture-paths';
|
||||
|
||||
const ADD_NUMBERS_UNIVERSAL_IDENTIFIER = 'f9e5589c-e951-4d99-85db-0a305ab53502';
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ import { defineFrontComponentsTests } from './tests/front-components.tests';
|
||||
import { defineLogicFunctionsTests } from './tests/logic-functions.tests';
|
||||
import { defineManifestTests } from './tests/manifest.tests';
|
||||
|
||||
describe('minimal-app app:dev', () => {
|
||||
describe('minimal-app dev', () => {
|
||||
beforeAll(async () => {
|
||||
const result = await runAppDevInProcess({ appPath: MINIMAL_APP_PATH });
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('minimal-app app:dev', () => {
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`app:dev did not produce manifest.json within timeout.\n${diagnostics}`,
|
||||
`dev did not produce manifest.json within timeout.\n${diagnostics}`,
|
||||
);
|
||||
}
|
||||
}, 60000);
|
||||
|
||||
+5
-3
@@ -16,11 +16,13 @@ export const defineManifestTests = (appPath: string): void => {
|
||||
|
||||
it('should have correct manifest content', async () => {
|
||||
const manifestPath = join(appPath, '.twenty/output/manifest.json');
|
||||
const manifest: Manifest = normalizeManifestForComparison(
|
||||
await readJson(manifestPath),
|
||||
const manifest = normalizeManifestForComparison(
|
||||
await readJson<Manifest>(manifestPath),
|
||||
);
|
||||
|
||||
expect(manifest).toEqual(EXPECTED_MANIFEST);
|
||||
expect(manifest).toEqual(
|
||||
normalizeManifestForComparison(EXPECTED_MANIFEST),
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
+6
-6
@@ -15,10 +15,10 @@ describe('Application: install delete and reinstall postcard-app', () => {
|
||||
expect(existsSync(appPath)).toBe(true);
|
||||
|
||||
const result = await runCliCommand({
|
||||
command: 'auth:status',
|
||||
args: [appPath],
|
||||
command: 'remote',
|
||||
args: ['status'],
|
||||
timeout: 5_000,
|
||||
waitForOutput: '✓ Valid',
|
||||
waitForOutput: '(valid)',
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
@@ -26,7 +26,7 @@ describe('Application: install delete and reinstall postcard-app', () => {
|
||||
|
||||
it(`should successfully install ${applicationName} application`, async () => {
|
||||
await runCliCommand({
|
||||
command: 'app:dev',
|
||||
command: 'dev',
|
||||
args: [appPath],
|
||||
waitForOutput: '✓ Synced',
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe('Application: install delete and reinstall postcard-app', () => {
|
||||
|
||||
it(`should successfully delete ${applicationName} application`, async () => {
|
||||
await runCliCommand({
|
||||
command: 'app:uninstall',
|
||||
command: 'uninstall',
|
||||
args: [appPath, '-y'],
|
||||
waitForOutput: 'Application uninstalled successfully',
|
||||
});
|
||||
@@ -44,7 +44,7 @@ describe('Application: install delete and reinstall postcard-app', () => {
|
||||
|
||||
it(`should successfully re-install ${applicationName} application`, async () => {
|
||||
await runCliCommand({
|
||||
command: 'app:dev',
|
||||
command: 'dev',
|
||||
args: [appPath],
|
||||
waitForOutput: '✓ Synced',
|
||||
});
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import { POSTCARD_APP_PATH } from '@/cli/__tests__/apps/fixture-paths';
|
||||
import { defineEntitiesTests } from './tests/entities.tests';
|
||||
import { defineManifestTests } from './tests/manifest.tests';
|
||||
|
||||
describe('postcard-app app:dev', () => {
|
||||
describe('postcard-app dev', () => {
|
||||
beforeAll(async () => {
|
||||
const result = await runAppDevInProcess({ appPath: POSTCARD_APP_PATH });
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('postcard-app app:dev', () => {
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`app:dev did not produce manifest.json within timeout.\n${diagnostics}`,
|
||||
`dev did not produce manifest.json within timeout.\n${diagnostics}`,
|
||||
);
|
||||
}
|
||||
}, 60000);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const SERVER_URL = 'http://localhost:3000';
|
||||
export const SERVER_URL = process.env.TWENTY_API_URL ?? 'http://localhost:3000';
|
||||
|
||||
@@ -11,12 +11,13 @@ beforeAll(async () => {
|
||||
await ensureDir(path.dirname(testConfigPath));
|
||||
|
||||
const configFile = {
|
||||
profiles: {
|
||||
default: {
|
||||
remotes: {
|
||||
local: {
|
||||
apiUrl: process.env.TWENTY_API_URL,
|
||||
apiKey: process.env.TWENTY_API_KEY,
|
||||
},
|
||||
},
|
||||
defaultRemote: 'local',
|
||||
};
|
||||
|
||||
await writeFile(testConfigPath, JSON.stringify(configFile, null, 2));
|
||||
|
||||
+32
-10
@@ -1,5 +1,10 @@
|
||||
import { type Manifest } from 'twenty-shared/application';
|
||||
|
||||
const sortById = <T extends { universalIdentifier: string }>(items: T[]): T[] =>
|
||||
[...items].sort((a, b) =>
|
||||
a.universalIdentifier.localeCompare(b.universalIdentifier),
|
||||
);
|
||||
|
||||
export const normalizeManifestForComparison = <T extends Manifest>(
|
||||
manifest: T,
|
||||
): T => ({
|
||||
@@ -16,14 +21,31 @@ export const normalizeManifestForComparison = <T extends Manifest>(
|
||||
? '[checksum]'
|
||||
: null,
|
||||
},
|
||||
logicFunctions: manifest.logicFunctions?.map((fn) => ({
|
||||
...fn,
|
||||
builtHandlerChecksum: fn.builtHandlerChecksum ? '[checksum]' : null,
|
||||
})),
|
||||
frontComponents: manifest.frontComponents?.map((component) => ({
|
||||
...component,
|
||||
builtComponentChecksum: component.builtComponentChecksum
|
||||
? '[checksum]'
|
||||
: '',
|
||||
})),
|
||||
objects: sortById(
|
||||
manifest.objects.map((object) => ({
|
||||
...object,
|
||||
fields: sortById(object.fields),
|
||||
})),
|
||||
),
|
||||
fields: sortById(manifest.fields),
|
||||
roles: sortById(manifest.roles),
|
||||
skills: sortById(manifest.skills),
|
||||
agents: sortById(manifest.agents),
|
||||
views: sortById(manifest.views),
|
||||
navigationMenuItems: sortById(manifest.navigationMenuItems),
|
||||
pageLayouts: sortById(manifest.pageLayouts),
|
||||
logicFunctions: sortById(
|
||||
manifest.logicFunctions?.map((fn) => ({
|
||||
...fn,
|
||||
builtHandlerChecksum: fn.builtHandlerChecksum ? '[checksum]' : null,
|
||||
})),
|
||||
),
|
||||
frontComponents: sortById(
|
||||
manifest.frontComponents?.map((component) => ({
|
||||
...component,
|
||||
builtComponentChecksum: component.builtComponentChecksum
|
||||
? '[checksum]'
|
||||
: '',
|
||||
})),
|
||||
),
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { join } from 'path';
|
||||
import { OUTPUT_DIR } from 'twenty-shared/application';
|
||||
|
||||
import { AppDevCommand } from '@/cli/commands/app/app-dev';
|
||||
import { AppDevCommand } from '@/cli/commands/dev';
|
||||
import { pathExists } from '@/cli/utilities/file/fs-utils';
|
||||
|
||||
export type RunAppDevResult = {
|
||||
|
||||
@@ -5,23 +5,11 @@ const mockApiService = {
|
||||
generateApplicationToken: vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
applicationAccessToken: { token: 'mock-access-token', expiresAt: '' },
|
||||
applicationRefreshToken: { token: 'mock-refresh-token', expiresAt: '' },
|
||||
},
|
||||
}),
|
||||
renewApplicationToken: vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
applicationAccessToken: {
|
||||
token: 'mock-renewed-access-token',
|
||||
expiresAt: '',
|
||||
},
|
||||
applicationRefreshToken: {
|
||||
token: 'mock-renewed-refresh-token',
|
||||
expiresAt: '',
|
||||
},
|
||||
accessToken: { token: 'mock-access-token', expiresAt: '' },
|
||||
refreshToken: { token: 'mock-refresh-token', expiresAt: '' },
|
||||
},
|
||||
}),
|
||||
refreshToken: vi.fn().mockResolvedValue('mock-renewed-access-token'),
|
||||
findApplicationRegistrationByUniversalIdentifier: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ success: true, data: null }),
|
||||
@@ -47,7 +35,7 @@ vi.mock('@/cli/utilities/api/api-service', () => ({
|
||||
ApiService: class {
|
||||
validateAuth = mockApiService.validateAuth;
|
||||
generateApplicationToken = mockApiService.generateApplicationToken;
|
||||
renewApplicationToken = mockApiService.renewApplicationToken;
|
||||
refreshToken = mockApiService.refreshToken;
|
||||
findApplicationRegistrationByUniversalIdentifier =
|
||||
mockApiService.findApplicationRegistrationByUniversalIdentifier;
|
||||
createApplicationRegistration =
|
||||
|
||||
Reference in New Issue
Block a user