Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cad56e1df5 | ||
|
|
6752d43d36 | ||
|
|
cbb1454ef8 | ||
|
|
72a69d5bd7 |
@@ -1,99 +0,0 @@
|
||||
# Twenty Development Rules
|
||||
|
||||
## General
|
||||
- Twenty is an open source CRM built with Typescript (React, NestJS)
|
||||
|
||||
### Main Packages / folders
|
||||
- packages/twenty-front: Main Frontend (React)
|
||||
- packages/twenty-server: Main Backend (NestJS)
|
||||
- packages/twenty-website: Marketing website + docs (NextJS)
|
||||
- packages/twenty-ui: UI library (React)
|
||||
- packages/twenty-shared: Shared utils, constants, types
|
||||
|
||||
### Development Stack
|
||||
- Package Manager: yarn
|
||||
- Monorepo: nx
|
||||
- Database: PostgreSQL + TypeORM (core, metadata schemas)
|
||||
- State Management: Recoil
|
||||
- Data Management: Apollo / GraphQL
|
||||
- Cache: redis
|
||||
- Auth: JWT
|
||||
- Queue: BullMQ
|
||||
- Storage: S3/local filesystem
|
||||
- Testing Backend: Jest, Supertest
|
||||
- Testing Frontend: Jest, Storybook, MSW
|
||||
- Testing E2E: Playwright
|
||||
|
||||
## Styling
|
||||
- Use @emotion/styled, never CSS classes/Tailwind
|
||||
- Prefix styled components with 'Styled'
|
||||
- Keep styled components at top of file
|
||||
- Use Theme object for colors/spacing/typography
|
||||
- Use Theme values instead of px/rem
|
||||
- Use mq helper for media queries
|
||||
|
||||
## TypeScript
|
||||
- No 'any' type - use proper typing
|
||||
- Use type over interface
|
||||
- String literals over enums (except GraphQL)
|
||||
- Props suffix for component props types
|
||||
- Use type inference when possible
|
||||
- Enable strict mode and noImplicitAny
|
||||
|
||||
## React
|
||||
- Only functional components
|
||||
- Named exports only
|
||||
- No useEffect, prefer event handlers
|
||||
- Small focused components
|
||||
- Proper prop naming (onClick, isActive)
|
||||
- Destructure props with types
|
||||
|
||||
## State Management
|
||||
- Recoil for global state
|
||||
- Apollo Client for GraphQL/server state
|
||||
- Atoms in states/ directory
|
||||
- Multiple small atoms over prop drilling
|
||||
- No useRef for state
|
||||
- Extract data fetching to siblings
|
||||
- useRecoilValue/useRecoilState appropriately
|
||||
|
||||
## File Structure
|
||||
- One component per file
|
||||
- Features in modules/
|
||||
- Hooks in hooks/
|
||||
- States in states/
|
||||
- Types in types/
|
||||
- PascalCase components, camelCase others
|
||||
|
||||
## Translation
|
||||
- Use @lingui/react/macro
|
||||
- Use <Trans> within components
|
||||
- Use t`string` elsewhere (from useLingui hook)
|
||||
- Don't translate metadata (field names, object names, etc)
|
||||
- Don't translate mocks
|
||||
|
||||
## Code Style
|
||||
- Early returns
|
||||
- No nested ternaries
|
||||
- No else-if
|
||||
- Optional chaining over &&
|
||||
- Small focused functions
|
||||
- Clear variable names
|
||||
- No console.logs in commits
|
||||
- Few comments, prefer code readability
|
||||
|
||||
## GraphQL
|
||||
- Use gql tag
|
||||
- Separate operation files
|
||||
- Proper codegen typing
|
||||
- Consistent naming (getX, updateX)
|
||||
- Use fragments
|
||||
- Use generated types
|
||||
|
||||
## Testing
|
||||
- Test every feature
|
||||
- React Testing Library
|
||||
- Test behavior not implementation
|
||||
- Mock external deps
|
||||
- Use data-testid
|
||||
- Follow naming conventions
|
||||
+4
-19
@@ -1,16 +1,8 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['plugin:prettier/recommended', 'plugin:lingui/recommended'],
|
||||
plugins: [
|
||||
'@nx',
|
||||
'prefer-arrow',
|
||||
'import',
|
||||
'unused-imports',
|
||||
'unicorn',
|
||||
'lingui',
|
||||
],
|
||||
extends: ['plugin:prettier/recommended'],
|
||||
plugins: ['@nx', 'prefer-arrow', 'import', 'unused-imports', 'unicorn'],
|
||||
rules: {
|
||||
'lingui/no-single-variables-to-translate': 'off',
|
||||
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
|
||||
'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }],
|
||||
'no-control-regex': 0,
|
||||
@@ -37,10 +29,6 @@ module.exports = {
|
||||
sourceTag: 'scope:frontend',
|
||||
onlyDependOnLibsWithTags: ['scope:shared', 'scope:frontend'],
|
||||
},
|
||||
{
|
||||
sourceTag: 'scope:zapier',
|
||||
onlyDependOnLibsWithTags: ['scope:shared'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -82,6 +70,7 @@ module.exports = {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-empty-interface': [
|
||||
'error',
|
||||
{
|
||||
@@ -107,11 +96,7 @@ module.exports = {
|
||||
rules: {},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'*.spec.@(ts|tsx|js|jsx)',
|
||||
'*.integration-spec.@(ts|tsx|js|jsx)',
|
||||
'*.test.@(ts|tsx|js|jsx)',
|
||||
],
|
||||
files: ['*.spec.@(ts|tsx|js|jsx)', '*.test.@(ts|tsx|js|jsx)'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Twenty's Pledge
|
||||
|
||||
The contributors and maintainers of this project pledge to ensure a harassment-free experience for everyone in the community.
|
||||
The contributors and maintainers of this project pledge to ensure a harassment-free experience for everyone in the community. This commitment applies to individuals of all backgrounds, including age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity, experience, education, socio-economic status, nationality, appearance, race, religion. It also applies to individuals of all sexual identities and orientations.
|
||||
|
||||
The focus of both contributors and maintainers is on acting and interacting in ways that promote an open, welcoming, friendly, diverse, inclusive, and healthy community.
|
||||
|
||||
|
||||
+42
-17
@@ -1,38 +1,47 @@
|
||||
# Contributing to Twenty
|
||||
|
||||
Thanks for considering contributing to Twenty!
|
||||
|
||||
Please make sure to go through the [documentation](https://docs.twenty.com) before.
|
||||
Thank you for considering contributing to Twenty! All community contributions are welcome.
|
||||
|
||||
This guide outlines the process for contributing to this project. Please make sure to go through the [documentation](https://docs.twenty.com) before making your contribution.
|
||||
|
||||
|
||||
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation:
|
||||
> - Star the project
|
||||
> - Tweet about it
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
## Good first issues
|
||||
## Getting Started
|
||||
|
||||
Good first issues are a great way to start contributing and get familiar with the codebase. You can find them on by filtering on the [good first issue](https://github.com/twentyhq/twenty/labels/good%20first%20issue) label.
|
||||
Good first issues are a great way to start contributing to the project and get familiar with the codebase. Here's how to find them:
|
||||
|
||||
## Issue assignment
|
||||
1. Visit the "[Issues](https://github.com/twentyhq/twenty/issues)" tab on the main [repository](https://github.com/twentyhq/twenty).
|
||||
2. Use the "Labels" filter and select "[Good First Issue](https://github.com/twentyhq/twenty/labels/good%20first%20issue)" to see a list of beginner-friendly tasks.
|
||||
3. Choose an issue that interests you, fork the project, and start working on it. Once you solve and test the issue, open a PR for review.
|
||||
|
||||
Having multiple contributors address the same issue can cause frustration.
|
||||
Note: We are aware that having multiple contributors address the same issue can cause frustration. To prevent this, we adhere to a specific guideline: if a core team member has assigned an issue to a contributor, either as the issue assignee or through explicit assignment in the issue comments within the past three days, that contributor's pull request takes precedence. Otherwise, the first PR submitted will be given priority. This delay is reduced to one day for PR tagged with "size: minutes" and extended to a week for PR tagged "size: days".
|
||||
|
||||
To avoid conflicts, we follow these guidelines:
|
||||
1. If a core team member assigned you the issue within the last three days, your PR takes priority.
|
||||
2. Otherwise, the first submitted PR is prioritized.
|
||||
3. For "size: long" PRs, the assignment period extends to one week.
|
||||
Therefore, ensure you are assigned to an issue before beginning work on it.
|
||||
|
||||
Please ensure you're assigned to an issue before starting work.
|
||||
<br>
|
||||
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
## How to Contribute
|
||||
|
||||
1. **Fork the Repository:** Click on the 'Fork' button in the upper right corner of the repository's GitHub page. This will create a copy of the repository in your GitHub account.
|
||||
|
||||
|
||||
2. **Clone the Repository:** Clone your forked repository to your local machine using `git clone`.
|
||||
|
||||
|
||||
```shell
|
||||
git clone https://github.com/yourusername/twenty.git
|
||||
cd twenty
|
||||
```
|
||||
|
||||
3. **Create a New Branch:** Create a new branch for your changes instead of using the main branch.
|
||||
|
||||
```shell
|
||||
@@ -47,24 +56,40 @@ git checkout -b your-branch-name
|
||||
|
||||
6. **Commit Changes:** Commit your changes with a clear and concise commit message.
|
||||
|
||||
|
||||
```shell
|
||||
git commit -m "Add your detailed description here"
|
||||
```
|
||||
|
||||
7. **Push Changes:** Push your changes to your forked repository.
|
||||
|
||||
|
||||
```shell
|
||||
git push origin your-branch-name
|
||||
```
|
||||
|
||||
8. **Create a Pull Request:** Go to the original Twenty repository and create a pull request. Please provide a detailed description of your changes. Submitting a PR means you agree to the CLA.
|
||||
|
||||
9. **Code Review:** Your pull request will undergo a code review.
|
||||
8. **Create a Pull Request:** Go to the original Twenty repository and create a pull request. Please provide a detailed description of your changes. To have your pull request accepted, you must sign a CLA.
|
||||
|
||||
|
||||
9. **Code Review:** Your pull request will undergo a code review. Note that you might need to make any necessary adjustments based on feedback.
|
||||
|
||||
|
||||
10. **Merge:** Once approved, maintainers will merge your pull request into the main repository.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please note that by contributing to this project, you're expected to follow Twenty's [Code of Conduct](./CODE_OF_CONDUCT.md). All maintainers strive to maintain a welcoming, friendly, and inclusive community for all contributors.
|
||||
|
||||
<br>
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
If you face any issues or have suggestions, please feel free to (create an issue on Twenty's GitHub repository)[https://github.com/twentyhq/twenty/issues/new]. Please provide as much detail as possible.
|
||||
If you encounter any issues or have suggestions for improvements, please feel free to (create an issue on Twenty's GitHub repository)[https://github.com/twentyhq/twenty/issues/new]. When reporting issues, please provide as much detail as possible to help in understanding and addressing the problem effectively.
|
||||
|
||||
---
|
||||
|
||||
Thank you for considering contributing to Twenty. Your contributions help make Twenty's CRM platform even better!
|
||||
|
||||
|
||||
@@ -2,11 +2,14 @@ name: Nx Affected CI
|
||||
inputs:
|
||||
parallel:
|
||||
required: false
|
||||
default: '3'
|
||||
types: [number]
|
||||
default: 3
|
||||
tag:
|
||||
required: false
|
||||
types: [string]
|
||||
tasks:
|
||||
required: true
|
||||
types: [string]
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
name: Restore cache
|
||||
inputs:
|
||||
key:
|
||||
required: true
|
||||
description: Prefix to the cache key
|
||||
additional-paths:
|
||||
required: false
|
||||
outputs:
|
||||
cache-primary-key:
|
||||
description: actions/cache/restore cache-primary-key outputs proxy
|
||||
value: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||
cache-hit:
|
||||
description: String bool indicating whether cache has been directly or indirectly hit
|
||||
value: ${{ steps.restore-cache.outputs.cache-hit == 'true' || steps.restore-cache.outputs.cache-matched-key != '' }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Cache primary key builder
|
||||
id: cache-primary-key-builder
|
||||
shell: bash
|
||||
run: |
|
||||
echo "CACHE_PRIMARY_KEY_PREFIX=${{ inputs.key }}-${{ github.ref_name }}" >> "${GITHUB_OUTPUT}"
|
||||
- name: Restore cache
|
||||
uses: actions/cache/restore@v4
|
||||
id: restore-cache
|
||||
with:
|
||||
key: ${{ steps.cache-primary-key-builder.outputs.CACHE_PRIMARY_KEY_PREFIX }}-${{ github.sha }}
|
||||
restore-keys: ${{ steps.cache-primary-key-builder.outputs.CACHE_PRIMARY_KEY_PREFIX }}-
|
||||
path: |
|
||||
.cache
|
||||
.nx/cache
|
||||
node_modules/.cache
|
||||
packages/*/node_modules/.cache
|
||||
${{ inputs.additional-paths }}
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Save cache
|
||||
inputs:
|
||||
key:
|
||||
required: true
|
||||
description: Primary key to the cache, should be retrieved from `cache-restore` composite action outputs.
|
||||
additional-paths:
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Save cache
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: ${{ inputs.key }}
|
||||
path: |
|
||||
.cache
|
||||
.nx/cache
|
||||
node_modules/.cache
|
||||
packages/*/node_modules/.cache
|
||||
${{ inputs.additional-paths }}
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Restore Tasks Cache CI
|
||||
inputs:
|
||||
tag:
|
||||
required: false
|
||||
types: [string]
|
||||
tasks:
|
||||
required: false
|
||||
types: [string]
|
||||
default: all
|
||||
suffix:
|
||||
required: false
|
||||
types: [string]
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Compute tasks key
|
||||
id: tasks-key
|
||||
shell: bash
|
||||
run: echo "key=${{ inputs.tasks }}" | tr , - >> $GITHUB_OUTPUT
|
||||
- name: Restore tasks cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
.nx/cache
|
||||
node_modules/.cache
|
||||
packages/*/node_modules/.cache
|
||||
key: tasks-cache-${{ github.ref_name }}-${{ inputs.tag }}-${{ steps.tasks-key.outputs.key }}${{ inputs.suffix }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
tasks-cache-${{ github.ref_name }}-${{ inputs.tag }}-${{ steps.tasks-key.outputs.key }}${{ inputs.suffix }}-
|
||||
@@ -1,43 +1,23 @@
|
||||
name: Yarn Install
|
||||
inputs:
|
||||
node-version:
|
||||
required: false
|
||||
default: '18'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Cache primary key builder
|
||||
id: globals
|
||||
shell: bash
|
||||
run: |
|
||||
echo "ACTION_SHELL=bash" >> "${GITHUB_OUTPUT}"
|
||||
echo "CACHE_KEY_PREFIX=node_modules-cache-node-${{ inputs.node-version }}-${{ hashFiles('yarn.lock') }}" >> "${GITHUB_OUTPUT}"
|
||||
echo 'PATH_TO_CACHE<<EOF' >> $GITHUB_OUTPUT
|
||||
echo "node_modules" >> $GITHUB_OUTPUT
|
||||
echo "packages/*/node_modules" >> $GITHUB_OUTPUT
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
- name: Setup Node.js and get yarn cache
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
- name: Restore node_modules
|
||||
id: cache-node-modules
|
||||
uses: actions/cache/restore@v4
|
||||
node-version: "18"
|
||||
cache: yarn
|
||||
- name: Cache node modules
|
||||
id: node-modules-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: ${{ steps.globals.outputs.CACHE_KEY_PREFIX }}-${{github.sha}}
|
||||
restore-keys: ${{ steps.globals.outputs.CACHE_KEY_PREFIX }}-
|
||||
path: ${{ steps.globals.outputs.PATH_TO_CACHE }}
|
||||
path: |
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
key: root-node_modules-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: root-node_modules-
|
||||
- name: Install Dependencies
|
||||
if: ${{ steps.cache-node-modules.outputs.cache-hit != 'true' && steps.cache-node-modules.outputs.cache-matched-key == '' }}
|
||||
shell: ${{ steps.globals.outputs.ACTION_SHELL }}
|
||||
run: |
|
||||
yarn config set enableHardenedMode true
|
||||
yarn --immutable --check-cache
|
||||
- name: Save cache
|
||||
if: ${{ steps.cache-node-modules.outputs.cache-hit != 'true' && steps.cache-node-modules.outputs.cache-matched-key == '' }}
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: ${{ steps.cache-node-modules.outputs.cache-primary-key }}
|
||||
path: ${{ steps.globals.outputs.PATH_TO_CACHE }}
|
||||
|
||||
shell: bash
|
||||
run: yarn --immutable --check-cache
|
||||
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
||||
@@ -5,7 +5,6 @@ on:
|
||||
- main
|
||||
jobs:
|
||||
deploy-main:
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
|
||||
@@ -5,7 +5,6 @@ on:
|
||||
- 'v*'
|
||||
jobs:
|
||||
deploy-tag:
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
name: Changed files reusable workflow
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
files:
|
||||
required: true
|
||||
type: string
|
||||
outputs:
|
||||
any_changed:
|
||||
value: ${{ jobs.changed-files.outputs.any_changed }}
|
||||
|
||||
jobs:
|
||||
changed-files:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
any_changed: ${{ steps.changed-files.outputs.any_changed }}
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check for changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
with:
|
||||
files: ${{ inputs.files }}
|
||||
@@ -3,24 +3,19 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-chrome-extension/**'
|
||||
pull_request:
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-chrome-extension/**'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
package.json
|
||||
packages/twenty-chrome-extension/**
|
||||
chrome-extension-build:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
VITE_SERVER_BASE_URL: http://localhost:3000
|
||||
@@ -31,18 +26,7 @@ jobs:
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Chrome Extension / Run build
|
||||
run: npx nx build twenty-chrome-extension
|
||||
ci-chrome-extension-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changed-files-check, chrome-extension-build]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
name: CI Demo check
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 7,19 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./packages/twenty-e2e-testing
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: yarn playwright install --with-deps
|
||||
|
||||
- name: Run Playwright tests
|
||||
id: test
|
||||
run: yarn playwright test --grep "@demo-only"
|
||||
|
||||
- name: Upload report after tests
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 90
|
||||
|
||||
- name: Send Discord notification
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
uses: Ilshidur/action-discord@0.3.2
|
||||
with:
|
||||
args: 'Demo check ${{ steps.test.outcome }} - check ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
|
||||
- name: Send email if demo is not working
|
||||
if: steps.test.outcome == 'failure'
|
||||
uses: dawidd6/action-send-mail@v3.12.0
|
||||
with:
|
||||
connection_url: ${{ secrets.MAIL_CONNECTION }}
|
||||
server_address: smtp.gmail.com
|
||||
server_port: 465
|
||||
secure: true
|
||||
username: ${{ secrets.MAIL_USERNAME }}
|
||||
subject: 'Demo is not working'
|
||||
from: 'Github CI Demo check'
|
||||
to: ${{ secrets.RECIPIENTS }}
|
||||
body: '<a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}">Link</a>'
|
||||
priority: high
|
||||
@@ -1,133 +0,0 @@
|
||||
name: CI E2E Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
packages/**
|
||||
playwright.config.ts
|
||||
.github/workflows/ci-e2e.yaml
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true' && ( github.event_name == 'push' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'run-e2e')))
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
# https://github.com/actions/runner-images/issues/70#issuecomment-589562148
|
||||
NODE_OPTIONS: "--max-old-space-size=10240"
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
env:
|
||||
PGUSER_SUPERUSER: postgres
|
||||
PGPASSWORD_SUPERUSER: postgres
|
||||
ALLOW_NOSSL: "true"
|
||||
SPILO_PROVIDER: "local"
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
- name: Check system resources
|
||||
run: |
|
||||
echo "Available memory:"
|
||||
free -h
|
||||
echo "Available disk space:"
|
||||
df -h
|
||||
echo "CPU info:"
|
||||
lscpu
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
|
||||
- name: Build twenty-shared
|
||||
run: npx nx build twenty-shared
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx nx setup twenty-e2e-testing
|
||||
|
||||
- name: Setup environment files
|
||||
run: |
|
||||
cp packages/twenty-front/.env.example packages/twenty-front/.env
|
||||
npx nx reset:env twenty-server
|
||||
|
||||
- name: Build frontend
|
||||
run: NODE_ENV=production NODE_OPTIONS="--max-old-space-size=10240" npx nx build twenty-front
|
||||
|
||||
- name: Build server
|
||||
run: npx nx build twenty-server
|
||||
|
||||
- name: Create and setup database
|
||||
run: |
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
|
||||
npx nx run twenty-server:database:reset
|
||||
|
||||
- name: Start server
|
||||
run: |
|
||||
npx nx start twenty-server &
|
||||
echo "Waiting for server to be ready..."
|
||||
timeout 60 bash -c 'until curl -s http://localhost:3000/health; do sleep 2; done'
|
||||
|
||||
- name: Start frontend
|
||||
run: |
|
||||
npm_config_yes=true npx serve -s packages/twenty-front/build -l 3001 &
|
||||
echo "Waiting for frontend to be ready..."
|
||||
timeout 60 bash -c 'until curl -s http://localhost:3001; do sleep 2; done'
|
||||
|
||||
- name: Start worker
|
||||
run: |
|
||||
npx nx run twenty-server:worker &
|
||||
echo "Worker started"
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: npx nx test twenty-e2e-testing
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: packages/twenty-e2e-testing/run_results/
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: packages/twenty-e2e-testing/playwright-report/
|
||||
retention-days: 30
|
||||
ci-e2e-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changed-files-check, test]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
+43
-107
@@ -3,30 +3,22 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-front/**'
|
||||
- 'packages/twenty-ui/**'
|
||||
pull_request:
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-front/**'
|
||||
- 'packages/twenty-ui/**'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
STORYBOOK_BUILD_CACHE_KEY: storybook-build-depot-ubuntu-24.04-8-runner
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
package.json
|
||||
packages/twenty-front/**
|
||||
packages/twenty-ui/**
|
||||
packages/twenty-shared/**
|
||||
front-sb-build:
|
||||
needs: [changed-files-check]
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
REACT_APP_SERVER_BASE_URL: http://localhost:3000
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
@@ -37,94 +29,62 @@ jobs:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch local actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Diagnostic disk space issue
|
||||
run: df -h
|
||||
- name: Restore storybook build cache
|
||||
id: restore-storybook-build-cache
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
- name: Front / Restore Storybook Task Cache
|
||||
uses: ./.github/workflows/actions/task-cache
|
||||
with:
|
||||
key: ${{ env.STORYBOOK_BUILD_CACHE_KEY }}
|
||||
tag: scope:frontend
|
||||
tasks: storybook:build
|
||||
- name: Front / Write .env
|
||||
run: npx nx reset:env twenty-front
|
||||
- name: Front / Build storybook
|
||||
run: npx nx storybook:build twenty-front
|
||||
- name: Save storybook build cache
|
||||
uses: ./.github/workflows/actions/save-cache
|
||||
with:
|
||||
key: ${{ steps.restore-storybook-build-cache.outputs.cache-primary-key }}
|
||||
front-sb-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
runs-on: ci-8-cores
|
||||
needs: front-sb-build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard: [1, 2, 3, 4]
|
||||
storybook_scope: [modules, pages, performance]
|
||||
storybook_scope: [pages, modules]
|
||||
env:
|
||||
SHARD_COUNTER: 4
|
||||
REACT_APP_SERVER_BASE_URL: http://localhost:3000
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
steps:
|
||||
- name: Fetch local actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Install Playwright
|
||||
run: cd packages/twenty-front && npx playwright install
|
||||
- name: Restore storybook build cache
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
- name: Front / Restore Storybook Task Cache
|
||||
uses: ./.github/workflows/actions/task-cache
|
||||
with:
|
||||
key: ${{ env.STORYBOOK_BUILD_CACHE_KEY }}
|
||||
tag: scope:frontend
|
||||
tasks: storybook:build
|
||||
- name: Front / Write .env
|
||||
run: npx nx reset:env twenty-front
|
||||
- name: Run storybook tests
|
||||
run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} --shard=${{ matrix.shard }}/${{ env.SHARD_COUNTER }} --checkCoverage=false
|
||||
- name: Rename coverage file
|
||||
run: mv packages/twenty-front/coverage/storybook/coverage-storybook.json packages/twenty-front/coverage/storybook/coverage-shard-${{matrix.shard}}.json
|
||||
- name: Upload coverage artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
retention-days: 1
|
||||
name: coverage-artifacts-${{ matrix.storybook_scope }}-${{ github.run_id }}-${{ matrix.shard }}
|
||||
path: packages/twenty-front/coverage/storybook/coverage-shard-${{matrix.shard}}.json
|
||||
merge-reports-and-check-coverage:
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
needs: front-sb-test
|
||||
run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }}
|
||||
front-sb-test-performance:
|
||||
runs-on: ci-8-cores
|
||||
env:
|
||||
PATH_TO_COVERAGE: packages/twenty-front/coverage/storybook
|
||||
strategy:
|
||||
matrix:
|
||||
storybook_scope: [modules, pages, performance]
|
||||
REACT_APP_SERVER_BASE_URL: http://localhost:3000
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch local actions
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: coverage-artifacts-${{ matrix.storybook_scope }}-${{ github.run_id }}-*
|
||||
merge-multiple: true
|
||||
path: coverage-artifacts
|
||||
- name: Merge coverage reports
|
||||
run: |
|
||||
mkdir -p ${{ env.PATH_TO_COVERAGE }}
|
||||
npx nyc merge coverage-artifacts ${{ env.PATH_TO_COVERAGE }}/coverage-storybook.json
|
||||
- name: Checking coverage
|
||||
run: npx nx storybook:coverage twenty-front --checkCoverage=true --configuration=${{ matrix.storybook_scope }}
|
||||
- name: Install Playwright
|
||||
run: cd packages/twenty-front && npx playwright install
|
||||
- name: Front / Write .env
|
||||
run: npx nx reset:env twenty-front
|
||||
- name: Run storybook tests
|
||||
run: npx nx storybook:serve-and-test:static:performance twenty-front
|
||||
front-chromatic-deployment:
|
||||
timeout-minutes: 30
|
||||
if: contains(github.event.pull_request.labels.*.name, 'run-chromatic') || github.event_name == 'push'
|
||||
needs: front-sb-build
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
REACT_APP_SERVER_BASE_URL: http://127.0.0.1:3000
|
||||
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
@@ -135,10 +95,11 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Restore storybook build cache
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
- name: Front / Restore Storybook Task Cache
|
||||
uses: ./.github/workflows/actions/task-cache
|
||||
with:
|
||||
key: ${{ env.STORYBOOK_BUILD_CACHE_KEY }}
|
||||
tag: scope:frontend
|
||||
tasks: storybook:build
|
||||
- name: Front / Write .env
|
||||
run: |
|
||||
cd packages/twenty-front
|
||||
@@ -147,13 +108,9 @@ jobs:
|
||||
- name: Publish to Chromatic
|
||||
run: npx nx run twenty-front:chromatic:ci
|
||||
front-task:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
TASK_CACHE_KEY: front-task-${{ matrix.task }}
|
||||
strategy:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
@@ -168,11 +125,11 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Restore ${{ matrix.task }} cache
|
||||
id: restore-task-cache
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
- name: Front / Restore ${{ matrix.task }} task cache
|
||||
uses: ./.github/workflows/actions/task-cache
|
||||
with:
|
||||
key: ${{ env.TASK_CACHE_KEY }}
|
||||
tag: scope:frontend
|
||||
tasks: ${{ matrix.task }}
|
||||
- name: Reset .env
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
@@ -182,25 +139,4 @@ jobs:
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
tag: scope:frontend
|
||||
tasks: ${{ matrix.task }}
|
||||
- name: Save ${{ matrix.task }} cache
|
||||
uses: ./.github/workflows/actions/save-cache
|
||||
with:
|
||||
key: ${{ steps.restore-task-cache.outputs.cache-primary-key }}
|
||||
ci-front-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
needs:
|
||||
[
|
||||
changed-files-check,
|
||||
front-task,
|
||||
front-chromatic-deployment,
|
||||
merge-reports-and-check-coverage,
|
||||
front-sb-test,
|
||||
front-sb-build,
|
||||
]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
tasks: ${{ matrix.task }}
|
||||
@@ -15,7 +15,6 @@ on:
|
||||
|
||||
jobs:
|
||||
create_pr:
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -6,7 +6,6 @@ on:
|
||||
|
||||
jobs:
|
||||
tag_and_release:
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release')
|
||||
steps:
|
||||
|
||||
@@ -3,51 +3,32 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-server/**'
|
||||
- 'packages/twenty-emails/**'
|
||||
pull_request:
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-server/**'
|
||||
- 'packages/twenty-emails/**'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVER_SETUP_CACHE_KEY: server-setup
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
package.json
|
||||
packages/twenty-server/**
|
||||
packages/twenty-emails/**
|
||||
packages/twenty-shared/**
|
||||
server-setup:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
server-test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
image: twentycrm/twenty-postgres
|
||||
env:
|
||||
PGUSER_SUPERUSER: postgres
|
||||
PGPASSWORD_SUPERUSER: postgres
|
||||
ALLOW_NOSSL: 'true'
|
||||
SPILO_PROVIDER: 'local'
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
@@ -55,167 +36,23 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Restore server setup
|
||||
id: restore-server-setup-cache
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
- name: Server / Restore Tasks Cache
|
||||
uses: ./.github/workflows/actions/task-cache
|
||||
with:
|
||||
key: ${{ env.SERVER_SETUP_CACHE_KEY }}
|
||||
- name: Build twenty-shared
|
||||
run: npx nx build twenty-shared
|
||||
tag: scope:backend
|
||||
- name: Server / Run lint & typecheck
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
tag: scope:backend
|
||||
tasks: lint,typecheck
|
||||
- name: Server / Build
|
||||
run: npx nx build twenty-server
|
||||
- name: Server / Write .env
|
||||
run: npx nx reset:env twenty-server
|
||||
- name: Server / Create DB
|
||||
run: |
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
|
||||
npx nx run twenty-server:database:init:prod
|
||||
npx nx run twenty-server:database:migrate:prod
|
||||
- name: Worker / Run
|
||||
run: |
|
||||
timeout 30s npx nx run twenty-server:worker || exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
# If timeout was reached (exit code 124), consider it a success
|
||||
exit 0
|
||||
elif [ $exit_code -ne 0 ]; then
|
||||
# If worker failed for other reasons, fail the build
|
||||
exit $exit_code
|
||||
fi
|
||||
- name: Server / Check for Pending Migrations
|
||||
run: |
|
||||
METADATA_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate metadata-migration-check -d src/database/typeorm/metadata/metadata.datasource.ts || true)
|
||||
|
||||
CORE_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate core-migration-check -d src/database/typeorm/core/core.datasource.ts || true)
|
||||
|
||||
METADATA_MIGRATION_FILE=$(ls packages/twenty-server/*metadata-migration-check.ts 2>/dev/null || echo "")
|
||||
CORE_MIGRATION_FILE=$(ls packages/twenty-server/*core-migration-check.ts 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$METADATA_MIGRATION_FILE" ] || [ -n "$CORE_MIGRATION_FILE" ]; then
|
||||
echo "::error::Unexpected migration files were generated. Please create a proper migration manually."
|
||||
echo "$METADATA_MIGRATION_OUTPUT"
|
||||
echo "$CORE_MIGRATION_OUTPUT"
|
||||
|
||||
rm -f packages/twenty-server/*metadata-migration-check.ts packages/twenty-server/*core-migration-check.ts
|
||||
|
||||
exit 1
|
||||
fi
|
||||
- name: GraphQL / Check for Pending Generation
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
GRAPHQL_GENERATE_OUTPUT=$(npx nx run twenty-front:graphql:generate || true)
|
||||
GRAPHQL_METADATA_OUTPUT=$(npx nx run twenty-front:graphql:generate --configuration=metadata || true)
|
||||
if [[ $GRAPHQL_GENERATE_OUTPUT == *"No changes detected"* && $GRAPHQL_METADATA_OUTPUT == *"No changes detected"* ]]; then
|
||||
echo "GraphQL generation check passed."
|
||||
else
|
||||
echo "::error::Unexpected GraphQL changes detected. Please run the required commands and commit the changes."
|
||||
echo "$GRAPHQL_GENERATE_OUTPUT"
|
||||
echo "$GRAPHQL_METADATA_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
- name: Save server setup
|
||||
uses: ./.github/workflows/actions/save-cache
|
||||
with:
|
||||
key: ${{ steps.restore-server-setup-cache.outputs.cache-primary-key }}
|
||||
|
||||
server-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
needs: server-setup
|
||||
env:
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Restore server setup
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
with:
|
||||
key: ${{ env.SERVER_SETUP_CACHE_KEY }}
|
||||
- name: Server / Run Tests
|
||||
- name: Server / Run tests
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
tag: scope:backend
|
||||
tasks: test
|
||||
|
||||
server-integration-test:
|
||||
timeout-minutes: 30
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
needs: server-setup
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
env:
|
||||
PGUSER_SUPERUSER: postgres
|
||||
PGPASSWORD_SUPERUSER: postgres
|
||||
ALLOW_NOSSL: 'true'
|
||||
SPILO_PROVIDER: 'local'
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
env:
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Update .env.test for billing
|
||||
run: |
|
||||
echo "IS_BILLING_ENABLED=true" >> .env.test
|
||||
echo "BILLING_STRIPE_API_KEY=test-api-key" >> .env.test
|
||||
echo "BILLING_STRIPE_BASE_PLAN_PRODUCT_ID=test-base-plan-product-id" >> .env.test
|
||||
echo "BILLING_STRIPE_WEBHOOK_SECRET=test-webhook-secret" >> .env.test
|
||||
- name: Restore server setup
|
||||
uses: ./.github/workflows/actions/restore-cache
|
||||
with:
|
||||
key: ${{ env.SERVER_SETUP_CACHE_KEY }}
|
||||
- name: Server / Build
|
||||
run: npx nx build twenty-server
|
||||
- name: Build dependencies
|
||||
run: |
|
||||
npx nx build twenty-shared
|
||||
npx nx build twenty-emails
|
||||
- name: Server / Create Test DB
|
||||
env:
|
||||
NODE_ENV: test
|
||||
run: |
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
|
||||
- name: Server / Run Integration Tests
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
tag: scope:backend
|
||||
tasks: 'test:integration:with-db-reset'
|
||||
- name: Server / Upload reset-logs file
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: reset-logs
|
||||
path: reset-logs.log
|
||||
ci-server-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: depot-ubuntu-24.04-8
|
||||
needs: [changed-files-check, server-setup, server-test, server-integration-test]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
- name: Server / Write .env
|
||||
run: npx nx reset:env twenty-server
|
||||
- name: Worker / Run
|
||||
run: MESSAGE_QUEUE_TYPE=sync npx nx worker twenty-server
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
name: CI Shared
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
packages/twenty-shared/**
|
||||
shared-test:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
|
||||
strategy:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Run ${{ matrix.task }} task
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
tag: scope:frontend
|
||||
tasks: ${{ matrix.task }}
|
||||
ci-shared-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changed-files-check, shared-test]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
@@ -1,97 +1,59 @@
|
||||
name: 'Test Docker Compose'
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
paths:
|
||||
- 'packages/twenty-docker/**'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
packages/twenty-docker/**
|
||||
docker-compose.yml
|
||||
test:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Run compose
|
||||
run: |
|
||||
echo "Patching docker-compose.yml..."
|
||||
# change image to localbuild using yq
|
||||
yq eval 'del(.services.server.image)' -i docker-compose.yml
|
||||
yq eval '.services.server.build.context = "../../"' -i docker-compose.yml
|
||||
yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i docker-compose.yml
|
||||
yq eval '.services.server.restart = "no"' -i docker-compose.yml
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
yq eval 'del(.services.db.image)' -i docker-compose.yml
|
||||
yq eval '.services.db.build.context = "../../"' -i docker-compose.yml
|
||||
yq eval '.services.db.build.dockerfile = "./packages/twenty-docker/twenty-postgres-spilo/Dockerfile"' -i docker-compose.yml
|
||||
- name: Run compose
|
||||
run: |
|
||||
echo "Patching docker-compose.yml..."
|
||||
# change image to localbuild using yq
|
||||
yq eval 'del(.services.server.image)' -i docker-compose.yml
|
||||
yq eval '.services.server.build.context = "../../"' -i docker-compose.yml
|
||||
yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i docker-compose.yml
|
||||
yq eval '.services.server.restart = "no"' -i docker-compose.yml
|
||||
|
||||
echo "Setting up .env file..."
|
||||
cp .env.example .env
|
||||
echo "Generating secrets..."
|
||||
echo "# === Randomly generated secrets ===" >>.env
|
||||
echo "APP_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "PGPASSWORD_SUPERUSER=$(openssl rand -hex 16)" >>.env
|
||||
yq eval 'del(.services.db.image)' -i docker-compose.yml
|
||||
yq eval '.services.db.build.context = "../../"' -i docker-compose.yml
|
||||
yq eval '.services.db.build.dockerfile = "./packages/twenty-docker/twenty-postgres/Dockerfile"' -i docker-compose.yml
|
||||
|
||||
echo "Docker compose up..."
|
||||
docker compose up -d || {
|
||||
echo "Docker compose failed to start"
|
||||
docker compose logs
|
||||
exit 1
|
||||
}
|
||||
docker compose logs db server -f &
|
||||
pid=$!
|
||||
echo "Setting up .env file..."
|
||||
cp .env.example .env
|
||||
echo "Generating secrets..."
|
||||
echo "# === Randomly generated secrets ===" >>.env
|
||||
echo "ACCESS_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "LOGIN_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "REFRESH_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "FILE_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "POSTGRES_ADMIN_PASSWORD=$(openssl rand -base64 32)" >>.env
|
||||
|
||||
echo "Waiting for database to start..."
|
||||
count=0
|
||||
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-db-1) = "healthy" ]; do
|
||||
sleep 1;
|
||||
count=$((count+1));
|
||||
if [ $(docker inspect --format='{{.State.Status}}' twenty-db-1) = "exited" ]; then
|
||||
echo "Database exited"
|
||||
docker compose logs db
|
||||
exit 1
|
||||
fi
|
||||
if [ $count -gt 300 ]; then
|
||||
echo "Failed to start database after 5 minutes"
|
||||
docker compose logs db
|
||||
exit 1
|
||||
fi
|
||||
echo "Still waiting for database... (${count}/60)"
|
||||
done
|
||||
echo "Starting server..."
|
||||
docker compose up -d
|
||||
docker compose logs db server -f &
|
||||
pid=$!
|
||||
|
||||
echo "Waiting for server to start..."
|
||||
count=0
|
||||
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do
|
||||
sleep 1;
|
||||
count=$((count+1));
|
||||
if [ $(docker inspect --format='{{.State.Status}}' twenty-server-1) = "exited" ]; then
|
||||
echo "Server exited"
|
||||
docker compose logs server
|
||||
exit 1
|
||||
fi
|
||||
if [ $count -gt 300 ]; then
|
||||
echo "Failed to start server after 5 minutes"
|
||||
docker compose logs server
|
||||
exit 1
|
||||
fi
|
||||
echo "Still waiting for server... (${count}/300s)"
|
||||
done
|
||||
working-directory: ./packages/twenty-docker/
|
||||
ci-test-docker-compose-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changed-files-check, test]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
echo "Waiting for server to start..."
|
||||
count=0
|
||||
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do
|
||||
sleep 1;
|
||||
count=$((count+1));
|
||||
if [ $(docker inspect --format='{{.State.Status}}' twenty-server-1) = "exited" ]; then
|
||||
echo "Server exited"
|
||||
exit 1
|
||||
fi
|
||||
if [ $count -gt 300 ]; then
|
||||
echo "Failed to start server"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
working-directory: ./packages/twenty-docker/
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
name: CI Tinybird
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-tinybird/**'
|
||||
|
||||
pull_request:
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-tinybird/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
uses: tinybirdco/ci/.github/workflows/ci.yml@main
|
||||
with:
|
||||
data_project_dir: packages/twenty-tinybird
|
||||
secrets:
|
||||
tb_admin_token: ${{ secrets.TB_ADMIN_TOKEN }}
|
||||
tb_host: https://api.eu-central-1.aws.tinybird.co
|
||||
@@ -15,13 +15,10 @@ permissions:
|
||||
statuses: write
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
# We don't cancel in-progress because this workflow is triggered on
|
||||
# pull_request_target, which means the ref can be the same accross two PRs.
|
||||
# cancel-in-progress: true
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
danger-js:
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.action != 'closed'
|
||||
steps:
|
||||
@@ -34,7 +31,6 @@ jobs:
|
||||
DANGER_GITHUB_API_TOKEN: ${{ github.token }}
|
||||
|
||||
congratulate:
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.action == 'closed' && github.event.pull_request.merged == true
|
||||
steps:
|
||||
|
||||
@@ -3,65 +3,37 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-website/**'
|
||||
pull_request:
|
||||
|
||||
paths:
|
||||
- 'package.json'
|
||||
- 'packages/twenty-website/**'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changed-files-check:
|
||||
uses: ./.github/workflows/changed-files.yaml
|
||||
with:
|
||||
files: |
|
||||
package.json
|
||||
packages/twenty-website/**
|
||||
website-build:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
image: twentycrm/twenty-postgres
|
||||
env:
|
||||
PGUSER_SUPERUSER: postgres
|
||||
PGPASSWORD_SUPERUSER: postgres
|
||||
ALLOW_NOSSL: 'true'
|
||||
SPILO_PROVIDER: 'local'
|
||||
POSTGRES_PASSWORD: twenty
|
||||
POSTGRES_USER: twenty
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
|
||||
- name: Server / Create DB
|
||||
run: PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
|
||||
|
||||
- name: Website / Run migrations
|
||||
run: npx nx database:migrate twenty-website
|
||||
run: npx nx database:migrate twenty-website
|
||||
env:
|
||||
DATABASE_PG_URL: postgres://postgres:postgres@localhost:5432/default
|
||||
DATABASE_PG_URL: postgres://twenty:twenty@localhost:5432/default
|
||||
- name: Website / Build Website
|
||||
run: npx nx build twenty-website
|
||||
env:
|
||||
DATABASE_PG_URL: postgres://postgres:postgres@localhost:5432/default
|
||||
ci-website-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 1
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changed-files-check, website-build]
|
||||
steps:
|
||||
- name: Fail job if any needs failed
|
||||
if: contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
DATABASE_PG_URL: postgres://twenty:twenty@localhost:5432/default
|
||||
@@ -1,136 +0,0 @@
|
||||
# Pull down translations from Crowdin every two hours or when triggered manually.
|
||||
# When force_pull input is true, translations will be pulled regardless of compilation status.
|
||||
|
||||
name: 'Pull translations'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */2 * * *' # Every two hours.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
force_pull:
|
||||
description: 'Force pull translations regardless of compilation status'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
workflow_call:
|
||||
inputs:
|
||||
force_pull:
|
||||
description: 'Force pull translations regardless of compilation status'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
pull_translations:
|
||||
name: Pull translations
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: ${{ github.head_ref || github.ref_name }}
|
||||
|
||||
- name: Setup i18n branch
|
||||
run: |
|
||||
git fetch origin i18n || true
|
||||
git checkout -B i18n origin/i18n || git checkout -b i18n
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
|
||||
- name: Build twenty-shared
|
||||
run: npx nx build twenty-shared
|
||||
|
||||
# Strict mode fails if there are missing translations.
|
||||
- name: Compile translations
|
||||
id: compile_translations
|
||||
run: |
|
||||
npx nx run twenty-server:lingui:compile --strict
|
||||
npx nx run twenty-emails:lingui:compile --strict
|
||||
npx nx run twenty-front:lingui:compile --strict
|
||||
continue-on-error: true
|
||||
|
||||
- name: Stash any changes before pulling translations
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'github-actions@twenty.com'
|
||||
git add .
|
||||
git stash
|
||||
|
||||
- name: Pull translations from Crowdin
|
||||
if: inputs.force_pull || steps.compile_translations.outcome == 'failure'
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
export_only_approved: false
|
||||
localization_branch_name: i18n
|
||||
base_url: 'https://twenty.api.crowdin.com'
|
||||
auto_approve_imported: false
|
||||
import_eq_suggestions: false
|
||||
download_sources: false
|
||||
push_sources: false
|
||||
skip_untranslated_strings: false
|
||||
skip_untranslated_files: false
|
||||
push_translations: true
|
||||
create_pull_request: false
|
||||
skip_ref_checkout: true
|
||||
dryrun_action: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
CROWDIN_PROJECT_ID: '1'
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
|
||||
# As the files are extracted from a Docker container, they belong to root:root
|
||||
# We need to fix this before the next steps
|
||||
- name: Fix file permissions
|
||||
run: sudo chown -R runner:docker .
|
||||
|
||||
- name: Compile translations
|
||||
if: inputs.force_pull || steps.compile_translations.outcome == 'failure'
|
||||
run: |
|
||||
npx nx run twenty-server:lingui:compile
|
||||
npx nx run twenty-emails:lingui:compile
|
||||
npx nx run twenty-front:lingui:compile
|
||||
|
||||
- name: Debug git status
|
||||
run: git status
|
||||
|
||||
- name: Check and commit compiled files
|
||||
id: check_changes
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'github-actions@twenty.com'
|
||||
git add .
|
||||
if ! git diff --staged --quiet --exit-code; then
|
||||
git commit -m "chore: compile translations"
|
||||
echo "changes_detected=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changes_detected=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
if: steps.check_changes.outputs.changes_detected == 'true'
|
||||
run: git push origin HEAD:i18n
|
||||
|
||||
- name: Create pull request
|
||||
if: steps.check_changes.outputs.changes_detected == 'true'
|
||||
run: |
|
||||
if git diff --name-only origin/main..HEAD | grep -q .; then
|
||||
gh pr create -B main -H i18n --title 'i18n - translations' --body 'Created by Github action' || true
|
||||
else
|
||||
echo "No file differences between branches, skipping PR creation"
|
||||
fi
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,103 +0,0 @@
|
||||
name: 'Extract translations when there is a push to main, and upload them to Crowdin'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
push:
|
||||
branches: ['main']
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
extract_translations:
|
||||
name: Extract and upload translations
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: main
|
||||
|
||||
- name: Setup i18n branch
|
||||
run: |
|
||||
git fetch origin i18n || true
|
||||
git checkout -B i18n origin/i18n || git checkout -b i18n
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
|
||||
- name: Build dependencies
|
||||
run: npx nx build twenty-shared
|
||||
|
||||
- name: Extract translations
|
||||
run: |
|
||||
npx nx run twenty-server:lingui:extract
|
||||
npx nx run twenty-emails:lingui:extract
|
||||
npx nx run twenty-front:lingui:extract
|
||||
|
||||
- name: Check and commit extracted files
|
||||
id: check_extract_changes
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'github-actions@twenty.com'
|
||||
git add .
|
||||
if ! git diff --staged --quiet --exit-code; then
|
||||
git commit -m "chore: extract translations"
|
||||
echo "changes_detected=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changes_detected=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Compile translations
|
||||
run: |
|
||||
npx nx run twenty-server:lingui:compile
|
||||
npx nx run twenty-emails:lingui:compile
|
||||
npx nx run twenty-front:lingui:compile
|
||||
|
||||
- name: Check and commit compiled files
|
||||
id: check_compile_changes
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'github-actions@twenty.com'
|
||||
git add .
|
||||
if ! git diff --staged --quiet --exit-code; then
|
||||
git commit -m "chore: compile translations"
|
||||
echo "changes_detected=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changes_detected=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Push changes and create remote branch if needed
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true' || steps.check_compile_changes.outputs.changes_detected == 'true'
|
||||
run: git push origin HEAD:i18n
|
||||
|
||||
- name: Upload missing translations
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true'
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: true
|
||||
download_translations: false
|
||||
localization_branch_name: i18n
|
||||
base_url: 'https://twenty.api.crowdin.com'
|
||||
env:
|
||||
# A numeric ID, found at https://crowdin.com/project/<projectName>/tools/api
|
||||
CROWDIN_PROJECT_ID: 1
|
||||
|
||||
# Visit https://crowdin.com/settings#api-key to create this token
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
- name: Create a pull request
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true' || steps.check_compile_changes.outputs.changes_detected == 'true'
|
||||
run: |
|
||||
if git diff --name-only origin/main..HEAD | grep -q .; then
|
||||
gh pr create -B main -H i18n --title 'i18n - translations' --body 'Created by Github action' || true
|
||||
else
|
||||
echo "No file differences between branches, skipping PR creation"
|
||||
fi
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+1
-16
@@ -18,7 +18,6 @@
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
.vercel
|
||||
.swc
|
||||
|
||||
**/**/logs/**
|
||||
|
||||
@@ -27,19 +26,5 @@ dist
|
||||
storybook-static
|
||||
*.tsbuildinfo
|
||||
.eslintcache
|
||||
.cache
|
||||
.nyc_output
|
||||
test-results/
|
||||
dump.rdb
|
||||
.tinyb
|
||||
|
||||
.notes
|
||||
/data/
|
||||
/.devenv/
|
||||
/.direnv/
|
||||
/.pre-commit-config.yaml
|
||||
/.envrc
|
||||
/devenv.nix
|
||||
/flake.lock
|
||||
/flake.nix
|
||||
|
||||
.crowdin.yml
|
||||
Vendored
+1
-2
@@ -14,7 +14,6 @@
|
||||
"styled-components.vscode-styled-components",
|
||||
"unifiedjs.vscode-mdx",
|
||||
"xyc.vscode-mdx-preview",
|
||||
"yoavbls.pretty-ts-errors",
|
||||
"ms-playwright.playwright"
|
||||
"yoavbls.pretty-ts-errors"
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+7
-37
@@ -6,11 +6,12 @@
|
||||
"name": "twenty-server - start debug",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeExecutable": "yarn",
|
||||
"runtimeVersion": "18",
|
||||
"runtimeArgs": [
|
||||
"nx",
|
||||
"run",
|
||||
"twenty-server:start"
|
||||
"twenty-server:start",
|
||||
],
|
||||
"outputCapture": "std",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
@@ -21,11 +22,12 @@
|
||||
"name": "twenty-server - worker debug",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeExecutable": "yarn",
|
||||
"runtimeVersion": "18",
|
||||
"runtimeArgs": [
|
||||
"nx",
|
||||
"run",
|
||||
"twenty-server:worker"
|
||||
"twenty-server:worker",
|
||||
],
|
||||
"outputCapture": "std",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
@@ -43,44 +45,12 @@
|
||||
"run",
|
||||
"twenty-server:command",
|
||||
"my-command",
|
||||
"--my-parameter value"
|
||||
"--my-parameter value",
|
||||
],
|
||||
"outputCapture": "std",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"console": "internalConsole",
|
||||
"cwd": "${workspaceFolder}/packages/twenty-server/"
|
||||
},
|
||||
{
|
||||
"name": "Playwright Test current file",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeArgs": ["nx", "test", "twenty-e2e-testing", "${file}"],
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"envFile": "${workspaceFolder}/packages/twenty-e2e-testing/.env"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "twenty-server - debug integration test file (to launch with test file open)",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeArgs": [
|
||||
"nx",
|
||||
"run",
|
||||
"twenty-server:jest",
|
||||
"--",
|
||||
"--config",
|
||||
"./jest-integration.config.ts",
|
||||
"${relativeFile}"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/packages/twenty-server",
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"env": {
|
||||
"NODE_ENV": "test"
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+1
-6
@@ -45,10 +45,5 @@
|
||||
"search.exclude": {
|
||||
"**/.yarn": true,
|
||||
},
|
||||
"eslint.debug": true,
|
||||
"files.associations": {
|
||||
".cursorrules": "markdown"
|
||||
},
|
||||
"jestrunner.codeLensSelector": "**/*.{test,spec,integration-spec}.{js,jsx,ts,tsx}"
|
||||
}
|
||||
"eslint.debug": true
|
||||
}
|
||||
|
||||
Vendored
+2
-10
@@ -21,12 +21,8 @@
|
||||
"path": "../packages/twenty-ui"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-emails",
|
||||
"path": "../packages/twenty-emails"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-shared",
|
||||
"path": "../packages/twenty-shared"
|
||||
"name": "packages/twenty-postgres",
|
||||
"path": "../packages/twenty-postgres"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-server",
|
||||
@@ -44,10 +40,6 @@
|
||||
"name": "tools/eslint-rules",
|
||||
"path": "../tools/eslint-rules"
|
||||
},
|
||||
{
|
||||
"name": "packages/twenty-e2e-testing",
|
||||
"path": "../packages/twenty-e2e-testing"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"editor.formatOnSave": false,
|
||||
|
||||
+894
File diff suppressed because one or more lines are too long
Vendored
-925
File diff suppressed because one or more lines are too long
+1
-3
@@ -1,7 +1,5 @@
|
||||
enableHardenedMode: true
|
||||
|
||||
enableInlineHunks: true
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.4.0.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.3.1.cjs
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
|
||||
This project is mostly licensed under the GNU General Public License (GPL) as described below. However, certain files within this project are licensed under a different commercial license. These files are clearly marked with the following comment at the top of the file: /* @license Enterprise */
|
||||
Files with this comment are not licensed under the aGPL v3, but instead are subject to the commercial license terms defined later in this file.
|
||||
|
||||
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
@@ -664,47 +659,3 @@ specific requirements.
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
------------------------------------
|
||||
|
||||
|
||||
|
||||
The Twenty.com Commercial License (the “Commercial License”)
|
||||
Copyright (c) 2023-present Twenty.com, PBC
|
||||
|
||||
With regard to Twenty's Software:
|
||||
|
||||
This part of the software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the Terms available
|
||||
at https://twenty.com/legal/terms, or other agreements governing
|
||||
the use of the Software, as mutually agreed by you and Twenty.com, PBC ("Twenty"),
|
||||
and otherwise have a valid Twenty Enterprise Edition subscription
|
||||
for the correct number of hosts and seats as defined in the Commercial Terms.
|
||||
Subject to the foregoing sentence,
|
||||
you are free to modify this Software and publish patches to the Software. You agree
|
||||
that Twenty and/or its licensors (as applicable) retain all right, title and interest in
|
||||
and to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid Commercial Subscription for the correct number of hosts and seats.
|
||||
Notwithstanding the foregoing, you may copy and modify the Software for development
|
||||
and testing purposes, without requiring a subscription. You agree that Twenty.Com and/or
|
||||
its licensors (as applicable) retain all right, title and interest in and to all such
|
||||
modifications. You are not granted any other rights beyond what is expressly stated herein.
|
||||
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the Twenty Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
@@ -1,20 +1,26 @@
|
||||
postgres-on-docker:
|
||||
docker run -d \
|
||||
--name twenty_pg \
|
||||
-e PGUSER_SUPERUSER=postgres \
|
||||
-e PGPASSWORD_SUPERUSER=postgres \
|
||||
-e ALLOW_NOSSL=true \
|
||||
-v twenty_db_data:/home/postgres/pgdata \
|
||||
-p 5432:5432 \
|
||||
twentycrm/twenty-postgres-spilo:latest
|
||||
@echo "Waiting for PostgreSQL to be ready..."
|
||||
@until docker exec twenty_pg psql -U postgres -d postgres \
|
||||
-c 'SELECT pg_is_in_recovery();' 2>/dev/null | grep -q 'f'; do \
|
||||
sleep 1; \
|
||||
done
|
||||
docker exec twenty_pg psql -U postgres -d postgres \
|
||||
-c "CREATE DATABASE \"default\" WITH OWNER postgres;" \
|
||||
-c "CREATE DATABASE \"test\" WITH OWNER postgres;"
|
||||
docker-dev-build:
|
||||
make -C packages/twenty-docker dev-build
|
||||
|
||||
redis-on-docker:
|
||||
docker run -d --name twenty_redis -p 6379:6379 redis/redis-stack-server:latest
|
||||
docker-dev-up:
|
||||
make -C packages/twenty-docker dev-up
|
||||
|
||||
docker-dev-start:
|
||||
make -C packages/twenty-docker dev-start
|
||||
|
||||
docker-dev-stop:
|
||||
make -C packages/twenty-docker dev-stop
|
||||
|
||||
docker-dev-sh:
|
||||
make -C packages/twenty-docker dev-sh
|
||||
|
||||
postgres-on-docker:
|
||||
make -C packages/twenty-postgres provision-on-docker
|
||||
|
||||
postgres-on-macos-arm:
|
||||
make -C packages/twenty-postgres provision-on-macos-arm
|
||||
|
||||
postgres-on-macos-intel:
|
||||
make -C packages/twenty-postgres provision-on-macos-intel
|
||||
|
||||
postgres-on-linux:
|
||||
make -C packages/twenty-postgres provision-on-linux
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
</p>
|
||||
|
||||
<h2 align="center" >The #1 Open-Source CRM </h3>
|
||||
<p align="center">Tailored to your unique business needs</p>
|
||||
|
||||
<p align="center"><a href="https://twenty.com">🌐 Website</a> · <a href="https://twenty.com/developers">📚 Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website/public/images/readme/planner-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a><p>
|
||||
<p align="center"><a href="https://twenty.com">🌐 Website</a> · <a href="https://twenty.com/developers">📚 Documentation</a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a><p>
|
||||
<br />
|
||||
|
||||
|
||||
@@ -21,33 +22,44 @@
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
We’ve spent thousands of hours grappling with traditional CRMs like Pipedrive and Salesforce to align them with our business needs, only to end up frustrated — customizations are complex and the closed ecosystems of these platforms can feel restrictive.
|
||||
|
||||
We felt the need for a CRM platform that empowers rather than constrains. We believe the next great CRM will come from the open-source community. We’ve packed Twenty with powerful features to give you full control and help you run your business efficiently.
|
||||
|
||||
<br>
|
||||
|
||||
# Installation
|
||||
# Demo
|
||||
Go to <a href="https://demo.twenty.com/">demo.twenty.com</a> and login with the following credentials:
|
||||
```
|
||||
email: noah@demo.dev
|
||||
password: Applecar2025
|
||||
```
|
||||
|
||||
See:
|
||||
See also:
|
||||
🚀 [Self-hosting](https://twenty.com/developers/section/self-hosting)
|
||||
🖥️ [Local Setup](https://twenty.com/developers/local-setup)
|
||||
|
||||
# Does the world need another CRM?
|
||||
# Why Choose Twenty?
|
||||
We understand that the CRM landscape is vast. So why should you choose us?
|
||||
|
||||
We built Twenty for three reasons:
|
||||
⛓️ **Full control, Full Freedom:** Contribute, self-host, fork. Break free from vendor lock-in and join us in shaping the open future of CRM.
|
||||
|
||||
**CRMs are too expensive, and users are trapped.** Companies use locked-in customer data to hike prices. It shouldn't be that way.
|
||||
📊 **Data, Your Way:** The days when the role of CRM platforms was to shift manual data entries to a database are over. Now, the data is already there. CRM 2.0 should be built around your data, allowing you to access and visualize any existing sources, not forcing you to retrofit your data into predefined objects on a remote cloud.
|
||||
|
||||
**A fresh start is required to build a better experience.** We can learn from past mistakes and craft a cohesive experience inspired by new UX patterns from tools like Notion, Airtable or Linear.
|
||||
🎨 **Effortlessly Intuitive:** We set out to create something that we ourselves would always enjoy using. The main application draws inspiration from Notion, a tool known for its user-friendly interface and customization capabilities.
|
||||
<br>
|
||||
|
||||
**We believe in Open-source and community.** Hundreds of developers are already building Twenty together. Once we have plugin capabilities, a whole ecosystem will grow around it.
|
||||
|
||||
<br>
|
||||
|
||||
# What You Can Do With Twenty
|
||||
We're currently developing Twenty's beta version.
|
||||
We're currently in the development phase of Twenty's alpha version.
|
||||
|
||||
Please feel free to flag any specific needs you have by creating an issue.
|
||||
Please feel free to flag any specific need you have need by creating an issue.
|
||||
|
||||
Below are a few features we have implemented to date:
|
||||
Below are some features we have implemented to date:
|
||||
|
||||
+ [Add, filter, sort, edit, and track customers](#add-filter-sort-edit-and-track-customers)
|
||||
+ [Create one or several opportunities for each company](#create-one-or-several-opportunities-for-each-company)
|
||||
@@ -55,7 +67,6 @@ Below are a few features we have implemented to date:
|
||||
+ [Create tasks on records](#create-tasks-on-records)
|
||||
+ [Navigate quickly through the app using keyboard shortcuts and search](#navigate-quickly-through-the-app-using-keyboard-shortcuts-and-search)
|
||||
|
||||
|
||||
## Add, filter, sort, edit, and track customers:
|
||||
|
||||
<p align="center">
|
||||
@@ -136,27 +147,24 @@ Below are a few features we have implemented to date:
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
# Stack
|
||||
- [TypeScript](https://www.typescriptlang.org/)
|
||||
- [Nx](https://nx.dev/)
|
||||
- [NestJS](https://nestjs.com/), with [BullMQ](https://bullmq.io/), [PostgreSQL](https://www.postgresql.org/), [Redis](https://redis.io/)
|
||||
- [React](https://reactjs.org/), with [Recoil](https://recoiljs.org/) and [Emotion](https://emotion.sh/)
|
||||
- [Greptile](https://greptile.com) for code reviews.
|
||||
- [Lingui](https://lingui.dev/) and [Crowdin](https://twenty.crowdin.com/twenty) for translations.
|
||||
# What's In Store
|
||||
|
||||
Here’s what you can look forward to:
|
||||
|
||||
⏳ **Frequent updates:** We’re shipping fast! Expect regular updates and new features that enhance your experience.
|
||||
|
||||
🔗 **Extensibility:** We’re putting the power in your hands. Soon, you’ll have the tools to extend and customize Twenty with plugins and more.
|
||||
|
||||
<br>
|
||||
|
||||
# Join the Community
|
||||
|
||||
- Star the repo
|
||||
- Subscribe to releases (watch -> custom -> releases)
|
||||
- Join [discussions](https://github.com/twentyhq/twenty/discussions) and track [issues](https://github.com/twentyhq/twenty/issues)
|
||||
- Follow us on [Twitter](https://twitter.com/twentycrm) or [LinkedIn](https://www.linkedin.com/company/twenty/)
|
||||
- Join our [Discord](https://discord.gg/cx5n4Jzs57)
|
||||
- Improve translations on [Crowdin](https://twenty.crowdin.com/twenty)
|
||||
- [Contributions](https://github.com/twentyhq/twenty/contribute) are, of course, most welcome!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
#
|
||||
# Basic Crowdin CLI configuration
|
||||
# See https://crowdin.github.io/crowdin-cli/configuration for more information
|
||||
# See https://support.crowdin.com/developer/configuration-file/ for all available options
|
||||
#
|
||||
|
||||
#
|
||||
# Defines whether to preserve the original directory structure in the Crowdin project
|
||||
# Recommended to set to true
|
||||
#
|
||||
"preserve_hierarchy": true
|
||||
|
||||
#
|
||||
# Files configuration.
|
||||
# See https://support.crowdin.com/developer/configuration-file/ for all available options
|
||||
#
|
||||
files: [
|
||||
{
|
||||
#
|
||||
# Source files filter
|
||||
# e.g. "/resources/en/*.json"
|
||||
#
|
||||
"source": "**/en.po",
|
||||
|
||||
#
|
||||
# Translation files filter
|
||||
# e.g. "/resources/%two_letters_code%/%original_file_name%"
|
||||
#
|
||||
"translation": "%original_path%/%locale%.po",
|
||||
}
|
||||
]
|
||||
@@ -44,10 +44,10 @@ function on_exit {
|
||||
trap on_exit EXIT
|
||||
|
||||
# Use environment variables VERSION and BRANCH, with defaults if not set
|
||||
version=${VERSION:-$(curl -s "https://hub.docker.com/v2/repositories/twentycrm/twenty/tags" | grep -o '"name":"[^"]*"' | grep -v 'latest' | cut -d'"' -f4 | sort -V | tail -n1)}
|
||||
branch=${BRANCH:-$(curl -s https://api.github.com/repos/twentyhq/twenty/tags | grep '"name":' | head -n 1 | cut -d '"' -f 4)}
|
||||
version=${VERSION:-$(curl -s https://api.github.com/repos/twentyhq/twenty/releases/latest | grep '"tag_name":' | cut -d '"' -f 4)}
|
||||
branch=${BRANCH:-main}
|
||||
|
||||
echo "🚀 Using docker version $version and Github branch $branch"
|
||||
echo "🚀 Using version $version and branch $branch"
|
||||
|
||||
dir_name="twenty"
|
||||
function ask_directory {
|
||||
@@ -72,7 +72,7 @@ done
|
||||
echo "📁 Creating directory '$dir_name'"
|
||||
mkdir -p "$dir_name" && cd "$dir_name" || { echo "❌ Failed to create/access directory '$dir_name'"; exit 1; }
|
||||
|
||||
# Copy twenty/packages/twenty-docker/docker-compose.yml in it
|
||||
# Copy the twenty/packages/twenty-docker/docker-compose.yml file in it
|
||||
echo -e "\t• Copying docker-compose.yml"
|
||||
curl -sLo docker-compose.yml https://raw.githubusercontent.com/twentyhq/twenty/$branch/packages/twenty-docker/docker-compose.yml
|
||||
|
||||
@@ -90,11 +90,13 @@ else
|
||||
fi
|
||||
|
||||
# Generate random strings for secrets
|
||||
echo "# === Randomly generated secret ===" >> .env
|
||||
echo "APP_SECRET=$(openssl rand -base64 32)" >> .env
|
||||
|
||||
echo "" >> .env
|
||||
echo "PG_DATABASE_PASSWORD=$(openssl rand -hex 16)" >> .env
|
||||
echo "# === Randomly generated secrets ===" >>.env
|
||||
echo "ACCESS_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "LOGIN_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "REFRESH_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "FILE_TOKEN_SECRET=$(openssl rand -base64 32)" >>.env
|
||||
echo "" >>.env
|
||||
echo "POSTGRES_ADMIN_PASSWORD=$(openssl rand -base64 32)" >>.env
|
||||
|
||||
echo -e "\t• .env configuration completed"
|
||||
|
||||
@@ -110,10 +112,8 @@ if command -v nc &> /dev/null; then
|
||||
read -p "Enter a new port number: " new_port
|
||||
if [[ $(uname) == "Darwin" ]]; then
|
||||
sed -i '' "s/$port:$port/$new_port:$port/g" docker-compose.yml
|
||||
sed -E -i '' "s|^SERVER_URL=http://localhost:[0-9]+|SERVER_URL=http://localhost:$new_port|g" .env
|
||||
else
|
||||
sed -i'' "s/$port:$port/$new_port:$port/g" docker-compose.yml
|
||||
sed -E -i'' "s|^SERVER_URL=http://localhost:[0-9]+|SERVER_URL=http://localhost:$new_port|g" .env
|
||||
fi
|
||||
port=$new_port
|
||||
done
|
||||
@@ -14,7 +14,6 @@
|
||||
"!{projectRoot}/**/tsconfig.spec.json",
|
||||
"!{projectRoot}/**/*.test.(ts|tsx)",
|
||||
"!{projectRoot}/**/*.spec.(ts|tsx)",
|
||||
"!{projectRoot}/**/*.integration-spec.ts",
|
||||
"!{projectRoot}/**/__tests__/*"
|
||||
],
|
||||
"production": [
|
||||
@@ -48,8 +47,7 @@
|
||||
"configurations": {
|
||||
"ci": { "cacheStrategy": "content" },
|
||||
"fix": { "fix": true }
|
||||
},
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"executor": "nx:run-commands",
|
||||
@@ -65,8 +63,7 @@
|
||||
"configurations": {
|
||||
"ci": { "cacheStrategy": "content" },
|
||||
"fix": { "write": true }
|
||||
},
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
},
|
||||
"typecheck": {
|
||||
"executor": "nx:run-commands",
|
||||
@@ -77,8 +74,7 @@
|
||||
},
|
||||
"configurations": {
|
||||
"watch": { "watch": true }
|
||||
},
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
@@ -112,15 +108,15 @@
|
||||
"storybook:build": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": true,
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": ["^default", "excludeTests"],
|
||||
"outputs": ["{projectRoot}/{options.output-dir}"],
|
||||
"options": {
|
||||
"cwd": "{projectRoot}",
|
||||
"command": "VITE_DISABLE_TYPESCRIPT_CHECKER=true VITE_DISABLE_ESLINT_CHECKER=true storybook build --test",
|
||||
"command": "storybook build",
|
||||
"output-dir": "storybook-static",
|
||||
"config-dir": ".storybook"
|
||||
},
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
},
|
||||
"storybook:serve:dev": {
|
||||
"executor": "nx:run-commands",
|
||||
@@ -152,14 +148,12 @@
|
||||
"options": {
|
||||
"cwd": "{projectRoot}",
|
||||
"commands": [
|
||||
"test-storybook --url http://localhost:{args.port} --maxWorkers=3 --coverage --coverageDirectory={args.coverageDir} --shard={args.shard}",
|
||||
"nx storybook:coverage {projectName} --coverageDir={args.coverageDir} --checkCoverage={args.checkCoverage}"
|
||||
"test-storybook --url http://localhost:{args.port} --maxWorkers=3 --coverage --coverageDirectory={args.coverageDir}",
|
||||
"nx storybook:coverage {projectName} --coverageDir={args.coverageDir}"
|
||||
],
|
||||
"shard": "1/1",
|
||||
"parallel": false,
|
||||
"coverageDir": "coverage/storybook",
|
||||
"port": 6006,
|
||||
"checkCoverage": true
|
||||
"port": 6006
|
||||
}
|
||||
},
|
||||
"storybook:test:no-coverage": {
|
||||
@@ -186,10 +180,9 @@
|
||||
"!{projectRoot}/coverage/storybook/coverage-storybook.json"
|
||||
],
|
||||
"options": {
|
||||
"command": "npx nyc report --reporter={args.reporter} --reporter=text-summary -t {args.coverageDir} --report-dir {args.coverageDir} --check-coverage={args.checkCoverage} --cwd={projectRoot}",
|
||||
"command": "npx nyc report --reporter={args.reporter} --reporter=text-summary -t {args.coverageDir} --report-dir {args.coverageDir} --check-coverage --cwd={projectRoot}",
|
||||
"coverageDir": "coverage/storybook",
|
||||
"reporter": "lcov",
|
||||
"checkCoverage": true
|
||||
"reporter": "lcov"
|
||||
},
|
||||
"configurations": {
|
||||
"text": { "reporter": "text" }
|
||||
@@ -199,10 +192,17 @@
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:serve:static {projectName} --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --shard={args.shard} --checkCoverage={args.checkCoverage} --port={args.port} --configuration={args.scope}'"
|
||||
"npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:serve:static {projectName} --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port}'"
|
||||
],
|
||||
"port": 6006
|
||||
}
|
||||
},
|
||||
"storybook:serve-and-test:static:performance": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:serve:dev {projectName} --configuration=performance --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test:no-coverage {projectName} --port={args.port} --configuration=performance'"
|
||||
],
|
||||
"shard": "1/1",
|
||||
"checkCoverage": true,
|
||||
"port": 6006
|
||||
}
|
||||
},
|
||||
|
||||
+39
-47
@@ -5,13 +5,16 @@
|
||||
"@apollo/server": "^4.7.3",
|
||||
"@aws-sdk/client-lambda": "^3.614.0",
|
||||
"@aws-sdk/client-s3": "^3.363.0",
|
||||
"@aws-sdk/client-sts": "^3.744.0",
|
||||
"@aws-sdk/credential-providers": "^3.363.0",
|
||||
"@blocknote/mantine": "^0.22.0",
|
||||
"@blocknote/react": "^0.22.0",
|
||||
"@blocknote/server-util": "0.17.1",
|
||||
"@blocknote/core": "^0.15.3",
|
||||
"@blocknote/mantine": "^0.15.3",
|
||||
"@blocknote/react": "^0.15.3",
|
||||
"@chakra-ui/accordion": "^2.3.0",
|
||||
"@chakra-ui/system": "^2.6.0",
|
||||
"@codesandbox/sandpack-react": "^2.13.5",
|
||||
"@dagrejs/dagre": "^1.1.2",
|
||||
"@docusaurus/core": "^3.1.0",
|
||||
"@docusaurus/preset-classic": "^3.1.0",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@envelop/on-resolve": "^4.1.0",
|
||||
@@ -24,10 +27,7 @@
|
||||
"@jsdevtools/rehype-toc": "^3.0.2",
|
||||
"@linaria/core": "^6.2.0",
|
||||
"@linaria/react": "^6.2.1",
|
||||
"@lingui/core": "^5.1.2",
|
||||
"@lingui/react": "^5.1.2",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||
"@nestjs/apollo": "^11.0.5",
|
||||
"@nestjs/axios": "^3.0.1",
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
@@ -39,19 +39,23 @@
|
||||
"@nestjs/passport": "^9.0.3",
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@nestjs/serve-static": "^4.0.1",
|
||||
"@nestjs/terminus": "^11.0.0",
|
||||
"@nestjs/terminus": "^9.2.2",
|
||||
"@nestjs/typeorm": "^10.0.0",
|
||||
"@nivo/calendar": "^0.84.0",
|
||||
"@nivo/core": "^0.84.0",
|
||||
"@nx/eslint-plugin": "^17.2.8",
|
||||
"@octokit/graphql": "^7.0.2",
|
||||
"@ptc-org/nestjs-query-core": "^4.2.0",
|
||||
"@ptc-org/nestjs-query-typeorm": "4.2.1-alpha.2",
|
||||
"@react-email/components": "0.0.32",
|
||||
"@react-email/render": "0.0.17",
|
||||
"@sentry/node": "^8",
|
||||
"@sentry/profiling-node": "^8",
|
||||
"@sentry/react": "^8",
|
||||
"@react-email/components": "0.0.12",
|
||||
"@react-email/render": "0.0.10",
|
||||
"@sentry/node": "^7.99.0",
|
||||
"@sentry/profiling-node": "^1.3.4",
|
||||
"@sentry/react": "^7.88.0",
|
||||
"@sentry/tracing": "^7.99.0",
|
||||
"@sniptt/guards": "^0.2.0",
|
||||
"@stoplight/elements": "^8.0.5",
|
||||
"@storybook/icons": "^1.2.9",
|
||||
"@swc/jest": "^0.2.29",
|
||||
"@tabler/icons-react": "^2.44.0",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
@@ -63,37 +67,37 @@
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/passport-microsoft": "^1.0.3",
|
||||
"@wyw-in-js/vite": "^0.5.3",
|
||||
"@xyflow/react": "^12.4.2",
|
||||
"add": "^2.0.6",
|
||||
"addressparser": "^1.0.1",
|
||||
"afterframe": "^1.0.2",
|
||||
"apollo-server-express": "^3.12.0",
|
||||
"apollo-upload-client": "^17.0.0",
|
||||
"archiver": "^7.0.1",
|
||||
"aws-sdk": "^2.1658.0",
|
||||
"axios": "^1.6.2",
|
||||
"bcrypt": "^5.1.1",
|
||||
"better-sqlite3": "^9.2.2",
|
||||
"body-parser": "^1.20.2",
|
||||
"bullmq": "^5.40.0",
|
||||
"bullmq": "^4.14.0",
|
||||
"bytes": "^3.1.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cron-validate": "^1.4.5",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^7.1.2",
|
||||
"danger-plugin-todos": "^1.3.1",
|
||||
"dataloader": "^2.2.2",
|
||||
"date-fns": "^2.30.0",
|
||||
"date-fns-tz": "^2.0.0",
|
||||
"debounce": "^2.0.0",
|
||||
"deep-equal": "^2.2.2",
|
||||
"docusaurus-node-polyfills": "^1.0.0",
|
||||
"dompurify": "^3.0.11",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"drizzle-orm": "^0.29.3",
|
||||
"esbuild-plugin-svgr": "^2.1.0",
|
||||
"facepaint": "^1.2.1",
|
||||
"file-type": "16.5.4",
|
||||
"framer-motion": "^11.18.0",
|
||||
"framer-motion": "^10.12.17",
|
||||
"fs-extra": "^11.2.0",
|
||||
"googleapis": "105",
|
||||
"graphiql": "^3.1.1",
|
||||
"graphql": "16.8.0",
|
||||
@@ -119,7 +123,6 @@
|
||||
"lodash.chunk": "^4.2.0",
|
||||
"lodash.compact": "^3.0.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.escaperegexp": "^4.1.2",
|
||||
"lodash.groupby": "^4.6.0",
|
||||
"lodash.identity": "^3.0.0",
|
||||
"lodash.isempty": "^4.4.0",
|
||||
@@ -167,13 +170,14 @@
|
||||
"react-hotkeys-hook": "^4.4.4",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-imask": "^7.6.0",
|
||||
"react-intersection-observer": "^9.15.1",
|
||||
"react-intersection-observer": "^9.5.2",
|
||||
"react-loading-skeleton": "^3.3.1",
|
||||
"react-phone-number-input": "^3.3.4",
|
||||
"react-responsive": "^9.0.2",
|
||||
"react-router-dom": "^6.4.4",
|
||||
"react-textarea-autosize": "^8.4.1",
|
||||
"react-tooltip": "^5.13.1",
|
||||
"reactflow": "^11.11.3",
|
||||
"recoil": "^0.7.7",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-behead": "^3.1.0",
|
||||
@@ -183,12 +187,12 @@
|
||||
"scroll-into-view": "^1.16.2",
|
||||
"semver": "^7.5.4",
|
||||
"sharp": "^0.32.1",
|
||||
"slash": "^5.1.0",
|
||||
"stripe": "^17.3.1",
|
||||
"stripe": "^14.17.0",
|
||||
"ts-key-enum": "^2.0.12",
|
||||
"tslib": "^2.3.0",
|
||||
"tsup": "^8.2.4",
|
||||
"tsup": "^8.0.1",
|
||||
"type-fest": "4.10.1",
|
||||
"typeorm": "^0.3.20",
|
||||
"typescript": "5.3.3",
|
||||
"use-context-selector": "^2.0.0",
|
||||
"use-debounce": "^10.0.0",
|
||||
@@ -202,15 +206,13 @@
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.24.6",
|
||||
"@crxjs/vite-plugin": "^1.0.14",
|
||||
"@docusaurus/module-type-aliases": "^3.1.0",
|
||||
"@docusaurus/tsconfig": "3.1.0",
|
||||
"@graphql-codegen/cli": "^3.3.1",
|
||||
"@graphql-codegen/client-preset": "^4.1.0",
|
||||
"@graphql-codegen/typescript": "^3.0.4",
|
||||
"@graphql-codegen/typescript-operations": "^3.0.4",
|
||||
"@graphql-codegen/typescript-react-apollo": "^3.3.7",
|
||||
"@lingui/cli": "^5.1.2",
|
||||
"@lingui/swc-plugin": "^5.1.0",
|
||||
"@lingui/vite-plugin": "^5.1.2",
|
||||
"@microsoft/microsoft-graph-types": "^2.40.0",
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
"@nestjs/schematics": "^9.0.0",
|
||||
"@nestjs/testing": "^9.0.0",
|
||||
@@ -223,7 +225,6 @@
|
||||
"@nx/storybook": "18.3.3",
|
||||
"@nx/vite": "18.3.3",
|
||||
"@nx/web": "18.3.3",
|
||||
"@playwright/test": "^1.46.0",
|
||||
"@sentry/types": "^7.109.0",
|
||||
"@storybook/addon-actions": "^7.6.3",
|
||||
"@storybook/addon-coverage": "^1.0.0",
|
||||
@@ -233,7 +234,6 @@
|
||||
"@storybook/addon-onboarding": "^1.0.10",
|
||||
"@storybook/blocks": "^7.6.3",
|
||||
"@storybook/core-server": "7.6.3",
|
||||
"@storybook/icons": "^1.2.9",
|
||||
"@storybook/jest": "^0.2.3",
|
||||
"@storybook/react": "^7.6.3",
|
||||
"@storybook/react-vite": "^7.6.3",
|
||||
@@ -243,7 +243,7 @@
|
||||
"@stylistic/eslint-plugin": "^1.5.0",
|
||||
"@swc-node/register": "1.8.0",
|
||||
"@swc/cli": "^0.3.12",
|
||||
"@swc/core": "1.7.42",
|
||||
"@swc/core": "~1.3.100",
|
||||
"@swc/helpers": "~0.5.2",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "14.0.0",
|
||||
@@ -255,15 +255,13 @@
|
||||
"@types/chrome": "^0.0.267",
|
||||
"@types/deep-equal": "^1.0.1",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/graphql-fields": "^1.3.6",
|
||||
"@types/graphql-upload": "^8.0.12",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/js-cookie": "^3.0.3",
|
||||
"@types/js-levenshtein": "^1.1.3",
|
||||
"@types/lodash.camelcase": "^4.3.7",
|
||||
"@types/lodash.compact": "^3.0.9",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/lodash.escaperegexp": "^4.1.9",
|
||||
"@types/lodash.groupby": "^4.6.9",
|
||||
"@types/lodash.identity": "^3.0.9",
|
||||
"@types/lodash.isempty": "^4.4.7",
|
||||
@@ -280,7 +278,6 @@
|
||||
"@types/node": "18.19.26",
|
||||
"@types/passport-google-oauth20": "^2.0.11",
|
||||
"@types/passport-jwt": "^3.0.8",
|
||||
"@types/pluralize": "^0.0.33",
|
||||
"@types/react": "^18.2.39",
|
||||
"@types/react-datepicker": "^6.2.0",
|
||||
"@types/react-dom": "^18.2.15",
|
||||
@@ -299,16 +296,14 @@
|
||||
"danger": "^11.3.0",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"drizzle-kit": "^0.20.14",
|
||||
"esbuild": "^0.23.0",
|
||||
"esbuild": "^0.20.2",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||
"eslint-plugin-lingui": "^0.9.0",
|
||||
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||
"eslint-plugin-prettier": "^5.1.2",
|
||||
"eslint-plugin-project-structure": "^3.9.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.4",
|
||||
@@ -325,7 +320,7 @@
|
||||
"msw": "^2.0.11",
|
||||
"msw-storybook-addon": "2.0.0--canary.122.b3ed3b1.0",
|
||||
"nx": "18.3.3",
|
||||
"playwright": "^1.46.0",
|
||||
"playwright": "^1.40.1",
|
||||
"prettier": "^3.1.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rimraf": "^5.0.5",
|
||||
@@ -333,14 +328,14 @@
|
||||
"storybook": "^7.6.3",
|
||||
"storybook-addon-cookie": "^3.2.0",
|
||||
"storybook-addon-pseudo-states": "^2.1.2",
|
||||
"storybook-dark-mode": "^3.0.3",
|
||||
"storybook-dark-mode": "^4.0.1",
|
||||
"supertest": "^6.1.3",
|
||||
"ts-jest": "^29.1.1",
|
||||
"ts-loader": "^9.2.3",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.17.0",
|
||||
"vite": "^5.4.0",
|
||||
"tsx": "^4.7.2",
|
||||
"vite": "^5.0.0",
|
||||
"vite-plugin-checker": "^0.6.2",
|
||||
"vite-plugin-dts": "3.8.1",
|
||||
"vite-plugin-svgr": "^4.2.0",
|
||||
@@ -353,17 +348,16 @@
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"name": "twenty",
|
||||
"packageManager": "yarn@4.4.0",
|
||||
"packageManager": "yarn@4.3.1",
|
||||
"resolutions": {
|
||||
"graphql": "16.8.0",
|
||||
"type-fest": "4.10.1",
|
||||
"typescript": "5.3.3",
|
||||
"prosemirror-model": "1.23.0"
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"version": "0.2.1",
|
||||
"nx": {},
|
||||
"scripts": {
|
||||
"start": "npx concurrently --kill-others 'npx nx run-many -t start -p twenty-server twenty-front' 'npx wait-on tcp:3000 && npx nx run twenty-server:worker'"
|
||||
"start": "npx nx run-many -t start -p twenty-server twenty-front"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
@@ -375,8 +369,6 @@
|
||||
"packages/twenty-utils",
|
||||
"packages/twenty-zapier",
|
||||
"packages/twenty-website",
|
||||
"packages/twenty-e2e-testing",
|
||||
"packages/twenty-shared",
|
||||
"tools/eslint-rules"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,8 +6,5 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "npx vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-shared": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "{projectRoot}/dist"
|
||||
},
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
},
|
||||
"start": {
|
||||
"executor": "nx:run-commands",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
// Open options page programmatically in a new tab.
|
||||
// chrome.runtime.onInstalled.addListener((details) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
interface CustomDiv extends HTMLDivElement {
|
||||
onClickHandler: (newHandler: () => void) => void;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { createDefaultButton } from '~/contentScript/createButton';
|
||||
import changeSidePanelUrl from '~/contentScript/utils/changeSidepanelUrl';
|
||||
import extractCompanyLinkedinLink from '~/contentScript/utils/extractCompanyLinkedinLink';
|
||||
import extractDomain from '~/contentScript/utils/extractDomain';
|
||||
import { createCompany, fetchCompany } from '~/db/company.db';
|
||||
import { CompanyInput } from '~/db/types/company.types';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const checkIfCompanyExists = async () => {
|
||||
const { tab: activeTab } = await chrome.runtime.sendMessage({
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { createDefaultButton } from '~/contentScript/createButton';
|
||||
import changeSidePanelUrl from '~/contentScript/utils/changeSidepanelUrl';
|
||||
import extractFirstAndLastName from '~/contentScript/utils/extractFirstAndLastName';
|
||||
import { createPerson, fetchPerson } from '~/db/person.db';
|
||||
import { PersonInput } from '~/db/types/person.types';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const checkIfPersonExists = async () => {
|
||||
const { tab: activeTab } = await chrome.runtime.sendMessage({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { insertButtonForCompany } from '~/contentScript/extractCompanyProfile';
|
||||
import { insertButtonForPerson } from '~/contentScript/extractPersonProfile';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
// Inject buttons into the DOM when SPA is reloaded on the resource url.
|
||||
// e.g. reload the page when on https://www.linkedin.com/in/mabdullahabaid/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const btn = document.getElementById('twenty-settings-btn');
|
||||
if (!isDefined(btn)) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const changeSidePanelUrl = async (url: string) => {
|
||||
if (isDefined(url)) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// Extract "https://www.linkedin.com/company/twenty/" from any of the following urls, which the user can visit while on the company page.
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
// "https://www.linkedin.com/company/twenty/" "https://www.linkedin.com/company/twenty/about/" "https://www.linkedin.com/company/twenty/people/".
|
||||
const extractCompanyLinkedinLink = (activeTabUrl: string) => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import {
|
||||
ExchangeAuthCodeInput,
|
||||
ExchangeAuthCodeResponse,
|
||||
Tokens,
|
||||
} from '~/db/types/auth.types';
|
||||
import { EXCHANGE_AUTHORIZATION_CODE } from '~/graphql/auth/mutations';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { callMutation } from '~/utils/requestDb';
|
||||
|
||||
export const exchangeAuthorizationCode = async (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import {
|
||||
CompanyInput,
|
||||
CreateCompanyResponse,
|
||||
@@ -7,6 +6,7 @@ import {
|
||||
import { Company, CompanyFilterInput } from '~/generated/graphql';
|
||||
import { CREATE_COMPANY } from '~/graphql/company/mutations';
|
||||
import { FIND_COMPANY } from '~/graphql/company/queries';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { callMutation, callQuery } from '../utils/requestDb';
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import {
|
||||
CreatePersonResponse,
|
||||
FindPersonResponse,
|
||||
@@ -7,6 +6,7 @@ import {
|
||||
import { Person, PersonFilterInput } from '~/generated/graphql';
|
||||
import { CREATE_PERSON } from '~/graphql/person/mutations';
|
||||
import { FIND_PERSON } from '~/graphql/person/queries';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { callMutation, callQuery } from '../utils/requestDb';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ApolloClient, InMemoryCache } from '@apollo/client';
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { Tokens } from '~/db/types/auth.types';
|
||||
import { RENEW_TOKEN } from '~/graphql/auth/mutations';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const renewToken = async (
|
||||
appToken: string,
|
||||
|
||||
@@ -2527,7 +2527,6 @@ export enum FieldMetadataType {
|
||||
Number = 'NUMBER',
|
||||
Numeric = 'NUMERIC',
|
||||
Phone = 'PHONE',
|
||||
Phones = 'PHONES',
|
||||
Position = 'POSITION',
|
||||
Rating = 'RATING',
|
||||
RawJson = 'RAW_JSON',
|
||||
@@ -7456,7 +7455,7 @@ export type Workspace = {
|
||||
billingSubscriptions?: Maybe<Array<BillingSubscription>>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
currentBillingSubscription?: Maybe<BillingSubscription>;
|
||||
metadataVersion?: Maybe<Scalars['String']>;
|
||||
currentCacheVersion?: Maybe<Scalars['String']>;
|
||||
deletedAt?: Maybe<Scalars['DateTime']>;
|
||||
displayName?: Maybe<Scalars['String']>;
|
||||
domainName?: Maybe<Scalars['String']>;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import Settings from '~/options/Settings';
|
||||
import Sidepanel from '~/options/Sidepanel';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const App = () => {
|
||||
const [currentScreen, setCurrentScreen] = useState('');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Loader } from '@/ui/display/loader/components/Loader';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { Loader } from '@/ui/display/loader/components/Loader';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
align-items: center;
|
||||
background: ${({ theme }) => theme.background.noisy};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { MainButton } from '@/ui/input/button/MainButton';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { clearStore } from '~/utils/apolloClient';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
align-items: center;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { MainButton } from '@/ui/input/button/MainButton';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const StyledIframe = styled.iframe`
|
||||
display: block;
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
||||
type H2TitleProps = {
|
||||
title: string;
|
||||
description?: string;
|
||||
adornment?: React.ReactNode;
|
||||
addornment?: React.ReactNode;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@@ -33,11 +33,11 @@ const StyledDescription = styled.h3`
|
||||
margin-top: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
export const H2Title = ({ title, description, adornment }: H2TitleProps) => (
|
||||
export const H2Title = ({ title, description, addornment }: H2TitleProps) => (
|
||||
<StyledContainer>
|
||||
<StyledTitleContainer>
|
||||
<StyledTitle>{title}</StyledTitle>
|
||||
{adornment}
|
||||
{addornment}
|
||||
</StyledTitleContainer>
|
||||
{description && <StyledDescription>{description}</StyledDescription>}
|
||||
</StyledContainer>
|
||||
|
||||
+3
-6
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import React, { useId } from 'react';
|
||||
|
||||
interface TextInputProps {
|
||||
label?: string;
|
||||
@@ -18,7 +18,7 @@ const StyledContainer = styled.div<{ fullWidth?: boolean }>`
|
||||
margin-bottom: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledLabel = styled.label`
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
@@ -65,15 +65,12 @@ const TextInput: React.FC<TextInputProps> = ({
|
||||
placeholder,
|
||||
icon,
|
||||
}) => {
|
||||
const inputId = useId();
|
||||
|
||||
return (
|
||||
<StyledContainer fullWidth={fullWidth}>
|
||||
{label && <StyledLabel htmlFor={inputId}>{label}</StyledLabel>}
|
||||
{label && <StyledLabel>{label}</StyledLabel>}
|
||||
<StyledInputContainer>
|
||||
{icon && <StyledIcon>{icon}</StyledIcon>}
|
||||
<StyledInput
|
||||
id={inputId}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export type ToggleSize = 'small' | 'medium';
|
||||
|
||||
@@ -15,7 +15,7 @@ type ContainerProps = {
|
||||
const StyledContainer = styled.div<ContainerProps>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme, isOn, color }) =>
|
||||
isOn ? (color ?? theme.color.blue) : theme.background.quaternary};
|
||||
isOn ? color ?? theme.color.blue : theme.background.quaternary};
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ApolloClient, from, HttpLink, InMemoryCache } from '@apollo/client';
|
||||
import { setContext } from '@apollo/client/link/context';
|
||||
import { onError } from '@apollo/client/link/error';
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const clearStore = () => {
|
||||
chrome.storage.local.remove([
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { OperationVariables } from '@apollo/client';
|
||||
import { DocumentNode } from 'graphql';
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import getApolloClient from '~/utils/apolloClient';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const callQuery = async <T>(
|
||||
query: DocumentNode,
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/options/modules/*"],
|
||||
"~/*": ["./src/*"]
|
||||
"@/*": ["packages/twenty-chrome-extension/src/options/modules/*"],
|
||||
"~/*": ["packages/twenty-chrome-extension/src/*"]
|
||||
},
|
||||
|
||||
/* Bundler mode */
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
TAG=latest
|
||||
|
||||
#PG_DATABASE_USER=postgres
|
||||
#PG_DATABASE_PASSWORD=replace_me_with_a_strong_password_without_special_characters
|
||||
#PG_DATABASE_HOST=db
|
||||
#PG_DATABASE_PORT=5432
|
||||
#REDIS_URL=redis://redis:6379
|
||||
# POSTGRES_ADMIN_PASSWORD=replace_me_with_a_strong_password
|
||||
|
||||
PG_DATABASE_HOST=db:5432
|
||||
|
||||
SERVER_URL=http://localhost:3000
|
||||
SIGN_IN_PREFILLED=false
|
||||
# Uncoment if you are serving your front on another server than the API (eg. bucket)
|
||||
# FRONT_BASE_URL=http://localhost:3000
|
||||
|
||||
# Use openssl rand -base64 32 for each secret
|
||||
# APP_SECRET=replace_me_with_a_random_string
|
||||
# ACCESS_TOKEN_SECRET=replace_me_with_a_random_string_access
|
||||
# LOGIN_TOKEN_SECRET=replace_me_with_a_random_string_login
|
||||
# REFRESH_TOKEN_SECRET=replace_me_with_a_random_string_refresh
|
||||
# FILE_TOKEN_SECRET=replace_me_with_a_random_string_refresh
|
||||
|
||||
SIGN_IN_PREFILLED=true
|
||||
|
||||
STORAGE_TYPE=local
|
||||
|
||||
# STORAGE_S3_REGION=eu-west3
|
||||
# STORAGE_S3_NAME=my-bucket
|
||||
# STORAGE_S3_ENDPOINT=
|
||||
|
||||
MESSAGE_QUEUE_TYPE=pg-boss
|
||||
|
||||
@@ -1,9 +1,37 @@
|
||||
dev-build:
|
||||
@docker compose -f dev/docker-compose.yml down -v
|
||||
@docker compose -f dev/docker-compose.yml build
|
||||
|
||||
dev-up:
|
||||
@docker compose -f dev/docker-compose.yml up -d
|
||||
|
||||
dev-start:
|
||||
@docker compose -f dev/docker-compose.yml start
|
||||
|
||||
dev-stop:
|
||||
@docker compose -f dev/docker-compose.yml stop
|
||||
|
||||
dev-down:
|
||||
@docker compose -f dev/docker-compose.yml down -v
|
||||
|
||||
dev-sh:
|
||||
@docker compose -f dev/docker-compose.yml exec twenty-dev sh
|
||||
|
||||
dev-postgres-build:
|
||||
@docker stop twenty_postgres || true
|
||||
@docker rm twenty_postgres || true
|
||||
@docker volume rm twenty_db_data || true
|
||||
@docker compose -f dev/docker-compose.yml up --build postgres -d
|
||||
|
||||
prod-build:
|
||||
@cd ../.. && docker build -f ./packages/twenty-docker/twenty/Dockerfile --tag twenty . && cd -
|
||||
|
||||
prod-run:
|
||||
@docker run -d -p 3000:3000 --name twenty twenty
|
||||
|
||||
prod-postgres-build:
|
||||
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-postgres/Dockerfile --tag twenty-postgres . && cd -
|
||||
|
||||
prod-postgres-run:
|
||||
@docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres
|
||||
|
||||
@@ -12,3 +40,11 @@ prod-website-build:
|
||||
|
||||
prod-website-run:
|
||||
@docker run -d -p 3000:3000 --name twenty-website twenty-website
|
||||
|
||||
release-postgres:
|
||||
@cd ../.. && docker buildx build \
|
||||
--push \
|
||||
--no-cache \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-f ./packages/twenty-docker/twenty-postgres/Dockerfile -t twentycrm/twenty-postgres:$(version) -t twentycrm/twenty-postgres:latest . \
|
||||
&& cd -
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
version: "3.9"
|
||||
name: twenty
|
||||
|
||||
services:
|
||||
@@ -13,24 +14,30 @@ services:
|
||||
&& chown -R 1000:1000 /tmp/docker-data"
|
||||
|
||||
server:
|
||||
image: twentycrm/twenty:${TAG:-latest}
|
||||
image: twentycrm/twenty:${TAG}
|
||||
volumes:
|
||||
- server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
|
||||
- docker-data:/app/docker-data
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
NODE_PORT: 3000
|
||||
PG_DATABASE_URL: postgres://${PG_DATABASE_USER:-postgres}:${PG_DATABASE_PASSWORD:-postgres}@${PG_DATABASE_HOST:-db}:${PG_DATABASE_PORT:-5432}/default
|
||||
PORT: 3000
|
||||
PG_DATABASE_URL: postgres://twenty:twenty@${PG_DATABASE_HOST}/default
|
||||
SERVER_URL: ${SERVER_URL}
|
||||
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
||||
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL}
|
||||
MESSAGE_QUEUE_TYPE: ${MESSAGE_QUEUE_TYPE}
|
||||
|
||||
ENABLE_DB_MIGRATIONS: "true"
|
||||
|
||||
SIGN_IN_PREFILLED: ${SIGN_IN_PREFILLED}
|
||||
STORAGE_TYPE: ${STORAGE_TYPE}
|
||||
STORAGE_S3_REGION: ${STORAGE_S3_REGION}
|
||||
STORAGE_S3_NAME: ${STORAGE_S3_NAME}
|
||||
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
|
||||
|
||||
APP_SECRET: ${APP_SECRET}
|
||||
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
|
||||
LOGIN_TOKEN_SECRET: ${LOGIN_TOKEN_SECRET}
|
||||
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
|
||||
FILE_TOKEN_SECRET: ${FILE_TOKEN_SECRET}
|
||||
depends_on:
|
||||
change-vol-ownership:
|
||||
condition: service_completed_successfully
|
||||
@@ -44,20 +51,24 @@ services:
|
||||
restart: always
|
||||
|
||||
worker:
|
||||
image: twentycrm/twenty:${TAG:-latest}
|
||||
image: twentycrm/twenty:${TAG}
|
||||
command: ["yarn", "worker:prod"]
|
||||
environment:
|
||||
PG_DATABASE_URL: postgres://${PG_DATABASE_USER:-postgres}:${PG_DATABASE_PASSWORD:-postgres}@${PG_DATABASE_HOST:-db}:${PG_DATABASE_PORT:-5432}/default
|
||||
PG_DATABASE_URL: postgres://twenty:twenty@${PG_DATABASE_HOST}/default
|
||||
SERVER_URL: ${SERVER_URL}
|
||||
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
||||
DISABLE_DB_MIGRATIONS: "true" # it already runs on the server
|
||||
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL}
|
||||
MESSAGE_QUEUE_TYPE: ${MESSAGE_QUEUE_TYPE}
|
||||
|
||||
ENABLE_DB_MIGRATIONS: "false" # it already runs on the server
|
||||
|
||||
STORAGE_TYPE: ${STORAGE_TYPE}
|
||||
STORAGE_S3_REGION: ${STORAGE_S3_REGION}
|
||||
STORAGE_S3_NAME: ${STORAGE_S3_NAME}
|
||||
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
|
||||
|
||||
APP_SECRET: ${APP_SECRET}
|
||||
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
|
||||
LOGIN_TOKEN_SECRET: ${LOGIN_TOKEN_SECRET}
|
||||
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
|
||||
FILE_TOKEN_SECRET: ${FILE_TOKEN_SECRET}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
@@ -66,25 +77,18 @@ services:
|
||||
restart: always
|
||||
|
||||
db:
|
||||
image: twentycrm/twenty-postgres-spilo:${TAG:-latest}
|
||||
image: twentycrm/twenty-postgres:${TAG}
|
||||
volumes:
|
||||
- db-data:/home/postgres/pgdata
|
||||
- db-data:/bitnami/postgresql
|
||||
environment:
|
||||
PGUSER_SUPERUSER: ${PG_DATABASE_USER:-postgres}
|
||||
PGPASSWORD_SUPERUSER: ${PG_DATABASE_PASSWORD:-postgres}
|
||||
ALLOW_NOSSL: "true"
|
||||
SPILO_PROVIDER: "local"
|
||||
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD}
|
||||
healthcheck:
|
||||
test: pg_isready -U ${PG_DATABASE_USER:-postgres} -h localhost -d postgres
|
||||
test: pg_isready -U twenty -d default
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: always
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
docker-data:
|
||||
db-data:
|
||||
|
||||
@@ -22,37 +22,33 @@ spec:
|
||||
app: twentycrm-db
|
||||
spec:
|
||||
volumes:
|
||||
- name: twentycrm-db-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-db-pvc
|
||||
- name: twentycrm-db-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-db-pvc
|
||||
containers:
|
||||
- name: twentycrm
|
||||
image: twentycrm/twenty-postgres-spilo:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: PGUSER_SUPERUSER
|
||||
value: "postgres"
|
||||
- name: PGPASSWORD_SUPERUSER
|
||||
value: "postgres"
|
||||
- name: SPILO_PROVIDER
|
||||
value: "local"
|
||||
- name: ALLOW_NOSSL
|
||||
value: "true"
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /home/postgres/pgdata
|
||||
name: twentycrm-db-data
|
||||
- env:
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "twenty"
|
||||
- name: BITNAMI_DEBUG
|
||||
value: "true"
|
||||
- image: twentycrm/twenty-postgres:latest
|
||||
imagePullPolicy: Always
|
||||
name: twentycrm
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /bitnami/postgresql
|
||||
name: twentycrm-db-data
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: twentycrm-redis
|
||||
name: twentycrm-redis
|
||||
namespace: twentycrm
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 1
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: twentycrm-redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: twentycrm-redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis/redis-stack-server:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: PORT
|
||||
value: 6379
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "1024Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "2048Mi"
|
||||
cpu: "500m"
|
||||
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
@@ -22,55 +22,61 @@ spec:
|
||||
app: twentycrm-server
|
||||
spec:
|
||||
volumes:
|
||||
- name: twentycrm-server-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-server-pvc
|
||||
- name: twentycrm-docker-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-docker-data-pvc
|
||||
- name: twentycrm-server-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-server-pvc
|
||||
containers:
|
||||
- name: twentycrm
|
||||
image: twentycrm/twenty:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: NODE_PORT
|
||||
value: 3000
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: "PG_DATABASE_URL"
|
||||
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
- name: "REDIS_URL"
|
||||
value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
|
||||
- name: SIGN_IN_PREFILLED
|
||||
value: "false"
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: "ACCESS_TOKEN_EXPIRES_IN"
|
||||
value: "7d"
|
||||
- name: "LOGIN_TOKEN_EXPIRES_IN"
|
||||
value: "1h"
|
||||
- name: APP_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http-tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /app/docker-data
|
||||
name: twentycrm-docker-data
|
||||
- mountPath: /app/packages/twenty-server/.local-storage
|
||||
name: twentycrm-server-data
|
||||
- env:
|
||||
- name: PORT
|
||||
value: 3000
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: PG_DATABASE_URL
|
||||
value: "postgres://twenty:twenty@twenty-db.twentycrm.svc.cluster.local/default"
|
||||
- name: ENABLE_DB_MIGRATIONS
|
||||
value: "true"
|
||||
- name: SIGN_IN_PREFILLED
|
||||
value: "true"
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: ACCESS_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
- name: LOGIN_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: loginToken
|
||||
- name: REFRESH_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: refreshToken
|
||||
- name: FILE_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: fileToken
|
||||
- image: twentycrm/twenty:latest
|
||||
imagePullPolicy: Always
|
||||
name: twentycrm
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http-tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /app/.local-storage
|
||||
name: twentycrm-server-data
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: twentycrm-worker
|
||||
name: twentycrm-worker
|
||||
namespace: twentycrm
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 1
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: twentycrm-worker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: twentycrm-worker
|
||||
spec:
|
||||
containers:
|
||||
- name: twentycrm
|
||||
image: twentycrm/twenty:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: PG_DATABASE_URL
|
||||
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
- name: DISABLE_DB_MIGRATIONS
|
||||
value: "false" # it already runs on the server
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: "REDIS_URL"
|
||||
value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
|
||||
- name: APP_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
command:
|
||||
- yarn
|
||||
- worker:prod
|
||||
resources:
|
||||
requests:
|
||||
memory: "1024Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "2048Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
@@ -4,21 +4,21 @@ metadata:
|
||||
name: twentycrm
|
||||
namespace: twentycrm
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "X-Forwarded-For $http_x_forwarded_for";
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: crm.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: twentycrm-server
|
||||
port:
|
||||
name: http-tcp
|
||||
- host: crm.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: twentycrm-server
|
||||
port:
|
||||
name: http-tcp
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: twentycrm-docker-data-pv
|
||||
spec:
|
||||
storageClassName: default
|
||||
capacity:
|
||||
storage: 100Mi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: twentycrm-docker-data-pvc
|
||||
namespace: twentycrm
|
||||
spec:
|
||||
storageClassName: default
|
||||
volumeName: twentycrm-docker-data-pv
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Mi
|
||||
@@ -6,9 +6,9 @@ metadata:
|
||||
spec:
|
||||
internalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
targetPort: 5432
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
targetPort: 5432
|
||||
selector:
|
||||
app: twentycrm-db
|
||||
sessionAffinity: ClientIP
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: twentycrm-redis
|
||||
namespace: twentycrm
|
||||
spec:
|
||||
internalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- port: 6379
|
||||
protocol: TCP
|
||||
targetPort: 6379
|
||||
selector:
|
||||
app: twentycrm-redis
|
||||
sessionAffinity: ClientIP
|
||||
sessionAffinityConfig:
|
||||
clientIP:
|
||||
timeoutSeconds: 10800
|
||||
type: ClusterIP
|
||||
@@ -6,10 +6,10 @@ metadata:
|
||||
spec:
|
||||
internalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- name: http-tcp
|
||||
port: 3000
|
||||
protocol: TCP
|
||||
targetPort: 3000
|
||||
- name: http-tcp
|
||||
port: 3000
|
||||
protocol: TCP
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: twentycrm-server
|
||||
sessionAffinity: ClientIP
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
formatter: "markdown table" # this is required
|
||||
|
||||
version: ""
|
||||
|
||||
header-from: main.tf
|
||||
|
||||
recursive:
|
||||
enabled: false
|
||||
path: modules
|
||||
|
||||
output:
|
||||
file: "README.md"
|
||||
mode: inject
|
||||
template: |-
|
||||
<!-- BEGIN_TF_DOCS -->
|
||||
# TwentyCRM Terraform Docs
|
||||
|
||||
This file was generated by [terraform-docs](https://terraform-docs.io/), for more information on how to install, configure, and use visit their website.
|
||||
|
||||
To update this `README.md` after changes to the Terraform code in this folder, run: `terraform-docs -c `./.terraform-docs.yml .`
|
||||
|
||||
To make configuration changes to how this doc is generated, see `./.terraform-docs.yml`
|
||||
|
||||
{{ .Content }}
|
||||
<!-- END_TF_DOCS -->
|
||||
|
||||
output-values:
|
||||
enabled: false
|
||||
from: "outputs.tf"
|
||||
|
||||
sort:
|
||||
enabled: true
|
||||
by: required
|
||||
|
||||
settings:
|
||||
anchor: true
|
||||
color: true
|
||||
default: true
|
||||
description: true
|
||||
escape: true
|
||||
hide-empty: true
|
||||
html: true
|
||||
indent: 2
|
||||
lockfile: true
|
||||
read-comments: true
|
||||
required: true
|
||||
sensitive: true
|
||||
type: true
|
||||
@@ -1,73 +0,0 @@
|
||||
<!-- BEGIN_TF_DOCS -->
|
||||
# TwentyCRM Terraform Docs
|
||||
|
||||
This file was generated by [terraform-docs](https://terraform-docs.io/), for more information on how to install, configure, and use visit their website.
|
||||
|
||||
To update this `README.md` after changes to the Terraform code in this folder, run: `terraform-docs -c `./.terraform-docs.yml .`
|
||||
|
||||
To make configuration changes to how this doc is generated, see `./.terraform-docs.yml`
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.2 |
|
||||
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | >= 2.32.0 |
|
||||
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.6.3 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="provider_kubernetes"></a> [kubernetes](#provider\_kubernetes) | >= 2.32.0 |
|
||||
| <a name="provider_random"></a> [random](#provider\_random) | >= 3.6.3 |
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [kubernetes_deployment.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_deployment.twentycrm_redis](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_deployment.twentycrm_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_deployment.twentycrm_worker](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_ingress.twentycrm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress) | resource |
|
||||
| [kubernetes_namespace.twentycrm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
|
||||
| [kubernetes_persistent_volume.db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
|
||||
| [kubernetes_persistent_volume.docker_data](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
|
||||
| [kubernetes_persistent_volume.server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
|
||||
| [kubernetes_persistent_volume_claim.db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
|
||||
| [kubernetes_persistent_volume_claim.docker_data](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
|
||||
| [kubernetes_persistent_volume_claim.server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
|
||||
| [kubernetes_secret.twentycrm_tokens](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
|
||||
| [kubernetes_service.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
|
||||
| [kubernetes_service.twentycrm_redis](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
|
||||
| [kubernetes_service.twentycrm_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
|
||||
| [random_bytes.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/bytes) | resource |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| <a name="input_twentycrm_app_hostname"></a> [twentycrm\_app\_hostname](#input\_twentycrm\_app\_hostname) | The protocol, DNS fully qualified hostname, and port used to access TwentyCRM in your environment. Ex: https://crm.example.com:443 | `string` | n/a | yes |
|
||||
| <a name="input_twentycrm_pgdb_admin_password"></a> [twentycrm\_pgdb\_admin\_password](#input\_twentycrm\_pgdb\_admin\_password) | TwentyCRM password for postgres database. | `string` | n/a | yes |
|
||||
| <a name="input_twentycrm_app_name"></a> [twentycrm\_app\_name](#input\_twentycrm\_app\_name) | A friendly name prefix to use for every component deployed. | `string` | `"twentycrm"` | no |
|
||||
| <a name="input_twentycrm_db_image"></a> [twentycrm\_db\_image](#input\_twentycrm\_db\_image) | TwentyCRM image for database deployment. This defaults to latest. | `string` | `"twentycrm/twenty-postgres-spilo:latest"` | no |
|
||||
| <a name="input_twentycrm_db_pv_capacity"></a> [twentycrm\_db\_pv\_capacity](#input\_twentycrm\_db\_pv\_capacity) | Storage capacity provisioned for database persistent volume. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_db_pv_path"></a> [twentycrm\_db\_pv\_path](#input\_twentycrm\_db\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
|
||||
| <a name="input_twentycrm_db_pvc_requests"></a> [twentycrm\_db\_pvc\_requests](#input\_twentycrm\_db\_pvc\_requests) | Storage capacity reservation for database persistent volume claim. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_db_replicas"></a> [twentycrm\_db\_replicas](#input\_twentycrm\_db\_replicas) | Number of replicas for the TwentyCRM database deployment. This defaults to 1. | `number` | `1` | no |
|
||||
| <a name="input_twentycrm_docker_data_mount_path"></a> [twentycrm\_docker\_data\_mount\_path](#input\_twentycrm\_docker\_data\_mount\_path) | TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'. | `string` | `"/app/docker-data"` | no |
|
||||
| <a name="input_twentycrm_docker_data_pv_capacity"></a> [twentycrm\_docker\_data\_pv\_capacity](#input\_twentycrm\_docker\_data\_pv\_capacity) | Storage capacity provisioned for server persistent volume. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_docker_data_pv_path"></a> [twentycrm\_docker\_data\_pv\_path](#input\_twentycrm\_docker\_data\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
|
||||
| <a name="input_twentycrm_docker_data_pvc_requests"></a> [twentycrm\_docker\_data\_pvc\_requests](#input\_twentycrm\_docker\_data\_pvc\_requests) | Storage capacity reservation for server persistent volume claim. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_namespace"></a> [twentycrm\_namespace](#input\_twentycrm\_namespace) | Namespace for all TwentyCRM resources | `string` | `"twentycrm"` | no |
|
||||
| <a name="input_twentycrm_redis_image"></a> [twentycrm\_redis\_image](#input\_twentycrm\_redis\_image) | TwentyCRM image for Redis deployment. This defaults to latest. | `string` | `"redis/redis-stack-server:latest"` | no |
|
||||
| <a name="input_twentycrm_redis_replicas"></a> [twentycrm\_redis\_replicas](#input\_twentycrm\_redis\_replicas) | Number of replicas for the TwentyCRM Redis deployment. This defaults to 1. | `number` | `1` | no |
|
||||
| <a name="input_twentycrm_server_data_mount_path"></a> [twentycrm\_server\_data\_mount\_path](#input\_twentycrm\_server\_data\_mount\_path) | TwentyCRM mount path for servers application data. Defaults to '/app/packages/twenty-server/.local-storage'. | `string` | `"/app/packages/twenty-server/.local-storage"` | no |
|
||||
| <a name="input_twentycrm_server_image"></a> [twentycrm\_server\_image](#input\_twentycrm\_server\_image) | TwentyCRM server image for the server deployment. This defaults to latest. This value is also used for the workers image. | `string` | `"twentycrm/twenty:latest"` | no |
|
||||
| <a name="input_twentycrm_server_pv_capacity"></a> [twentycrm\_server\_pv\_capacity](#input\_twentycrm\_server\_pv\_capacity) | Storage capacity provisioned for server persistent volume. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_server_pv_path"></a> [twentycrm\_server\_pv\_path](#input\_twentycrm\_server\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
|
||||
| <a name="input_twentycrm_server_pvc_requests"></a> [twentycrm\_server\_pvc\_requests](#input\_twentycrm\_server\_pvc\_requests) | Storage capacity reservation for server persistent volume claim. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_server_replicas"></a> [twentycrm\_server\_replicas](#input\_twentycrm\_server\_replicas) | Number of replicas for the TwentyCRM server deployment. This defaults to 1. | `number` | `1` | no |
|
||||
| <a name="input_twentycrm_worker_replicas"></a> [twentycrm\_worker\_replicas](#input\_twentycrm\_worker\_replicas) | Number of replicas for the TwentyCRM worker deployment. This defaults to 1. | `number` | `1` | no |
|
||||
<!-- END_TF_DOCS -->
|
||||
@@ -1,17 +1,17 @@
|
||||
resource "kubernetes_deployment" "twentycrm_db" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-db"
|
||||
name = "${local.twentycrm_app_name}-db"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-db"
|
||||
app = "${local.twentycrm_app_name}-db"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
replicas = var.twentycrm_db_replicas
|
||||
replicas = 1
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "${var.twentycrm_app_name}-db"
|
||||
app = "${local.twentycrm_app_name}-db"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,17 @@ resource "kubernetes_deployment" "twentycrm_db" {
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-db"
|
||||
app = "${local.twentycrm_app_name}-db"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
# security_context {
|
||||
# fs_group = 0
|
||||
# }
|
||||
container {
|
||||
image = var.twentycrm_db_image
|
||||
name = var.twentycrm_app_name
|
||||
image = local.twentycrm_db_image
|
||||
name = local.twentycrm_app_name
|
||||
stdin = true
|
||||
tty = true
|
||||
security_context {
|
||||
@@ -42,7 +45,7 @@ resource "kubernetes_deployment" "twentycrm_db" {
|
||||
|
||||
env {
|
||||
name = "POSTGRES_PASSWORD"
|
||||
value = var.twentycrm_pgdb_admin_password
|
||||
value = "twenty"
|
||||
}
|
||||
env {
|
||||
name = "BITNAMI_DEBUG"
|
||||
@@ -66,16 +69,16 @@ resource "kubernetes_deployment" "twentycrm_db" {
|
||||
}
|
||||
|
||||
volume_mount {
|
||||
name = "db-data"
|
||||
name = "nfs-twentycrm-db-data"
|
||||
mount_path = "/bitnami/postgresql"
|
||||
}
|
||||
}
|
||||
|
||||
volume {
|
||||
name = "db-data"
|
||||
name = "nfs-twentycrm-db-data"
|
||||
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.db.metadata.0.name
|
||||
claim_name = "nfs-twentycrm-db-data-pvc"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
resource "kubernetes_deployment" "twentycrm_redis" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-redis"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-redis"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
replicas = var.twentycrm_redis_replicas
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "${var.twentycrm_app_name}-redis"
|
||||
}
|
||||
}
|
||||
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
rolling_update {
|
||||
max_surge = "1"
|
||||
max_unavailable = "1"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-redis"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
container {
|
||||
image = var.twentycrm_redis_image
|
||||
name = "redis"
|
||||
|
||||
port {
|
||||
container_port = 6379
|
||||
protocol = "TCP"
|
||||
}
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "250m"
|
||||
memory = "1024Mi"
|
||||
}
|
||||
limits = {
|
||||
cpu = "500m"
|
||||
memory = "2048Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
dns_policy = "ClusterFirst"
|
||||
restart_policy = "Always"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
resource "kubernetes_deployment" "twentycrm_server" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-server"
|
||||
name = "${local.twentycrm_app_name}-server"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-server"
|
||||
app = "${local.twentycrm_app_name}-server"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
replicas = var.twentycrm_server_replicas
|
||||
replicas = 1
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "${var.twentycrm_app_name}-server"
|
||||
app = "${local.twentycrm_app_name}-server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,54 +26,69 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-server"
|
||||
app = "${local.twentycrm_app_name}-server"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
container {
|
||||
image = var.twentycrm_server_image
|
||||
name = var.twentycrm_app_name
|
||||
image = local.twentycrm_server_image
|
||||
name = local.twentycrm_app_name
|
||||
stdin = true
|
||||
tty = true
|
||||
|
||||
security_context {
|
||||
allow_privilege_escalation = true
|
||||
privileged = true
|
||||
run_as_user = 1000
|
||||
}
|
||||
|
||||
env {
|
||||
name = "NODE_PORT"
|
||||
name = "PORT"
|
||||
value = "3000"
|
||||
}
|
||||
env {
|
||||
name = "DEBUG_MODE"
|
||||
value = false
|
||||
}
|
||||
|
||||
env {
|
||||
name = "SERVER_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
value = "https://crm.example.com:443"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "FRONT_BASE_URL"
|
||||
value = "https://crm.example.com:443"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "BACKEND_SERVER_URL"
|
||||
value = "https://crm.example.com:443"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "PG_DATABASE_URL"
|
||||
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${kubernetes_service.twentycrm_db.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default"
|
||||
value = "postgres://twenty:twenty@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "REDIS_URL"
|
||||
value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
|
||||
name = "ENABLE_DB_MIGRATIONS"
|
||||
value = "true"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "DISABLE_DB_MIGRATIONS"
|
||||
value = "false"
|
||||
name = "SIGN_IN_PREFILLED"
|
||||
value = "true"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "STORAGE_TYPE"
|
||||
value = "local"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "ACCESS_TOKEN_EXPIRES_IN"
|
||||
value = "7d"
|
||||
}
|
||||
env {
|
||||
name = "LOGIN_TOKEN_EXPIRES_IN"
|
||||
value = "1h"
|
||||
}
|
||||
env {
|
||||
name = "APP_SECRET"
|
||||
name = "ACCESS_TOKEN_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "tokens"
|
||||
@@ -82,6 +97,36 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
}
|
||||
}
|
||||
|
||||
env {
|
||||
name = "LOGIN_TOKEN_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "tokens"
|
||||
key = "loginToken"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env {
|
||||
name = "REFRESH_TOKEN_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "tokens"
|
||||
key = "refreshToken"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env {
|
||||
name = "FILE_TOKEN_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "tokens"
|
||||
key = "fileToken"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
port {
|
||||
container_port = 3000
|
||||
protocol = "TCP"
|
||||
@@ -99,29 +144,16 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
}
|
||||
|
||||
volume_mount {
|
||||
name = "server-data"
|
||||
mount_path = var.twentycrm_server_data_mount_path
|
||||
}
|
||||
|
||||
volume_mount {
|
||||
name = "docker-data"
|
||||
mount_path = var.twentycrm_docker_data_mount_path
|
||||
name = "nfs-twentycrm-server-data"
|
||||
mount_path = "/app/.local-storage"
|
||||
}
|
||||
}
|
||||
|
||||
volume {
|
||||
name = "server-data"
|
||||
name = "nfs-twentycrm-server-data"
|
||||
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.server.metadata.0.name
|
||||
}
|
||||
}
|
||||
|
||||
volume {
|
||||
name = "docker-data"
|
||||
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.docker_data.metadata.0.name
|
||||
claim_name = "nfs-twentycrm-server-data-pvc"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +164,6 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
}
|
||||
depends_on = [
|
||||
kubernetes_deployment.twentycrm_db,
|
||||
kubernetes_deployment.twentycrm_redis,
|
||||
kubernetes_secret.twentycrm_tokens
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
resource "kubernetes_deployment" "twentycrm_worker" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-worker"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-worker"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
replicas = var.twentycrm_worker_replicas
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "${var.twentycrm_app_name}-worker"
|
||||
}
|
||||
}
|
||||
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
rolling_update {
|
||||
max_surge = "1"
|
||||
max_unavailable = "1"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "${var.twentycrm_app_name}-worker"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
container {
|
||||
image = var.twentycrm_server_image
|
||||
name = var.twentycrm_app_name
|
||||
stdin = true
|
||||
tty = true
|
||||
command = ["yarn", "worker:prod"]
|
||||
|
||||
env {
|
||||
name = "SERVER_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "PG_DATABASE_URL"
|
||||
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${kubernetes_service.twentycrm_db.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "REDIS_URL"
|
||||
value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "DISABLE_DB_MIGRATIONS"
|
||||
value = "true" #it already runs on the server
|
||||
}
|
||||
|
||||
env {
|
||||
name = "STORAGE_TYPE"
|
||||
value = "local"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "APP_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "tokens"
|
||||
key = "accessToken"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "250m"
|
||||
memory = "1024Mi"
|
||||
}
|
||||
limits = {
|
||||
cpu = "1000m"
|
||||
memory = "2048Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dns_policy = "ClusterFirst"
|
||||
restart_policy = "Always"
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [
|
||||
kubernetes_deployment.twentycrm_db,
|
||||
kubernetes_deployment.twentycrm_redis,
|
||||
kubernetes_deployment.twentycrm_server,
|
||||
kubernetes_secret.twentycrm_tokens,
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
resource "kubernetes_ingress" "twentycrm" {
|
||||
wait_for_load_balancer = true
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-ingress"
|
||||
name = "${local.twentycrm_app_name}-ingress"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
@@ -15,7 +15,7 @@ resource "kubernetes_ingress" "twentycrm" {
|
||||
spec {
|
||||
ingress_class_name = "nginx"
|
||||
rule {
|
||||
host = var.twentycrm_app_hostname
|
||||
host = local.twentycrm_app_hostname
|
||||
http {
|
||||
path {
|
||||
path = "/*"
|
||||
|
||||
@@ -5,19 +5,32 @@ provider "kubernetes" {
|
||||
config_path = "~/.kube/config"
|
||||
}
|
||||
|
||||
#################
|
||||
# Global Locals #
|
||||
#################
|
||||
locals {
|
||||
twentycrm_app_name = "twentycrm"
|
||||
twentycrm_app_hostname = "crm.example.com"
|
||||
twentycrm_server_image = "twentycrm/twenty:v0.10.4"
|
||||
twentycrm_db_image = "twentycrm/twenty-postgres:v0.10.4"
|
||||
twentycrm_db_pv_path = "/path/to/mystorage"
|
||||
twentycrm_db_pv_capacity = "10Gi"
|
||||
twentycrm_db_pvc_requests = "10Gi"
|
||||
twentycrm_server_pv_path = "/path/to/mystorage"
|
||||
twentycrm_server_pv_capacity = "10Gi"
|
||||
twentycrm_server_pvc_requests = "10Gi"
|
||||
}
|
||||
|
||||
####################
|
||||
# Terraform Config #
|
||||
####################
|
||||
terraform {
|
||||
required_version = ">= 1.9.2"
|
||||
required_version = ">= 1.7.4"
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = ">= 2.32.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = ">= 3.6.3"
|
||||
version = ">= 2.23.0"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
resource "kubernetes_namespace" "twentycrm" {
|
||||
metadata {
|
||||
annotations = {
|
||||
name = var.twentycrm_namespace
|
||||
name = "twentycrm"
|
||||
}
|
||||
|
||||
name = var.twentycrm_namespace
|
||||
name = "twentycrm"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
resource "kubernetes_persistent_volume" "db" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-db-pv"
|
||||
name = "${local.twentycrm_app_name}-db-pv"
|
||||
}
|
||||
spec {
|
||||
storage_class_name = "default"
|
||||
capacity = {
|
||||
storage = var.twentycrm_db_pv_capacity
|
||||
storage = local.twentycrm_db_pv_capacity
|
||||
}
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
# refer to Terraform Docs for your specific implementation requirements
|
||||
# refer to Terraform Docs for your specific implementation requirements
|
||||
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
|
||||
persistent_volume_source {
|
||||
local {
|
||||
path = var.twentycrm_db_pv_path
|
||||
path = local.twentycrm_db_pv_path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
resource "kubernetes_persistent_volume" "docker_data" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-docker-data-pv"
|
||||
}
|
||||
spec {
|
||||
storage_class_name = "default"
|
||||
capacity = {
|
||||
storage = var.twentycrm_docker_data_pv_capacity
|
||||
}
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
# refer to Terraform Docs for your specific implementation requirements
|
||||
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
|
||||
persistent_volume_source {
|
||||
local {
|
||||
path = var.twentycrm_docker_data_pv_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
resource "kubernetes_persistent_volume" "server" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-server-pv"
|
||||
name = "${local.twentycrm_app_name}-server-pv"
|
||||
}
|
||||
spec {
|
||||
storage_class_name = "default"
|
||||
capacity = {
|
||||
storage = var.twentycrm_server_pv_capacity
|
||||
storage = local.twentycrm_server_pv_capacity
|
||||
}
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
# refer to Terraform Docs for your specific implementation requirements
|
||||
# refer to Terraform Docs for your specific implementation requirements
|
||||
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
|
||||
persistent_volume_source {
|
||||
local {
|
||||
path = var.twentycrm_server_pv_path
|
||||
path = local.twentycrm_server_pv_path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
resource "kubernetes_persistent_volume_claim" "db" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-db-pvc"
|
||||
name = "${local.twentycrm_app_name}-db-pvc"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
resources {
|
||||
requests = {
|
||||
storage = var.twentycrm_db_pvc_requests
|
||||
storage = local.twentycrm_db_pvc_requests
|
||||
}
|
||||
}
|
||||
volume_name = kubernetes_persistent_volume.db.metadata.0.name
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
resource "kubernetes_persistent_volume_claim" "docker_data" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-docker-data-pvc"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
resources {
|
||||
requests = {
|
||||
storage = var.twentycrm_docker_data_pvc_requests
|
||||
}
|
||||
}
|
||||
volume_name = kubernetes_persistent_volume.docker_data.metadata.0.name
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
resource "kubernetes_persistent_volume_claim" "server" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-server-pvc"
|
||||
name = "${local.twentycrm_app_name}-server-pvc"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
resources {
|
||||
requests = {
|
||||
storage = var.twentycrm_server_pvc_requests
|
||||
storage = local.twentycrm_server_pvc_requests
|
||||
}
|
||||
}
|
||||
volume_name = kubernetes_persistent_volume.server.metadata.0.name
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
locals {
|
||||
tokens = [
|
||||
"accessToken",
|
||||
"loginToken",
|
||||
"refreshToken",
|
||||
"fileToken"
|
||||
]
|
||||
}
|
||||
|
||||
resource "random_bytes" "this" {
|
||||
for_each = toset(local.tokens)
|
||||
|
||||
length = 32
|
||||
}
|
||||
|
||||
resource "kubernetes_secret" "twentycrm_tokens" {
|
||||
metadata {
|
||||
name = "tokens"
|
||||
@@ -20,9 +5,11 @@ resource "kubernetes_secret" "twentycrm_tokens" {
|
||||
}
|
||||
|
||||
data = {
|
||||
accessToken = random_bytes.this["accessToken"].base64
|
||||
loginToken = random_bytes.this["loginToken"].base64
|
||||
refreshToken = random_bytes.this["refreshToken"].base64
|
||||
fileToken = random_bytes.this["fileToken"].base64
|
||||
accessToken = var.twentycrm_token_accessToken
|
||||
loginToken = var.twentycrm_token_loginToken
|
||||
refreshToken = var.twentycrm_token_refreshToken
|
||||
fileToken = var.twentycrm_token_fileToken
|
||||
}
|
||||
|
||||
# type = "kubernetes.io/basic-auth"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
resource "kubernetes_service" "twentycrm_db" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-db"
|
||||
name = "${local.twentycrm_app_name}-db"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
selector = {
|
||||
app = "${var.twentycrm_app_name}-db"
|
||||
app = "${local.twentycrm_app_name}-db"
|
||||
}
|
||||
session_affinity = "ClientIP"
|
||||
port {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
resource "kubernetes_service" "twentycrm_redis" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-redis"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
selector = {
|
||||
app = "${var.twentycrm_app_name}-redis"
|
||||
}
|
||||
session_affinity = "ClientIP"
|
||||
port {
|
||||
port = 6379
|
||||
target_port = 6379
|
||||
}
|
||||
|
||||
type = "ClusterIP"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
resource "kubernetes_service" "twentycrm_server" {
|
||||
metadata {
|
||||
name = "${var.twentycrm_app_name}-server"
|
||||
name = "${local.twentycrm_app_name}-server"
|
||||
namespace = kubernetes_namespace.twentycrm.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
selector = {
|
||||
app = "${var.twentycrm_app_name}-server"
|
||||
app = "${local.twentycrm_app_name}-server"
|
||||
}
|
||||
session_affinity = "ClientIP"
|
||||
port {
|
||||
|
||||
@@ -1,136 +1,24 @@
|
||||
######################
|
||||
# Required Variables #
|
||||
######################
|
||||
variable "twentycrm_token_accessToken" {
|
||||
type = string
|
||||
description = "TwentyCRM access Token"
|
||||
}
|
||||
|
||||
variable "twentycrm_token_loginToken" {
|
||||
type = string
|
||||
description = "TwentyCRM login Token"
|
||||
}
|
||||
|
||||
variable "twentycrm_token_refreshToken" {
|
||||
type = string
|
||||
description = "TwentyCRM refresh Token"
|
||||
}
|
||||
|
||||
variable "twentycrm_token_fileToken" {
|
||||
type = string
|
||||
description = "TwentyCRM file Token"
|
||||
}
|
||||
|
||||
variable "twentycrm_pgdb_admin_password" {
|
||||
type = string
|
||||
description = "TwentyCRM password for postgres database."
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "twentycrm_app_hostname" {
|
||||
type = string
|
||||
description = "The protocol, DNS fully qualified hostname, and port used to access TwentyCRM in your environment. Ex: https://crm.example.com:443"
|
||||
}
|
||||
|
||||
######################
|
||||
# Optional Variables #
|
||||
######################
|
||||
variable "twentycrm_app_name" {
|
||||
type = string
|
||||
default = "twentycrm"
|
||||
description = "A friendly name prefix to use for every component deployed."
|
||||
}
|
||||
|
||||
variable "twentycrm_server_image" {
|
||||
type = string
|
||||
default = "twentycrm/twenty:latest"
|
||||
description = "TwentyCRM server image for the server deployment. This defaults to latest. This value is also used for the workers image."
|
||||
}
|
||||
|
||||
variable "twentycrm_db_image" {
|
||||
type = string
|
||||
default = "twentycrm/twenty-postgres-spilo:latest"
|
||||
description = "TwentyCRM image for database deployment. This defaults to latest."
|
||||
}
|
||||
|
||||
variable "twentycrm_server_replicas" {
|
||||
type = number
|
||||
default = 1
|
||||
description = "Number of replicas for the TwentyCRM server deployment. This defaults to 1."
|
||||
}
|
||||
|
||||
variable "twentycrm_worker_replicas" {
|
||||
type = number
|
||||
default = 1
|
||||
description = "Number of replicas for the TwentyCRM worker deployment. This defaults to 1."
|
||||
}
|
||||
|
||||
variable "twentycrm_db_replicas" {
|
||||
type = number
|
||||
default = 1
|
||||
description = "Number of replicas for the TwentyCRM database deployment. This defaults to 1."
|
||||
}
|
||||
|
||||
variable "twentycrm_server_data_mount_path" {
|
||||
type = string
|
||||
default = "/app/packages/twenty-server/.local-storage"
|
||||
description = "TwentyCRM mount path for servers application data. Defaults to '/app/packages/twenty-server/.local-storage'."
|
||||
}
|
||||
|
||||
variable "twentycrm_db_pv_path" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Local path to use to store the physical volume if using local storage on nodes."
|
||||
}
|
||||
|
||||
variable "twentycrm_server_pv_path" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Local path to use to store the physical volume if using local storage on nodes."
|
||||
}
|
||||
|
||||
variable "twentycrm_db_pv_capacity" {
|
||||
type = string
|
||||
default = "10Gi"
|
||||
description = "Storage capacity provisioned for database persistent volume."
|
||||
}
|
||||
|
||||
variable "twentycrm_db_pvc_requests" {
|
||||
type = string
|
||||
default = "10Gi"
|
||||
description = "Storage capacity reservation for database persistent volume claim."
|
||||
}
|
||||
|
||||
variable "twentycrm_server_pv_capacity" {
|
||||
type = string
|
||||
default = "10Gi"
|
||||
description = "Storage capacity provisioned for server persistent volume."
|
||||
}
|
||||
|
||||
variable "twentycrm_server_pvc_requests" {
|
||||
type = string
|
||||
default = "10Gi"
|
||||
description = "Storage capacity reservation for server persistent volume claim."
|
||||
}
|
||||
|
||||
variable "twentycrm_namespace" {
|
||||
type = string
|
||||
default = "twentycrm"
|
||||
description = "Namespace for all TwentyCRM resources"
|
||||
}
|
||||
|
||||
variable "twentycrm_redis_replicas" {
|
||||
type = number
|
||||
default = 1
|
||||
description = "Number of replicas for the TwentyCRM Redis deployment. This defaults to 1."
|
||||
}
|
||||
|
||||
variable "twentycrm_redis_image" {
|
||||
type = string
|
||||
default = "redis/redis-stack-server:latest"
|
||||
description = "TwentyCRM image for Redis deployment. This defaults to latest."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_mount_path" {
|
||||
type = string
|
||||
default = "/app/docker-data"
|
||||
description = "TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_pv_path" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Local path to use to store the physical volume if using local storage on nodes."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_pv_capacity" {
|
||||
type = string
|
||||
default = "100Mi"
|
||||
description = "Storage capacity provisioned for server persistent volume."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_pvc_requests" {
|
||||
type = string
|
||||
default = "100Mi"
|
||||
description = "Storage capacity reservation for server persistent volume claim."
|
||||
description = "TwentyCRM password for postgres database"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user