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
294 lines
24 KiB
Plaintext
294 lines
24 KiB
Plaintext
---
|
||
title: Публикация
|
||
icon: upload
|
||
description: Распространяйте своё приложение Twenty в маркетплейсе или разверните его для внутреннего использования.
|
||
---
|
||
|
||
## Обзор
|
||
|
||
После того как ваше приложение [собрано и протестировано локально](/l/ru/developers/extend/apps/getting-started/concepts), у вас есть два пути для его распространения:
|
||
|
||
* **Разверните tar-архив** — загрузите своё приложение напрямую на конкретный сервер Twenty для внутреннего или частного использования.
|
||
* **Опубликовать в npm** — разместите ваше приложение в маркетплейсе Twenty, чтобы любое рабочее пространство могло его найти и установить.
|
||
|
||
Оба пути начинаются с одного и того же шага **build**.
|
||
|
||
## Сборка вашего приложения
|
||
|
||
Выполните команду сборки, чтобы скомпилировать приложение и сгенерировать готовый к распространению `manifest.json`:
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty dev:build
|
||
```
|
||
|
||
Это компилирует исходные файлы TypeScript, транспилирует функции логики и фронтенд-компоненты и записывает всё в `.twenty/output/`. Добавьте `--tarball`, чтобы также создать пакет `.tgz` для ручного распространения или для команды publish.
|
||
|
||
## Развертывание на сервер (tarball)
|
||
|
||
Для приложений, которые вы не хотите делать общедоступными — собственные инструменты, интеграции только для предприятий или экспериментальные сборки — вы можете развернуть tarball напрямую на сервер Twenty.
|
||
|
||
### Требования
|
||
|
||
Перед развертыванием вам нужен настроенный remote, указывающий на целевой сервер. Remotes локально хранят URL сервера и учётные данные аутентификации в `~/.twenty/config.json`.
|
||
|
||
Добавьте remote:
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty remote:add --url https://your-twenty-server.com --as production
|
||
```
|
||
|
||
### Развертывание
|
||
|
||
Соберите и загрузите ваше приложение на сервер в одном шаге:
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty app:publish --private
|
||
# To deploy to a specific remote:
|
||
# yarn twenty app:publish --private --remote production
|
||
```
|
||
|
||
### Общий доступ к развернутому приложению
|
||
|
||
Приложения в формате tarball не отображаются в публичном маркетплейсе, поэтому другие рабочие пространства на том же сервере не найдут их при просмотре. Чтобы поделиться развернутым приложением:
|
||
|
||
1. Перейдите в **Настройки > Приложения > Регистрации** и откройте ваше приложение
|
||
2. На вкладке **Распространение** нажмите **Копировать ссылку для общего доступа**
|
||
3. Поделитесь этой ссылкой с пользователями в других рабочих пространствах — она ведёт их прямо на страницу установки приложения
|
||
|
||
Ссылка общего доступа использует базовый URL сервера (без какого-либо поддомена рабочего пространства), поэтому она работает для любого рабочего пространства на сервере.
|
||
|
||
### Управление версиями
|
||
|
||
При обновлении уже развернутого tarball-приложения сервер требует, чтобы значение `version` в `package.json` было **строго выше** (согласно упорядочиванию по [semver](https://semver.org)), чем текущая развернутая версия. Повторное развёртывание той же версии или публикация более низкой версии отклоняются до сохранения tarball — в CLI вы увидите ошибку `VERSION_ALREADY_EXISTS`.
|
||
|
||
Чтобы выпустить обновление:
|
||
|
||
1. Увеличьте значение поля `version` в вашем `package.json` (например: `1.2.3` → `1.2.4`, `1.3.0` или `2.0.0`).
|
||
2. Выполните `yarn twenty app:publish --private` (или `yarn twenty app:publish --private --remote production`)
|
||
3. Рабочие пространства, в которых приложение установлено и для него включено автообновление (на вкладке «Настройки» приложения), обновляются автоматически в фоновом режиме; в остальных рабочих пространствах пользователи увидят доступное обновление в своих настройках
|
||
|
||
<Note>
|
||
Пререлизные теги работают как ожидается: повышение версии `1.0.0-rc.1` → `1.0.0-rc.2` допускается, а финальный релиз вроде `1.0.0` корректно распознаётся как более высокий, чем `1.0.0-rc.5`. Версия в `package.json` должна сама по себе быть корректной строкой semver.
|
||
</Note>
|
||
|
||
{/* TODO: add screenshot of the Upgrade button */}
|
||
|
||
### Совместимость версий сервера
|
||
|
||
Если ваше приложение использует функцию, появившуюся в конкретной версии сервера Twenty (например, провайдеры OAuth, добавленные в v2.3.0), следует объявить минимальную требуемую версию сервера с помощью поля `engines.twenty` в `package.json`:
|
||
|
||
```json filename="package.json"
|
||
{
|
||
"name": "twenty-my-app",
|
||
"version": "1.0.0",
|
||
"engines": {
|
||
"node": "^24.5.0",
|
||
"twenty": ">=2.3.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
Значение — это стандартный [диапазон semver](https://github.com/npm/node-semver#ranges). Типовые шаблоны:
|
||
|
||
| Диапазон | Значение |
|
||
| ---------------------------------- | -------------------------------------------------- |
|
||
| `>=2.3.0` | Любой сервер версии 2.3.0 и новее |
|
||
| `>=2.3.0 \<3.0.0` | 2.3.0 или новее, но ниже следующей мажорной версии |
|
||
| `^2.3.0` | То же, что и `>=2.3.0 \<3.0.0` |
|
||
|
||
**Что происходит при развёртывании и установке:**
|
||
|
||
* Если `engines.twenty` задано и версия целевого сервера не удовлетворяет диапазону, развёртывание (загрузка tarball-архива) или установка отклоняются с ошибкой `SERVER_VERSION_INCOMPATIBLE` и сообщением, указывающим как требуемый диапазон, так и фактическую версию сервера.
|
||
* Если `engines.twenty` **не задано**, приложение принимается на сервере любой версии (обратная совместимость с существующими приложениями).
|
||
* Если на сервере `APP_VERSION` не задано, проверка пропускается.
|
||
|
||
<Note>
|
||
Сервер выполняет окончательную проверку — он проверяет `engines.twenty` как при загрузке tarball-архива, так и при установке в рабочем пространстве. Если вы развёртываете tarball вне стандартного процесса или устанавливаете из маркетплейса, сервер всё равно принудительно проверяет совместимость.
|
||
</Note>
|
||
|
||
## Автоматизированный CI/CD (рабочие процессы, сгенерированные шаблоном)
|
||
|
||
Приложения, созданные с помощью `create-twenty-app`, «из коробки» включают три рабочих процесса GitHub Actions в каталоге `.github/workflows/`. CI запускается без какой-либо настройки, для CD требуется один секрет, а публикация в npm требует однократной настройки доверенного издателя npm (trusted-publisher).
|
||
|
||
### CI — `ci.yml`
|
||
|
||
Автоматически запускает интеграционные тесты при каждом пуше в `main` и для каждого pull request.
|
||
|
||
**Что делает:**
|
||
|
||
1. Извлекает исходный код вашего приложения.
|
||
2. Запускает изолированный тестовый экземпляр Twenty с помощью составного действия `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test@main` (эквивалент для CI `yarn twenty docker:start --test`).
|
||
3. Включает Corepack, настраивает Node.js на основе вашего `.nvmrc` и устанавливает зависимости с помощью `yarn install --immutable`.
|
||
4. Запускает `yarn test`, передавая `TWENTY_API_URL` и `TWENTY_API_KEY` из запущенного экземпляра, чтобы ваши тесты могли взаимодействовать с реальным сервером.
|
||
|
||
**Параметры конфигурации:**
|
||
|
||
* `TWENTY_VERSION` (переменная окружения, по умолчанию `latest`) — зафиксируйте версию сервера Twenty, используемую в CI, отредактировав это значение в `ci.yml`.
|
||
* Параллельные запуски группируются по `github.ref` и отменяют выполняющиеся прогоны при новых пушах.
|
||
|
||
Секреты не требуются — тестовый экземпляр эфемерен и существует только на время выполнения задания.
|
||
|
||
### CD — `cd.yml`
|
||
|
||
Разворачивает ваше приложение на настроенном сервере Twenty при каждом пуше в `main` и, при необходимости, из pull request при наличии метки `deploy`.
|
||
|
||
**Что делает:**
|
||
|
||
1. Извлекает head-коммит PR (для PR с меткой) или запушенный коммит.
|
||
2. Запускает `twentyhq/twenty/.github/actions/deploy-twenty-app@main` — эквивалент для CI `yarn twenty app:publish --private`.
|
||
3. Запускает `twentyhq/twenty/.github/actions/install-twenty-app@main`, чтобы новая развернутая версия была установлена в целевое рабочее пространство.
|
||
|
||
**Обязательная конфигурация:**
|
||
|
||
| Настройка | Где | Назначение |
|
||
| ----------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||
| `TWENTY_DEPLOY_URL` | `env` в `cd.yml` (по умолчанию `http://localhost:3000`) | Сервер Twenty, на который выполняется деплой. Перед первым использованием замените это на URL вашего реального сервера. |
|
||
| `TWENTY_DEPLOY_API_KEY` | В репозитории GitHub — **Settings → Secrets and variables → Actions** | Ключ API с правом деплоя на целевом сервере. |
|
||
|
||
<Note>
|
||
Значение `TWENTY_DEPLOY_URL` по умолчанию — `http://localhost:3000` — это заглушка: с хостируемого GitHub раннера к ней не будет доступа. Перед включением CD замените его на публичный URL вашего сервера (или используйте self-hosted раннер с сетевым доступом).
|
||
</Note>
|
||
|
||
**Запуск предварительного деплоя из PR:**
|
||
|
||
Добавьте к pull request метку `deploy`. Условие `if:` в `cd.yml` запустит задачу для этого PR, используя его head-коммит, что позволит проверить изменение на целевом сервере до слияния.
|
||
|
||
### Публикация — `publish.yml`
|
||
|
||
Публикует ваше приложение в npm с указанием происхождения (provenance), когда вы отправляете тег версии (например, `v1.0.0`), или когда вы запускаете рабочий процесс вручную на вкладке Actions.
|
||
|
||
**Что делает:**
|
||
|
||
1. Клонирует ваше приложение, настраивает Node.js и обновляет npm (для доверенной публикации требуется npm версии 11.5.1 или новее).
|
||
2. Запускает `yarn twenty app:publish`, который собирает приложение и публикует `.twenty/output` в npm. В CI он автоматически добавляет `--provenance` и `--access public`, поэтому в рабочем процессе флаги не требуются.
|
||
|
||
**Первоначальная настройка:**
|
||
|
||
На npmjs.com откройте свой пакет > **Settings → Trusted Publisher** и зарегистрируйте этот репозиторий, указав рабочий процесс `publish.yml` (см. [документацию по доверенной публикации в npm](https://docs.npmjs.com/trusted-publishers)). Публикация с provenance подтверждает, какой репозиторий GitHub собрал пакет, а также позволяет вам заявить права на ваше приложение в маркетплейсе Twenty.
|
||
|
||
<Note>
|
||
npm принимает подтверждение происхождения только из **публичных** репозиториев с исходным кодом. Если вы публикуете из приватного репозитория, npm отклоняет пакет подтверждения происхождения OIDC с ошибкой `E422 ... Ошибка `Unsupported GitHub Actions source repository visibility: "private"`. Чтобы публиковать из приватного репозитория, отключите подтверждение происхождения, установив `TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'`в`env`шага публикации (закомментированная подсказка включена в сгенерированный`publish.yml\`):
|
||
|
||
```yaml filename=".github/workflows/publish.yml"
|
||
- name: Publish to npm
|
||
env:
|
||
TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'
|
||
run: yarn twenty app:publish
|
||
```
|
||
</Note>
|
||
|
||
### Закрепление версий повторно используемых действий
|
||
|
||
Рабочие процессы `ci.yml` и `cd.yml` ссылаются на повторно используемые действия с указанием `@main`, поэтому обновления действий в репозитории `twentyhq/twenty` подхватываются автоматически. Если вам нужны детерминированные сборки, замените `@main` на SHA коммита или тег релиза в каждой строке `uses:`.
|
||
|
||
## Публикация в npm
|
||
|
||
Публикация в npm делает ваше приложение видимым в маркетплейсе Twenty. Любое рабочее пространство Twenty может просматривать, устанавливать и обновлять приложения из маркетплейса непосредственно из интерфейса.
|
||
|
||
### Требования
|
||
|
||
* Учётная запись [npm](https://www.npmjs.com)
|
||
* Ключевое слово `twenty-app` в массиве `keywords` вашего `package.json` (добавьте его вручную — по умолчанию оно не включено в шаблон `create-twenty-app`)
|
||
|
||
```json filename="package.json"
|
||
{
|
||
"name": "twenty-app-postcard-sender",
|
||
"version": "1.0.0",
|
||
"keywords": ["twenty-app"]
|
||
}
|
||
```
|
||
|
||
### Метаданные маркетплейса
|
||
|
||
Конфигурация `defineApplication()` поддерживает необязательные поля, которые определяют, как ваше приложение отображается в маркетплейсе. Используйте `logo` и `galleryImages`, чтобы ссылаться на изображения из папки `public/`:
|
||
|
||
```ts src/application-config.ts
|
||
export default defineApplication({
|
||
universalIdentifier: '...',
|
||
displayName: 'My App',
|
||
description: 'A great app',
|
||
logo: 'public/logo.png',
|
||
galleryImages: [
|
||
'public/screenshot-1.png',
|
||
'public/screenshot-2.png',
|
||
],
|
||
});
|
||
```
|
||
|
||
См. [аккордеон defineApplication](/l/ru/developers/extend/apps/config/application#marketplace-metadata) на странице «Создание приложений» для полного списка полей маркетплейса (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl` и т. д.).
|
||
|
||
#### Рекомендуемые размеры изображений галереи
|
||
|
||
Маркетплейс отображает `galleryImages` в контейнере с фиксированным соотношением сторон `8:5` (например, `1600×1000 px`).
|
||
|
||
<Note>
|
||
Изображения галереи с любым соотношением сторон отображаются полностью и никогда не обрезаются, но всё, что значительно выше или уже, чем `8:5`, будет иметь пустые поля по бокам.
|
||
</Note>
|
||
|
||
#### Ограничение размера изображения
|
||
|
||
Файл `logo` и каждый файл из `galleryImages` не должны превышать **10 MB**. Более крупные файлы пропускаются при повторном размещении ваших опубликованных ресурсов на маркетплейсе, поэтому они не будут отображаться.
|
||
|
||
### Публикация
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty app:publish
|
||
```
|
||
|
||
Чтобы опубликовать с определённым dist-tag (например, `beta` или `next`):
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty app:publish --tag beta
|
||
```
|
||
|
||
### Как работает обнаружение приложений в маркетплейсе
|
||
|
||
Сервер Twenty синхронизирует каталог маркетплейса из реестра npm **каждый час**.
|
||
|
||
Вы можете запустить синхронизацию немедленно, вместо ожидания:
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty dev:catalog-sync
|
||
# To target a specific remote:
|
||
# yarn twenty dev:catalog-sync --remote production
|
||
```
|
||
|
||
Метаданные, отображаемые в маркетплейсе, берутся из вашей конфигурации `defineApplication()` — см. раздел [Метаданные маркетплейса](#marketplace-metadata) выше.
|
||
|
||
<Note>
|
||
Если ваше приложение не определяет `aboutDescription` в `defineApplication()`, маркетплейс автоматически использует `README.md` вашего пакета из npm в качестве содержимого страницы «О приложении». Это означает, что вы можете поддерживать единый README как для npm, так и для маркетплейса Twenty. Если вы хотите другое описание в маркетплейсе, явно задайте `aboutDescription`.
|
||
</Note>
|
||
|
||
### Публикация через CI
|
||
|
||
Сгенерированный выше рабочий процесс `publish.yml` автоматически публикует в npm по тегам версий, с provenance. Поскольку `yarn twenty app:publish` при запуске в CI добавляет за вас `--provenance` и `--access public`, в рабочем процессе не нужны флаги npm — требуется только однократная настройка доверенного издателя.
|
||
|
||
Для других систем CI (GitLab CI, CircleCI и т. д.) запустите `yarn install`, затем `yarn twenty app:publish`. Provenance создается, когда среда может выпустить токен OIDC, и в противном случае автоматически пропускается.
|
||
|
||
<Note>
|
||
**npm provenance** добавляет значок доверия к вашему пакету в npm, позволяя пользователям проверить, что пакет был собран из конкретного коммита в общедоступном конвейере CI. Это также то, что позволяет вам заявить права на ваше приложение в маркетплейсе Twenty. Подробности см. в [документации по npm provenance](https://docs.npmjs.com/generating-provenance-statements).
|
||
</Note>
|
||
|
||
## Установка приложений
|
||
|
||
После публикации приложения (npm) или его развертывания (tarball) рабочие пространства могут установить его через интерфейс.
|
||
|
||
Перейдите на страницу **Настройки > Приложения** в Twenty, где можно просматривать и устанавливать как приложения из маркетплейса, так и развернутые через tarball.
|
||
|
||
{/* TODO: add screenshot of the UI when the app is registered */}
|
||
|
||
Вы также можете устанавливать приложения из командной строки:
|
||
|
||
```bash filename="Terminal"
|
||
yarn twenty app:install
|
||
```
|
||
|
||
<Note>
|
||
Сервер при установке применяет версионирование semver, аналогичное правилам при развёртывании:
|
||
|
||
* Установка той же версии, которая уже установлена в вашем рабочем пространстве, отклоняется с ошибкой `APP_ALREADY_INSTALLED`.
|
||
* Установка версии ниже текущей отклоняется с ошибкой `CANNOT_DOWNGRADE_APPLICATION`.
|
||
|
||
Чтобы установить более новую версию, сначала разверните или опубликуйте её, затем снова выполните `yarn twenty app:install`.
|
||
</Note>
|