Skip to content

Commit 9c95335

Browse files
CI: Add CI/CD pipeline and test with gtm/healthcare demos
1 parent 9dddf74 commit 9c95335

File tree

3 files changed

+293
-18
lines changed

3 files changed

+293
-18
lines changed

.github/workflows/create-build.yml

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
name: Create PromptQL Build
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
paths:
7+
- "demos/**"
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Detect all changed demos
18+
id: demo-setup
19+
run: |
20+
# Fetch the base branch to compare against
21+
git fetch origin ${{ github.base_ref }}
22+
23+
# Get changed files between base and current branch
24+
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}..HEAD)
25+
CHANGED_DEMOS=$(echo "$CHANGED_FILES" | grep '^demos/' | cut -d'/' -f2 | sort -u)
26+
27+
if [ -z "$CHANGED_DEMOS" ]; then
28+
echo "No demo changes detected"
29+
exit 1
30+
fi
31+
32+
echo "demos<<EOF" >> $GITHUB_OUTPUT
33+
echo "$CHANGED_DEMOS" >> $GITHUB_OUTPUT
34+
echo "EOF" >> $GITHUB_OUTPUT
35+
36+
- name: Load secrets from 1Password
37+
uses: 1password/load-secrets-action@v1
38+
with:
39+
export-env: true
40+
env:
41+
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
42+
43+
- name: Install DDN CLI
44+
run: |
45+
curl -L https://graphql-engine-cdn.hasura.io/ddn/cli/v4/get.sh | bash
46+
echo "$HOME/.local/bin" >> $GITHUB_PATH
47+
48+
- name: Verify DDN CLI installation
49+
run: ddn --version
50+
51+
- name: Build all changed demos
52+
id: build
53+
uses: 1password/load-secrets-action@v1
54+
with:
55+
export-env: true
56+
env:
57+
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
58+
run: |
59+
BUILDS_JSON="[]"
60+
61+
while IFS= read -r demo; do
62+
echo "Building demo: $demo"
63+
64+
# Load secrets for this specific demo from 1Password
65+
case $demo in
66+
gtm)
67+
HASURA_DDN_PAT=$(op read "op://Product ACT/axiom_gtm/ddn-service-account")
68+
JWT_SECRET=$(op read "op://Product ACT/axiom_gtm/JWT_SECRET")
69+
OPERATIONS_AUTH_JDBC_URL=$(op read "op://Product ACT/axiom_gtm/OPERATIONS_AUTH_JDBC_URL")
70+
REVOPS_CLARI_JDBC_URL=$(op read "op://Product ACT/axiom_gtm/REVOPS_CLARI_JDBC_URL")
71+
REVOPS_SALESFORCE_JDBC_URL=$(op read "op://Product ACT/axiom_gtm/REVOPS_SALESFORCE_JDBC_URL")
72+
;;
73+
healthcare)
74+
HASURA_DDN_PAT=$(op read "op://Product ACT/axiom_healthcare/ddn-service-account")
75+
JWT_SECRET=$(op read "op://Product ACT/axiom_healthcare/JWT_SECRET")
76+
PATIENT_OPS_OPERATIONS_JDBC_URL=$(op read "op://Product ACT/axiom_healthcare/PATIENT_OPS_OPERATIONS_JDBC_URL")
77+
PATIENT_OPS_PATIENTS_JDBC_URL=$(op read "op://Product ACT/axiom_healthcare/PATIENT_OPS_PATIENTS_JDBC_URL")
78+
REFERENCE_REFERENCE_JDBC_URL=$(op read "op://Product ACT/axiom_healthcare/REFERENCE_REFERENCE_JDBC_URL")
79+
;;
80+
aml|cpg|diligence|supplychain|telco)
81+
echo "Demo $demo not configured for builds yet - skipping"
82+
continue
83+
;;
84+
*)
85+
echo "Unknown demo: $demo"
86+
continue
87+
;;
88+
esac
89+
90+
cd demos/$demo
91+
ddn auth login --pat "$HASURA_DDN_PAT"
92+
93+
# Create .env.cloud file
94+
case $demo in
95+
gtm)
96+
cat > .env.cloud << EOF
97+
JWT_SECRET=$JWT_SECRET
98+
OPERATIONS_AUTH_JDBC_URL=$OPERATIONS_AUTH_JDBC_URL
99+
REVOPS_CLARI_JDBC_URL=$REVOPS_CLARI_JDBC_URL
100+
REVOPS_SALESFORCE_JDBC_URL=$REVOPS_SALESFORCE_JDBC_URL
101+
EOF
102+
;;
103+
healthcare)
104+
cat > .env.cloud << EOF
105+
JWT_SECRET=$JWT_SECRET
106+
PATIENT_OPS_OPERATIONS_JDBC_URL=$PATIENT_OPS_OPERATIONS_JDBC_URL
107+
PATIENT_OPS_PATIENTS_JDBC_URL=$PATIENT_OPS_PATIENTS_JDBC_URL
108+
REFERENCE_REFERENCE_JDBC_URL=$REFERENCE_REFERENCE_JDBC_URL
109+
EOF
110+
;;
111+
esac
112+
113+
# Build this demo
114+
BUILD_OUTPUT=$(ddn supergraph build create --out json -d "PR #${{ github.event.number }}: ${{ github.event.pull_request.title }} ($demo)")
115+
116+
# Add demo name to build output and append to array
117+
BUILD_WITH_DEMO=$(echo "$BUILD_OUTPUT" | jq ". + {\"demo\": \"$demo\"}")
118+
BUILDS_JSON=$(echo "$BUILDS_JSON" | jq ". += [$BUILD_WITH_DEMO]")
119+
120+
cd ../..
121+
done <<< "${{ steps.demo-setup.outputs.demos }}"
122+
123+
echo "builds_output<<EOF" >> $GITHUB_OUTPUT
124+
echo "$BUILDS_JSON" >> $GITHUB_OUTPUT
125+
echo "EOF" >> $GITHUB_OUTPUT
126+
127+
- name: Comment on PR
128+
if: always()
129+
uses: actions/github-script@v7
130+
with:
131+
script: |
132+
const builds = JSON.parse(`${{ steps.build.outputs.builds_output }}`);
133+
134+
let comment = `## 🚀 PromptQL Builds Complete\n\n`;
135+
136+
builds.forEach(build => {
137+
comment += `### ${build.demo.toUpperCase()} Demo\n`;
138+
comment += `**Build Version:** \`${build.build_version || 'N/A'}\`\n`;
139+
comment += `**Project:** \`${build.project_name || 'pql-docs'}\`\n`;
140+
comment += `**PromptQL Playground:** ${build.promptql_url ? `[Open Playground](${build.promptql_url})` : 'N/A'}\n`;
141+
if (build.description) {
142+
comment += `**Description:** ${build.description}\n`;
143+
}
144+
comment += `\n`;
145+
});
146+
147+
// Find and update existing comment logic...
148+
const comments = await github.rest.issues.listComments({
149+
issue_number: context.issue.number,
150+
owner: context.repo.owner,
151+
repo: context.repo.repo,
152+
});
153+
154+
const existingComment = comments.data.find(comment =>
155+
comment.body.includes('🚀 PromptQL Build Complete')
156+
);
157+
158+
if (existingComment) {
159+
// Update existing comment
160+
await github.rest.issues.updateComment({
161+
comment_id: existingComment.id,
162+
owner: context.repo.owner,
163+
repo: context.repo.repo,
164+
body: comment
165+
});
166+
} else {
167+
// Create new comment
168+
await github.rest.issues.createComment({
169+
issue_number: context.issue.number,
170+
owner: context.repo.owner,
171+
repo: context.repo.repo,
172+
body: comment
173+
});
174+
}
175+
176+
- name: Notify Slack
177+
if: always()
178+
uses: actions/github-script@v7
179+
env:
180+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
181+
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
182+
with:
183+
script: |
184+
const buildOutput = JSON.parse(`${{ steps.build.outputs.build_output }}`);
185+
186+
console.log('Environment check:');
187+
console.log('SLACK_BOT_TOKEN exists:', !!process.env.SLACK_BOT_TOKEN);
188+
console.log('SLACK_CHANNEL_ID:', process.env.SLACK_CHANNEL_ID);
189+
190+
const slackMessage = `🚀 *PromptQL Build Complete*
191+
192+
*Build Version:* \`${buildOutput.build_version || 'N/A'}\`
193+
*Project:* \`${buildOutput.project_name || 'pql-docs'}\`
194+
*PromptQL Playground:* ${buildOutput.promptql_url ? buildOutput.promptql_url : 'N/A'}
195+
196+
${buildOutput.description ? `*Description:* ${buildOutput.description}` : ''}`;
197+
198+
// Check if thread exists in PR metadata
199+
const comments = await github.rest.issues.listComments({
200+
issue_number: context.issue.number,
201+
owner: context.repo.owner,
202+
repo: context.repo.repo,
203+
});
204+
205+
let threadTs = null;
206+
const threadComment = comments.data.find(comment =>
207+
comment.body.includes('<!-- slack-thread-ts:')
208+
);
209+
210+
if (threadComment) {
211+
const match = threadComment.body.match(/<!-- slack-thread-ts:([^-]+) -->/);
212+
threadTs = match ? match[1] : null;
213+
console.log('Found existing thread:', threadTs);
214+
}
215+
216+
if (!threadTs) {
217+
console.log('Creating new Slack thread...');
218+
const prAuthor = context.payload.pull_request.user.login;
219+
const prTitle = context.payload.pull_request.title;
220+
const prNumber = context.payload.pull_request.number;
221+
222+
const initialMessage = `@${prAuthor} opened a PR »\n\n#${prNumber} ${prTitle}`;
223+
224+
const response = await fetch('https://slack.com/api/chat.postMessage', {
225+
method: 'POST',
226+
headers: {
227+
'Authorization': `Bearer ${process.env.SLACK_BOT_TOKEN}`,
228+
'Content-Type': 'application/json',
229+
},
230+
body: JSON.stringify({
231+
channel: process.env.SLACK_CHANNEL_ID,
232+
text: initialMessage,
233+
}),
234+
});
235+
236+
const slackData = await response.json();
237+
console.log('Slack thread response:', JSON.stringify(slackData, null, 2));
238+
239+
if (!slackData.ok) {
240+
console.error('Failed to create Slack thread:', slackData.error);
241+
return;
242+
}
243+
244+
threadTs = slackData.ts;
245+
246+
// Store thread timestamp in PR comment
247+
await github.rest.issues.createComment({
248+
issue_number: context.issue.number,
249+
owner: context.repo.owner,
250+
repo: context.repo.repo,
251+
body: `<!-- slack-thread-ts:${threadTs} -->`
252+
});
253+
}
254+
255+
// Only post to thread if we have a valid threadTs
256+
if (threadTs) {
257+
console.log('Posting build info to thread:', threadTs);
258+
const buildResponse = await fetch('https://slack.com/api/chat.postMessage', {
259+
method: 'POST',
260+
headers: {
261+
'Authorization': `Bearer ${process.env.SLACK_BOT_TOKEN}`,
262+
'Content-Type': 'application/json',
263+
},
264+
body: JSON.stringify({
265+
channel: process.env.SLACK_CHANNEL_ID,
266+
thread_ts: threadTs,
267+
text: slackMessage,
268+
}),
269+
});
270+
271+
const buildData = await buildResponse.json();
272+
console.log('Slack build response:', JSON.stringify(buildData, null, 2));
273+
274+
if (!buildData.ok) {
275+
console.error('Failed to post build info:', buildData.error);
276+
}
277+
} else {
278+
console.error('No valid thread timestamp available');
279+
}

demos/gtm/.hasura/context.yaml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,14 @@ definition:
99
subgraph: ../revops/subgraph.yaml
1010
localEnvFile: ../.env
1111
cloudEnvFile: ../.env.cloud
12-
sandbox-gtm:
13-
project: sandbox-gtm
14-
supergraph: ../supergraph.yaml
15-
subgraph: ../revops/subgraph.yaml
16-
localEnvFile: ../.env
17-
cloudEnvFile: ../.env.cloud
1812
scripts:
1913
docker-start:
20-
bash: HASURA_DDN_PAT=$(ddn auth print-access-token) PROMPTQL_SECRET_KEY=$(ddn auth print-promptql-secret-key) docker compose -f compose.yaml --env-file .env up --build --pull always
21-
powershell: $Env:HASURA_DDN_PAT = ddn auth print-access-token; $Env:PROMPTQL_SECRET_KEY = ddn auth print-promptql-secret-key; docker compose -f compose.yaml --env-file .env up --build --pull always
14+
bash:
15+
HASURA_DDN_PAT=$(ddn auth print-access-token) PROMPTQL_SECRET_KEY=$(ddn auth print-promptql-secret-key) docker
16+
compose -f compose.yaml --env-file .env up --build --pull always
17+
powershell:
18+
$Env:HASURA_DDN_PAT = ddn auth print-access-token; $Env:PROMPTQL_SECRET_KEY = ddn auth
19+
print-promptql-secret-key; docker compose -f compose.yaml --env-file .env up --build --pull always
2220
dataset-up:
2321
bash: ../../scripts/ddn-run/dataset-up.sh gtm
2422
powershell: ../../scripts/ddn-run/dataset-up.ps1 gtm
@@ -28,4 +26,4 @@ definition:
2826
jwt-gen:
2927
bash: node ../../scripts/jwt/jwt.mjs
3028
powershell: node ../../scripts/jwt/jwt.mjs
31-
promptQL: true
29+
promptQL: true

demos/healthcare/.hasura/context.yaml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,14 @@ definition:
99
subgraph: ../patient_ops/subgraph.yaml
1010
localEnvFile: ../.env
1111
cloudEnvFile: ../.env.cloud
12-
sandbox-healthcare:
13-
project: sandbox-healthcare
14-
supergraph: ../supergraph.yaml
15-
subgraph: ../patient_ops/subgraph.yaml
16-
localEnvFile: ../.env
17-
cloudEnvFile: ../.env.cloud
1812
scripts:
1913
docker-start:
20-
bash: HASURA_DDN_PAT=$(ddn auth print-access-token) PROMPTQL_SECRET_KEY=$(ddn auth print-promptql-secret-key) docker compose -f compose.yaml --env-file .env up --build --pull always
21-
powershell: $Env:HASURA_DDN_PAT = ddn auth print-access-token; $Env:PROMPTQL_SECRET_KEY = ddn auth print-promptql-secret-key; docker compose -f compose.yaml --env-file .env up --build --pull always
14+
bash:
15+
HASURA_DDN_PAT=$(ddn auth print-access-token) PROMPTQL_SECRET_KEY=$(ddn auth print-promptql-secret-key) docker
16+
compose -f compose.yaml --env-file .env up --build --pull always
17+
powershell:
18+
$Env:HASURA_DDN_PAT = ddn auth print-access-token; $Env:PROMPTQL_SECRET_KEY = ddn auth
19+
print-promptql-secret-key; docker compose -f compose.yaml --env-file .env up --build --pull always
2220
dataset-up:
2321
bash: ../../scripts/ddn-run/dataset-up.sh healthcare
2422
powershell: ../../scripts/ddn-run/dataset-up.ps1 healthcare
@@ -28,4 +26,4 @@ definition:
2826
jwt-gen:
2927
bash: node ../../scripts/jwt/jwt.mjs
3028
powershell: node ../../scripts/jwt/jwt.mjs
31-
promptQL: true
29+
promptQL: true

0 commit comments

Comments
 (0)