Files
upstream-twenty/.github/workflows/discover-apps.yaml
upstream-mirror e7da97194a
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
2026-09-17 23:28:13 +05:00

120 lines
4.7 KiB
YAML

name: Discover apps reusable workflow
on:
workflow_call:
inputs:
scope:
description: 'App roots to scan: "public" or "internal-and-public".'
required: false
type: string
default: internal-and-public
changed-only:
description: 'Only include apps changed in this PR, else every app in scope.'
required: false
type: boolean
default: true
application:
description: 'workflow_dispatch: restrict to a single app folder name.'
required: false
type: string
default: ''
outputs:
matrix:
value: ${{ jobs.discover.outputs.matrix }}
has_apps:
value: ${{ jobs.discover.outputs.has_apps }}
permissions:
contents: read
jobs:
discover:
timeout-minutes: 5
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
has_apps: ${{ steps.set-matrix.outputs.has_apps }}
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: ${{ inputs.changed-only && '0' || '1' }}
- name: Ensure no .github folder inside app folders
run: |
offenders=$(find packages/twenty-apps/internal packages/twenty-apps/public -mindepth 2 -maxdepth 2 -type d -name .github)
if [ -n "$offenders" ]; then
echo "::error::Apps must not define their own .github folder. Offenders:"
echo "$offenders"
exit 1
fi
- name: Detect changed files
id: changed-files
if: inputs.changed-only && github.event_name != 'workflow_dispatch'
uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c # v45.0.9
with:
json: true
escape_json: false
files: |
packages/twenty-apps/internal/**
packages/twenty-apps/public/**
- name: Build matrix of apps
id: set-matrix
env:
SCOPE: ${{ inputs.scope }}
CHANGED_ONLY: ${{ inputs.changed-only }}
EVENT_NAME: ${{ github.event_name }}
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
APPLICATION_INPUT: ${{ inputs.application }}
run: |
node <<'NODE'
const fs = require('fs');
const path = require('path');
const changedOnly = process.env.CHANGED_ONLY === 'true';
const roots = process.env.SCOPE === 'public'
? ['packages/twenty-apps/public']
: ['packages/twenty-apps/internal', 'packages/twenty-apps/public'];
const eventName = process.env.EVENT_NAME;
const changedFiles = JSON.parse(process.env.CHANGED_FILES || '[]');
const changedApps = new Set();
for (const file of changedFiles) {
const match = file.match(/^packages\/twenty-apps\/(?:internal|public)\/([^/]+)\//);
if (match) changedApps.add(match[1]);
}
const requestedApp = (process.env.APPLICATION_INPUT || '').trim();
const matrix = roots
.filter((root) => fs.existsSync(root))
.flatMap((root) =>
fs.readdirSync(root, { withFileTypes: true })
.filter((entry) => entry.isDirectory() && entry.name !== 'node_modules')
.map((entry) => entry.name)
.filter((name) => fs.existsSync(path.join(root, name, 'package.json')))
.filter((name) => {
if (!changedOnly) return true;
if (eventName === 'workflow_dispatch') {
return requestedApp ? name === requestedApp : true;
}
return changedApps.has(name);
})
.map((name) => {
const appPath = path.join(root, name);
const scripts = JSON.parse(fs.readFileSync(path.join(appPath, 'package.json'), 'utf8')).scripts || {};
return {
name,
path: appPath,
hasTypecheck: Boolean(scripts.typecheck),
hasUnit: Boolean(scripts['test:unit']),
hasIntegration: Boolean(scripts.test),
};
})
);
if (changedOnly && eventName === 'workflow_dispatch' && requestedApp && matrix.length === 0) {
console.error(`::error::Requested app "${requestedApp}" was not found under ${roots.join(', ')}`);
process.exit(1);
}
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix=${JSON.stringify(matrix)}\n`);
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has_apps=${matrix.length > 0}\n`);
NODE