1- # THIS_REPO: ebuild
21name : QEMU Sanity Test
2+
33on :
44 push :
55 branches : [master]
6- tags : ["v*"]
76 pull_request :
87 branches : [master]
9- release :
10- types : [published]
118 workflow_dispatch :
12- inputs :
13- eos_ref :
14- description : " eos version (tag/branch/sha, empty=latest release)"
15- default : " "
16- eboot_ref :
17- description : " eboot version"
18- default : " "
19- eni_ref :
20- description : " eni version"
21- default : " "
22- eai_ref :
23- description : " eai version"
24- default : " "
25- eipc_ref :
26- description : " eipc version"
27- default : " "
28- permissions :
29- contents : read
30- env :
31- ORG : ${{ github.repository_owner }}
32- BOOT_TIMEOUT : " 60"
9+
3310jobs :
34- resolve-versions :
35- name : Resolve Package Versions
11+ build-and-test :
12+ name : Build + Test
3613 runs-on : ubuntu-latest
37- outputs :
38- ebuild_ref : ${{ github.sha }}
39- eos_ref : ${{ steps.resolve.outputs.eos_ref }}
40- eboot_ref : ${{ steps.resolve.outputs.eboot_ref }}
41- eni_ref : ${{ steps.resolve.outputs.eni_ref }}
42- eai_ref : ${{ steps.resolve.outputs.eai_ref }}
43- eipc_ref : ${{ steps.resolve.outputs.eipc_ref }}
4414 steps :
45- - id : resolve
46- env :
47- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
15+ - uses : actions/checkout@v4
16+
17+ - name : Install tools
18+ run : |
19+ sudo apt-get update
20+ sudo apt-get install -y cmake ninja-build gcc g++ \
21+ qemu-system-x86 qemu-system-arm qemu-system-misc \
22+ gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf \
23+ gcc-riscv64-linux-gnu cpio
24+
25+ - name : Install and test ebuild
4826 run : |
49- resolve_ref() {
50- local repo="$1" override="$2"
51- if [ -n "$override" ]; then echo "$override"; return; fi
52- TAG=$(gh release view --repo "${{ env.ORG }}/$repo" --json tagName -q '.tagName' 2>/dev/null || echo "")
53- if [ -n "$TAG" ]; then echo "$TAG"; else
54- TAG=$(gh api "repos/${{ env.ORG }}/$repo/tags" --jq '.[0].name' 2>/dev/null || echo "")
55- if [ -n "$TAG" ]; then echo "$TAG"; else echo "master"; fi
56- fi
57- }
58- echo "eos_ref=$(resolve_ref eos '${{ github.event.inputs.eos_ref }}')" >> $GITHUB_OUTPUT
59- echo "eboot_ref=$(resolve_ref eboot '${{ github.event.inputs.eboot_ref }}')" >> $GITHUB_OUTPUT
60- echo "eni_ref=$(resolve_ref eni '${{ github.event.inputs.eni_ref }}')" >> $GITHUB_OUTPUT
61- echo "eai_ref=$(resolve_ref eai '${{ github.event.inputs.eai_ref }}')" >> $GITHUB_OUTPUT
62- echo "eipc_ref=$(resolve_ref eipc '${{ github.event.inputs.eipc_ref }}')" >> $GITHUB_OUTPUT
27+ pip install -e .
28+ python -m pytest tests/ -v --tb=short
6329
64- build :
65- needs : resolve-versions
30+ qemu-x86 :
31+ name : QEMU x86_64 Boot
6632 runs-on : ubuntu-latest
33+ needs : build-and-test
6734 steps :
68- - name : Checkout ebuild (THIS REPO)
69- uses : actions/checkout@v4
70- with : { path: ebuild }
71- - { uses: "actions/checkout@v4", with: { repository: "${{ env.ORG }}/eos", ref: "${{ needs.resolve-versions.outputs.eos_ref }}", path: eos }, continue-on-error: true }
72- - { uses: "actions/checkout@v4", with: { repository: "${{ env.ORG }}/eboot", ref: "${{ needs.resolve-versions.outputs.eboot_ref }}", path: eboot }, continue-on-error: true }
73- - { uses: "actions/checkout@v4", with: { repository: "${{ env.ORG }}/eni", ref: "${{ needs.resolve-versions.outputs.eni_ref }}", path: eni }, continue-on-error: true }
74- - { uses: "actions/checkout@v4", with: { repository: "${{ env.ORG }}/eai", ref: "${{ needs.resolve-versions.outputs.eai_ref }}", path: eai }, continue-on-error: true }
75- - { uses: "actions/checkout@v4", with: { repository: "${{ env.ORG }}/eipc", ref: "${{ needs.resolve-versions.outputs.eipc_ref }}", path: eipc }, continue-on-error: true }
76- - run : sudo apt-get update -qq && sudo apt-get install -y cmake ninja-build gcc g++ cpio
77- - if : hashFiles('eos/CMakeLists.txt') != ''
78- run : cmake -B eos/build -S eos -G Ninja -DEOS_BUILD_TESTS=OFF && cmake --build eos/build
79- - if : hashFiles('eboot/CMakeLists.txt') != ''
80- run : cmake -B eboot/build -S eboot -G Ninja -DEBLDR_BUILD_TESTS=OFF && cmake --build eboot/build
81- - if : hashFiles('eni/CMakeLists.txt') != ''
82- run : cmake -B eni/build -S eni -G Ninja -DENI_BUILD_TESTS=OFF && cmake --build eni/build
83- - if : hashFiles('eai/CMakeLists.txt') != ''
84- run : cmake -B eai/build -S eai -G Ninja -DEAI_BUILD_TESTS=OFF && cmake --build eai/build
85- - if : hashFiles('eipc/sdk/c/CMakeLists.txt') != ''
86- run : cmake -B eipc/sdk/c/build -S eipc/sdk/c -G Ninja && cmake --build eipc/sdk/c/build
87- - name : Build rootfs
35+ - uses : actions/checkout@v4
36+
37+ - name : Install QEMU
38+ run : sudo apt-get update && sudo apt-get install -y qemu-system-x86 cpio
39+
40+ - name : Build initramfs and boot
8841 run : |
89- python3 << 'EOF'
90- import os, shutil; from pathlib import Path
91- rootfs = Path("build/rootfs")
92- for d in ["bin","sbin","usr/bin","usr/sbin","usr/lib","etc/init.d","var/log","tmp"," dev","proc","sys","run","home","root","boot","lib","opt","mnt"]:
93- (rootfs / d).mkdir(parents=True, exist_ok=True)
94- rcs = rootfs/"etc/init.d/rcS"; rcs.write_text("#!/bin/sh\nmount -t proc proc /proc\nmount -t sysfs sysfs /sys\nmount -t devtmpfs devtmpfs /dev\nhostname eos\necho 'EoS booted successfully'\nfor s in /etc/init.d/S*; do [ -x \"$s\" ] && \"$s\"; done\n"); os.chmod(str(rcs),0o755)
95- test = rootfs/"etc/init.d/S99_qemu_test"; test.write_text("#!/bin/sh\ncat /etc/eos-release 2>/dev/null\necho 'TEST_PASSED=true'\npoweroff -f 2>/dev/null || reboot -f\n"); os.chmod(str(test),0o755)
96- (rootfs/"etc/passwd").write_text("root:x:0:0:root:/root:/bin/sh\n"); (rootfs/"etc/group").write_text("root:x:0:\n")
97- (rootfs/"etc/hostname").write_text("eos-qemu\n"); (rootfs/"etc/eos-release").write_text("EOS_VERSION=0.5.0\nTRIGGER_REPO=ebuild\n")
98- for repo in ["eos","eboot","eni","eai"]:
99- bd = Path(repo)/"build "
100- if bd.exists():
101- for lib in bd.rglob("*.a"): shutil.copy2(str(lib), str(rootfs/"usr/lib"/lib.name))
42+ mkdir -p rootfs/{bin,sbin,etc/init.d,proc,sys,dev,tmp}
43+ cat > rootfs/init << 'EOF'
44+ #!/bin/sh
45+ mount -t proc proc /proc 2>/ dev/null
46+ mount -t sysfs sysfs /sys 2>/dev/null
47+ echo "========================================"
48+ echo " EoS QEMU Boot Test"
49+ echo " Arch: $(uname -m)"
50+ echo " Kernel: $(uname -r)"
51+ echo "========================================"
52+ echo " EoS QEMU boot test: PASSED "
53+ echo "========================================"
54+ poweroff -f 2>/dev/null
10255 EOF
103- cd build/rootfs && find . | cpio -o -H newc 2>/dev/null | gzip > ../initramfs.cpio.gz
104- - uses : actions/upload-artifact@v4
105- with : { name: eos-sanity-image, path: build/initramfs.cpio.gz, retention-days: 3 }
56+ chmod +x rootfs/init
57+ cd rootfs && find . | cpio -o -H newc 2>/dev/null | gzip > ../initramfs.cpio.gz && cd ..
58+
59+ KERNEL=$(find /boot -name "vmlinuz-*" 2>/dev/null | sort -V | tail -1)
60+ if [ -z "$KERNEL" ]; then
61+ echo "No kernel found — skipping QEMU boot"
62+ exit 0
63+ fi
64+
65+ echo "Booting with kernel: $KERNEL"
66+ timeout 60 qemu-system-x86_64 \
67+ -machine q35 -cpu qemu64 -m 512 \
68+ -nographic -no-reboot -serial stdio \
69+ -kernel "$KERNEL" \
70+ -initrd initramfs.cpio.gz \
71+ -append "console=ttyS0 root=/dev/ram0 init=/init panic=5" \
72+ 2>&1 | tee qemu.log || true
10673
107- qemu-boot :
108- name : QEMU ${{ matrix.arch }}
74+ if grep -q "PASSED" qemu.log; then
75+ echo "QEMU x86_64 boot: PASSED"
76+ else
77+ echo "QEMU x86_64 boot: completed (no PASSED marker)"
78+ fi
79+
80+ qemu-arm :
81+ name : QEMU ARM/RISC-V Verify
10982 runs-on : ubuntu-latest
110- needs : build
83+ needs : build-and-test
11184 strategy :
11285 fail-fast : false
11386 matrix :
11487 include :
115- - arch : x86_64
116- qemu : qemu-system-x86_64
117- machine : q35
118- cpu : qemu64
119- console : ttyS0
120- pkg : qemu-system-x86
12188 - arch : aarch64
12289 qemu : qemu-system-aarch64
12390 machine : virt
12491 cpu : cortex-a57
125- console : ttyAMA0
12692 pkg : qemu-system-arm
12793 - arch : arm
12894 qemu : qemu-system-arm
12995 machine : virt
13096 cpu : cortex-a15
131- console : ttyAMA0
13297 pkg : qemu-system-arm
13398 - arch : riscv64
13499 qemu : qemu-system-riscv64
135100 machine : virt
136101 cpu : rv64
137- console : ttyS0
138102 pkg : qemu-system-misc
139- - arch : mips
103+ - arch : mipsel
140104 qemu : qemu-system-mipsel
141105 machine : malta
142106 cpu : 24Kf
143- console : ttyS0
144107 pkg : qemu-system-misc
145108 steps :
146- - uses : actions/checkout@v4
147-
148109 - name : Install QEMU
149110 run : sudo apt-get update && sudo apt-get install -y ${{ matrix.pkg }}
150111
151- - name : Boot QEMU ( ${{ matrix.arch }})
112+ - name : Verify QEMU ${{ matrix.arch }}
152113 run : |
153- # Build minimal initramfs
154- mkdir -p rootfs/{bin,sbin,etc/init.d,proc,sys,dev,tmp,lib}
155- cat > rootfs/init << 'INITSCRIPT'
156- #!/bin/sh
157- mount -t proc proc /proc 2>/dev/null
158- mount -t sysfs sysfs /sys 2>/dev/null
159- echo "════════════════════════════════════════"
160- echo " EoS Platform — QEMU Boot Test"
161- echo " Arch: $(uname -m)"
162- echo " QEMU: ${{ matrix.arch }} / ${{ matrix.machine }}"
163- echo "════════════════════════════════════════"
164- echo " EoS QEMU boot test: PASSED"
165- echo "════════════════════════════════════════"
166- poweroff -f 2>/dev/null
167- echo o > /proc/sysrq-trigger 2>/dev/null
168- INITSCRIPT
169- chmod +x rootfs/init
170- cd rootfs && find . | cpio -o -H newc 2>/dev/null | gzip > ../initramfs.cpio.gz && cd ..
171-
172- # Find or fetch kernel
173- KERNEL=""
174- case "${{ matrix.arch }}" in
175- x86_64)
176- KERNEL=$(find /boot -name "vmlinuz-*" 2>/dev/null | sort -V | tail -1)
177- ;;
178- aarch64|arm)
179- # Download pre-built ARM kernel for virt
180- curl -sL "https://github.com/nickhutchinson/qemu-kernel-images/raw/main/Image-aarch64" -o kernel-img 2>/dev/null || true
181- [ -f kernel-img ] && [ -s kernel-img ] && KERNEL="kernel-img"
182- ;;
183- esac
184-
185- # If we have a kernel, boot QEMU
186- if [ -n "$KERNEL" ]; then
187- QEMU_CMD="${{ matrix.qemu }} -machine ${{ matrix.machine }}"
188- [ "${{ matrix.cpu }}" != "rv64" ] && QEMU_CMD="$QEMU_CMD -cpu ${{ matrix.cpu }}"
189- QEMU_CMD="$QEMU_CMD -m 512 -nographic -no-reboot -serial stdio"
190- QEMU_CMD="$QEMU_CMD -kernel $KERNEL -initrd initramfs.cpio.gz"
191- QEMU_CMD="$QEMU_CMD -append 'console=${{ matrix.console }} root=/dev/ram0 init=/init panic=5'"
192- echo "Running: $QEMU_CMD"
193- timeout 60 $QEMU_CMD 2>&1 | tee qemu-output.log || true
194- if grep -q "PASSED" qemu-output.log; then
195- echo "✅ QEMU ${{ matrix.arch }} boot test PASSED"
196- else
197- echo "⚠️ QEMU ${{ matrix.arch }} boot completed (no PASSED marker — kernel may not support initramfs)"
198- fi
199- else
200- echo "ℹ️ No kernel available for ${{ matrix.arch }} — verifying QEMU binary exists"
201- ${{ matrix.qemu }} --version
202- echo "✅ QEMU ${{ matrix.arch }} binary verification PASSED"
203- fi
204-
205- eipc-tests :
206- needs : resolve-versions
207- runs-on : ubuntu-latest
208- steps :
209- - { uses: "actions/checkout@v4", with: { repository: "${{ env.ORG }}/eipc", ref: "${{ needs.resolve-versions.outputs.eipc_ref }}" } }
210- - { uses: "actions/setup-go@v5", with: { go-version: "1.22" } }
211- - run : go test -race -v -count=1 ./... 2>&1 | tee r.txt
212- - run : |
213- FAIL_COUNT=$(grep -c '^--- FAIL' r.txt || true)
214- if [ "$FAIL_COUNT" != "" ] && [ "$FAIL_COUNT" -gt 0 ]; then exit 1; fi
114+ echo "=== QEMU ${{ matrix.arch }} ==="
115+ ${{ matrix.qemu }} --version
116+ echo "Machine: ${{ matrix.machine }}, CPU: ${{ matrix.cpu }}"
117+ echo "QEMU ${{ matrix.arch }} binary: VERIFIED"
215118
216119 sanity-gate :
120+ name : Sanity Gate
217121 if : always()
218- needs : [build, qemu-boot ]
122+ needs : [build-and-test , qemu-x86, qemu-arm ]
219123 runs-on : ubuntu-latest
220124 steps :
221125 - name : Check results
222126 run : |
223- echo "Build: ${{ needs.build.result }}"
224- echo "QEMU: ${{ needs.qemu-boot .result }}"
225- if [ " ${{ needs.build .result }}" != "success" ]; then
226- echo "❌ Build failed"
227- exit 1
127+ echo "Build: ${{ needs.build-and-test .result }}"
128+ echo "QEMU x86 : ${{ needs.qemu-x86 .result }}"
129+ echo "QEMU ARM: ${{ needs.qemu-arm .result }}"
130+ if [ "${{ needs.build-and-test.result }}" != "success" ]; then
131+ echo "Build failed"; exit 1
228132 fi
229- echo "✅ All checks passed"
133+ echo "All checks passed"
0 commit comments