name: 'Preview Environment Keep Alive' permissions: contents: read on: repository_dispatch: types: [preview-environment] jobs: preview-environment: timeout-minutes: 310 runs-on: ubuntu-latest steps: - name: Checkout PR uses: actions/checkout@v4 with: ref: ${{ github.event.client_payload.pr_head_sha }} - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} - name: Run compose setup run: | echo "Patching docker-compose.yml..." # change image to localbuild using yq yq eval 'del(.services.server.image)' -i packages/twenty-docker/docker-compose.yml yq eval '.services.server.build.context = "../../"' -i packages/twenty-docker/docker-compose.yml yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i packages/twenty-docker/docker-compose.yml yq eval '.services.server.build.target = "twenty"' -i packages/twenty-docker/docker-compose.yml yq eval 'del(.services.worker.image)' -i packages/twenty-docker/docker-compose.yml yq eval '.services.worker.build.context = "../../"' -i packages/twenty-docker/docker-compose.yml yq eval '.services.worker.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i packages/twenty-docker/docker-compose.yml yq eval '.services.worker.build.target = "twenty"' -i packages/twenty-docker/docker-compose.yml echo "Adding SIGN_IN_PREFILLED environment variable to server service..." yq eval '.services.server.environment.SIGN_IN_PREFILLED = "${SIGN_IN_PREFILLED}"' -i packages/twenty-docker/docker-compose.yml echo "Setting up .env file..." cp packages/twenty-docker/.env.example packages/twenty-docker/.env echo "Generating secrets..." echo "" >> packages/twenty-docker/.env echo "# === Randomly generated secrets ===" >> packages/twenty-docker/.env echo "APP_SECRET=$(openssl rand -base64 32)" >> packages/twenty-docker/.env echo "PG_DATABASE_PASSWORD=$(openssl rand -hex 16)" >> packages/twenty-docker/.env echo "SIGN_IN_PREFILLED=true" >> packages/twenty-docker/.env echo "Docker compose build..." cd packages/twenty-docker/ docker compose build working-directory: ./ - name: Create Tunnel id: expose-tunnel uses: codetalkio/expose-tunnel@v1.5.0 with: service: bore.pub port: 3000 - name: Start services with correct SERVER_URL env: TUNNEL_URL: ${{ steps.expose-tunnel.outputs.tunnel-url }} run: | cd packages/twenty-docker/ echo "Setting SERVER_URL to $TUNNEL_URL" sed -i '/SERVER_URL=/d' .env echo "" >> .env echo "SERVER_URL=$TUNNEL_URL" >> .env # Start the services echo "Docker compose up..." docker compose up -d || { echo "Docker compose failed to start" docker compose logs exit 1 } echo "Waiting for services to be ready..." count=0 while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-db-1) = "healthy" ] || [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do sleep 5 count=$((count+1)) if [ $count -gt 60 ]; then echo "Timeout waiting for services to be ready" docker compose logs exit 1 fi echo "Still waiting for services... ($count/60)" done echo "All services are up and running!" working-directory: ./ - name: Seed Dev Workspace run: | cd packages/twenty-docker/ echo "Seeding full dev workspace..." if ! docker compose exec -T server yarn command:prod -- workspace:seed:dev; then echo "❌ Seeding full dev workspace failed. Dumping server logs..." docker compose logs server exit 1 fi working-directory: ./ - name: Output tunnel URL env: TUNNEL_URL: ${{ steps.expose-tunnel.outputs.tunnel-url }} run: | echo "✅ Preview Environment Ready!" echo "🔗 Preview URL: $TUNNEL_URL" echo "⏱️ This environment will be available for 5 hours" echo "## 🚀 Preview Environment Ready!" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "Preview URL: $TUNNEL_URL" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "This environment will automatically shut down after 5 hours." >> "$GITHUB_STEP_SUMMARY" echo "$TUNNEL_URL" > tunnel-url.txt - name: Upload tunnel URL artifact uses: actions/upload-artifact@v4 with: name: tunnel-url path: tunnel-url.txt retention-days: 1 - name: Keep tunnel alive for 5 hours run: timeout 300m sleep 18000 # Stop on whichever we reach first (300m or 5hour sleep) - name: Cleanup if: always() run: | cd packages/twenty-docker/ docker compose down -v working-directory: ./