|  | 
| 1 | 1 | # Control Plane GitHub Action | 
| 2 | 2 | 
 | 
| 3 |  | -name: Deploy-To-Control-Plane | 
| 4 |  | -description: 'Deploys both to staging and to review apps' | 
|  | 3 | +name: Deploy to ControlPlane | 
|  | 4 | +description: 'Deploys an application to Control Plane' | 
| 5 | 5 | 
 | 
| 6 | 6 | inputs: | 
| 7 | 7 |  app_name: | 
| 8 |  | - description: 'The name of the app to deploy' | 
|  | 8 | + description: 'Name of the application' | 
| 9 | 9 |  required: true | 
| 10 |  | - default: | 
| 11 | 10 |  org: | 
| 12 |  | - description: 'The org of the app to deploy' | 
|  | 11 | + description: 'Organization name' | 
| 13 | 12 |  required: true | 
| 14 |  | - default: | 
|  | 13 | + github_token: | 
|  | 14 | + description: 'GitHub token' | 
|  | 15 | + required: true | 
|  | 16 | + wait_timeout: | 
|  | 17 | + description: 'Timeout in seconds for waiting for workloads to be ready' | 
|  | 18 | + required: false | 
|  | 19 | + default: '900' | 
|  | 20 | + | 
|  | 21 | +outputs: | 
|  | 22 | + review_app_url: | 
|  | 23 | + description: 'URL of the deployed application' | 
|  | 24 | + value: ${{ steps.deploy.outputs.review_app_url }} | 
| 15 | 25 | 
 | 
| 16 | 26 | runs: | 
| 17 |  | - using: 'composite' | 
|  | 27 | + using: "composite" | 
| 18 | 28 |  steps: | 
| 19 | 29 |  - name: Setup Environment | 
| 20 | 30 |  uses: ./.github/actions/setup-environment | 
| 21 | 31 | 
 | 
| 22 |  | - - name: Set Short SHA | 
| 23 |  | - id: vars | 
|  | 32 | + - name: Get Commit SHA | 
|  | 33 | + id: get_sha | 
| 24 | 34 |  shell: bash | 
| 25 |  | - run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" | 
| 26 |  | - | 
| 27 |  | - # Caching step | 
| 28 |  | - - uses: actions/cache@v2 | 
| 29 |  | - with: | 
| 30 |  | - path: /tmp/.docker-cache | 
| 31 |  | - key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}-${{ github.sha }} | 
| 32 |  | - restore-keys: | | 
| 33 |  | - ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }} | 
| 34 |  | - ${{ runner.os }}-docker- | 
|  | 35 | + run: ${{ github.action_path }}/scripts/get-commit-sha.sh | 
|  | 36 | + env: | 
|  | 37 | + GITHUB_TOKEN: ${{ inputs.github_token }} | 
|  | 38 | + PR_NUMBER: ${{ env.PR_NUMBER }} | 
| 35 | 39 | 
 | 
| 36 |  | - - name: cpflow setup-app | 
| 37 |  | - shell: bash | 
| 38 |  | - run: | | 
| 39 |  | - if ! cpflow exists -a ${{ inputs.app_name }} ; then | 
| 40 |  | - cpflow setup-app -a ${{ inputs.app_name }} | 
| 41 |  | - fi | 
| 42 |  | - # Provision all infrastructure on Control Plane. | 
| 43 |  | - # app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml | 
| 44 |  | - - name: cpflow build-image | 
| 45 |  | - shell: bash | 
| 46 |  | - run: | | 
| 47 |  | - cpln image docker-login | 
| 48 |  | - # Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build | 
| 49 |  | - # BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}} | 
| 50 |  | - cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}} | 
| 51 |  | - # --cache /tmp/.docker-cache | 
| 52 | 40 |  - name: Deploy to Control Plane | 
|  | 41 | + id: deploy | 
| 53 | 42 |  shell: bash | 
| 54 | 43 |  run: | | 
| 55 |  | - echo "Deploying to Control Plane" | 
| 56 |  | - cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose | 
|  | 44 | + echo "🚀 Deploying app for PR #${PR_NUMBER}..." | 
|  | 45 | + | 
|  | 46 | + # Create temp file for output | 
|  | 47 | + TEMP_OUTPUT=$(mktemp) | 
|  | 48 | + trap 'rm -f "${TEMP_OUTPUT}"' EXIT | 
|  | 49 | + | 
|  | 50 | + # Deploy the application and show output in real-time while capturing it | 
|  | 51 | + if ! cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1 | tee "${TEMP_OUTPUT}"; then | 
|  | 52 | + echo "❌ Deployment failed for PR #${PR_NUMBER}" | 
|  | 53 | + echo "Error output:" | 
|  | 54 | + cat "${TEMP_OUTPUT}" | 
|  | 55 | + exit 1 | 
|  | 56 | + fi | 
|  | 57 | + | 
|  | 58 | + # Extract app URL from captured output | 
|  | 59 | + REVIEW_APP_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "${TEMP_OUTPUT}" | head -n1) | 
|  | 60 | + if [ -z "${REVIEW_APP_URL}" ]; then | 
|  | 61 | + echo "❌ Failed to get app URL from deployment output" | 
|  | 62 | + echo "Deployment output:" | 
|  | 63 | + cat "${TEMP_OUTPUT}" | 
|  | 64 | + exit 1 | 
|  | 65 | + fi | 
|  | 66 | + | 
|  | 67 | + # Wait for all workloads to be ready | 
|  | 68 | + WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}} | 
|  | 69 | + if ! [[ "${WAIT_TIMEOUT}" =~ ^[0-9]+$ ]]; then | 
|  | 70 | + echo "❌ Invalid timeout value: ${WAIT_TIMEOUT}" | 
|  | 71 | + exit 1 | 
|  | 72 | + fi | 
|  | 73 | + echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)" | 
|  | 74 | + | 
|  | 75 | + # Use timeout command with ps:wait and show output in real-time | 
|  | 76 | + if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1 | tee -a "${TEMP_OUTPUT}"; then | 
|  | 77 | + TIMEOUT_EXIT=$? | 
|  | 78 | + if [ ${TIMEOUT_EXIT} -eq 124 ]; then | 
|  | 79 | + echo "❌ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds" | 
|  | 80 | + else | 
|  | 81 | + echo "❌ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})" | 
|  | 82 | + fi | 
|  | 83 | + echo "Full output:" | 
|  | 84 | + cat "${TEMP_OUTPUT}" | 
|  | 85 | + exit 1 | 
|  | 86 | + fi | 
|  | 87 | + | 
|  | 88 | + echo "✅ Deployment successful for PR #${PR_NUMBER}" | 
|  | 89 | + echo "🌐 App URL: ${REVIEW_APP_URL}" | 
|  | 90 | + echo "review_app_url=${REVIEW_APP_URL}" >> $GITHUB_OUTPUT | 
|  | 91 | + echo "REVIEW_APP_URL=${REVIEW_APP_URL}" >> $GITHUB_ENV | 
0 commit comments