Skip to content

Commit a20f92b

Browse files
authored
Added common copy steps and common run step (#161)
1 parent 1e159dc commit a20f92b

1 file changed

Lines changed: 249 additions & 0 deletions

File tree

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
name: EBS Common - Staging/Prod Deploy
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
branch:
7+
description: "Select a Branch to deploy"
8+
required: true
9+
default: "main"
10+
environment:
11+
description: "Select environment to deploy (staging or prod)"
12+
required: true
13+
default: "staging"
14+
email:
15+
description: "Admin email for deployment"
16+
required: true
17+
default: "saravana.k.r@gmail.com"
18+
commit_id:
19+
description: "Commit ID to deploy (leave blank for latest on branch)"
20+
required: false
21+
default: ""
22+
23+
env:
24+
STAGING_HOST: staging.visualaiagentsbuilder.com
25+
PROD_HOST: visualaiagentsbuilder.com
26+
27+
jobs:
28+
build-and-push:
29+
runs-on: ubuntu-latest
30+
31+
steps:
32+
- name: Checkout selected branch
33+
uses: actions/checkout@v4
34+
with:
35+
ref: ${{ github.event.inputs.branch }}
36+
37+
- name: Checkout specific commit if provided
38+
if: ${{ github.event.inputs.commit_id != '' }}
39+
run: |
40+
git fetch --depth=1 origin ${{ github.event.inputs.commit_id }}
41+
git checkout ${{ github.event.inputs.commit_id }}
42+
echo "✅ Checked out commit ${{ github.event.inputs.commit_id }}"
43+
44+
- name: Determine Commit ID
45+
id: commit
46+
run: |
47+
if [ -n "${{ github.event.inputs.commit_id }}" ]; then
48+
echo "commit_id=${{ github.event.inputs.commit_id }}" >> $GITHUB_OUTPUT
49+
else
50+
if [ "${{ github.event.inputs.branch }}" = "main" ]; then
51+
COMMIT_ID=$(git rev-parse HEAD)
52+
else
53+
COMMIT_ID=$(git log -1 --format="%H")
54+
fi
55+
echo "commit_id=$COMMIT_ID" >> $GITHUB_OUTPUT
56+
fi
57+
58+
- name: Determine Branch Name
59+
id: branch
60+
run: |
61+
BRANCH_NAME=$(echo "${{ github.event.inputs.branch }}" | tr '/' '-')
62+
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
63+
64+
- name: Install sshpass
65+
run: sudo apt-get update && sudo apt-get install -y sshpass
66+
67+
- name: Create GitHub Deployment
68+
env:
69+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70+
run: |
71+
COMMIT_ID=${{ steps.commit.outputs.commit_id }}
72+
ENVIRONMENT=${{ github.event.inputs.environment }}
73+
BRANCH=${{ github.event.inputs.branch }}
74+
ACTOR=${{ github.actor }}
75+
76+
echo "📦 Creating deployment for $ENVIRONMENT commit=$COMMIT_ID branch=$BRANCH"
77+
78+
DEPLOYMENT_ID=$(gh api repos/${{ github.repository }}/deployments \
79+
-F ref=${{ github.event.inputs.branch }} \
80+
-F environment=$ENVIRONMENT \
81+
-F description="Deployment by $ACTOR from branch $BRANCH with commit $COMMIT_ID" \
82+
-F auto_merge=false \
83+
-F required_contexts[]=null --jq '.id')
84+
85+
echo "DEPLOYMENT_ID=$DEPLOYMENT_ID" >> $GITHUB_ENV
86+
87+
- name: Mark Deployment In Progress
88+
env:
89+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
90+
run: |
91+
gh api repos/${{ github.repository }}/deployments/${{ env.DEPLOYMENT_ID }}/statuses \
92+
-F state=in_progress \
93+
-F description="Deployment started and is in progress"
94+
95+
- name: Set up Docker Buildx
96+
uses: docker/setup-buildx-action@v3
97+
98+
- name: Log in to Docker Hub
99+
uses: docker/login-action@v3
100+
with:
101+
username: forwardemailforaifirstdesk
102+
password: ${{ secrets.DOCKERHUB_TOKEN }}
103+
104+
- name: Build Docker Image (for staging)
105+
if: ${{ github.event.inputs.environment == 'staging' }}
106+
run: |
107+
COMMIT_ID=${{ steps.commit.outputs.commit_id }}
108+
BRANCH_NAME=${{ steps.branch.outputs.branch_name }}
109+
echo "Using branch=$BRANCH_NAME commit=$COMMIT_ID"
110+
111+
echo "=== Building Staging Image ==="
112+
DOCKER_BUILDKIT=1 \
113+
VITE_AUTO_LOGIN=false \
114+
VITE_CLERK_AUTH_ENABLED=true \
115+
VITE_CLERK_PUBLISHABLE_KEY=${{ secrets.CLERK_PUBLISHABLE_KEY }} \
116+
make docker_build TAG=langflow:staging-$BRANCH_NAME-$COMMIT_ID
117+
118+
docker tag langflow:staging-$BRANCH_NAME-$COMMIT_ID forwardemailforaifirstdesk/langflow:staging-$BRANCH_NAME-$COMMIT_ID
119+
docker push forwardemailforaifirstdesk/langflow:staging-$BRANCH_NAME-$COMMIT_ID
120+
121+
echo "=== Building Prod Image ==="
122+
DOCKER_BUILDKIT=1 \
123+
VITE_AUTO_LOGIN=false \
124+
VITE_CLERK_AUTH_ENABLED=true \
125+
VITE_CLERK_PUBLISHABLE_KEY=${{ secrets.PROD_CLERK_PUBLISHABLE_KEY }} \
126+
make docker_build TAG=langflow:prod-$BRANCH_NAME-$COMMIT_ID
127+
128+
docker tag langflow:prod-$BRANCH_NAME-$COMMIT_ID forwardemailforaifirstdesk/langflow:prod-$BRANCH_NAME-$COMMIT_ID
129+
docker push forwardemailforaifirstdesk/langflow:prod-$BRANCH_NAME-$COMMIT_ID
130+
131+
- name: Cleanup old Docker Hub tags (skip for prod)
132+
if: ${{ github.event.inputs.environment == 'staging' }}
133+
run: |
134+
#!/usr/bin/env bash
135+
set -euo pipefail
136+
137+
DOCKERHUB_USERNAME="forwardemailforaifirstdesk"
138+
DOCKERHUB_PASSWORD="${{ secrets.DOCKERHUB_TOKEN }}"
139+
REPOSITORY="forwardemailforaifirstdesk/langflow"
140+
141+
echo "=== Getting Docker Hub token ==="
142+
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST \
143+
-d '{"username": "'$DOCKERHUB_USERNAME'", "password": "'$DOCKERHUB_PASSWORD'"}' \
144+
https://hub.docker.com/v2/users/login/ | jq -r .token)
145+
146+
if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then
147+
echo "❌ Failed to authenticate"
148+
exit 1
149+
fi
150+
echo "✅ Authentication successful"
151+
152+
echo "=== Fetching tags ==="
153+
RESPONSE=$(curl -s -H "Authorization: JWT $TOKEN" \
154+
"https://hub.docker.com/v2/repositories/$REPOSITORY/tags?page_size=100")
155+
156+
TAGS=$(echo "$RESPONSE" | jq -r '.results[] | .name')
157+
158+
if [ -z "$TAGS" ]; then
159+
echo "ℹ️ No tags found in repository $REPOSITORY. Nothing to delete."
160+
exit 0
161+
fi
162+
163+
echo "Found tags: $TAGS"
164+
165+
for TAG in $TAGS; do
166+
COMMIT_ID=${{ steps.commit.outputs.commit_id }}
167+
BRANCH_NAME=${{ steps.branch.outputs.branch_name }}
168+
if [[ "$TAG" == "staging-$BRANCH_NAME-$COMMIT_ID" || "$TAG" == "prod-$BRANCH_NAME-$COMMIT_ID" ]]; then
169+
echo "⏭️ Skipping current branch+commit tag: $TAG"
170+
continue
171+
fi
172+
173+
echo "Deleting old tag: $TAG"
174+
DELETE_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \
175+
-X DELETE -H "Authorization: JWT $TOKEN" \
176+
"https://hub.docker.com/v2/repositories/$REPOSITORY/tags/$TAG/")
177+
178+
HTTP_CODE=$(echo $DELETE_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
179+
180+
if [ "$HTTP_CODE" = "204" ]; then
181+
echo " ✅ Successfully deleted tag $TAG"
182+
else
183+
echo " ❌ Failed to delete tag $TAG (HTTP: $HTTP_CODE)"
184+
fi
185+
186+
sleep 1
187+
done
188+
189+
echo "Note: Docker Hub will automatically clean up unreferenced images within 24-48 hours"
190+
191+
- name: Copy deployment files to VM
192+
uses: appleboy/scp-action@v0.1.7
193+
with:
194+
host: ${{ github.event.inputs.environment == 'staging' && env.STAGING_HOST || env.PROD_HOST }}
195+
username: root
196+
password: ${{ github.event.inputs.environment == 'staging' && secrets.VM_PASSWORD || secrets.PROD_VM_PASSWORD }}
197+
source: "./deploy/ebs-staging-prod.sh,./.env-file"
198+
target: /root/
199+
200+
- name: Run deployment script on VM
201+
uses: appleboy/ssh-action@v1.1.0
202+
with:
203+
host: ${{ github.event.inputs.environment == 'staging' && env.STAGING_HOST || env.PROD_HOST }}
204+
username: root
205+
password: ${{ github.event.inputs.environment == 'staging' && secrets.VM_PASSWORD || secrets.PROD_VM_PASSWORD }}
206+
script: |
207+
chmod +x /root/deploy/ebs-staging-prod.sh
208+
209+
if [ "${{ github.event.inputs.environment }}" = "staging" ]; then
210+
/root/deploy/ebs-staging-prod.sh \
211+
--image forwardemailforaifirstdesk/langflow:staging-${{ steps.branch.outputs.branch_name }}-${{ steps.commit.outputs.commit_id }} \
212+
--domain ${{env.STAGING_HOST}} \
213+
--email ${{ github.event.inputs.email }} \
214+
--env-file /root/.env-file \
215+
--db-user ${{ secrets.POSTGRES_USER }} \
216+
--db-password ${{ secrets.POSTGRES_PASSWD }} \
217+
--db-name ${{ secrets.POSTGRES_DB }} \
218+
--volume-name ${{ vars.STAGING_VOLUME_NAME }}
219+
else
220+
/root/deploy/ebs-staging-prod.sh \
221+
--image forwardemailforaifirstdesk/langflow:prod-${{ steps.branch.outputs.branch_name }}-${{ steps.commit.outputs.commit_id }} \
222+
--domain ${{env.PROD_HOST}} \
223+
--email ${{ github.event.inputs.email }} \
224+
--env-file /root/.env-file \
225+
--db-user ${{ secrets.PROD_POSTGRES_USER }} \
226+
--db-password ${{ secrets.PROD_POSTGRES_PASSWD }} \
227+
--db-name ${{ secrets.PROD_POSTGRES_DB }} \
228+
--volume-name ${{ vars.PROD_VOLUME_NAME }}
229+
fi
230+
231+
- name: Copy deploy_status.env from VM
232+
run: |
233+
sshpass -p "${{ secrets.VM_PASSWORD }}" scp -o StrictHostKeyChecking=no \
234+
root@staging.visualaiagentsbuilder.com:/root/deploy_status.env \
235+
$GITHUB_WORKSPACE/deploy_status.env
236+
237+
- name: Update GitHub Deployment Status with Docker info
238+
if: always()
239+
env:
240+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
241+
run: |
242+
source "${GITHUB_WORKSPACE}/deploy_status.env"
243+
# Encode container info for safe URL usage
244+
CONTAINER_ENCODED=$(echo "$FINAL_CONTAINER" | jq -s -R -r @uri)
245+
246+
gh api repos/${{ github.repository }}/deployments/${{ env.DEPLOYMENT_ID }}/statuses \
247+
-F state=$FINAL_STATUS \
248+
-F description="$FINAL_DESCRIPTION" \
249+
-F log_url="https://logs.${{ github.repository_owner }}.com/deploy/${{ env.DEPLOYMENT_ID }}?container=${CONTAINER_ENCODED}"

0 commit comments

Comments
 (0)