Skip to content

Commit 9167eb3

Browse files
authored
Merge pull request #39 from oslabs-beta/lorenc-cicd
Add gcp_adapter file to generate yaml and deploy to gcp
2 parents 24cc6a0 + 809a45f commit 9167eb3

File tree

6 files changed

+819
-70
lines changed

6 files changed

+819
-70
lines changed

.github/workflows/ci-docker.yml

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ jobs:
3434
run: |
3535
cd server
3636
npm test --if-present
37-
#backend image
37+
38+
# backend image
3839
docker-image:
3940
needs: build-test
4041
runs-on: ubuntu-latest
@@ -50,6 +51,13 @@ jobs:
5051
- name: Checkout repository
5152
uses: actions/checkout@v4
5253

54+
- name: Compute lowercase owner
55+
id: vars
56+
shell: bash
57+
run: |
58+
OWNER_LC="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
59+
echo "owner_lc=$OWNER_LC" >> "$GITHUB_OUTPUT"
60+
5361
- name: Login to GitHub Container Registry
5462
uses: docker/login-action@v3
5563
with:
@@ -59,20 +67,20 @@ jobs:
5967

6068
- name: Build Docker image
6169
run: |
62-
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
63-
VERSION=${{ github.sha }}
70+
IMAGE_ID="ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ env.IMAGE_NAME }}"
71+
VERSION="${{ github.sha }}"
6472
6573
echo "IMAGE_ID=$IMAGE_ID" >> $GITHUB_ENV
6674
echo "VERSION=$VERSION" >> $GITHUB_ENV
6775
68-
docker build -t $IMAGE_ID:$VERSION -t $IMAGE_ID:latest .
76+
docker build -t "$IMAGE_ID:$VERSION" -t "$IMAGE_ID:latest" .
6977
7078
- name: Push Docker image
7179
run: |
72-
docker push $IMAGE_ID:$VERSION
73-
docker push $IMAGE_ID:latest
80+
docker push "$IMAGE_ID:$VERSION"
81+
docker push "$IMAGE_ID:latest"
7482
75-
#frontend image
83+
# frontend image
7684
frontend-docker-image:
7785
needs: build-test
7886
runs-on: ubuntu-latest
@@ -88,6 +96,13 @@ jobs:
8896
- name: Checkout repository
8997
uses: actions/checkout@v4
9098

99+
- name: Compute lowercase owner
100+
id: vars
101+
shell: bash
102+
run: |
103+
OWNER_LC="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
104+
echo "owner_lc=$OWNER_LC" >> "$GITHUB_OUTPUT"
105+
91106
- name: Login to GitHub Container Registry
92107
uses: docker/login-action@v3
93108
with:
@@ -97,20 +112,20 @@ jobs:
97112

98113
- name: Build frontend Docker image
99114
run: |
100-
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
101-
VERSION=${{ github.sha }}
115+
FRONTEND_IMAGE_ID="ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ env.IMAGE_NAME }}"
116+
FRONTEND_VERSION="${{ github.sha }}"
102117
103-
echo "FRONTEND_IMAGE_ID=$IMAGE_ID" >> $GITHUB_ENV
104-
echo "FRONTEND_VERSION=$VERSION" >> $GITHUB_ENV
118+
echo "FRONTEND_IMAGE_ID=$FRONTEND_IMAGE_ID" >> $GITHUB_ENV
119+
echo "FRONTEND_VERSION=$FRONTEND_VERSION" >> $GITHUB_ENV
105120
106-
docker build -f Dockerfile.frontend -t $IMAGE_ID:$VERSION -t $IMAGE_ID:latest .
121+
docker build -f Dockerfile.frontend -t "$FRONTEND_IMAGE_ID:$FRONTEND_VERSION" -t "$FRONTEND_IMAGE_ID:latest" .
107122
108123
- name: Push frontend Docker image
109124
run: |
110-
docker push $FRONTEND_IMAGE_ID:$FRONTEND_VERSION
111-
docker push $FRONTEND_IMAGE_ID:latest
125+
docker push "$FRONTEND_IMAGE_ID:$FRONTEND_VERSION"
126+
docker push "$FRONTEND_IMAGE_ID:latest"
112127
113-
#backend cloud deployment
128+
# backend cloud deployment
114129
deploy-gcp:
115130
needs: docker-image
116131
runs-on: ubuntu-latest
@@ -122,6 +137,13 @@ jobs:
122137
- name: Checkout repository
123138
uses: actions/checkout@v4
124139

140+
- name: Compute lowercase owner
141+
id: vars
142+
shell: bash
143+
run: |
144+
OWNER_LC="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
145+
echo "owner_lc=$OWNER_LC" >> "$GITHUB_OUTPUT"
146+
125147
- name: Authenticate to Google Cloud
126148
uses: google-github-actions/auth@v2
127149
with:
@@ -138,25 +160,27 @@ jobs:
138160
139161
- name: Pull image from GHCR
140162
run: |
141-
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/mcp-backend
142-
VERSION=${{ github.sha }}
163+
IMAGE_ID="ghcr.io/${{ steps.vars.outputs.owner_lc }}/mcp-backend"
164+
VERSION="${{ github.sha }}"
165+
143166
echo "IMAGE_ID=$IMAGE_ID" >> $GITHUB_ENV
144167
echo "VERSION=$VERSION" >> $GITHUB_ENV
145-
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
146-
docker pull $IMAGE_ID:$VERSION
168+
169+
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
170+
docker pull "$IMAGE_ID:$VERSION"
147171
148172
- name: Tag and push image to Artifact Registry
149173
run: |
150-
AR_IMAGE=us-east1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/mcp-backend/mcp-backend
151-
docker tag ghcr.io/${{ github.repository_owner }}/mcp-backend:${{ github.sha }} $AR_IMAGE:${{ github.sha }}
152-
docker push $AR_IMAGE:${{ github.sha }}
174+
AR_IMAGE="us-east1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/mcp-backend/mcp-backend"
175+
docker tag "$IMAGE_ID:$VERSION" "$AR_IMAGE:$VERSION"
176+
docker push "$AR_IMAGE:$VERSION"
153177
echo "AR_IMAGE=$AR_IMAGE" >> $GITHUB_ENV
154178
155179
- name: Deploy to Cloud Run
156180
run: |
157181
gcloud run deploy mcp-backend \
158-
--image $AR_IMAGE:${{ github.sha }} \
159-
--region ${{ secrets.GCP_REGION }} \
182+
--image "$AR_IMAGE:${{ github.sha }}" \
183+
--region "${{ secrets.GCP_REGION }}" \
160184
--platform managed \
161185
--allow-unauthenticated \
162186
--port 3000
@@ -173,6 +197,13 @@ jobs:
173197
- name: Checkout repository
174198
uses: actions/checkout@v4
175199

200+
- name: Compute lowercase owner
201+
id: vars
202+
shell: bash
203+
run: |
204+
OWNER_LC="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
205+
echo "owner_lc=$OWNER_LC" >> "$GITHUB_OUTPUT"
206+
176207
- name: Authenticate to Google Cloud
177208
uses: google-github-actions/auth@v2
178209
with:
@@ -189,25 +220,27 @@ jobs:
189220
190221
- name: Pull frontend image from GHCR
191222
run: |
192-
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/mcp-frontend
193-
VERSION=${{ github.sha }}
194-
echo "FRONTEND_IMAGE_ID=$IMAGE_ID" >> $GITHUB_ENV
195-
echo "FRONTEND_VERSION=$VERSION" >> $GITHUB_ENV
196-
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
197-
docker pull $IMAGE_ID:$VERSION
223+
FRONTEND_IMAGE_ID="ghcr.io/${{ steps.vars.outputs.owner_lc }}/mcp-frontend"
224+
FRONTEND_VERSION="${{ github.sha }}"
225+
226+
echo "FRONTEND_IMAGE_ID=$FRONTEND_IMAGE_ID" >> $GITHUB_ENV
227+
echo "FRONTEND_VERSION=$FRONTEND_VERSION" >> $GITHUB_ENV
228+
229+
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
230+
docker pull "$FRONTEND_IMAGE_ID:$FRONTEND_VERSION"
198231
199232
- name: Tag & push frontend image to Artifact Registry
200233
run: |
201-
AR_FRONTEND_IMAGE=us-east1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/mcp-frontend/mcp-frontend
202-
docker tag ghcr.io/${{ github.repository_owner }}/mcp-frontend:${{ github.sha }} $AR_FRONTEND_IMAGE:${{ github.sha }}
203-
docker push $AR_FRONTEND_IMAGE:${{ github.sha }}
234+
AR_FRONTEND_IMAGE="us-east1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/mcp-frontend/mcp-frontend"
235+
docker tag "$FRONTEND_IMAGE_ID:$FRONTEND_VERSION" "$AR_FRONTEND_IMAGE:$FRONTEND_VERSION"
236+
docker push "$AR_FRONTEND_IMAGE:$FRONTEND_VERSION"
204237
echo "AR_FRONTEND_IMAGE=$AR_FRONTEND_IMAGE" >> $GITHUB_ENV
205238
206239
- name: Deploy frontend to Cloud Run
207240
run: |
208241
gcloud run deploy mcp-frontend \
209-
--image $AR_FRONTEND_IMAGE:${{ github.sha }} \
210-
--region ${{ secrets.GCP_REGION }} \
242+
--image "$AR_FRONTEND_IMAGE:${{ github.sha }}" \
243+
--region "${{ secrets.GCP_REGION }}" \
211244
--platform managed \
212245
--allow-unauthenticated \
213246
--port 80

server/routes/agent.js

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,16 @@ router.post('/wizard', requireSession, async (req, res) => {
1818
try {
1919
const { repoUrl, provider, branch } = req.body;
2020
if (!repoUrl || !provider || !branch) {
21-
return res
22-
.status(400)
23-
.json({
24-
success: false,
25-
error: 'Missing required fields: repoUrl, provider, branch',
26-
});
21+
return res.status(400).json({
22+
success: false,
23+
error: 'Missing required fields: repoUrl, provider, branch',
24+
});
2725
}
2826
const result = await runWizardAgent({
2927
repoUrl,
3028
provider,
3129
branch,
32-
cookie: req.headers.cookie
30+
cookie: req.headers.cookie,
3331
});
3432
res.json({ success: true, data: result });
3533
} catch (err) {
@@ -43,11 +41,13 @@ router.post('/wizard/ai', requireSession, async (req, res) => {
4341
try {
4442
const { prompt } = req.body;
4543
if (!prompt) {
46-
return res.status(400).json({ success: false, error: 'Missing required field: prompt' });
44+
return res
45+
.status(400)
46+
.json({ success: false, error: 'Missing required field: prompt' });
4747
}
4848
const result = await runWizardAgent({
4949
prompt,
50-
cookie: req.headers.cookie
50+
cookie: req.headers.cookie,
5151
});
5252
res.json({ success: true, data: result });
5353
} catch (err) {
@@ -56,26 +56,81 @@ router.post('/wizard/ai', requireSession, async (req, res) => {
5656
}
5757
});
5858

59+
// Normailize the repoUrl
60+
function normalizeRepo(repoUrlOrSlug) {
61+
// If it's already "owner/repo", return it
62+
if (repoUrlOrSlug && !repoUrlOrSlug.startsWith('http')) {
63+
return repoUrlOrSlug;
64+
}
65+
66+
// If it's a URL, extract owner/repo
67+
const url = new URL(repoUrlOrSlug);
68+
const parts = url.pathname
69+
.replace(/^\//, '')
70+
.replace(/\.git$/, '')
71+
.split('/');
72+
73+
return `${parts[0]}/${parts[1]}`;
74+
}
75+
5976
// Generate pipeline only
6077
router.post('/pipeline', requireSession, async (req, res) => {
6178
try {
62-
const { repoUrl } = req.body;
79+
const {
80+
repoUrl,
81+
branch = 'main',
82+
template = 'node_app',
83+
options = {},
84+
} = req.body;
85+
6386
if (!repoUrl) {
6487
return res
6588
.status(400)
6689
.json({ success: false, error: 'Missing required field: repoUrl' });
6790
}
68-
const yaml = await pipeline_generator.handler({
69-
repo: repoUrl,
70-
provider: 'aws',
71-
template: 'node_app',
91+
92+
const repoSlug = normalizeRepo(repoUrl);
93+
94+
const result = await pipeline_generator.handler({
95+
repo: repoSlug, // ✅ owner/repo (GitHub API safe)
96+
repoUrl, // optional: keep if cloning elsewhere
97+
branch,
98+
provider: 'gcp',
99+
template,
100+
options,
72101
});
73-
res.json({ success: true, data: yaml });
102+
103+
return res.json(result);
74104
} catch (err) {
75-
res.status(500).json({ success: false, error: err.message });
105+
console.error('[pipeline error]', err);
106+
return res.status(500).json({
107+
success: false,
108+
error: err.message,
109+
});
76110
}
77111
});
78112

113+
// Generate pipeline only
114+
// router.post('/pipeline', requireSession, async (req, res) => {
115+
// try {
116+
// const { repoUrl } = req.body;
117+
// if (!repoUrl) {
118+
// return res
119+
// .status(400)
120+
// .json({ success: false, error: 'Missing required field: repoUrl' });
121+
// }
122+
// const yaml = await pipeline_generator.handler({
123+
// repo: repoUrl,
124+
// // provider: 'aws', testing
125+
// provider: 'gcp',
126+
// template: 'node_app',
127+
// });
128+
// res.json({ success: true, data: yaml });
129+
// } catch (err) {
130+
// res.status(500).json({ success: false, error: err.message });
131+
// }
132+
// });
133+
79134
// Read repository metadata
80135
router.post('/analyze', requireSession, async (req, res) => {
81136
try {

0 commit comments

Comments
 (0)