Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f8fcf9d
Squashed commit of the following:
mantrakp04 Mar 18, 2026
0010642
Refactor QEMU emulator setup and consolidate cloud-init configurations
mantrakp04 Mar 18, 2026
c2e4698
Refactor local emulator configuration management and remove obsolete …
mantrakp04 Mar 18, 2026
4508f24
Enhance Dockerfile for local emulator and server setup
mantrakp04 Mar 19, 2026
dec62a0
Refactor QEMU emulator build and snapshot handling
mantrakp04 Mar 19, 2026
580ff10
Refactor local emulator setup and consolidate services
mantrakp04 Mar 19, 2026
e3592bb
Add base image fingerprinting for QEMU snapshots
mantrakp04 Mar 19, 2026
5a729ec
Enhance configuration and permissions in local emulator setup
mantrakp04 Mar 19, 2026
c1a15ff
Enhance local emulator configuration and file management
mantrakp04 Mar 19, 2026
0496cd2
Add QEMU emulator build workflow and emulator command integration
mantrakp04 Mar 19, 2026
4a43a88
Update emulator configuration and enhance CLI functionality
mantrakp04 Mar 19, 2026
fe16a71
Merge branch 'dev' into emu-with-a-q
mantrakp04 Mar 19, 2026
5d98b44
Remove deprecated configuration files and streamline emulator CLI com…
mantrakp04 Mar 19, 2026
3321e5c
Update QEMU emulator scripts to improve KVM detection and service sta…
mantrakp04 Mar 19, 2026
8336d48
Refactor local emulator type handling and architecture detection
mantrakp04 Mar 19, 2026
298062a
Enhance local emulator configuration handling and file management
mantrakp04 Mar 19, 2026
578593a
Enhance QEMU emulator build workflow and local emulator configuration
mantrakp04 Mar 19, 2026
80ee1ab
Merge branch 'dev' into emu-with-a-q
mantrakp04 Mar 19, 2026
42bc125
Enhance setBranchConfigOverride for local emulator file handling
mantrakp04 Mar 19, 2026
4be8a82
Update QEMU emulator build workflow for improved performance and reli…
mantrakp04 Mar 19, 2026
f3514f8
Refactor QEMU emulator build and local emulator configuration
mantrakp04 Mar 20, 2026
d5d2a09
Increase EMULATOR_READY_TIMEOUT in QEMU emulator build workflow
mantrakp04 Mar 20, 2026
e509947
Enhance local emulator setup with environment generation and configur…
mantrakp04 Mar 20, 2026
ad2db19
Refactor local emulator configuration validation and enhance CLI tests
mantrakp04 Mar 20, 2026
a233e64
Update local emulator environment handling and documentation
mantrakp04 Mar 20, 2026
14f8164
Enhance local emulator project handling and configuration validation
mantrakp04 Mar 23, 2026
9d0f7c1
Refactor local emulator scripts and configuration management
mantrakp04 Mar 23, 2026
77d87fd
Refactor local emulator setup and enhance GitHub Actions workflow
mantrakp04 Mar 23, 2026
bef4aab
Enhance QEMU emulator build workflow and add documentation
mantrakp04 Mar 24, 2026
6d9d4e7
Merge branch 'dev' into emu-with-a-q
mantrakp04 Mar 24, 2026
771ed15
Update CLI tests for emulator commands
mantrakp04 Mar 24, 2026
0f3daeb
Merge branch 'dev' into emu-with-a-q
mantrakp04 Mar 27, 2026
950d74a
remove stack.config.ts
mantrakp04 Apr 1, 2026
26254c4
Merge branch 'dev' into emu-with-a-q
mantrakp04 Apr 2, 2026
7daea68
Increase QEMU smoke test timeout to 60 minutes
mantrakp04 Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ dist
.docusaurus
.cache-loader
**.tsbuildinfo
docker/local-emulator/qemu/images
docker/local-emulator/qemu/run

.xata*

Expand Down Expand Up @@ -149,4 +151,3 @@ packages/stack/*
!packages/react/package.json
!packages/next/package.json
!packages/stack/package.json

255 changes: 255 additions & 0 deletions .github/workflows/qemu-emulator-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
name: Build & Publish QEMU Emulator Images
Comment thread
mantrakp04 marked this conversation as resolved.

on:
push:
branches:
- main
- dev
pull_request:
paths:
- 'docker/local-emulator/**'
- '.github/workflows/qemu-emulator-build.yaml'
workflow_dispatch:
inputs:
publish:
description: 'Publish images to GitHub Releases'
type: boolean
default: false

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/dev' }}

env:
EMULATOR_IMAGE_NAME: stack-local-emulator

jobs:
build:
name: Build QEMU Image (${{ matrix.arch }})
runs-on: ubicloud-standard-8
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
- arch: arm64

steps:
- uses: actions/checkout@v6

- name: Set up QEMU user-mode emulation
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Install QEMU dependencies
run: |
sudo apt-get update
sudo apt-get install -y qemu-system-x86 qemu-system-arm qemu-utils genisoimage socat qemu-efi-aarch64

- name: Build QEMU image
run: |
chmod +x docker/local-emulator/qemu/build-image.sh
EMULATOR_PROVISION_TIMEOUT=6000 \
docker/local-emulator/qemu/build-image.sh ${{ matrix.arch }}

- name: Generate emulator env
run: node docker/local-emulator/generate-env-development.mjs

- name: Start emulator and verify
run: |
chmod +x docker/local-emulator/qemu/run-emulator.sh
EMULATOR_ARCH=${{ matrix.arch }} \
EMULATOR_READY_TIMEOUT=3200 \
docker/local-emulator/qemu/run-emulator.sh start

- name: Verify services are healthy
run: |
EMULATOR_ARCH=${{ matrix.arch }} \
docker/local-emulator/qemu/run-emulator.sh status

- name: Stop emulator
if: always()
run: |
EMULATOR_ARCH=${{ matrix.arch }} \
docker/local-emulator/qemu/run-emulator.sh stop
Comment thread
mantrakp04 marked this conversation as resolved.

- name: Package image
run: |
BASE_IMG="docker/local-emulator/qemu/images/stack-emulator-${{ matrix.arch }}.qcow2"
cp "$BASE_IMG" "stack-emulator-${{ matrix.arch }}.qcow2"

- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: qemu-emulator-${{ matrix.arch }}
path: stack-emulator-${{ matrix.arch }}.qcow2
retention-days: 30
compression-level: 0

test:
name: Smoke Test (${{ matrix.arch }})
needs: build
runs-on: ubicloud-standard-8
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- arch: amd64

steps:
- uses: actions/checkout@v6

- name: Install QEMU dependencies
run: |
sudo apt-get update
sudo apt-get install -y qemu-system-x86 qemu-utils genisoimage socat

- name: Download built image
uses: actions/download-artifact@v4
with:
name: qemu-emulator-${{ matrix.arch }}
path: docker/local-emulator/qemu/images/

- name: Generate emulator env
run: node docker/local-emulator/generate-env-development.mjs

- name: Start emulator from artifact
run: |
chmod +x docker/local-emulator/qemu/run-emulator.sh docker/local-emulator/qemu/common.sh
EMULATOR_ARCH=${{ matrix.arch }} \
EMULATOR_READY_TIMEOUT=600 \
docker/local-emulator/qemu/run-emulator.sh start

- name: Verify services are healthy
run: |
EMULATOR_ARCH=${{ matrix.arch }} \
docker/local-emulator/qemu/run-emulator.sh status

- name: Smoke test — backend health
run: curl -sf http://localhost:26701/health?db=1

- name: Smoke test — dashboard reachable
run: curl -sf -o /dev/null -w "HTTP %{http_code}\n" http://localhost:26700/handler/sign-in

- name: Smoke test — MinIO health
run: curl -sf http://localhost:26702/minio/health/live

- name: Smoke test — Inbucket reachable
run: curl -sf -o /dev/null -w "HTTP %{http_code}\n" http://localhost:26703/

- name: Stop emulator
if: always()
run: |
EMULATOR_ARCH=${{ matrix.arch }} \
docker/local-emulator/qemu/run-emulator.sh stop

- name: Print serial log on failure
if: failure()
run: tail -100 docker/local-emulator/qemu/run/vm/serial.log 2>/dev/null || true

publish:
name: Publish to GitHub Releases
needs: [build, test]
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' || (github.event_name == 'workflow_dispatch' && inputs.publish)
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@v6

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: Prepare release assets
run: |
mkdir -p release
SHORT_SHA="${GITHUB_SHA:0:8}"
BRANCH="${GITHUB_REF_NAME}"
DATE="$(date -u +%Y%m%d)"
TAG="emulator-${BRANCH}-${DATE}-${SHORT_SHA}"
echo "RELEASE_TAG=${TAG}" >> "$GITHUB_ENV"
echo "SHORT_SHA=${SHORT_SHA}" >> "$GITHUB_ENV"

for f in artifacts/qemu-emulator-*/*.qcow2; do
cp "$f" release/
done

cat > release-notes.md <<EOF
## QEMU Emulator Images

Built from \`${BRANCH}\` @ \`${GITHUB_SHA}\`

### Images
| File | Description |
|------|-------------|
| \`stack-emulator-arm64.qcow2\` | ARM64 emulator image |
| \`stack-emulator-amd64.qcow2\` | AMD64 emulator image |

### Usage
\`\`\`bash
stack emulator pull
stack emulator start
\`\`\`
EOF

ls -lh release/

- name: Create or update GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TITLE="QEMU Emulator — ${{ github.ref_name }} ($SHORT_SHA)"

if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release edit "$RELEASE_TAG" \
--title "$TITLE" \
--notes-file release-notes.md \
--prerelease
gh release upload "$RELEASE_TAG" release/* --clobber
else
gh release create "$RELEASE_TAG" \
--title "$TITLE" \
--notes-file release-notes.md \
--prerelease \
release/*
fi

- name: Update latest tag for branch
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LATEST_TAG="emulator-${{ github.ref_name }}-latest"
TITLE="QEMU Emulator — ${{ github.ref_name }} (latest)"
NOTES="Latest emulator images from \`${{ github.ref_name }}\`. Auto-updated on each build."

if gh release view "$LATEST_TAG" >/dev/null 2>&1; then
gh release edit "$LATEST_TAG" \
--draft \
--prerelease \
--target "${{ github.sha }}" \
--title "$TITLE" \
--notes "$NOTES"
else
gh release create "$LATEST_TAG" \
--draft \
--prerelease \
--target "${{ github.sha }}" \
--title "$TITLE" \
--notes "$NOTES" \
|| gh release edit "$LATEST_TAG" \
--draft \
--prerelease \
--target "${{ github.sha }}" \
--title "$TITLE" \
--notes "$NOTES"
fi

gh release upload "$LATEST_TAG" release/* --clobber
gh release edit "$LATEST_TAG" --draft=false --prerelease
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ vite.config.ts.timestamp-*
.eslintcache
.env.local
.env.*.local
docker/local-emulator/.env.development
scratch/

npm-debug.log*
Expand Down
7 changes: 7 additions & 0 deletions apps/backend/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,13 @@ export async function seed() {
} else {
console.log('Ensured emulator user is a member of emulator team');
}

await grantTeamPermission(internalPrisma, {
tenancy: internalTenancy,
teamId: LOCAL_EMULATOR_OWNER_TEAM_ID,
userId: LOCAL_EMULATOR_ADMIN_USER_ID,
permissionId: "team_admin",
});
Comment thread
mantrakp04 marked this conversation as resolved.
}

console.log('Seeding complete!');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
LOCAL_EMULATOR_OWNER_TEAM_ID,
isLocalEmulatorEnabled,
readConfigFromFile,
resolveEmulatorPath,
writeConfigToFile,
} from "@/lib/local-emulator";
import { DEFAULT_BRANCH_ID, getSoleTenancyFromProjectBranch } from "@/lib/tenancies";
Expand Down Expand Up @@ -192,11 +193,12 @@ export const POST = createSmartRouteHandler({
}

const absoluteFilePath = path.resolve(req.body.absolute_file_path);
const resolvedFilePath = resolveEmulatorPath(absoluteFilePath);

// Validate file exists before creating a project
let fileExists: boolean;
try {
await fs.access(absoluteFilePath);
await fs.access(resolvedFilePath);
fileExists = true;
} catch {
fileExists = false;
Expand All @@ -206,7 +208,7 @@ export const POST = createSmartRouteHandler({
}

// If the file is empty, write a default config
const fileContent = await fs.readFile(absoluteFilePath, "utf-8");
const fileContent = await fs.readFile(resolvedFilePath, "utf-8");
if (fileContent.trim() === "") {
await writeConfigToFile(absoluteFilePath, {});
}
Expand Down
Loading
Loading