Skip to content

Commit 70f8828

Browse files
authored
Merge pull request #43 from CopilotKit/port-kite-to-aws-cdk
feat(ci): manage Kite releases and deployments from GitHub
2 parents ded2f45 + b017103 commit 70f8828

15 files changed

Lines changed: 925 additions & 119 deletions

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/.github/workflows/ @CopilotKit/engineering
2+
/deployment/aws/ @CopilotKit/engineering
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Kite / _Deploy environment
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
agent_image:
7+
required: true
8+
type: string
9+
environment:
10+
required: true
11+
type: string
12+
github_environment:
13+
required: true
14+
type: string
15+
runtime_image:
16+
required: true
17+
type: string
18+
19+
permissions:
20+
contents: read
21+
id-token: write
22+
23+
concurrency:
24+
group: kite-deploy-${{ inputs.environment }}
25+
cancel-in-progress: ${{ inputs.environment == 'staging' }}
26+
27+
jobs:
28+
deploy:
29+
runs-on: ubuntu-latest
30+
timeout-minutes: 30
31+
environment: ${{ inputs.github_environment }}
32+
steps:
33+
- name: Configure AWS credentials
34+
uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3
35+
with:
36+
aws-region: ${{ vars.AWS_REGION }}
37+
role-to-assume: ${{ vars.AWS_ROLE_ARN }}
38+
role-session-name: kite-${{ inputs.environment }}-${{ github.run_id }}
39+
- name: Register images and update ECS service
40+
env:
41+
AGENT_IMAGE: ${{ inputs.agent_image }}
42+
DEPLOY_ENVIRONMENT: ${{ inputs.environment }}
43+
RUNTIME_IMAGE: ${{ inputs.runtime_image }}
44+
run: |
45+
set -euo pipefail
46+
[[ "$AGENT_IMAGE" =~ ^ghcr\.io/copilotkit/opentag-agent@sha256:[0-9a-f]{64}$ ]]
47+
[[ "$RUNTIME_IMAGE" =~ ^ghcr\.io/copilotkit/opentag-runtime@sha256:[0-9a-f]{64}$ ]]
48+
[[ "$DEPLOY_ENVIRONMENT" =~ ^(staging|prod|community)$ ]]
49+
service="kite-$DEPLOY_ENVIRONMENT"
50+
current_task_definition=$(aws ecs describe-services \
51+
--cluster kite --services "$service" \
52+
--query 'services[0].taskDefinition' --output text)
53+
test "$current_task_definition" != None
54+
55+
current_response="$RUNNER_TEMP/current-task-definition-response.json"
56+
current_json="$RUNNER_TEMP/current-task-definition.json"
57+
next_json="$RUNNER_TEMP/next-task-definition.json"
58+
aws ecs describe-task-definition \
59+
--task-definition "$current_task_definition" \
60+
--include TAGS > "$current_response"
61+
jq '.taskDefinition' "$current_response" > "$current_json"
62+
current_agent=$(jq -r '.containerDefinitions[] | select(.name == "agent") | .image' "$current_json")
63+
current_runtime=$(jq -r '.containerDefinitions[] | select(.name == "runtime") | .image' "$current_json")
64+
65+
task_definition="$current_task_definition"
66+
if [ "$current_agent" != "$AGENT_IMAGE" ] || [ "$current_runtime" != "$RUNTIME_IMAGE" ]; then
67+
jq --arg agent "$AGENT_IMAGE" --arg runtime "$RUNTIME_IMAGE" '
68+
.containerDefinitions |= map(
69+
if .name == "agent" then .image = $agent
70+
elif .name == "runtime" then .image = $runtime
71+
else . end
72+
)
73+
| del(
74+
.taskDefinitionArn,
75+
.revision,
76+
.status,
77+
.requiresAttributes,
78+
.compatibilities,
79+
.registeredAt,
80+
.registeredBy
81+
)
82+
' "$current_json" > "$next_json"
83+
task_definition=$(aws ecs register-task-definition \
84+
--cli-input-json "file://$next_json" \
85+
--tags "$(jq -c '.tags' "$current_response")" \
86+
--query 'taskDefinition.taskDefinitionArn' --output text)
87+
aws ecs update-service \
88+
--cluster kite \
89+
--service "$service" \
90+
--task-definition "$task_definition" \
91+
--force-new-deployment >/dev/null
92+
fi
93+
94+
aws ecs wait services-stable --cluster kite --services "$service"
95+
deployed_task_definition=$(aws ecs describe-services \
96+
--cluster kite --services "$service" \
97+
--query 'services[0].taskDefinition' --output text)
98+
test "$deployed_task_definition" = "$task_definition"
99+
agent=$(aws ecs describe-task-definition --task-definition "$deployed_task_definition" \
100+
--query "taskDefinition.containerDefinitions[?name=='agent'].image | [0]" --output text)
101+
runtime=$(aws ecs describe-task-definition --task-definition "$deployed_task_definition" \
102+
--query "taskDefinition.containerDefinitions[?name=='runtime'].image | [0]" --output text)
103+
test "$agent" = "$AGENT_IMAGE"
104+
test "$runtime" = "$RUNTIME_IMAGE"
105+
running=$(aws ecs describe-services --cluster kite --services "$service" \
106+
--query 'services[0].runningCount' --output text)
107+
test "$running" = "1"

.github/workflows/ci.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
runtime:
12+
runs-on: ubuntu-latest
13+
timeout-minutes: 15
14+
steps:
15+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
16+
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
17+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
18+
with:
19+
node-version: 22.x
20+
cache: pnpm
21+
- run: pnpm install --frozen-lockfile
22+
- run: pnpm check-types
23+
- run: pnpm test
24+
- name: Validate Railway graph
25+
run: node node_modules/railway/dist/iac/bin.js
26+
27+
agent:
28+
runs-on: ubuntu-latest
29+
timeout-minutes: 15
30+
steps:
31+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
33+
with:
34+
enable-cache: true
35+
- name: Install locked dependencies
36+
run: uv sync --project agent --locked
37+
- name: Test agent
38+
working-directory: agent
39+
run: uv run pytest
40+
41+
verify:
42+
name: verify
43+
if: always()
44+
needs: [runtime, agent]
45+
runs-on: ubuntu-latest
46+
steps:
47+
- name: Require every verification job
48+
env:
49+
RESULTS: ${{ join(needs.*.result, ' ') }}
50+
run: |
51+
test "$RESULTS" = "success success" || {
52+
echo "Verification failed: $RESULTS"
53+
exit 1
54+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: Kite / Deploy released version
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
environment:
7+
description: Environment to redeploy or roll back
8+
required: true
9+
type: choice
10+
options: [staging, prod, community]
11+
version:
12+
description: Exact released version, for example v0.2.0
13+
required: true
14+
type: string
15+
16+
permissions:
17+
contents: read
18+
19+
jobs:
20+
resolve-version:
21+
runs-on: ubuntu-latest
22+
outputs:
23+
agent_image: ${{ steps.manifest.outputs.agent_image }}
24+
runtime_image: ${{ steps.manifest.outputs.runtime_image }}
25+
steps:
26+
- name: Verify release manifest
27+
id: manifest
28+
env:
29+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
RELEASE_VERSION: ${{ inputs.version }}
31+
run: |
32+
set -euo pipefail
33+
[[ "$RELEASE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
34+
gh release download "$RELEASE_VERSION" \
35+
--repo "$GITHUB_REPOSITORY" --pattern container-images.json
36+
37+
expected_commit=$(gh api "repos/$GITHUB_REPOSITORY/commits/$RELEASE_VERSION" --jq .sha)
38+
jq -e \
39+
--arg version "$RELEASE_VERSION" \
40+
--arg commit "$expected_commit" '
41+
.version == $version and
42+
.commit == $commit and
43+
.images.agent.repository == "ghcr.io/copilotkit/opentag-agent" and
44+
.images.runtime.repository == "ghcr.io/copilotkit/opentag-runtime" and
45+
.images.agent.reference == (.images.agent.repository + "@" + .images.agent.digest) and
46+
.images.runtime.reference == (.images.runtime.repository + "@" + .images.runtime.digest)
47+
' container-images.json >/dev/null
48+
49+
agent_image=$(jq -r .images.agent.reference container-images.json)
50+
runtime_image=$(jq -r .images.runtime.reference container-images.json)
51+
[[ "$agent_image" =~ ^ghcr\.io/copilotkit/opentag-agent@sha256:[0-9a-f]{64}$ ]]
52+
[[ "$runtime_image" =~ ^ghcr\.io/copilotkit/opentag-runtime@sha256:[0-9a-f]{64}$ ]]
53+
echo "agent_image=$agent_image" >> "$GITHUB_OUTPUT"
54+
echo "runtime_image=$runtime_image" >> "$GITHUB_OUTPUT"
55+
56+
deploy:
57+
needs: resolve-version
58+
permissions:
59+
contents: read
60+
id-token: write
61+
uses: ./.github/workflows/_deploy-kite-environment.yml
62+
with:
63+
agent_image: ${{ needs.resolve-version.outputs.agent_image }}
64+
environment: ${{ inputs.environment }}
65+
github_environment: kite-${{ inputs.environment }}
66+
runtime_image: ${{ needs.resolve-version.outputs.runtime_image }}

.github/workflows/publish-images.yml

Lines changed: 0 additions & 67 deletions
This file was deleted.

0 commit comments

Comments
 (0)