|
4 | 4 | workflow_dispatch: |
5 | 5 |
|
6 | 6 | workflow_call: |
7 | | - |
8 | | -permissions: |
9 | | - id-token: write # This is needed for OIDC authentication |
10 | | - contents: read # This is usually needed for checking out code |
11 | | - packages: read # Allow reading packages from the organization ╎ |
12 | | - |
13 | | -env: |
14 | | - AGENTEX_SERVER_IMAGE_NAME: agentex |
15 | | - AGENTEX_AUTH_IMAGE_NAME: agentex-auth |
16 | | - SCALE_PROD_ACCOUNT_ID: "307185671274" |
17 | | - EGP_PROD_ACCOUNT_ID: "022465994601" |
18 | | - AWS_REGION: us-west-2 |
19 | | - |
20 | | -jobs: |
21 | | - detect-changes: |
22 | | - runs-on: ubuntu-latest |
23 | | - outputs: |
24 | | - changed-tutorials: ${{ steps.check.outputs.changed-tutorials }} |
25 | | - all-tutorials: ${{ steps.find-all.outputs.all-tutorials }} |
26 | | - steps: |
27 | | - - name: Checkout repository |
28 | | - uses: actions/checkout@v3 |
29 | | - with: |
30 | | - ref: ${{ github.event.pull_request.head.sha || github.sha }} |
31 | | - fetch-depth: 2 # Fetch current commit and parent for comparison |
32 | | - |
33 | | - - name: Check for changes in tutorials directory |
34 | | - id: check |
35 | | - run: | |
36 | | - # Determine the base branch to compare against |
37 | | - if [ "${{ github.event_name }}" == "pull_request" ]; then |
38 | | - BASE_REF="${{ github.event.pull_request.base.sha }}" |
39 | | - else |
40 | | - # For push events or workflow_dispatch, fetch only latest main |
41 | | - git fetch --depth=1 origin main:main || true |
42 | | - BASE_REF="origin/main" |
43 | | - fi |
44 | | -
|
45 | | - echo "📊 Comparing current commit with base: $BASE_REF" |
46 | | -
|
47 | | - # Get list of changed files in examples/tutorials directory |
48 | | - CHANGED_FILES=$(git diff --name-only $BASE_REF HEAD -- examples/tutorials/ || echo "") |
49 | | -
|
50 | | - if [ -z "$CHANGED_FILES" ]; then |
51 | | - echo "⚠️ No changes detected in examples/tutorials/" |
52 | | - echo "changed-tutorials=[]" >> $GITHUB_OUTPUT |
53 | | - exit 0 |
54 | | - fi |
55 | | -
|
56 | | - echo "📝 Changed files:" |
57 | | - echo "$CHANGED_FILES" |
58 | | -
|
59 | | - # Extract unique tutorial directories that have changes |
60 | | - CHANGED_TUTORIALS=$(echo "$CHANGED_FILES" | \ |
61 | | - grep "^examples/tutorials/" | \ |
62 | | - sed 's|^examples/tutorials/||' | \ |
63 | | - awk -F'/' '{print $1"/"$2"/"$3}' | \ |
64 | | - sort -u | \ |
65 | | - while read tutorial_dir; do |
66 | | - # Check if manifest.yaml exists in this tutorial directory |
67 | | - if [ -f "examples/tutorials/$tutorial_dir/manifest.yaml" ]; then |
68 | | - echo "$tutorial_dir" |
69 | | - fi |
70 | | - done | \ |
71 | | - jq -R -s -c 'split("\n") | map(select(length > 0))') |
72 | | -
|
73 | | - echo "🎯 Changed tutorials with manifest.yaml: $CHANGED_TUTORIALS" |
74 | | - echo "changed-tutorials=$CHANGED_TUTORIALS" >> $GITHUB_OUTPUT |
75 | | -
|
76 | | - - name: Find all tutorials |
77 | | - id: find-all |
78 | | - run: | |
79 | | - # Find all tutorials with manifest.yaml files |
80 | | - ALL_TUTORIALS=$(find examples/tutorials -name "manifest.yaml" -type f | \ |
81 | | - sed 's|examples/tutorials/||' | \ |
82 | | - sed 's|/manifest.yaml||' | \ |
83 | | - jq -R -s -c 'split("\n") | map(select(length > 0))') |
84 | | -
|
85 | | - echo "📚 All tutorials: $ALL_TUTORIALS" |
86 | | - echo "all-tutorials=$ALL_TUTORIALS" >> $GITHUB_OUTPUT |
87 | | -
|
88 | | - run-agent-tutorials-test: |
89 | | - runs-on: ubuntu-latest |
90 | | - steps: |
91 | | - # Login to Amazon ECR |
92 | | - - name: Login to Amazon ECR |
93 | | - id: login-ecr |
94 | | - uses: aws-actions/amazon-ecr-login@v2 |
95 | | - |
96 | | - - name: Create Docker network |
97 | | - run: | |
98 | | - echo "🌐 Creating Docker network..." |
99 | | - docker network create agentex-network |
100 | | -
|
101 | | - - name: Start all dependencies |
102 | | - run: | |
103 | | - echo "🚀 Starting dependencies (Postgres, Redis, Temporal, MongoDB)..." |
104 | | -
|
105 | | - # Start main Postgres for AgentEx |
106 | | - docker run -d \ |
107 | | - --name agentex-postgres \ |
108 | | - --network agentex-network \ |
109 | | - -p 5432:5432 \ |
110 | | - -e POSTGRES_PASSWORD=postgres \ |
111 | | - -e POSTGRES_USER=postgres \ |
112 | | - -e POSTGRES_DB=agentex \ |
113 | | - --health-cmd "pg_isready -U postgres" \ |
114 | | - --health-interval 5s \ |
115 | | - --health-timeout 5s \ |
116 | | - --health-retries 5 \ |
117 | | - --health-start-period 5s \ |
118 | | - postgres:17 |
119 | | -
|
120 | | - # Start Redis |
121 | | - docker run -d \ |
122 | | - --name agentex-redis \ |
123 | | - --network agentex-network \ |
124 | | - -p 6379:6379 \ |
125 | | - --health-cmd "redis-cli ping" \ |
126 | | - --health-interval 5s \ |
127 | | - --health-timeout 5s \ |
128 | | - --health-retries 5 \ |
129 | | - --health-start-period 5s \ |
130 | | - redis:7.4.0-alpine |
131 | | -
|
132 | | - # Start MongoDB |
133 | | - docker run -d \ |
134 | | - --name agentex-mongodb \ |
135 | | - --network agentex-network \ |
136 | | - -p 27017:27017 \ |
137 | | - -e MONGO_INITDB_DATABASE=agentex \ |
138 | | - --health-cmd "mongosh --eval 'db.runCommand(\"ping\").ok' localhost:27017/agentex --quiet" \ |
139 | | - --health-interval 5s \ |
140 | | - --health-timeout 5s \ |
141 | | - --health-retries 5 \ |
142 | | - --health-start-period 5s \ |
143 | | - mongo:6.0 |
144 | | -
|
145 | | - # Start Temporal's PostgreSQL database |
146 | | - docker run -d \ |
147 | | - --name agentex-temporal-postgresql \ |
148 | | - --network agentex-network \ |
149 | | - -p 5433:5432 \ |
150 | | - -e POSTGRES_PASSWORD=temporal \ |
151 | | - -e POSTGRES_USER=temporal \ |
152 | | - -e LOG_LEVEL=error \ |
153 | | - --health-cmd "pg_isready -U temporal" \ |
154 | | - --health-interval 5s \ |
155 | | - --health-timeout 5s \ |
156 | | - --health-retries 5 \ |
157 | | - --health-start-period 5s \ |
158 | | - postgres:12 |
159 | | -
|
160 | | - echo "⏳ Waiting for databases to be healthy..." |
161 | | - sleep 10 |
162 | | -
|
163 | | - # Start Temporal |
164 | | - docker run -d \ |
165 | | - --name agentex-temporal \ |
166 | | - --network agentex-network \ |
167 | | - -p 7233:7233 \ |
168 | | - -e DB=postgres12 \ |
169 | | - -e DB_PORT=5432 \ |
170 | | - -e POSTGRES_USER=temporal \ |
171 | | - -e POSTGRES_PWD=temporal \ |
172 | | - -e POSTGRES_SEEDS=agentex-temporal-postgresql \ |
173 | | - -e LOG_LEVEL=error \ |
174 | | - --health-cmd "nc -z localhost 7233 || exit 0" \ |
175 | | - --health-interval 5s \ |
176 | | - --health-timeout 5s \ |
177 | | - --health-retries 5 \ |
178 | | - --health-start-period 10s \ |
179 | | - temporalio/auto-setup:1.25.0 |
180 | | -
|
181 | | - echo "⏳ Waiting for all dependencies to be healthy..." |
182 | | - sleep 15 |
183 | | -
|
184 | | - # Verify all deps are up |
185 | | - docker ps |
186 | | -
|
187 | | - - name: Pull and start AgentEx Auth |
188 | | - run: | |
189 | | - set -e |
190 | | -
|
191 | | - # Get the latest tag that doesn't contain "fips" |
192 | | - AUTH_REPO="${{ env.SCALE_PROD_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.AGENTEX_AUTH_IMAGE_NAME }}" |
193 | | -
|
194 | | - echo "🔍 Finding latest non-FIPS tag for auth image..." |
195 | | - LATEST_TAG=$(aws ecr describe-images \ |
196 | | - --repository-name ${{ env.AGENTEX_AUTH_IMAGE_NAME }} \ |
197 | | - --region ${{ env.AWS_REGION }} \ |
198 | | - --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[?!contains(@, `fips`)] | [0]' \ |
199 | | - --output text) |
200 | | -
|
201 | | - AUTH_IMAGE="${AUTH_REPO}:${LATEST_TAG}" |
202 | | -
|
203 | | - echo "📥 Pulling AgentEx Auth image: $AUTH_IMAGE" |
204 | | - docker pull "$AUTH_IMAGE" |
205 | | -
|
206 | | - echo "🔐 Starting AgentEx Auth..." |
207 | | - docker run -d \ |
208 | | - --name agentex-auth \ |
209 | | - --network agentex-network \ |
210 | | - -p 5000:5000 \ |
211 | | - -e ENVIRONMENT=development \ |
212 | | - -e DATABASE_URL=postgresql://postgres:postgres@agentex-postgres:5432/agentex \ |
213 | | - -e REDIS_URL=redis://agentex-redis:6379 \ |
214 | | - "$AUTH_IMAGE" |
215 | | -
|
216 | | - echo "⏳ Waiting for auth service to be ready..." |
217 | | - sleep 5 |
218 | | -
|
219 | | - # Health check for auth |
220 | | - for i in {1..30}; do |
221 | | - if curl -f -s http://localhost:5000/healthz > /dev/null 2>&1; then |
222 | | - echo "✅ Auth service is healthy!" |
223 | | - break |
224 | | - fi |
225 | | - echo " Attempt $i/30: Waiting for auth service..." |
226 | | - sleep 3 |
227 | | - done |
228 | | -
|
229 | | - - name: Pull and start AgentEx Server |
230 | | - run: | |
231 | | - set -e |
232 | | -
|
233 | | - # Get the latest tag that doesn't contain "fips" |
234 | | - SERVER_REPO="${{ env.SCALE_PROD_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.AGENTEX_SERVER_IMAGE_NAME }}" |
235 | | -
|
236 | | - echo "🔍 Finding latest non-FIPS tag for server image..." |
237 | | - LATEST_TAG=$(aws ecr describe-images \ |
238 | | - --repository-name ${{ env.AGENTEX_SERVER_IMAGE_NAME }} \ |
239 | | - --region ${{ env.AWS_REGION }} \ |
240 | | - --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[?!contains(@, `fips`)] | [0]' \ |
241 | | - --output text) |
242 | | -
|
243 | | - SERVER_IMAGE="${SERVER_REPO}:${LATEST_TAG}" |
244 | | -
|
245 | | - echo "📥 Pulling AgentEx Server image: $SERVER_IMAGE" |
246 | | - docker pull "$SERVER_IMAGE" |
247 | | -
|
248 | | - echo "🐤 Starting AgentEx server..." |
249 | | - docker run -d \ |
250 | | - --name agentex-server \ |
251 | | - --network agentex-network \ |
252 | | - -p 5003:5003 \ |
253 | | - -e ENVIRONMENT=development \ |
254 | | - -e UVICORN_PORT=5003 \ |
255 | | - -e DATABASE_URL=postgresql://postgres:postgres@agentex-postgres:5432/agentex \ |
256 | | - -e TEMPORAL_ADDRESS=agentex-temporal:7233 \ |
257 | | - -e REDIS_URL=redis://agentex-redis:6379 \ |
258 | | - -e MONGODB_URI=mongodb://agentex-mongodb:27017 \ |
259 | | - -e MONGODB_DATABASE_NAME=agentex \ |
260 | | - -e AGENTEX_AUTH_URL=http://agentex-auth:5000 \ |
261 | | - --workdir /app \ |
262 | | - "$SERVER_IMAGE" \ |
263 | | - bash -c " |
264 | | - echo 'Running database migrations...' && |
265 | | - cd database/migrations && |
266 | | - alembic upgrade head && |
267 | | - cd ../.. && |
268 | | - echo 'Starting API server...' && |
269 | | - uvicorn src.api.app:app --host 0.0.0.0 --port 5003 |
270 | | - " |
271 | | -
|
272 | | - echo "⏳ Waiting for server to be ready..." |
273 | | - sleep 10 |
274 | | -
|
275 | | - # Health check |
276 | | - for i in {1..30}; do |
277 | | - if curl -f -s http://localhost:5003/healthz > /dev/null 2>&1; then |
278 | | - echo "✅ AgentEx server is healthy!" |
279 | | - break |
280 | | - fi |
281 | | - echo " Attempt $i/30: Waiting for server..." |
282 | | - sleep 3 |
283 | | - done |
284 | | -
|
285 | | - build-all-tutorial-agents: |
286 | | - needs: [detect-changes] |
287 | | - runs-on: ubuntu-latest |
288 | | - # Only run when code is pushed to main (i.e., after PR is merged) |
289 | | - if: github.event_name == 'push' && github.ref == 'refs/heads/main' |
290 | | - strategy: |
291 | | - matrix: |
292 | | - tutorial: ${{ fromJson(needs.detect-changes.outputs.changed-tutorials) }} |
293 | | - fail-fast: false |
294 | | - max-parallel: 10 |
295 | | - |
296 | | - steps: |
297 | | - - name: Checkout code |
298 | | - uses: actions/checkout@v3 |
299 | | - with: |
300 | | - ref: ${{ github.event.pull_request.head.sha || github.sha }} |
301 | | - |
302 | | - - name: Set up Python |
303 | | - uses: actions/setup-python@v4 |
304 | | - with: |
305 | | - python-version: "3.12" |
306 | | - |
307 | | - - name: Install Rye |
308 | | - run: | |
309 | | - curl -sSf https://rye.astral.sh/get | bash |
310 | | - echo "$HOME/.rye/shims" >> $GITHUB_PATH |
311 | | - env: |
312 | | - RYE_VERSION: "0.44.0" |
313 | | - RYE_INSTALL_OPTION: "--yes" |
314 | | - |
315 | | - - name: Build and install agentex SDK (same as release) |
316 | | - run: | |
317 | | - rye build --clean |
318 | | - # Get the wheel filename |
319 | | - WHEEL_FILE=$(ls dist/*.whl | head -n 1) |
320 | | - echo "Built wheel: $WHEEL_FILE" |
321 | | - # Install the wheel to make the CLI available |
322 | | - pip install "$WHEEL_FILE" |
323 | | - # Verify CLI is available |
324 | | - agentex --help | head -n 5 |
325 | | - # Store wheel path for later use if needed |
326 | | - echo "AGENTEX_WHEEL=$WHEEL_FILE" >> $GITHUB_ENV |
327 | | -
|
328 | | - - name: Login to Docker Hub |
329 | | - uses: docker/login-action@v3 |
330 | | - with: |
331 | | - username: ${{ vars.DOCKERHUB_USERNAME }} |
332 | | - password: ${{ secrets.DOCKERHUB_PASSWORD }} |
333 | | - |
334 | | - - name: Set up Docker Buildx |
335 | | - uses: docker/setup-buildx-action@v3 |
336 | | - |
337 | | - - name: Build and push tutorial agent |
338 | | - run: | |
339 | | - TUTORIAL="${{ matrix.tutorial }}" |
340 | | - echo "🔨 Building tutorial: $TUTORIAL" |
341 | | -
|
342 | | - TUTORIAL_PATH="examples/tutorials/$TUTORIAL" |
343 | | -
|
344 | | - if [ -f "$TUTORIAL_PATH/manifest.yaml" ]; then |
345 | | - echo "📦 Building with agentex CLI..." |
346 | | -
|
347 | | - # Extract the last folder name from the tutorial path |
348 | | - TAG_NAME=$(basename "$TUTORIAL") |
349 | | -
|
350 | | - # Build and push with agentex agents build command |
351 | | - agentex agents build \ |
352 | | - --manifest "$TUTORIAL_PATH/manifest.yaml" \ |
353 | | - --registry "docker.io" \ |
354 | | - --repository-name "${{ vars.DOCKERHUB_USERNAME }}/agentex-tutorials" \ |
355 | | - --tag "${TAG_NAME}-stable-release" \ |
356 | | - --push |
357 | | -
|
358 | | - echo "✅ Successfully built and pushed: ${{ vars.DOCKERHUB_USERNAME }}/agentex-tutorials:${TAG_NAME}-stable-release" |
359 | | - else |
360 | | - echo "⚠️ No manifest.yaml found in $TUTORIAL_PATH, skipping..." |
361 | | - exit 1 |
362 | | - fi |
0 commit comments