Skip to content

ci, docs: build, smoke-test and release openipc-allwinner - #66

Merged
dimerr merged 2 commits into
openipcfrom
ci/build-allwinner
Oct 25, 2026
Merged

dimerr merged 2 commits into
openipcfrom
ci/build-allwinner

Conversation

@dimerr

@dimerr dimerr commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

CI for the new openipc-allwinner branch (U-Boot for Allwinner V831/V833, #65). build-allwinner.yml is build-anyka.yml with this family's settings:

  • One build leg per SoC through its build.sh, which makes u-boot-<soc>-nor.bin and u-boot-<soc>-mmc.bin (the SD card image, for unbricking). Both get the 256 KiB partition check.
  • The build legs also install xz-utils: U-Boot is LZMA-packed to fit the boot partition.
  • A two-boot smoke test per SoC and kind, on qemu-bench's v831/v833 machines. The second boot must load the environment the first saved.
    • -nor: from an 8 MiB flash holding only the image.
    • -mmc: from a 64 MiB card with the image at 8 KiB and the flash erased.
  • release to the allwinner tag, and publish to OpenIPC/firmware latest with a uboot-allwinner-… build id. The names don't overlap with OpenIPC/u-boot-allwinner's u-boot-v851s-nor.bin.

The README and CLAUDE.md describe the family, the card boot and the workflow.

Dependencies:

Checked: the smoke step, extracted from this file, was run locally against all four images on qemu-bench master plus u-boot#204. All four pass.

build-allwinner.yml is build-anyka.yml for the new openipc-allwinner
branch: one leg per SoC through its build.sh, which makes
u-boot-<soc>-nor.bin and u-boot-<soc>-mmc.bin (the same layout with an
SPL that loads U-Boot from an SD card, for unbricking); the 256 KiB
check for both; a two-boot smoke test per SoC and kind in qemu-bench's
v831/v833 machines -- the -nor image from an 8 MiB flash, the -mmc one
from a 64 MiB card with the flash erased -- where the second boot must
load the environment the first saved; release to the `allwinner` tag and
publish to OpenIPC/firmware latest.

The build legs also install xz-utils (U-Boot is LZMA-packed to fit the
boot partition). The -mmc legs need qemu-bench's boot ROM stand-in to
boot from the card (qemu-bench u-boot#204). The smoke step was run locally
against all four images and passed. README and CLAUDE.md describe the
family.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add Allwinner V831/V833 build, smoke-test, and release workflow

⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Build V831/V833 NOR and SD-card images, enforcing the 256 KiB boot-partition limit.
• Smoke-test both image types across two boots; hold artifacts until QEMU support is available.
• Add manual release and firmware publishing paths, and document the family and recovery workflow.
Diagram

graph TD
  R["Resolve revision"] --> B["Build V831/V833"] --> S["Two-boot smoke"] -->|"dispatch; unheld images"| L["Allwinner release"]
  Q["Build QEMU"] --> S
  S -->|"dispatch; unheld images"| P["Firmware publish"]
Loading
High-Level Assessment

Following the existing family-specific workflow is appropriate: it preserves established provenance, smoke-test, and publishing conventions while accommodating MMC boot tests and held artifacts. Extracting a shared workflow would broaden this PR without a clear benefit for this family-specific addition.

Files changed (3) +494 / -0

Documentation (2) +109 / -0
CLAUDE.mdDocument Allwinner workflow behavior and publishing prerequisites +34/-0

Document Allwinner workflow behavior and publishing prerequisites

• Adds the new family and explains its hold policy, boot tests, release destinations, and website allowlist prerequisite. The workflow introduction says “NOR only,” although the subsequent section and workflow cover MMC images too.

CLAUDE.md

README.mdDescribe Allwinner images, SD-card recovery, and CI +75/-0

Describe Allwinner images, SD-card recovery, and CI

• Adds the build badge and family listing, documents the V831/V833 boot layout and SD-card recovery procedure, and explains workflow triggers and publishing. Its build-output sentence names only NOR images, although the workflow also builds MMC images.

README.md

Other (1) +385 / -0
build-allwinner.ymlAdd held Allwinner build, smoke-test, and publishing jobs +385/-0

Add held Allwinner build, smoke-test, and publishing jobs

• Pins the source revision, builds V831/V833 NOR and MMC images, checks their 256 KiB limit, and tests both boot paths twice in QEMU. Manual release and firmware publishing jobs exclude held artifacts; MMC smoke tests depend on upstream SD-card boot support.

.github/workflows/build-allwinner.yml

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Environment persistence is never exercised ✓ Resolved
Description
The smoke loop only waits for Hit Ctrl-C and kills each QEMU process without sending a command
such as saveenv through the UART. Because the first boot never saves an environment, the second
boot cannot verify persistence and the test's CRC check merely detects the resulting failure after
both boots have otherwise been accepted.
Code

.github/workflows/build-allwinner.yml[R253-267]

+          for boot in 1 2; do
+            mkfifo /tmp/uart.in /tmp/uart.out
+            ./qemu-arm $FLASH \
+              -nographic -serial pipe:/tmp/uart \
+              -monitor none > /tmp/qemu.log 2>&1 &
+            QEMU_PID=$!
+            # Wait for the autoboot prompt, not the banner: the banner prints
+            # before the board init that can hang. Up to 30 s.
+            cat /tmp/uart.out > /tmp/uboot$boot.txt &
+            CAT_PID=$!
+            for i in $(seq 1 60); do
+              grep -q 'Hit Ctrl-C' /tmp/uboot$boot.txt 2>/dev/null && break
+              sleep 0.5
+            done
+            kill "$QEMU_PID" "$CAT_PID" 2>/dev/null || true
Evidence
The smoke-test implementation waits for the autoboot prompt, captures output, kills QEMU, and
repeats; it never writes a save command or any other input to the UART. This fails the requirement
that the second boot load the environment saved by the first boot.

CLAUDE.md: Smoke-test both boots and persisted environment for every applicable image: CLAUDE.md: Smoke-test both boots and persisted environment for every applicable image: CLAUDE.md: Smoke-test both boots and persisted environment for every applicable image: CLAUDE.md: Smoke-test both boots and persisted environment for every applicable image
.github/workflows/build-allwinner.yml[253-280]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The smoke test starts two boots but never sends a save command during the first boot, so the second boot does not verify that a persisted environment can be written and loaded.
## Fix Focus Areas
- .github/workflows/build-allwinner.yml[253-280]
## Recommended Fix
Drive the first boot through the UART after reaching `Hit Ctrl-C`, issue a deterministic environment change followed by `saveenv`, then reboot using the same media and fail if the second boot reports a bad environment CRC or does not load the saved value.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. A failed upload can still be reported 📘 Rule violation ≡ Correctness
Description
The publication loop pipes find and sort into a while loop, so a failed upload exits only
that pipeline stage while the pipeline still returns the successful status from sort. When all
upload retries fail, the job can therefore continue to push_build.py and report local assets that
were never uploaded to the firmware release.
Code

.github/workflows/build-allwinner.yml[R344-358]

+          upload() {
+            local f="$1" i
+            for i in 1 2 3 4 5; do
+              if gh release upload latest "$f" --clobber -R OpenIPC/firmware; then
+                return 0
+              fi
+              [ "$i" = "5" ] && return 1
+              echo "upload attempt $i failed; sleeping $((i*10))s" >&2
+              sleep $((i*10))
+            done
+          }
+          find artifacts -type f -name '*.bin' | sort | while read -r f; do
+            echo "publishing $f"
+            upload "$f"
+          done
Evidence
The script retries each upload and returns failure after the fifth attempt, but the command is
executed inside a find | sort | while pipeline. Without pipefail, the pipeline status is
supplied by sort, so the subsequent report can describe assets that were not successfully
uploaded.

CLAUDE.md: Keep release and publish isolated and publication provenance intact: CLAUDE.md: Keep release and publish isolated and publication provenance intact: CLAUDE.md: Keep release and publish isolated and publication provenance intact: CLAUDE.md: Keep release and publish isolated and publication provenance intact
.github/workflows/build-allwinner.yml[344-358]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The upload loop is the final stage of a pipeline without `pipefail`, allowing an upload failure to be masked by the successful `sort` command and letting the provenance report run for assets that were not published.
## Fix Focus Areas
- .github/workflows/build-allwinner.yml[344-358]
## Recommended Fix
Ensure any failed asset upload terminates the job before the report step, either by enabling `set -o pipefail` or by collecting the sorted file list first and iterating over it without a masking pipeline.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Manual Allwinner releases upload no images ✓ Resolved
Description
build marks both SoCs as held, so its artifact names start with hold-, while the release and
publish jobs download only names matching u-boot-*. When an operator requests either documented
manual action, no image reaches those jobs: the release fails its required-file check, and publish
has no binaries to upload or report.
Code

.github/workflows/build-allwinner.yml[R140-141]

+          name: ${{ matrix.hold && 'hold-' || '' }}u-boot-${{ matrix.soc }}
+          path: ${{ matrix.files }}
Evidence
Both matrix entries set hold: true; the artifact upload prepends hold-, but both downstream
downloads select only u-boot-*. The release requires matching .bin files, and the publish steps
operate only on downloaded files. The README nevertheless provides a command requesting both
actions.

.github/workflows/build-allwinner.yml[63-68]
.github/workflows/build-allwinner.yml[135-142]
.github/workflows/build-allwinner.yml[288-310]
.github/workflows/build-allwinner.yml[319-358]
README.md[416-423]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Manual release and publish runs proceed despite both build artifacts being held and excluded from their download pattern.
## Fix Focus Areas
- .github/workflows/build-allwinner.yml[63-68]
- .github/workflows/build-allwinner.yml[287-335]
- README.md[416-423]
## Recommended Fix
Do not offer or run release and publish while every SoC is held. Gate or clearly reject those requests until the hold can be removed after validation, and make the documented manual command reflect that state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Novatek readers see the wrong card image ✓ Resolved
Description
The new SD-card recovery block sits inside the Novatek section but tells readers to write
u-boot-v831-mmc.bin, an Allwinner image. A reader following the Novatek instructions encounters a
recovery procedure for a different SoC, while the Allwinner section lists only its NOR build output
and contains no card-writing procedure.
Code

README.md[R218-221]

+**SD card (unbricking):** `u-boot-<soc>-mmc.bin` is the same image with
+an SPL that loads U-Boot from the card. The boot ROM tries the card
+before the flash, so a camera with a broken or empty flash boots from a
+card that has it at 8 KiB, before the first partition:
Evidence
The surrounding README heading and text identify this location as Novatek, whereas the inserted
command names a V831 image. Novatek CI builds NT98562 and NT98566 and checks NOR output only; the
new Allwinner workflow requires MMC output.

README.md[200-224]
README.md[251-287]
.github/workflows/build-novatek.yml[52-55]
.github/workflows/build-novatek.yml[127-128]
.github/workflows/build-allwinner.yml[129-132]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The V831 SD-card recovery instructions are embedded in the Novatek section, and the Allwinner build-output description omits the MMC image.
## Fix Focus Areas
- README.md[218-230]
- README.md[251-287]
## Recommended Fix
Move the SD-card block into the Allwinner section beside its image layout. State there that builds produce both NOR and MMC images.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/build-allwinner.yml Resolved
Comment thread .github/workflows/build-allwinner.yml Resolved
Comment thread .github/workflows/build-allwinner.yml Resolved
Comment thread README.md Resolved
- The hold on both SoCs was meant to go before the push (qemu-bench has
  had the v831/v833 machines since u-boot#203) and did not: the artifacts were
  named hold-u-boot-*, so release and publish would have found nothing.
  Both SoCs are now released like the other families; the smoke legs are
  a hard gate.
- The smoke test now also fails if the first boot does not report saving
  the environment, so the second boot's CRC check is known to test a
  saved one (the OpenIPC helper saves the default environment when it
  finds the area erased).
- README: the SD card block had landed in the novatek section; it is in
  the allwinner one, which also names the -mmc images.

The smoke step, extracted from the workflow, passes for v831/v833 x
nor/mmc on qemu-bench master plus u-boot#204.
@dimerr
dimerr merged commit b3ccdf2 into openipc Oct 25, 2026
3 of 45 checks passed
@dimerr
dimerr deleted the ci/build-allwinner branch October 25, 2026 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant