Skip to content

Commit 6f29365

Browse files
feat: prebaked platform VM (#2251)
Co-authored-by: Jan Pokorný <JanPokorny@users.noreply.github.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
1 parent b089d2a commit 6f29365

File tree

31 files changed

+752
-577
lines changed

31 files changed

+752
-577
lines changed

.github/actions/setup/action.yml

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,83 @@
11
name: 'Setup environment'
22
description: 'Set up mise tools (Python, Node.js, ...) and install project dependencies'
33

4+
inputs:
5+
install_vm_deps:
6+
description: 'Install VM dependencies: none, run (QEMU + OVMF), or build (QEMU + OVMF + xorriso)'
7+
required: false
8+
default: 'none'
9+
maximize_space:
10+
description: 'Maximize available disk space (removes .NET, reclaims swap)'
11+
required: false
12+
default: 'false'
13+
414
runs:
515
using: "composite"
616
steps:
7-
- name: Cache uv .venv
8-
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
17+
- if: inputs.maximize_space == 'true'
18+
uses: ./.github/actions/maximize-build-space
19+
with:
20+
root-reserve-mb: 15360
21+
temp-reserve-mb: 2048
22+
swap-size-mb: 1024
23+
remove-dotnet: 'true'
24+
25+
- if: inputs.maximize_space == 'true'
26+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
27+
28+
- if: inputs.install_vm_deps != 'none'
29+
shell: bash
30+
run: |
31+
sudo apt-get update -qq
32+
PACKAGES="qemu-utils"
33+
ARCH=$(uname -m)
34+
if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then
35+
PACKAGES="$PACKAGES qemu-system-x86 ovmf"
36+
else
37+
PACKAGES="$PACKAGES qemu-system-arm qemu-efi-aarch64"
38+
fi
39+
if [ "${{ inputs.install_vm_deps }}" = "build" ]; then
40+
PACKAGES="$PACKAGES xorriso"
41+
fi
42+
sudo apt-get install -qqy --no-install-recommends $PACKAGES
43+
sudo modprobe kvm || true
44+
[ -e /dev/kvm ] && sudo chown $(whoami) /dev/kvm || true
45+
46+
- shell: bash
47+
run: |
48+
echo "UV_FROZEN=true" >> $GITHUB_ENV
49+
echo "UV_CACHE_DIR=/tmp/.uv-cache" >> $GITHUB_ENV
50+
echo "ARCH=$(uname -m | sed -e 's/arm64/aarch64/;s/amd64/x86_64/')" >> $GITHUB_ENV
51+
52+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
53+
id: uv-cache
954
with:
1055
path: /tmp/.uv-cache
1156
key: uv-cache-v1-${{ runner.os }}-${{ hashFiles('**/uv.lock') }}
1257
restore-keys: uv-cache-v1-${{ runner.os }}-
1358

14-
- name: Cache pnpm store
15-
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
59+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
1660
with:
1761
path: ~/.local/share/pnpm/store
1862
key: pnpm-store-v1-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
1963
restore-keys: pnpm-store-v1-${{ runner.os }}-
2064

21-
- name: Cache Next.js cache
22-
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
65+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
2366
with:
2467
path: ${{ github.workspace }}/**/.next/cache
2568
key: nextjs-cache-v1-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
2669
restore-keys: |
2770
nextjs-cache-v1-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-
2871
nextjs-cache-v1-${{ runner.os }}-
2972
30-
- name: Set environment variables
31-
shell: bash
32-
run: |
33-
echo "UV_FROZEN=true" >> $GITHUB_ENV
34-
echo "UV_CACHE_DIR=/tmp/.uv-cache" >> $GITHUB_ENV
73+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
74+
with:
75+
path: apps/microshift-vm/dist/${{ env.ARCH }}
76+
key: microshift-vm-dist-v1-${{ runner.os }}-${{ env.ARCH }}-${{ hashFiles('apps/microshift-vm/**') }}
3577

3678
- uses: jdx/mise-action@e79ddf65a11cec7b0e882bedced08d6e976efb2d
79+
80+
- if: steps.uv-cache.outputs.cache-hit != 'true'
81+
uses: gacts/run-and-post-run@4f9ae8f313ea7ec57ab5e6f82ae343c9a614bfbf # v1
3782
with:
38-
version: 2026.2.20
83+
post: uv cache prune --ci

.github/workflows/ci.yml

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
name: CI
2+
3+
permissions:
4+
contents: read
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
on:
11+
workflow_dispatch: {}
12+
pull_request:
13+
push:
14+
branches: [main]
15+
16+
jobs:
17+
changes:
18+
runs-on: ubuntu-latest
19+
outputs:
20+
agentstack-server: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.agentstack-server == 'true' }}
21+
agentstack-cli: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.agentstack-cli == 'true' }}
22+
agentstack-sdk-py: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.agentstack-sdk-py == 'true' }}
23+
helm: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.helm == 'true' }}
24+
examples: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.examples == 'true' }}
25+
microshift-vm: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.microshift-vm == 'true' }}
26+
steps:
27+
- uses: dorny/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c
28+
id: filter
29+
with:
30+
filters: |
31+
agentstack-server: 'apps/agentstack-server/**'
32+
agentstack-cli: 'apps/agentstack-cli/**'
33+
agentstack-sdk-py: 'apps/agentstack-sdk-py/**'
34+
helm: 'helm/**'
35+
examples: 'examples/**'
36+
microshift-vm: 'apps/microshift-vm/**'
37+
38+
check:
39+
name: mise check
40+
runs-on: ubuntu-latest
41+
steps:
42+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
43+
- uses: ./.github/actions/setup
44+
env:
45+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46+
- run: mise run check
47+
48+
test:
49+
name: mise test
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
53+
- uses: ./.github/actions/setup
54+
env:
55+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56+
- run: mise run test
57+
58+
microshift-vm-build:
59+
name: mise microshift-vm:build:qemu
60+
needs: changes
61+
if: needs.changes.outputs.microshift-vm == 'true'
62+
timeout-minutes: 10
63+
runs-on: ubuntu-latest
64+
steps:
65+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
66+
- name: Set arch
67+
run: echo "ARCH=$(uname -m | sed -e 's/arm64/aarch64/;s/amd64/x86_64/')" >> $GITHUB_ENV
68+
- id: cache-check
69+
uses: actions/cache@565629816435f6c0b50676926c9b05c254113c0c
70+
with:
71+
path: apps/microshift-vm/dist/${{ env.ARCH }}
72+
key: microshift-vm-dist-v1-${{ runner.os }}-${{ env.ARCH }}-${{ hashFiles('apps/microshift-vm/**') }}
73+
lookup-only: true
74+
- if: steps.cache-check.outputs.cache-hit != 'true'
75+
uses: ./.github/actions/setup
76+
with:
77+
install_vm_deps: 'build'
78+
- if: steps.cache-check.outputs.cache-hit != 'true'
79+
run: mise run microshift-vm:build:qemu
80+
81+
agentstack-server-test-integration:
82+
name: mise agentstack-server:test:integration
83+
needs: [changes, microshift-vm-build]
84+
if: >-
85+
always() &&
86+
needs.microshift-vm-build.result != 'failure' &&
87+
(needs.changes.outputs.agentstack-server == 'true' ||
88+
needs.changes.outputs.agentstack-cli == 'true')
89+
timeout-minutes: 25
90+
runs-on: ubuntu-latest
91+
steps:
92+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
93+
- uses: ./.github/actions/setup
94+
with:
95+
maximize_space: 'true'
96+
install_vm_deps: 'run'
97+
env:
98+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99+
- run: mise run agentstack-server:test:integration
100+
env:
101+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
102+
LLM_API_BASE: "${{ secrets.OPENAI_API_BASE }}"
103+
LLM_MODEL: "${{ vars.OPENAI_MODEL }}"
104+
LLM_API_KEY: "${{ secrets.OPENAI_API_KEY }}"
105+
106+
agentstack-server-test-e2e:
107+
name: mise agentstack-server:test:e2e
108+
needs: [changes, microshift-vm-build]
109+
if: >-
110+
always() &&
111+
needs.microshift-vm-build.result != 'failure' &&
112+
(needs.changes.outputs.agentstack-server == 'true' ||
113+
needs.changes.outputs.agentstack-cli == 'true' ||
114+
needs.changes.outputs.agentstack-sdk-py == 'true' ||
115+
needs.changes.outputs.helm == 'true')
116+
timeout-minutes: 25
117+
runs-on: ubuntu-latest
118+
env:
119+
AGENTSTACK__HOME: ${{ github.workspace }}/.agentstack
120+
steps:
121+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
122+
- uses: ./.github/actions/setup
123+
with:
124+
maximize_space: 'true'
125+
install_vm_deps: 'run'
126+
env:
127+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
128+
- run: mise run agentstack-server:test:e2e
129+
env:
130+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131+
LLM_API_BASE: "${{ secrets.OPENAI_API_BASE }}"
132+
LLM_MODEL: "${{ vars.OPENAI_MODEL }}"
133+
EMBEDDING_MODEL: "${{ vars.OPENAI_EMBEDDING_MODEL }}"
134+
LLM_API_KEY: "${{ secrets.OPENAI_API_KEY }}"
135+
136+
agentstack-server-test-e2e-examples:
137+
name: mise agentstack-server:test:e2e-examples
138+
needs: [changes, microshift-vm-build]
139+
if: >-
140+
always() &&
141+
needs.microshift-vm-build.result != 'failure' &&
142+
(needs.changes.outputs.agentstack-server == 'true' ||
143+
needs.changes.outputs.agentstack-sdk-py == 'true' ||
144+
needs.changes.outputs.examples == 'true' ||
145+
needs.changes.outputs.helm == 'true') &&
146+
(github.event_name != 'pull_request' ||
147+
contains(github.event.pull_request.labels.*.name, 'e2e-examples'))
148+
timeout-minutes: 45
149+
runs-on: ubuntu-latest
150+
env:
151+
AGENTSTACK__HOME: ${{ github.workspace }}/.agentstack
152+
steps:
153+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
154+
- uses: ./.github/actions/setup
155+
with:
156+
maximize_space: 'true'
157+
install_vm_deps: 'run'
158+
env:
159+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
160+
- run: mise run agentstack-server:test:e2e-examples
161+
env:
162+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
163+
LLM_API_BASE: "${{ secrets.OPENAI_API_BASE }}"
164+
LLM_MODEL: "${{ vars.OPENAI_MODEL }}"
165+
EMBEDDING_MODEL: "${{ vars.OPENAI_EMBEDDING_MODEL }}"
166+
LLM_API_KEY: "${{ secrets.OPENAI_API_KEY }}"
167+
168+
agentstack-sdk-py-test-all:
169+
name: "mise agentstack-sdk-py:test-all --python=${{ matrix.python }}"
170+
needs: changes
171+
if: needs.changes.outputs.agentstack-sdk-py == 'true'
172+
runs-on: ubuntu-latest
173+
strategy:
174+
fail-fast: false
175+
matrix:
176+
python:
177+
- "3.11"
178+
- "3.14"
179+
steps:
180+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
181+
- uses: ./.github/actions/setup
182+
with:
183+
install_vm_deps: 'run'
184+
env:
185+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
186+
- run: mise run agentstack-sdk-py:test-all --python=${{ matrix.python }}

.github/workflows/common.yml

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

.github/workflows/e2e-examples-test.yml

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

0 commit comments

Comments
 (0)