Skip to content

Commit 9d0c6b4

Browse files
authored
Merge pull request #141 from rostilos/1.5.1-rc
Refactor deployment scripts and configuration
2 parents e4e9d51 + 47ffc32 commit 9d0c6b4

12 files changed

Lines changed: 621 additions & 188 deletions

.github/workflows/deploy.yml

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
###############################################################################
2+
# CodeCrow CI/CD Pipeline
3+
#
4+
# Triggers: push to main branch, or manual dispatch
5+
#
6+
# Flow:
7+
# 1. Checkout code (with submodules)
8+
# 2. Build Java artifacts (Maven)
9+
# 3. Build all 5 Docker images
10+
# 4. Save images as a compressed tarball
11+
# 5. SCP tarball to production server
12+
# 6. SSH into server and run deployment script
13+
#
14+
# Required GitHub Secrets:
15+
# DEPLOY_SSH_KEY — Private SSH key for env
16+
# DEPLOY_HOST — Server IP
17+
# DEPLOY_USER — SSH user
18+
# DEPLOY_HOST_FINGERPRINT — Server SSH host key (ssh-keyscan -H <ip>)
19+
# ENV_INFERENCE_ORCHESTRATOR — Contents of inference-orchestrator/.env
20+
# ENV_RAG_PIPELINE — Contents of rag-pipeline/.env
21+
# ENV_WEB_FRONTEND — Contents of frontend/.env
22+
###############################################################################
23+
24+
name: Deploy to Production
25+
26+
on:
27+
push:
28+
branches: [main]
29+
workflow_dispatch:
30+
inputs:
31+
skip_build:
32+
description: "Skip build (deploy existing images on server)"
33+
required: false
34+
default: "false"
35+
36+
concurrency:
37+
group: production-deploy
38+
cancel-in-progress: false
39+
40+
env:
41+
DEPLOY_PATH: /opt/codecrow
42+
43+
jobs:
44+
build:
45+
name: Build Docker Images
46+
runs-on: ubuntu-latest
47+
if: github.event.inputs.skip_build != 'true'
48+
timeout-minutes: 30
49+
50+
steps:
51+
- name: Checkout code
52+
uses: actions/checkout@v4
53+
with:
54+
submodules: recursive
55+
fetch-depth: 0
56+
57+
- name: Set up JDK 17
58+
uses: actions/setup-java@v4
59+
with:
60+
distribution: temurin
61+
java-version: 17
62+
cache: maven
63+
64+
- name: Set up Docker Buildx
65+
uses: docker/setup-buildx-action@v3
66+
67+
- name: Build (ci-build.sh)
68+
env:
69+
ENV_INFERENCE_ORCHESTRATOR: ${{ secrets.ENV_INFERENCE_ORCHESTRATOR }}
70+
ENV_RAG_PIPELINE: ${{ secrets.ENV_RAG_PIPELINE }}
71+
ENV_WEB_FRONTEND: ${{ secrets.ENV_WEB_FRONTEND }}
72+
run: |
73+
chmod +x deployment/ci/ci-build.sh
74+
deployment/ci/ci-build.sh
75+
76+
- name: Upload artifact
77+
uses: actions/upload-artifact@v4
78+
with:
79+
name: codecrow-images
80+
path: build-output/codecrow-images.tar.gz
81+
retention-days: 7
82+
compression-level: 0
83+
84+
deploy:
85+
name: Deploy to Server
86+
runs-on: ubuntu-latest
87+
needs: [build]
88+
if: always() && (needs.build.result == 'success' || github.event.inputs.skip_build == 'true')
89+
timeout-minutes: 15
90+
environment: production
91+
92+
steps:
93+
- name: Checkout (for compose file + deploy script)
94+
uses: actions/checkout@v4
95+
96+
- name: Download artifact
97+
if: github.event.inputs.skip_build != 'true'
98+
uses: actions/download-artifact@v4
99+
with:
100+
name: codecrow-images
101+
path: build-output
102+
103+
- name: Setup SSH
104+
run: |
105+
mkdir -p ~/.ssh
106+
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
107+
chmod 600 ~/.ssh/deploy_key
108+
# Use pre-registered host fingerprint instead of ssh-keyscan (MITM-safe)
109+
# Generate with: ssh-keyscan -H <server-ip> 2>/dev/null
110+
echo "${{ secrets.DEPLOY_HOST_FINGERPRINT }}" >> ~/.ssh/known_hosts
111+
112+
- name: Upload docker-compose.prod.yml and deploy script
113+
run: |
114+
scp -i ~/.ssh/deploy_key \
115+
deployment/docker-compose.prod.yml \
116+
deployment/ci/server-deploy.sh \
117+
${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ env.DEPLOY_PATH }}/
118+
119+
- name: Upload Docker images tarball
120+
if: github.event.inputs.skip_build != 'true'
121+
run: |
122+
scp -i ~/.ssh/deploy_key \
123+
build-output/codecrow-images.tar.gz \
124+
${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ env.DEPLOY_PATH }}/releases/
125+
126+
- name: Deploy on server
127+
run: |
128+
ssh -i ~/.ssh/deploy_key \
129+
${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} \
130+
"chmod +x ${{ env.DEPLOY_PATH }}/server-deploy.sh && ${{ env.DEPLOY_PATH }}/server-deploy.sh"
131+
132+
- name: Verify deployment
133+
run: |
134+
ssh -i ~/.ssh/deploy_key \
135+
${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} \
136+
"cd ${{ env.DEPLOY_PATH }} && docker compose -f docker-compose.prod.yml ps --format 'table {{.Name}}\t{{.Status}}'"
137+
138+
- name: Cleanup SSH key
139+
if: always()
140+
run: rm -f ~/.ssh/deploy_key

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
*.iws
44
*.iml
55
*.ipr
6-
.github
76
.vscode
87
.venv
9-
docker-compose.yml
8+
109

1110
**/newrelic.jar
1211
**/newrelic.yml

deployment/.env.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
INTERNAL_API_SECRET=secret-change-me
2+
POSTGRES_DB=codecrow_ai
3+
POSTGRES_USER=codecrow
4+
POSTGRES_PASSWORD=codecrow_pass

deployment/.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
### IntelliJ IDEA ###
21
.idea
32
*.iws
43
*.iml
54
*.ipr
6-
docker-compose.yml
75
.env
Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ set -e
44
MCP_SERVERS_JAR_PATH="java-ecosystem/mcp-servers/vcs-mcp/target/codecrow-vcs-mcp-1.0.jar"
55
PLATFORM_MCP_JAR_PATH="java-ecosystem/mcp-servers/platform-mcp/target/codecrow-platform-mcp-1.0.jar"
66
FRONTEND_DIR="frontend"
7-
FRONTEND_BRANCH="epic/CA-1-self-host"
7+
FRONTEND_BRANCH="main"
88
JAVA_DIR="java-ecosystem"
99
DOCKER_PATH="deployment"
1010
CONFIG_PATH="deployment/config"
1111

12-
cd "$(dirname "$0")/../"
13-
14-
echo "--- 1. Ensuring frontend submodule is synchronized ---"
15-
if [ -d "$FRONTEND_DIR" ] && [ ! -f "$FRONTEND_DIR/.git" ]; then
16-
echo "Stale frontend directory detected (not a submodule). Removing and re-initializing..."
17-
rm -rf "$FRONTEND_DIR"
18-
git submodule update --init --remote -- "$FRONTEND_DIR"
19-
elif [ -d "$FRONTEND_DIR" ]; then
20-
echo "Frontend submodule exists. Updating..."
21-
git submodule update --remote -- "$FRONTEND_DIR"
22-
else
23-
echo "Initializing frontend submodule..."
24-
git submodule update --init --remote -- "$FRONTEND_DIR"
25-
fi
26-
(cd "$FRONTEND_DIR" && git checkout "$FRONTEND_BRANCH" && git pull origin "$FRONTEND_BRANCH")
12+
cd "$(dirname "$0")/../../"
13+
14+
# echo "--- 1. Ensuring frontend submodule is synchronized ---"
15+
# if [ -d "$FRONTEND_DIR" ] && [ ! -f "$FRONTEND_DIR/.git" ]; then
16+
# echo "Stale frontend directory detected (not a submodule). Removing and re-initializing..."
17+
# rm -rf "$FRONTEND_DIR"
18+
# git submodule update --init --remote -- "$FRONTEND_DIR"
19+
# elif [ -d "$FRONTEND_DIR" ]; then
20+
# echo "Frontend submodule exists. Updating..."
21+
# git submodule update --remote -- "$FRONTEND_DIR"
22+
# else
23+
# echo "Initializing frontend submodule..."
24+
# git submodule update --init --remote -- "$FRONTEND_DIR"
25+
# fi
26+
# (cd "$FRONTEND_DIR" && git checkout "$FRONTEND_BRANCH" && git pull origin "$FRONTEND_BRANCH")
2727

2828
echo "--- 2. Injecting Environment Configurations ---"
2929

deployment/ci/ci-build.sh

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/bin/bash
2+
###############################################################################
3+
# ci-build.sh — Runs inside the GitHub Actions runner.
4+
#
5+
# 1. Builds Java artifacts (Maven)
6+
# 2. Copies MCP JARs to inference-orchestrator context
7+
# 3. Writes .env files from GitHub secrets
8+
# 4. Builds all 5 Docker images
9+
# 5. Saves them to a single compressed tarball
10+
#
11+
# Required env vars (set by GH Actions):
12+
# ENV_INFERENCE_ORCHESTRATOR — contents of inference-orchestrator/.env
13+
# ENV_RAG_PIPELINE — contents of rag-pipeline/.env
14+
# ENV_WEB_FRONTEND — contents of web-frontend/.env
15+
###############################################################################
16+
set -euo pipefail
17+
18+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
19+
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
20+
21+
MCP_JAR="java-ecosystem/mcp-servers/vcs-mcp/target/codecrow-vcs-mcp-1.0.jar"
22+
PLATFORM_MCP_JAR="java-ecosystem/mcp-servers/platform-mcp/target/codecrow-platform-mcp-1.0.jar"
23+
JAVA_DIR="java-ecosystem"
24+
OUTPUT_DIR="$ROOT_DIR/build-output"
25+
26+
cd "$ROOT_DIR"
27+
mkdir -p "$OUTPUT_DIR"
28+
29+
echo "=========================================="
30+
echo " CodeCrow CI Build"
31+
echo "=========================================="
32+
33+
# ── 1. Inject .env files from secrets ──────────────────────────────────────
34+
echo "--- 1. Writing .env files from CI secrets ---"
35+
36+
if [ -n "${ENV_INFERENCE_ORCHESTRATOR:-}" ]; then
37+
echo "$ENV_INFERENCE_ORCHESTRATOR" > python-ecosystem/inference-orchestrator/.env
38+
echo " ✓ inference-orchestrator/.env written"
39+
fi
40+
41+
if [ -n "${ENV_RAG_PIPELINE:-}" ]; then
42+
echo "$ENV_RAG_PIPELINE" > python-ecosystem/rag-pipeline/.env
43+
echo " ✓ rag-pipeline/.env written"
44+
fi
45+
46+
if [ -n "${ENV_WEB_FRONTEND:-}" ]; then
47+
echo "$ENV_WEB_FRONTEND" > frontend/.env
48+
echo " ✓ web-frontend/.env written"
49+
fi
50+
51+
# ── 2. Build Java Artifacts ────────────────────────────────────────────────
52+
echo "--- 2. Building Java artifacts (mvn clean package) ---"
53+
(cd "$JAVA_DIR" && mvn clean package -DskipTests -q)
54+
echo " ✓ Java build complete"
55+
56+
# ── 3. Copy MCP JARs ──────────────────────────────────────────────────────
57+
echo "--- 3. Copying MCP server JARs ---"
58+
cp "$MCP_JAR" python-ecosystem/inference-orchestrator/codecrow-vcs-mcp-1.0.jar
59+
echo " ✓ VCS MCP JAR copied"
60+
61+
if [ -f "$PLATFORM_MCP_JAR" ]; then
62+
cp "$PLATFORM_MCP_JAR" python-ecosystem/inference-orchestrator/codecrow-platform-mcp-1.0.jar
63+
echo " ✓ Platform MCP JAR copied"
64+
else
65+
echo " ⚠ Platform MCP JAR not found (optional)"
66+
fi
67+
68+
# ── 4. Build Docker Images ────────────────────────────────────────────────
69+
echo "--- 4. Building Docker images ---"
70+
71+
IMAGES=(
72+
"codecrow/web-server|java-ecosystem/services/web-server|Dockerfile.observable"
73+
"codecrow/pipeline-agent|java-ecosystem/services/pipeline-agent|Dockerfile.observable"
74+
"codecrow/inference-orchestrator|python-ecosystem/inference-orchestrator"
75+
"codecrow/rag-pipeline|python-ecosystem/rag-pipeline"
76+
"codecrow/web-frontend|frontend"
77+
)
78+
79+
for entry in "${IMAGES[@]}"; do
80+
IFS='|' read -r IMAGE_NAME CONTEXT DOCKERFILE <<< "$entry"
81+
echo " Building $IMAGE_NAME from $CONTEXT ..."
82+
if [ -n "${DOCKERFILE:-}" ]; then
83+
docker build -t "${IMAGE_NAME}:latest" -f "$CONTEXT/$DOCKERFILE" "$CONTEXT"
84+
else
85+
docker build -t "${IMAGE_NAME}:latest" "$CONTEXT"
86+
fi
87+
echo "$IMAGE_NAME built"
88+
done
89+
90+
# ── 5. Save images to tarball ─────────────────────────────────────────────
91+
echo "--- 5. Saving Docker images to tarball ---"
92+
93+
IMAGE_LIST=""
94+
for entry in "${IMAGES[@]}"; do
95+
IFS='|' read -r IMAGE_NAME _ _ <<< "$entry"
96+
IMAGE_LIST="$IMAGE_LIST ${IMAGE_NAME}:latest"
97+
done
98+
99+
docker save $IMAGE_LIST | gzip > "$OUTPUT_DIR/codecrow-images.tar.gz"
100+
101+
TARBALL_SIZE=$(du -h "$OUTPUT_DIR/codecrow-images.tar.gz" | cut -f1)
102+
echo " ✓ Tarball created: codecrow-images.tar.gz ($TARBALL_SIZE)"
103+
104+
echo ""
105+
echo "=========================================="
106+
echo " Build complete! Artifact: build-output/codecrow-images.tar.gz"
107+
echo "=========================================="

0 commit comments

Comments
 (0)