From 8bbda86eb689d8b3d535430b60a49d26aa87047a Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Tue, 10 Mar 2026 10:35:41 +0100 Subject: [PATCH] `[CREATE_APP]` Generate basic CI workflow (#18511) --- .../src/utils/__tests__/app-template.spec.ts | 12 +++++ .../src/utils/__tests__/test-template.spec.ts | 31 +++++++++++ .../src/utils/test-template.ts | 54 +++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts b/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts index fcd54c39f7..c70b2aca9e 100644 --- a/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts +++ b/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts @@ -386,6 +386,12 @@ describe('copyBaseApplicationProject', () => { ), ).toBe(true); + expect( + await fs.pathExists( + join(testAppDirectory, '.github', 'workflows', 'ci.yml'), + ), + ).toBe(true); + // Install functions should always exist expect( await fs.pathExists( @@ -464,6 +470,12 @@ describe('copyBaseApplicationProject', () => { join(srcPath, '__tests__', 'app-install.integration-test.ts'), ), ).toBe(false); + + expect( + await fs.pathExists( + join(testAppDirectory, '.github', 'workflows', 'ci.yml'), + ), + ).toBe(false); }); }); diff --git a/packages/create-twenty-app/src/utils/__tests__/test-template.spec.ts b/packages/create-twenty-app/src/utils/__tests__/test-template.spec.ts index 94e168cd2b..ea9c4a0368 100644 --- a/packages/create-twenty-app/src/utils/__tests__/test-template.spec.ts +++ b/packages/create-twenty-app/src/utils/__tests__/test-template.spec.ts @@ -110,6 +110,37 @@ describe('scaffoldIntegrationTest', () => { }); }); + describe('github workflow', () => { + it('should create .github/workflows/ci.yml with correct structure', async () => { + await scaffoldIntegrationTest({ + appDirectory: testAppDirectory, + sourceFolderPath, + }); + + const workflowPath = join( + testAppDirectory, + '.github', + 'workflows', + 'ci.yml', + ); + + expect(await fs.pathExists(workflowPath)).toBe(true); + + const content = await fs.readFile(workflowPath, 'utf8'); + + expect(content).toContain('name: CI'); + expect(content).toContain('TWENTY_VERSION: latest'); + expect(content).toContain('twenty-version: ${{ env.TWENTY_VERSION }}'); + expect(content).toContain('actions/checkout@v4'); + expect(content).toContain('spawn-twenty-docker-image@main'); + expect(content).toContain('actions/setup-node@v4'); + expect(content).toContain('yarn install --immutable'); + expect(content).toContain('yarn test'); + expect(content).toContain('TWENTY_API_URL'); + expect(content).toContain('TWENTY_TEST_API_KEY'); + }); + }); + describe('tsconfig.spec.json', () => { it('should create tsconfig.spec.json extending the base tsconfig', async () => { await scaffoldIntegrationTest({ diff --git a/packages/create-twenty-app/src/utils/test-template.ts b/packages/create-twenty-app/src/utils/test-template.ts index 599b6f1ace..12e21b764a 100644 --- a/packages/create-twenty-app/src/utils/test-template.ts +++ b/packages/create-twenty-app/src/utils/test-template.ts @@ -25,6 +25,7 @@ export const scaffoldIntegrationTest = async ({ await createVitestConfig(appDirectory); await createTsconfigSpec(appDirectory); + await createGithubWorkflow(appDirectory); }; const createVitestConfig = async (appDirectory: string) => { @@ -211,3 +212,56 @@ describe('App installation', () => { await fs.ensureDir(join(appDirectory, fileFolder ?? '')); await fs.writeFile(join(appDirectory, fileFolder ?? '', fileName), content); }; + +const DEFAULT_TWENTY_VERSION = 'latest'; + +const createGithubWorkflow = async (appDirectory: string) => { + const content = `name: CI + +on: + push: + branches: + - main + pull_request: {} + +env: + TWENTY_VERSION: ${DEFAULT_TWENTY_VERSION} + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Spawn Twenty instance + id: twenty + uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main + with: + twenty-version: \${{ env.TWENTY_VERSION }} + github-token: \${{ secrets.GITHUB_TOKEN }} + + - name: Enable Corepack + run: corepack enable + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --immutable + + - name: Run integration tests + run: yarn test + env: + TWENTY_API_URL: \${{ steps.twenty.outputs.server-url }} + TWENTY_TEST_API_KEY: \${{ steps.twenty.outputs.access-token }} +`; + + const workflowDir = join(appDirectory, '.github', 'workflows'); + + await fs.ensureDir(workflowDir); + await fs.writeFile(join(workflowDir, 'ci.yml'), content); +};