diff --git a/.deploy/k8s/k8s-manifest-api.stage.yaml b/.deploy/k8s/k8s-manifest-api.stage.yaml new file mode 100644 index 000000000..8addd90f8 --- /dev/null +++ b/.deploy/k8s/k8s-manifest-api.stage.yaml @@ -0,0 +1,234 @@ +--- +kind: Service +apiVersion: v1 +metadata: + name: ever-teams-stage-api-lb + annotations: + service.beta.kubernetes.io/do-loadbalancer-name: 'apistage.ever.team' + service.beta.kubernetes.io/do-loadbalancer-protocol: 'http2' + service.beta.kubernetes.io/do-loadbalancer-http2-ports: '443' + # Replace with your Certificate Id. You can get a list of Ids with 'doctl compute certificate list' + service.beta.kubernetes.io/do-loadbalancer-certificate-id: '0c4085c5-9692-4320-86f3-34f52b775a88' + service.beta.kubernetes.io/do-loadbalancer-size-slug: 'lb-small' + service.beta.kubernetes.io/do-loadbalancer-hostname: 'apistage.ever.team' +spec: + type: LoadBalancer + selector: + app: ever-teams-stage-api + ports: + - name: http + protocol: TCP + port: 443 + targetPort: 3000 +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: ever-teams-stage-api +spec: + replicas: 6 + selector: + matchLabels: + app: ever-teams-stage-api + template: + metadata: + labels: + app: ever-teams-stage-api + spec: + containers: + - name: ever-teams-stage-api + image: registry.digitalocean.com/ever/gauzy-api-stage:latest + resources: + requests: + memory: '1536Mi' + cpu: '1000m' + limits: + memory: '2048Mi' + env: + - name: API_HOST + value: 0.0.0.0 + - name: DEMO + value: 'false' + - name: NODE_ENV + value: 'production' + - name: ADMIN_PASSWORD_RESET + value: 'true' + - name: LOG_LEVEL + value: 'info' + - name: CLOUD_PROVIDER + value: '$CLOUD_PROVIDER' + - name: SENTRY_DSN + value: '$SENTRY_DSN' + - name: SENTRY_HTTP_TRACING_ENABLED + value: '$SENTRY_HTTP_TRACING_ENABLED' + - name: SENTRY_PROFILING_ENABLED + value: '$SENTRY_PROFILING_ENABLED' + - name: SENTRY_POSTGRES_TRACKING_ENABLED + value: '$SENTRY_POSTGRES_TRACKING_ENABLED' + - name: API_BASE_URL + value: 'https://apistage.ever.team' + - name: CLIENT_BASE_URL + value: 'https://stage.ever.team' + - name: DB_URI + value: '$DB_URI' + - name: DB_HOST + value: '$DB_HOST' + - name: DB_SSL_MODE + value: '$DB_SSL_MODE' + - name: DB_CA_CERT + value: '$DB_CA_CERT' + - name: DB_USER + value: '$DB_USER' + - name: DB_PASS + value: '$DB_PASS' + - name: DB_TYPE + value: '$DB_TYPE' + - name: DB_NAME + value: '$DB_NAME' + - name: DB_PORT + value: '$DB_PORT' + - name: REDIS_ENABLED + value: '$REDIS_ENABLED' + - name: REDIS_URL + value: '$REDIS_URL' + - name: AWS_ACCESS_KEY_ID + value: '$AWS_ACCESS_KEY_ID' + - name: AWS_SECRET_ACCESS_KEY + value: '$AWS_SECRET_ACCESS_KEY' + - name: AWS_REGION + value: '$AWS_REGION' + - name: AWS_S3_BUCKET + value: '$AWS_S3_BUCKET' + - name: WASABI_ACCESS_KEY_ID + value: '$WASABI_ACCESS_KEY_ID' + - name: WASABI_SECRET_ACCESS_KEY + value: '$WASABI_SECRET_ACCESS_KEY' + - name: WASABI_REGION + value: '$WASABI_REGION' + - name: WASABI_SERVICE_URL + value: '$WASABI_SERVICE_URL' + - name: WASABI_S3_BUCKET + value: '$WASABI_S3_BUCKET' + - name: EXPRESS_SESSION_SECRET + value: '$EXPRESS_SESSION_SECRET' + - name: JWT_SECRET + value: '$JWT_SECRET' + - name: JWT_REFRESH_TOKEN_SECRET + value: '$JWT_REFRESH_TOKEN_SECRET' + - name: JWT_REFRESH_TOKEN_EXPIRATION_TIME + value: '$JWT_REFRESH_TOKEN_EXPIRATION_TIME' + - name: CLOUDINARY_API_KEY + value: '$CLOUDINARY_API_KEY' + - name: CLOUDINARY_API_SECRET + value: '$CLOUDINARY_API_SECRET' + - name: CLOUDINARY_CLOUD_NAME + value: '$CLOUDINARY_CLOUD_NAME' + - name: DEFAULT_CURRENCY + value: 'USD' + - name: MAIL_FROM_ADDRESS + value: '$MAIL_FROM_ADDRESS' + - name: MAIL_HOST + value: '$MAIL_HOST' + - name: MAIL_PORT + value: '$MAIL_PORT' + - name: MAIL_USERNAME + value: '$MAIL_USERNAME' + - name: MAIL_PASSWORD + value: '$MAIL_PASSWORD' + - name: ALLOW_SUPER_ADMIN_ROLE + value: '$ALLOW_SUPER_ADMIN_ROLE' + - name: GOOGLE_CLIENT_ID + value: '$GOOGLE_CLIENT_ID' + - name: GOOGLE_CLIENT_SECRET + value: '$GOOGLE_CLIENT_SECRET' + - name: GOOGLE_CALLBACK_URL + value: '$GOOGLE_CALLBACK_URL' + - name: FACEBOOK_CLIENT_ID + value: '$FACEBOOK_CLIENT_ID' + - name: FACEBOOK_CLIENT_SECRET + value: '$FACEBOOK_CLIENT_SECRET' + - name: FACEBOOK_GRAPH_VERSION + value: '$FACEBOOK_GRAPH_VERSION' + - name: FACEBOOK_CALLBACK_URL + value: '$FACEBOOK_CALLBACK_URL' + - name: INTEGRATED_USER_DEFAULT_PASS + value: '$INTEGRATED_USER_DEFAULT_PASS' + - name: UPWORK_REDIRECT_URL + value: '$UPWORK_REDIRECT_URL' + - name: FILE_PROVIDER + value: '$FILE_PROVIDER' + - name: GAUZY_AI_GRAPHQL_ENDPOINT + value: '$GAUZY_AI_GRAPHQL_ENDPOINT' + - name: GAUZY_AI_REST_ENDPOINT + value: '$GAUZY_AI_REST_ENDPOINT' + - name: UNLEASH_APP_NAME + value: '$UNLEASH_APP_NAME' + - name: UNLEASH_API_URL + value: '$UNLEASH_API_URL' + - name: UNLEASH_INSTANCE_ID + value: '$UNLEASH_INSTANCE_ID' + - name: UNLEASH_REFRESH_INTERVAL + value: '$UNLEASH_REFRESH_INTERVAL' + - name: UNLEASH_METRICS_INTERVAL + value: '$UNLEASH_METRICS_INTERVAL' + - name: UNLEASH_API_KEY + value: '$UNLEASH_API_KEY' + - name: PM2_PUBLIC_KEY + value: '$PM2_PUBLIC_KEY' + - name: PM2_SECRET_KEY + value: '$PM2_SECRET_KEY' + - name: PM2_MACHINE_NAME + value: '$PM2_MACHINE_NAME' + - name: JITSU_SERVER_URL + value: '$JITSU_SERVER_URL' + - name: JITSU_SERVER_WRITE_KEY + value: '$JITSU_SERVER_WRITE_KEY' + - name: OTEL_ENABLED + value: '$OTEL_ENABLED' + - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT + value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' + - name: OTEL_EXPORTER_OTLP_HEADERS + value: '$OTEL_EXPORTER_OTLP_HEADERS' + - name: GAUZY_GITHUB_CLIENT_ID + value: '$GAUZY_GITHUB_CLIENT_ID' + - name: GAUZY_GITHUB_CLIENT_SECRET + value: '$GAUZY_GITHUB_CLIENT_SECRET' + - name: GAUZY_GITHUB_WEBHOOK_URL + value: '$GAUZY_GITHUB_WEBHOOK_URL' + - name: GAUZY_GITHUB_WEBHOOK_SECRET + value: '$GAUZY_GITHUB_WEBHOOK_SECRET' + - name: GAUZY_GITHUB_APP_PRIVATE_KEY + value: '$GAUZY_GITHUB_APP_PRIVATE_KEY' + - name: GAUZY_GITHUB_APP_ID + value: '$GAUZY_GITHUB_APP_ID' + - name: GAUZY_GITHUB_APP_NAME + value: '$GAUZY_GITHUB_APP_NAME' + - name: GAUZY_GITHUB_POST_INSTALL_URL + value: '$GAUZY_GITHUB_POST_INSTALL_URL' + - name: GAUZY_GITHUB_OAUTH_CLIENT_ID + value: '$GAUZY_GITHUB_OAUTH_CLIENT_ID' + - name: GAUZY_GITHUB_OAUTH_CLIENT_SECRET + value: '$GAUZY_GITHUB_OAUTH_CLIENT_SECRET' + - name: GAUZY_GITHUB_OAUTH_CALLBACK_URL + value: '$GAUZY_GITHUB_OAUTH_CALLBACK_URL' + - name: MAGIC_CODE_EXPIRATION_TIME + value: '$MAGIC_CODE_EXPIRATION_TIME' + - name: APP_NAME + value: '$APP_NAME' + - name: APP_LOGO + value: '$APP_LOGO' + - name: APP_SIGNATURE + value: '$APP_SIGNATURE' + - name: APP_LINK + value: '$APP_LINK' + - name: APP_EMAIL_CONFIRMATION_URL + value: '$APP_EMAIL_CONFIRMATION_URL' + - name: APP_MAGIC_SIGN_URL + value: '$APP_MAGIC_SIGN_URL' + - name: COMPANY_LINK + value: '$COMPANY_LINK' + - name: COMPANY_NAME + value: '$COMPANY_NAME' + ports: + - containerPort: 3000 + protocol: TCP diff --git a/.deploy/k8s/k8s-manifest.prod.yaml b/.deploy/k8s/k8s-manifest.prod.yaml index 4d2b9b7e3..37275c528 100644 --- a/.deploy/k8s/k8s-manifest.prod.yaml +++ b/.deploy/k8s/k8s-manifest.prod.yaml @@ -41,7 +41,7 @@ spec: image: registry.digitalocean.com/ever/ever-teams-webapp:latest env: - name: DEMO - value: 'true' + value: 'false' - name: NEXT_PUBLIC_SENTRY_DNS value: '$NEXT_PUBLIC_SENTRY_DNS' - name: SENTRY_DSN diff --git a/.deploy/k8s/k8s-manifest.stage.yaml b/.deploy/k8s/k8s-manifest.stage.yaml new file mode 100644 index 000000000..8aa211513 --- /dev/null +++ b/.deploy/k8s/k8s-manifest.stage.yaml @@ -0,0 +1,110 @@ +--- +kind: Service +apiVersion: v1 +metadata: + name: ever-teams-state-lb + annotations: + service.beta.kubernetes.io/do-loadbalancer-name: 'stage.ever.team' + service.beta.kubernetes.io/do-loadbalancer-protocol: 'http2' + service.beta.kubernetes.io/do-loadbalancer-http2-ports: '443' + # Replace with your Certificate Id. You can get a list of Ids with 'doctl compute certificate list' + service.beta.kubernetes.io/do-loadbalancer-certificate-id: '0c4085c5-9692-4320-86f3-34f52b775a88' + service.beta.kubernetes.io/do-loadbalancer-size-slug: 'lb-small' + service.beta.kubernetes.io/do-loadbalancer-hostname: 'stage.ever.team' +spec: + type: LoadBalancer + selector: + app: ever-teams-stage-webapp + ports: + - name: http + protocol: TCP + port: 443 + targetPort: 3030 + +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: ever-teams-stage-webapp +spec: + replicas: 2 + selector: + matchLabels: + app: ever-teams-stage-webapp + template: + metadata: + labels: + app: ever-teams-stage-webapp + spec: + containers: + - name: ever-teams-stage-webapp + image: registry.digitalocean.com/ever/ever-teams-webapp-stage:latest + env: + - name: DEMO + value: 'false' + - name: NEXT_PUBLIC_SENTRY_DNS + value: '$NEXT_PUBLIC_SENTRY_DNS' + - name: SENTRY_DSN + value: '$SENTRY_DSN' + - name: NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY + value: '$NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY' + - name: NEXT_PUBLIC_JITSU_BROWSER_URL + value: '$NEXT_PUBLIC_JITSU_BROWSER_URL' + - name: SENTRY_AUTH_TOKEN + value: '$SENTRY_AUTH_TOKEN' + - name: NEXT_PUBLIC_CHATWOOT_API_KEY + value: '$NEXT_PUBLIC_CHATWOOT_API_KEY' + - name: NEXT_PUBLIC_SENTRY_DEBUG + value: '$NEXT_PUBLIC_SENTRY_DEBUG' + - name: SENTRY_PROJECT + value: '$SENTRY_PROJECT' + - name: SENTRY_ORG + value: '$SENTRY_ORG' + - name: SMTP_FROM_ADDRESS + value: '$SMTP_FROM_ADDRESS' + - name: JITSU_SERVER_WRITE_KEY + value: '$JITSU_SERVER_WRITE_KEY' + - name: JITSU_SERVER_URL + value: '$JITSU_SERVER_URL' + - name: NEXT_PUBLIC_COOKIE_DOMAINS + value: '$NEXT_PUBLIC_COOKIE_DOMAINS' + - name: NEXT_PUBLIC_BOARD_FIREBASE_CONFIG + value: '$NEXT_PUBLIC_BOARD_FIREBASE_CONFIG' + - name: NEXT_PUBLIC_BOARD_BACKEND_POST_URL + value: '$NEXT_PUBLIC_BOARD_BACKEND_POST_URL' + - name: NEXT_PUBLIC_BOARD_APP_DOMAIN + value: '$NEXT_PUBLIC_BOARD_APP_DOMAIN' + - name: MEET_JWT_APP_SECRET + value: '$MEET_JWT_APP_SECRET' + - name: MEET_JWT_APP_ID + value: '$MEET_JWT_APP_ID' + - name: NEXT_PUBLIC_MEET_DOMAIN + value: '$NEXT_PUBLIC_MEET_DOMAIN' + - name: GAUZY_API_SERVER_URL + value: '$GAUZY_API_SERVER_URL' + - name: NEXT_PUBLIC_GAUZY_API_SERVER_URL + value: '$NEXT_PUBLIC_GAUZY_API_SERVER_URL' + - name: MAILCHIMP_LIST_ID + value: '$MAILCHIMP_LIST_ID' + - name: MAILCHIMP_API_KEY + value: '$MAILCHIMP_API_KEY' + - name: POSTMARK_SERVER_API_TOKEN + value: '$POSTMARK_SERVER_API_TOKEN' + - name: NEXT_PUBLIC_GA_MEASUREMENT_ID + value: '$NEXT_PUBLIC_GA_MEASUREMENT_ID' + - name: SMTP_HOST + value: '$SMTP_HOST' + - name: SMTP_SECURE + value: '$SMTP_SECURE' + - name: SMTP_USERNAME + value: '$SMTP_USERNAME' + - name: SMTP_PASSWORD + value: '$SMTP_PASSWORD' + - name: CAPTCHA_SECRET_KEY + value: '$CAPTCHA_SECRET_KEY' + - name: NEXT_PUBLIC_CAPTCHA_SITE_KEY + value: '$NEXT_PUBLIC_CAPTCHA_SITE_KEY' + + ports: + - containerPort: 3030 + protocol: TCP diff --git a/.github/workflows/deploy-api-do-stage.yml b/.github/workflows/deploy-api-do-stage.yml new file mode 100644 index 000000000..a4f863303 --- /dev/null +++ b/.github/workflows/deploy-api-do-stage.yml @@ -0,0 +1,131 @@ +name: Deploy API to DigitalOcean Stage + +on: + push: + branches: [stage] + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + deploy-api-stage: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: prod + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Log in to DigitalOcean Container Registry with short-lived credentials + run: doctl registry login --expiry-seconds 600 + + - name: Save DigitalOcean kubeconfig with short-lived credentials + run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 k8s-gauzy + + - name: Apply k8s manifests changes in DigitalOcean k8s cluster (if any) + run: | + envsubst < $GITHUB_WORKSPACE/.deploy/k8s/k8s-manifest-api.stage.yaml | kubectl --context do-sfo2-k8s-gauzy apply -f - + env: + # below we are using GitHub secrets for both frontend and backend + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ secrets.DB_HOST }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ secrets.REDIS_URL }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + # we need this step because for now we just use :latest tag + # note: for production we will use different strategy later + - name: Restart Pods to pick up :latest tag version + run: | + kubectl --context do-sfo2-k8s-gauzy rollout restart deployment/ever-teams-stage-api diff --git a/.github/workflows/deploy-do-stage.yml b/.github/workflows/deploy-do-stage.yml new file mode 100644 index 000000000..52b84cddb --- /dev/null +++ b/.github/workflows/deploy-do-stage.yml @@ -0,0 +1,73 @@ +name: Deploy to DigitalOcean Stage + +on: + workflow_run: + workflows: ['Build and Publish Docker Images Stage'] + branches: [stage] + types: + - completed + +jobs: + deploy-demo: + runs-on: ubuntu-latest + + environment: prod + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Log in to DigitalOcean Container Registry with short-lived credentials + run: doctl registry login --expiry-seconds 600 + + - name: Save DigitalOcean kubeconfig with short-lived credentials + run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 k8s-gauzy + + - name: Apply k8s manifests changes in DigitalOcean k8s cluster (if any) + run: | + envsubst < $GITHUB_WORKSPACE/.deploy/k8s/k8s-manifest.stage.yaml | kubectl --context do-sfo2-k8s-gauzy apply -f - + env: + # below we are using GitHub secrets for both frontend and backend + CLOUD_PROVIDER: 'DO' + NEXT_PUBLIC_SENTRY_DNS: '${{ secrets.NEXT_PUBLIC_SENTRY_DNS }}' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY: '${{ secrets.NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY }}' + NEXT_PUBLIC_JITSU_BROWSER_URL: '${{ secrets.NEXT_PUBLIC_JITSU_BROWSER_URL }}' + SENTRY_AUTH_TOKEN: '${{ secrets.SENTRY_AUTH_TOKEN }}' + NEXT_PUBLIC_CHATWOOT_API_KEY: '${{ secrets.NEXT_PUBLIC_CHATWOOT_API_KEY }}' + NEXT_PUBLIC_SENTRY_DEBUG: '${{ secrets.NEXT_PUBLIC_SENTRY_DEBUG }}' + SENTRY_PROJECT: '${{ secrets.SENTRY_PROJECT }}' + SENTRY_ORG: '${{ secrets.SENTRY_ORG }}' + SMTP_FROM_ADDRESS: '${{ secrets.SMTP_FROM_ADDRESS }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + NEXT_PUBLIC_COOKIE_DOMAINS: '${{ secrets.NEXT_PUBLIC_COOKIE_DOMAINS }}' + NEXT_PUBLIC_BOARD_FIREBASE_CONFIG: '${{ secrets.NEXT_PUBLIC_BOARD_FIREBASE_CONFIG }}' + NEXT_PUBLIC_BOARD_BACKEND_POST_URL: '${{ secrets.NEXT_PUBLIC_BOARD_BACKEND_POST_URL }}' + NEXT_PUBLIC_BOARD_APP_DOMAIN: '${{ secrets.NEXT_PUBLIC_BOARD_APP_DOMAIN }}' + MEET_JWT_APP_SECRET: '${{ secrets.MEET_JWT_APP_SECRET }}' + MEET_JWT_APP_ID: '${{ secrets.MEET_JWT_APP_ID }}' + NEXT_PUBLIC_MEET_DOMAIN: '${{ secrets.NEXT_PUBLIC_MEET_DOMAIN }}' + GAUZY_API_SERVER_URL: 'https://apistage.ever.team' + NEXT_PUBLIC_GAUZY_API_SERVER_URL: 'https://apistage.ever.team' + MAILCHIMP_LIST_ID: '${{ secrets.MAILCHIMP_LIST_ID }}' + MAILCHIMP_API_KEY: '${{ secrets.MAILCHIMP_API_KEY }}' + POSTMARK_SERVER_API_TOKEN: '${{ secrets.POSTMARK_SERVER_API_TOKEN }}' + NEXT_PUBLIC_GA_MEASUREMENT_ID: '${{ secrets.NEXT_PUBLIC_GA_MEASUREMENT_ID }}' + SMTP_HOST: '${{ secrets.SMTP_HOST }}' + SMTP_SECURE: '${{ secrets.SMTP_SECURE }}' + SMTP_USERNAME: '${{ secrets.SMTP_USERNAME }}' + SMTP_PASSWORD: '${{ secrets.SMTP_PASSWORD }}' + CAPTCHA_SECRET_KEY: '${{ secrets.CAPTCHA_SECRET_KEY }}' + NEXT_PUBLIC_CAPTCHA_SITE_KEY: '${{ secrets.NEXT_PUBLIC_CAPTCHA_SITE_KEY }}' + + # we need this step because for now we just use :latest tag + # note: for production we will use different strategy later + - name: Restart Pods to pick up :latest tag version + run: | + kubectl --context do-sfo2-k8s-gauzy rollout restart deployment/ever-teams-stage-webapp diff --git a/.github/workflows/deploy-vercel-dev.yml b/.github/workflows/deploy-vercel-dev.yml index e5b025b68..89413d221 100644 --- a/.github/workflows/deploy-vercel-dev.yml +++ b/.github/workflows/deploy-vercel-dev.yml @@ -5,7 +5,7 @@ on: - develop paths: - '.deploy/web/**' - - '.github/workflows/web.dev.yml' + - '.github/workflows/**' - 'apps/web/**' - 'package.json' - 'yarn.lock' diff --git a/.github/workflows/deploy-vercel-prod.yml b/.github/workflows/deploy-vercel-prod.yml index 494a60de1..7e31e89ec 100644 --- a/.github/workflows/deploy-vercel-prod.yml +++ b/.github/workflows/deploy-vercel-prod.yml @@ -5,7 +5,7 @@ on: - main paths: - '.deploy/web/**' - - '.github/workflows/web.prod.yml' + - '.github/workflows/**' - 'apps/web/**' - 'package.json' - 'yarn.lock' diff --git a/.github/workflows/deploy-vercel-stage.yml b/.github/workflows/deploy-vercel-stage.yml new file mode 100644 index 000000000..050a7778e --- /dev/null +++ b/.github/workflows/deploy-vercel-stage.yml @@ -0,0 +1,47 @@ +name: Web Build & Vercel Deploy Stage +on: + push: + branches: + - stage_fix_to_be_different_from_prod + paths: + - '.deploy/web/**' + - '.github/workflows/**' + - 'apps/web/**' + - 'package.json' + - 'yarn.lock' + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js 18.x + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'yarn' + + - name: Install Packages + run: | + yarn install --frozen-lockfile + + - name: Build Web + run: | + yarn build:web + + - name: Deploy to Vercel + uses: BetaHuhn/deploy-to-vercel-action@v1 + with: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} # Required + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Optional + GITHUB_DEPLOYMENT_ENV: Preview + PRODUCTION: false + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID}} #Required + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID}} #Required + WORKING_DIRECTORY: ./ diff --git a/.github/workflows/docker-build-publish-stage.yml b/.github/workflows/docker-build-publish-stage.yml new file mode 100644 index 000000000..1e592aa8e --- /dev/null +++ b/.github/workflows/docker-build-publish-stage.yml @@ -0,0 +1,103 @@ +name: Build and Publish Docker Images Stage + +on: + push: + branches: [stage] + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + ever-teams-webapp: + runs-on: buildjet-8vcpu-ubuntu-2204 + + environment: prod + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Output NEXT_PUBLIC_GAUZY_API_SERVER_URL + run: echo "NEXT_PUBLIC_GAUZY_API_SERVER_URL=${{ secrets.NEXT_PUBLIC_GAUZY_API_SERVER_URL }}" + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + load: true + tags: | + ghcr.io/ever-co/ever-teams-webapp-stage:latest + everco/ever-teams-webapp-stage:latest + registry.digitalocean.com/ever/ever-teams-webapp-stage:latest + ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/ever-teams-webapp-stage:latest + cache-from: type=registry,ref=everco/ever-teams-webapp-stage:latest + cache-to: type=inline + build-args: | + NODE_ENV=production + NEXT_PUBLIC_GAUZY_API_SERVER_URL='https://apistage.ever.team' + NEXT_PUBLIC_GA_MEASUREMENT_ID=${{ secrets.NEXT_PUBLIC_GA_MEASUREMENT_ID }} + NEXT_PUBLIC_CAPTCHA_SITE_KEY=${{ secrets.NEXT_PUBLIC_CAPTCHA_SITE_KEY }} + NEXT_PUBLIC_DISABLE_AUTO_REFRESH=false + NEXT_PUBLIC_COOKIE_DOMAINS=${{ secrets.NEXT_PUBLIC_COOKIE_DOMAINS }} + NEXT_PUBLIC_BOARD_APP_DOMAIN=${{ secrets.NEXT_PUBLIC_BOARD_APP_DOMAIN }} + NEXT_PUBLIC_BOARD_BACKEND_POST_URL=${{ secrets.NEXT_PUBLIC_BOARD_BACKEND_POST_URL }} + NEXT_PUBLIC_BOARD_FIREBASE_CONFIG=${{ secrets.NEXT_PUBLIC_BOARD_FIREBASE_CONFIG }} + NEXT_PUBLIC_MEET_DOMAIN=${{ secrets.NEXT_PUBLIC_MEET_DOMAIN }} + NEXT_PUBLIC_SENTRY_DSN=${{ secrets.NEXT_PUBLIC_SENTRY_DSN }} + NEXT_PUBLIC_SENTRY_DEBUG=${{ secrets.NEXT_PUBLIC_SENTRY_DEBUG }} + NEXT_PUBLIC_JITSU_BROWSER_URL=${{ secrets.NEXT_PUBLIC_JITSU_BROWSER_URL }} + NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY=${{ secrets.NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY }} + NEXT_PUBLIC_GITHUB_APP_NAME=ever-github + NEXT_PUBLIC_CHATWOOT_API_KEY=${{ secrets.NEXT_PUBLIC_CHATWOOT_API_KEY }} + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Push to Docker Hub Registry + run: | + docker push everco/ever-teams-webapp-stage:latest + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Log in to DigitalOcean Container Registry with short-lived credentials + run: doctl registry login --expiry-seconds 3600 + + - name: Push to DigitalOcean Registry + run: | + docker push registry.digitalocean.com/ever/ever-teams-webapp-stage:latest + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GH_TOKEN }} + + - name: Push to Github Registry + run: | + docker push ghcr.io/ever-co/ever-teams-webapp-stage:latest + + - name: Login to CW Container Registry + uses: docker/login-action@v2 + with: + registry: ${{ secrets.CW_DOCKER_REGISTRY }} + username: ${{ secrets.CW_DOCKER_USER }} + password: ${{ secrets.CW_DOCKER_USER_PASSWORD }} + + - name: Push to CW Registry + run: | + docker push ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/ever-teams-webapp-stage:latest diff --git a/.github/workflows/release.stage.yml b/.github/workflows/release.stage.yml new file mode 100644 index 000000000..8538e8c89 --- /dev/null +++ b/.github/workflows/release.stage.yml @@ -0,0 +1,36 @@ +name: Release Stage + +on: + push: + branches: [stage] + +jobs: + release: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Bump version and push tag + uses: mathieudutour/github-tag-action@v6.1 + id: tag_version + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + release_branches: apps,master,main,develop,stage + pre_release_branches: something_to_possible_use_later + + - name: Create a GitHub release + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + generateReleaseNotes: true + prerelease: true + token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ steps.tag_version.outputs.new_tag }} + name: ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }}