From 3fc498dba7e646555a5a6b55d02fceb883e1406c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Fri, 25 Apr 2025 15:42:40 +0200 Subject: [PATCH] Attempt to add preview environments (#11734) Just doing a quick test --- .github/workflows/preview-env-dispatch.yaml | 34 +++++ .github/workflows/preview-env-keepalive.yaml | 148 +++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 .github/workflows/preview-env-dispatch.yaml create mode 100644 .github/workflows/preview-env-keepalive.yaml diff --git a/.github/workflows/preview-env-dispatch.yaml b/.github/workflows/preview-env-dispatch.yaml new file mode 100644 index 000000000..2ffe53cb5 --- /dev/null +++ b/.github/workflows/preview-env-dispatch.yaml @@ -0,0 +1,34 @@ +name: 'Preview Environment Dispatch' + +on: + 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: | + .github/workflows/preview-env-dispatch.yaml + .github/workflows/preview-env-keepalive.yaml + packages/twenty-docker/** + docker-compose.yml + packages/twenty-server/** + packages/twenty-front/** + + trigger-preview: + needs: changed-files-check + if: needs.changed-files-check.outputs.any_changed == 'true' || contains(github.event.pull_request.labels.*.name, 'preview') + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - name: Trigger preview environment workflow + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: preview-env-keepalive.yaml + token: ${{ secrets.GITHUB_TOKEN }} + inputs: '{"pr_number": "${{ github.event.pull_request.number }}", "pr_head_sha": "${{ github.event.pull_request.head.sha }}", "repo_full_name": "${{ github.repository }}"}' \ No newline at end of file diff --git a/.github/workflows/preview-env-keepalive.yaml b/.github/workflows/preview-env-keepalive.yaml new file mode 100644 index 000000000..5d192e4d9 --- /dev/null +++ b/.github/workflows/preview-env-keepalive.yaml @@ -0,0 +1,148 @@ +name: 'Preview Environment Keep Alive' + +on: + workflow_dispatch: + inputs: + pr_number: + description: 'PR number' + required: true + pr_head_sha: + description: 'PR head SHA' + required: true + repo_full_name: + description: 'Repository full name (owner/repo)' + required: true + +jobs: + preview-environment: + timeout-minutes: 310 + runs-on: ubuntu-latest + steps: + - name: Checkout PR + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha }} + + - 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 '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 + + echo "Setting up .env file..." + cp packages/twenty-docker/.env.example packages/twenty-docker/.env + + echo "Generating secrets..." + 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 "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 + run: | + cd packages/twenty-docker/ + + # Update the SERVER_URL with the tunnel URL + echo "Setting SERVER_URL to ${{ steps.expose-tunnel.outputs.tunnel-url }}" + sed -i '/SERVER_URL=/d' .env + echo "SERVER_URL=${{ steps.expose-tunnel.outputs.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: Output tunnel URL to logs + run: | + echo "✅ Preview Environment Ready!" + echo "🔗 Preview URL: ${{ steps.expose-tunnel.outputs.tunnel-url }}" + echo "⏱️ This environment will be available for 5 hours" + + - name: Post comment on PR + uses: actions/github-script@v6 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const COMMENT_MARKER = ''; + const commentBody = `${COMMENT_MARKER} + 🚀 **Preview Environment Ready!** + + Your preview environment is available at: ${{ steps.expose-tunnel.outputs.tunnel-url }} + + This environment will automatically shut down when the PR is closed or after 5 hours.`; + + // Get all comments + const {data: comments} = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ inputs.pr_number }}, + }); + + // Find our comment + const botComment = comments.find(comment => comment.body.includes(COMMENT_MARKER)); + + if (botComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: commentBody + }); + console.log('Updated existing comment'); + } else { + // Create new comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ inputs.pr_number }}, + body: commentBody + }); + console.log('Created new comment'); + } + + - 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: ./ \ No newline at end of file