From eff3768886c0392faf922730aa79db745285135c Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Sat, 22 Nov 2025 21:21:29 -0800 Subject: [PATCH] feat: enhance build status reporting --- .github/workflows/custom_build.yml | 72 ++++++++++++++++++++++++++++-- convex/actions.ts | 2 + convex/builds.ts | 30 +++++++++++++ convex/http.ts | 37 ++++++++++++++- 4 files changed, 137 insertions(+), 4 deletions(-) diff --git a/.github/workflows/custom_build.yml b/.github/workflows/custom_build.yml index 21e9aaf..ae5aeb5 100644 --- a/.github/workflows/custom_build.yml +++ b/.github/workflows/custom_build.yml @@ -14,14 +14,34 @@ on: version: description: 'Firmware Version (Tag/Branch)' required: true + build_id: + description: 'Convex Build ID' + required: true + type: string + convex_url: + description: 'Convex Site URL' + required: true + type: string jobs: build: runs-on: ubuntu-latest steps: + - name: Log - Build Started + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "🚀 Build started for ${{ inputs.target }}\n"}' + - name: Checkout Web Flasher (this repo) uses: actions/checkout@v4 + - name: Log - Checked out web flasher + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "✓ Checked out web flasher repo\n"}' + - name: Checkout Firmware uses: actions/checkout@v4 with: @@ -31,6 +51,12 @@ jobs: submodules: recursive fetch-depth: 1 + - name: Log - Checked out firmware + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "✓ Checked out firmware ${{ inputs.version }}\n"}' + - name: Cache PlatformIO uses: actions/cache@v4 with: @@ -46,11 +72,23 @@ jobs: with: python-version: '3.x' + - name: Log - Installing PlatformIO + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "📦 Installing PlatformIO...\n"}' + - name: Install PlatformIO run: | python -m pip install --upgrade pip pip install platformio + - name: Log - Building firmware + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "🔨 Building firmware for ${{ inputs.target }}...\n"}' + - name: Build Firmware working-directory: firmware run: | @@ -65,14 +103,42 @@ jobs: pio run -e ${{ inputs.target }} + - name: Log - Build complete + if: success() + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "✅ Build completed successfully!\n"}' + - name: Upload Artifact uses: actions/upload-artifact@v4 with: name: firmware-${{ inputs.target }} path: firmware/.pio/build/${{ inputs.target }}/firmware.bin - - name: Notify Convex + - name: Log - Artifact uploaded + if: success() + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "📤 Artifact uploaded: firmware-${{ inputs.target }}\n"}' + + - name: Log - Build failed + if: failure() + run: | + curl -X POST "${{ inputs.convex_url }}/api/logs" \ + -H "Content-Type: application/json" \ + -d '{"buildId": "${{ inputs.build_id }}", "logs": "❌ Build failed - check GitHub Actions logs for details\n"}' + + - name: Update Build Status if: always() run: | - # TODO: Send webhook to Convex with status - echo "Build finished with status: ${{ job.status }}" + STATUS="${{ job.status }}" + if [ "$STATUS" = "success" ]; then + STATUS_MSG="success" + else + STATUS_MSG="failure" + fi + curl -X POST "${{ inputs.convex_url }}/github-webhook" \ + -H "Content-Type: application/json" \ + -d "{\"action\": \"completed\", \"build_id\": \"${{ inputs.build_id }}\", \"status\": \"$STATUS_MSG\"}" diff --git a/convex/actions.ts b/convex/actions.ts index 80cefc6..c2033b5 100644 --- a/convex/actions.ts +++ b/convex/actions.ts @@ -31,6 +31,8 @@ export const dispatchGithubBuild = action({ target: args.target, flags: args.flags, version: args.version, + build_id: args.buildId, + convex_url: process.env.CONVEX_SITE_URL, }, }), }, diff --git a/convex/builds.ts b/convex/builds.ts index abd9d1e..9b5040a 100644 --- a/convex/builds.ts +++ b/convex/builds.ts @@ -140,3 +140,33 @@ export const logBuildError = internalMutation({ }); }, }); + +// Internal mutation to append logs +export const appendLogs = internalMutation({ + args: { + buildId: v.id("builds"), + logs: v.string(), + }, + handler: async (ctx, args) => { + const build = await ctx.db.get(args.buildId); + if (!build) return; + + await ctx.db.patch(args.buildId, { + logs: (build.logs || "") + args.logs, + }); + }, +}); + +// Internal mutation to update build status +export const updateBuildStatus = internalMutation({ + args: { + buildId: v.id("builds"), + status: v.union(v.literal("success"), v.literal("failure")), + }, + handler: async (ctx, args) => { + await ctx.db.patch(args.buildId, { + status: args.status, + completedAt: Date.now(), + }); + }, +}); diff --git a/convex/http.ts b/convex/http.ts index e347dc6..f1eeeec 100644 --- a/convex/http.ts +++ b/convex/http.ts @@ -1,4 +1,5 @@ import { httpRouter } from "convex/server"; +import { internal } from "./_generated/api"; import { httpAction } from "./_generated/server"; import { auth } from "./auth"; @@ -9,11 +10,24 @@ auth.addHttpRoutes(http); http.route({ path: "/github-webhook", method: "POST", - handler: httpAction(async (_ctx, request) => { + handler: httpAction(async (ctx, request) => { const payload = await request.json(); // Verify signature (TODO: Add HMAC verification) + // Handle build completion from our custom workflow + if (payload.action === "completed" && payload.build_id) { + const status = payload.status === "success" ? "success" : "failure"; + + await ctx.runMutation(internal.builds.updateBuildStatus, { + buildId: payload.build_id, + status, + }); + + return new Response(null, { status: 200 }); + } + + // Legacy handling for GitHub webhook events if (payload.action === "completed" && payload.workflow_job) { const runId = payload.workflow_job.run_id; const status = payload.workflow_job.conclusion; @@ -27,4 +41,25 @@ http.route({ }), }); +http.route({ + path: "/api/logs", + method: "POST", + handler: httpAction(async (ctx, request) => { + const { buildId, logs } = await request.json(); + + if (!buildId || !logs) { + return new Response("Missing buildId or logs", { status: 400 }); + } + + // TODO: Add some verification (e.g. secret token) + + await ctx.runMutation(internal.builds.appendLogs, { + buildId, + logs, + }); + + return new Response(null, { status: 200 }); + }), +}); + export default http;