Skip to content

Building on working for review apps #620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .controlplane/controlplane.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ aliases:
release_script: release_script.sh

apps:
react-webpack-rails-tutorial:
react-webpack-rails-tutorial-production:
# Simulate Production Version
<<: *common
# Don't allow overriding the org and app by ENV vars b/c production is sensitive!
Expand Down
248 changes: 51 additions & 197 deletions .github/actions/deploy-to-control-plane/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,205 +44,59 @@ runs:
- name: Setup Environment
uses: ./.github/actions/setup-environment

- name: Set shared functions
id: shared-functions
uses: actions/github-script@v7
with:
script: |
core.exportVariable('GET_CONSOLE_LINK', `
function getConsoleLink(prNumber) {
return ' [Control Plane Console for Review App with PR #' + prNumber + '](' +
'https://console.cpln.io/org/' + process.env.CPLN_ORG + '/workloads/' + process.env.APP_NAME + ')';
}
`);

- name: Initialize Deployment
id: init-deployment
uses: actions/github-script@v7
with:
script: |
eval(process.env.GET_CONSOLE_LINK);

async function getWorkflowUrl(runId) {
// Get the current job ID
const jobs = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: runId
});

const currentJob = jobs.data.jobs.find(job => job.status === 'in_progress');
const jobId = currentJob?.id;

if (!jobId) {
console.log('Warning: Could not find current job ID');
return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`;
}

return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}`;
}

// Create initial deployment comment
const comment = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: process.env.PR_NUMBER,
body: ' Initializing deployment...'
});

// Create GitHub deployment
const deployment = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'review',
auto_merge: false,
required_contexts: []
});

const workflowUrl = await getWorkflowUrl(context.runId);

core.exportVariable('WORKFLOW_URL', workflowUrl);
core.exportVariable('COMMENT_ID', comment.data.id);
core.exportVariable('DEPLOYMENT_ID', deployment.data.id);

- name: Set commit hash
shell: bash
run: |
FULL_COMMIT=$(git rev-parse HEAD)
echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV

- name: Update Status - Setting Up
uses: actions/github-script@v7
with:
script: |
eval(process.env.GET_CONSOLE_LINK);

const setupMessage = [
'🔧 Setting up Control Plane app...',
'',
' [View Setup Logs](' + process.env.WORKFLOW_URL + ')',
'',
getConsoleLink(process.env.PR_NUMBER)
].join('\n');

await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: setupMessage
});

- name: Setup Control Plane App
- name: Get Commit SHA
id: get_sha
shell: bash
run: |
echo "🔧 Checking if app exists..."
if ! cpflow exists -a ${{ inputs.app_name }} ; then
echo "📦 Setting up new Control Plane app..."
cpflow setup-app -a ${{ inputs.app_name }}
fi

- name: Update Status - Building
uses: actions/github-script@v7
with:
script: |
eval(process.env.GET_CONSOLE_LINK);

const buildingMessage = [
'🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + process.env.COMMIT_HASH,
'',
' [View Build Logs](' + process.env.WORKFLOW_URL + ')',
'',
getConsoleLink(process.env.PR_NUMBER)
].join('\n');

await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: buildingMessage
});

- name: Update Status - Deploying
uses: actions/github-script@v7
with:
script: |
eval(process.env.GET_CONSOLE_LINK);

const deployingMessage = [
'🚀 Deploying to Control Plane...',
'',
'⏳ Waiting for deployment to be ready...',
'',
' [View Deploy Logs](' + process.env.WORKFLOW_URL + ')',
'',
getConsoleLink(process.env.PR_NUMBER)
].join('\n');

await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: deployingMessage
});
run: ${{ github.action_path }}/scripts/get-commit-sha.sh
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
PR_NUMBER: ${{ env.PR_NUMBER }}

- name: Deploy to Control Plane
id: deploy
shell: bash
run: ${{ github.action_path }}/scripts/deploy.sh
env:
APP_NAME: ${{ inputs.app_name }}
CPLN_ORG: ${{ inputs.org }}
WAIT_TIMEOUT: ${{ inputs.wait_timeout }}

- name: Update Status - Deployment Complete
if: always()
uses: actions/github-script@v7
with:
script: |
eval(process.env.GET_CONSOLE_LINK);

const prNumber = process.env.PR_NUMBER;
const appUrl = process.env.REVIEW_APP_URL;
const workflowUrl = process.env.WORKFLOW_URL;
const isSuccess = '${{ job.status }}' === 'success';

// Create GitHub deployment status
const deploymentStatus = {
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: process.env.DEPLOYMENT_ID,
state: isSuccess ? 'success' : 'failure',
environment_url: isSuccess ? appUrl : undefined,
log_url: workflowUrl,
environment: 'review'
};

await github.rest.repos.createDeploymentStatus(deploymentStatus);

// Define messages based on deployment status
const successMessage = [
'✅ Deployment complete for PR #' + prNumber + ', commit ' + process.env.COMMIT_HASH,
'',
'🌐 [Review App for PR #' + prNumber + '](' + appUrl + ')',
'',
' [View Completed Action Build and Deploy Logs](' + workflowUrl + ')',
'',
getConsoleLink(prNumber)
].join('\n');

const failureMessage = [
'❌ Deployment failed for PR #' + prNumber + ', commit ' + process.env.COMMIT_HASH,
'',
' [View Deployment Logs with Errors](' + workflowUrl + ')',
'',
getConsoleLink(prNumber)
].join('\n');

// Update the existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: isSuccess ? successMessage : failureMessage
});
run: |
echo "🚀 Deploying app for PR #${PR_NUMBER}..."

# Create temp file for output
TEMP_OUTPUT=$(mktemp)
trap 'rm -f "${TEMP_OUTPUT}"' EXIT

# Deploy the application and show output in real-time while capturing it
if ! cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1 | tee "${TEMP_OUTPUT}"; then
echo "❌ Deployment failed for PR #${PR_NUMBER}"
echo "Error output:"
cat "${TEMP_OUTPUT}"
exit 1
fi

# Extract app URL from captured output
REVIEW_APP_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "${TEMP_OUTPUT}" | head -n1)
if [ -z "${REVIEW_APP_URL}" ]; then
echo "❌ Failed to get app URL from deployment output"
echo "Deployment output:"
cat "${TEMP_OUTPUT}"
exit 1
fi

# Wait for all workloads to be ready
WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}}
echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)..."

# Use timeout command with ps:wait and show output in real-time
if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1 | tee -a "${TEMP_OUTPUT}"; then
TIMEOUT_EXIT=$?
if [ ${TIMEOUT_EXIT} -eq 124 ]; then
echo "❌ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds"
else
echo "❌ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})"
fi
echo "Full output:"
cat "${TEMP_OUTPUT}"
exit 1
fi

echo "✅ Deployment successful for PR #${PR_NUMBER}"
echo "🌐 App URL: ${REVIEW_APP_URL}"
echo "review_app_url=${REVIEW_APP_URL}" >> $GITHUB_OUTPUT
echo "REVIEW_APP_URL=${REVIEW_APP_URL}" >> $GITHUB_ENV
25 changes: 18 additions & 7 deletions .github/actions/setup-environment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
name: 'Setup Environment'
description: 'Sets up Ruby, installs Control Plane CLI, cpflow gem, and sets up the default profile'

inputs:
token:
description: 'Control Plane token'
required: true
org:
description: 'Control Plane organization'
required: true

runs:
using: 'composite'
steps:
Expand All @@ -22,19 +30,22 @@ runs:
- name: Setup Control Plane Profile
shell: bash
run: |
if [ -z "$CPLN_TOKEN" ]; then
echo " Error: CPLN_TOKEN environment variable is not set"
TOKEN="${{ inputs.token }}"
ORG="${{ inputs.org }}"

if [ -z "$TOKEN" ]; then
echo " Error: Control Plane token not provided"
exit 1
fi

if [ -z "$CPLN_ORG" ]; then
echo " Error: CPLN_ORG environment variable is not set"
if [ -z "$ORG" ]; then
echo " Error: Control Plane organization not provided"
exit 1
fi

echo "Setting up Control Plane profile..."
echo "Organization: $CPLN_ORG"
cpln profile update default --org "$CPLN_ORG" --token "$CPLN_TOKEN"
echo "Organization: $ORG"
cpln profile update default --org "$ORG" --token "$TOKEN"

echo "Setting up Docker login for Control Plane registry..."
cpln image docker-login --org "$CPLN_ORG"
cpln image docker-login --org "$ORG"
29 changes: 24 additions & 5 deletions .github/workflows/delete-review-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ permissions:
issues: write

env:
CPLN_ORG: ${{ secrets.CPLN_ORG }}
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}

Expand All @@ -29,6 +29,18 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Get PR number
id: pr
uses: actions/github-script@v7
with:
script: |
const prNumber = context.payload.issue.number;
core.setOutput('pr_number', prNumber);
core.exportVariable('PR_NUMBER', prNumber);

- name: Set App Name
run: echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" >> $GITHUB_ENV

- uses: actions/checkout@v4

- name: Validate Required Secrets
Expand All @@ -46,7 +58,10 @@ jobs:
fi

- name: Setup Environment
uses: ./.github/actions/setup-environment
uses: ./.github/actions/setup-environment@justin808-working-for-deploys
with:
org: ${{ env.CPLN_ORG }}
token: ${{ env.CPLN_TOKEN }}

- name: Set shared functions
id: shared-functions
Expand Down Expand Up @@ -105,23 +120,26 @@ jobs:
issue_number: process.env.PR_NUMBER,
owner: context.repo.owner,
repo: context.repo.repo,
body: '🗑️ Starting app deletion...'
body: [
message,
'',
' [View Delete Logs](' + process.env.WORKFLOW_URL + ')',
' 🗑️ [View Delete Logs](' + process.env.WORKFLOW_URL + ')',
'',
getConsoleLink(process.env.PR_NUMBER)
].join('\n')
});
return { commentId: comment.data.id };

- name: Delete Review App
uses: ./.github/actions/delete-control-plane-app
uses: ./.github/actions/delete-control-plane-app@justin808-working-for-deploys
with:
app_name: ${{ env.APP_NAME }}
org: ${{ env.CPLN_ORG }}
github_token: ${{ secrets.GITHUB_TOKEN }}
env:
APP_NAME: ${{ env.APP_NAME }}
CPLN_ORG: ${{ secrets.CPLN_ORG }}
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
Comment on lines +135 to 143
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix environment variable inconsistency in delete app step.

The step redefines CPLN_ORG and CPLN_TOKEN in the env block, potentially overriding the values from the workflow's env block.

uses: ./.github/actions/delete-control-plane-app@justin808-working-for-deploys
with:
  app_name: ${{ env.APP_NAME }}
  org: ${{ env.CPLN_ORG }}
  github_token: ${{ secrets.GITHUB_TOKEN }}
env:
  APP_NAME: ${{ env.APP_NAME }}
-  CPLN_ORG: ${{ secrets.CPLN_ORG }}
-  CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uses: ./.github/actions/delete-control-plane-app@justin808-working-for-deploys
with:
app_name: ${{ env.APP_NAME }}
org: ${{ env.CPLN_ORG }}
github_token: ${{ secrets.GITHUB_TOKEN }}
env:
APP_NAME: ${{ env.APP_NAME }}
CPLN_ORG: ${{ secrets.CPLN_ORG }}
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
uses: ./.github/actions/delete-control-plane-app@justin808-working-for-deploys
with:
app_name: ${{ env.APP_NAME }}
org: ${{ env.CPLN_ORG }}
github_token: ${{ secrets.GITHUB_TOKEN }}
env:
APP_NAME: ${{ env.APP_NAME }}


- name: Update Delete Status
Expand All @@ -133,6 +151,7 @@ jobs:

const success = '${{ job.status }}' === 'success';
const prNumber = process.env.PR_NUMBER;
const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`;

const successMessage = [
'✅ Review app for PR #' + prNumber + ' was successfully deleted',
Expand Down
Loading
Loading