Skip to content

feat(docker): add linux/riscv64 image to Docker release#1

Open
gounthar wants to merge 7 commits intomainfrom
feat/riscv64-docker
Open

feat(docker): add linux/riscv64 image to Docker release#1
gounthar wants to merge 7 commits intomainfrom
feat/riscv64-docker

Conversation

@gounthar
Copy link
Owner

@gounthar gounthar commented Feb 8, 2026

Summary

  • Make Bun installation architecture-conditional in the Dockerfile (skip on riscv64 where no binary exists)
  • Add a QEMU-emulated build-riscv64 job to the Docker release workflow
  • riscv64 build is non-blocking: amd64 + arm64 releases proceed even if it fails
  • Multi-platform manifest conditionally includes riscv64 digest on success
  • Fix per-job metadata tags so each arch only generates its own suffix

Ref: openclaw#11977

Details

Dockerfile: Bun has no riscv64 binary, but it is not used during Docker builds (all build scripts use pnpm, and OPENCLAW_PREFER_PNPM=1 is already set). The install is wrapped in an arch check so it still installs on amd64/arm64.

Workflow: The new build-riscv64 job follows the same pattern as the existing jobs but runs under QEMU on ubuntu-latest with a 120-minute timeout. The create-manifest job uses always() with explicit success checks so that a riscv64 failure never blocks releases.

Tag fix: The existing amd64 job was generating -arm64 suffix tags and vice versa. Each job now only generates its own arch suffix.

Test plan

  • Push to fork, verify riscv64 build job triggers and completes
  • Verify amd64 and arm64 builds are unaffected
  • Verify manifest includes all 3 architectures when riscv64 succeeds
  • Verify manifest includes only amd64 + arm64 when riscv64 fails
  • Pull riscv64 image and run node openclaw.mjs --version on QEMU or hardware

Summary by CodeRabbit

  • Chores
    • Added RISC‑V 64-bit support to the CI/docker build pipeline with a dedicated riscv64 build job and QEMU-emulated execution.
    • Multi-platform image publishing now conditionally includes riscv64 digests only when the riscv64 build succeeds, via a follow-up manifest update.
    • Container setup now skips a specific runtime installation on riscv64 hosts while keeping other setup steps intact.

@gemini-code-assist
Copy link

Summary of Changes

Hello @gounthar, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request extends the Docker release process to include support for the linux/riscv64 architecture. It modifies the Dockerfile to conditionally install Bun, introduces a new QEMU-emulated build job for riscv64 in the CI/CD workflow, and ensures that riscv64 build failures do not impede releases for other architectures. Additionally, it refines the multi-platform manifest generation and corrects metadata tagging for architecture-specific builds.

Highlights

  • Conditional Bun Installation: The Dockerfile now conditionally installs Bun, skipping riscv64 where a binary is not yet available, ensuring builds proceed on other architectures.
  • QEMU-emulated riscv64 Build Job: A new build-riscv64 job has been added to the Docker release workflow, running under QEMU to support the new architecture.
  • Non-blocking riscv64 Build: The riscv64 build is configured to be non-blocking, meaning amd64 and arm64 releases will proceed even if the riscv64 build fails.
  • Conditional Multi-platform Manifest Inclusion: The multi-platform manifest will now conditionally include the riscv64 digest only upon successful completion of its build.
  • Fix for Metadata Tags: Corrected an issue where per-job metadata tags were incorrectly generating suffixes for other architectures, ensuring each job now generates only its own architecture suffix.
Changelog
  • Dockerfile
    • Modified the Bun installation command to be conditional, skipping installation on riscv64 architecture.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/docker-release.yml
Activity
  • The author has provided a detailed test plan outlining steps to verify the riscv64 build, ensure amd64 and arm64 builds are unaffected, check manifest inclusion logic, and validate the riscv64 image functionality.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Important

Review skipped

Too many files!

This PR contains 298 files, which is 148 over the limit of 150.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds linux/riscv64 to the multi-platform Docker build via a new QEMU-based build-riscv64 job and a follow-up update-manifest step that conditionally inserts the riscv64 digest into the multi-arch manifest. Also modifies the Dockerfile to skip Bun installation on riscv64.

Changes

Cohort / File(s) Summary
Docker Release Workflow
.github/workflows/docker-release.yml
Adds a QEMU-emulated build-riscv64 job (non-blocking), extracts riscv64-specific metadata/tags, and introduces an update-manifest job that conditionally updates the multi-platform manifest to include the riscv64 digest. Adjusts manifest creation flow to allow post-hoc inclusion of riscv64.
Dockerfile
Dockerfile
Makes Bun installation conditional: skip Bun install when architecture is riscv64; retains PATH update and remaining build steps.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions Runner
    participant QEMU as QEMU (user-mode)
    participant Buildx as docker buildx
    participant Registry as Container Registry
    participant Manifest as create-manifest / update-manifest

    GH->>QEMU: setup QEMU binfmt & qemu-user-static
    GH->>Buildx: setup buildx builder
    GH->>Buildx: run buildx build for linux/riscv64 (emulated)
    Buildx->>Registry: push riscv64 image
    Registry-->>Buildx: return riscv64 digest
    GH->>Manifest: create-manifest with amd64, arm64 digests
    alt riscv64 digest available
        GH->>Manifest: update-manifest with riscv64 digest
        Manifest->>Registry: update multi-arch manifest to include riscv64
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I hopped through QEMU, tiny paws aflutter,
Built riscv64 while nibbling butter.
Digests gathered, manifest grew wide,
Multi-arch carrots, all systems ride.
A hop, a push — CI’s cozy stride. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding linux/riscv64 image support to Docker release workflow.
Linked Issues check ✅ Passed Code changes implement all primary objectives: add build-riscv64 job with QEMU emulation, make riscv64 non-blocking, conditionally include riscv64 in manifest, and skip Bun on riscv64.
Out of Scope Changes check ✅ Passed All changes are directly within scope: docker-release.yml modifications for riscv64 build/manifest workflow and Dockerfile conditional for architecture-specific installation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/riscv64-docker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for linux/riscv64 Docker images. The change in the Dockerfile correctly makes the installation of Bun conditional, skipping it on the riscv64 architecture where it's not available. My review includes a suggestion to make the shell command in the Dockerfile more concise. The changes are well-aligned with the goal of the pull request.

Dockerfile Outdated
Comment on lines 4 to 6
RUN if [ "$(dpkg --print-architecture)" != "riscv64" ]; then \
curl -fsSL https://bun.sh/install | bash; \
fi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better readability and conciseness, you can combine the conditional check and the command into a single line using &&. This is a common shell scripting idiom for conditional execution and achieves the same result as the multi-line if statement.

RUN [ "$(dpkg --print-architecture)" != "riscv64" ] && curl -fsSL https://bun.sh/install | bash

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if/fi form is more readable and matches the existing conditional pattern used later in the same Dockerfile (the OPENCLAW_DOCKER_APT_PACKAGES block). Keeping the multi-line form for consistency.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/docker-release.yml:
- Around line 143-147: The riscv64 job's tags block currently includes
unsuffixed tag types ("type=ref,event=branch" and
"type=semver,pattern={{version}}") which can overwrite shared tags; remove those
two unsuffixed entries from the riscv64 job's tags so it only emits
architecture-specific tags (e.g., keep only
"type=semver,pattern={{version}},suffix=-riscv64" and
"type=ref,event=branch,suffix=-riscv64"); update the tags list in the riscv64
job (the block containing those four tag lines) to exclude unsuffixed tag lines
to ensure only suffixed image tags are pushed.
🧹 Nitpick comments (1)
.github/workflows/docker-release.yml (1)

43-47: Consider removing unsuffixed tags from per-arch jobs entirely.

Both build-amd64 and build-arm64 also generate unsuffixed tags (Lines 43–44, 91–92), which means whichever finishes last temporarily "wins" the shared tag with a single-arch image until the manifest job overwrites it. Since the manifest job creates the canonical multi-arch tags, the per-arch jobs only need their suffixed variants.

This is a pre-existing pattern and outside the scope of this PR, but it would be cleaner and safer to address it holistically.

Also applies to: 91-94

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Docker image support for linux/riscv64 by making Bun installation architecture-conditional and extending the Docker release workflow to build/publish riscv64 (via QEMU) and optionally include it in the multi-arch manifest.

Changes:

  • Update Dockerfile to skip Bun installation on riscv64.
  • Add a QEMU-emulated build-riscv64 job and conditionally include its digest in the manifest.
  • Fix per-arch tag suffix generation so each job only emits its own arch-suffixed tags.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
Dockerfile Skip Bun install on riscv64 while keeping the existing build flow intact.
.github/workflows/docker-release.yml Add riscv64 build job, update manifest creation to include riscv64 on success, and fix tag suffix generation per architecture.

Comment on lines 109 to 116
# Build riscv64 image (QEMU-emulated, non-blocking)
build-riscv64:
runs-on: ubuntu-latest
timeout-minutes: 120
permissions:
packages: write
contents: read
outputs:
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build-riscv64 is described as non-blocking, but without continue-on-error: true this job failing will still mark the entire workflow run as failed (which can block releases/branch protection even though amd64/arm64 images + manifest are produced). Consider adding continue-on-error: true to this job (or otherwise ensuring a riscv64 failure doesn’t fail the workflow).

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — added continue-on-error: true to the riscv64 job so it won't fail the overall workflow. Fixed in e10c2cb.

Comment on lines 168 to 169
needs: [build-amd64, build-arm64, build-riscv64]
if: always() && needs.build-amd64.result == 'success' && needs.build-arm64.result == 'success'
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create-manifest now needs: [build-amd64, build-arm64, build-riscv64], which means publishing the multi-arch tags waits for the QEMU riscv64 build to finish (up to 120 minutes) even when you only need amd64+arm64. If the intent is that amd64+arm64 releases proceed promptly, consider publishing the amd64+arm64 manifest without waiting for riscv64, and only adding riscv64 later on success (this also requires ensuring the riscv64 build job does not push the unsuffixed tags that the manifest job owns).

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Restructured into two manifest jobs: create-manifest runs immediately after amd64+arm64 (no waiting), and update-manifest runs after riscv64 completes to add it to the manifest. This way releases ship promptly. Fixed in e10c2cb.

Comment on lines +5 to 7
curl -fsSL https://bun.sh/install | bash; \
fi
ENV PATH="/root/.bun/bin:${PATH}"
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On riscv64, Bun is intentionally not installed, but PATH is still unconditionally prefixed with /root/.bun/bin. Since the image later switches to USER node, that path entry is typically inaccessible/nonexistent at runtime and can make debugging harder if any command lookup hits it. Consider either installing/linking Bun into a non-root location (e.g., /usr/local/bin) when present, or only adding the Bun directory to PATH when Bun is installed (or removing it before switching users).

Suggested change
curl -fsSL https://bun.sh/install | bash; \
fi
ENV PATH="/root/.bun/bin:${PATH}"
curl -fsSL https://bun.sh/install | bash && \
ln -s /root/.bun/bin/bun /usr/local/bin/bun; \
fi

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stale PATH entry is harmless (empty dir lookup is a no-op) and keeps the Dockerfile diff minimal. The existing comment on line 28 already documents that Bun may not be present on all architectures. Leaving as-is to keep the change focused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/docker-release.yml:
- Around line 200-201: The current conditional for the update-manifest job uses
needs.build-riscv64.result which will be 'success' when the riscv64 job had
continue-on-error: true even if it actually failed; change the guard to verify
the riscv64 digest output is non-empty instead (e.g. replace the if:
needs.build-riscv64.result == 'success' check with an output existence check
like if: needs.build-riscv64.outputs.riscv_digest != ''), and ensure the
build-riscv64 job publishes that digest as an output (name the output e.g.
riscv_digest) so update-manifest only runs when a valid digest is present.
🧹 Nitpick comments (1)
.github/workflows/docker-release.yml (1)

43-47: Consider removing unsuffixed tags from per-arch jobs to avoid a transient race.

Both build-amd64 and build-arm64 push unsuffixed tags (type=ref,event=branch and type=semver,pattern={{version}}). Whichever job finishes last briefly overwrites those shared tags with a single-architecture image until create-manifest runs. This is pre-existing and the window is small for these two fast native builds, but it could be cleaned up so only the manifest job owns the unsuffixed tags.

@gounthar
Copy link
Owner Author

gounthar commented Feb 8, 2026

Addressed the remaining feedback in 9f44ce8:

  • Unsuffixed tags race (nitpick): Removed type=ref,event=branch and type=semver,pattern={{version}} from both build-amd64 and build-arm64 jobs. Now only the manifest jobs own the shared tags — no more transient window where a single-arch image overwrites the multi-arch tag.

  • continue-on-error + .result guard bug: Changed update-manifest condition from needs.build-riscv64.result == 'success' to needs.build-riscv64.outputs.image-digest != ''. With continue-on-error: true at the job level, .result is always 'success' — the digest output is the reliable signal.

@gounthar gounthar force-pushed the feat/riscv64-docker branch from 9f44ce8 to 363d894 Compare February 8, 2026 18:57
Skip Bun installation on riscv64 (no binary available) and add a
QEMU-emulated build job for linux/riscv64 to the Docker release.

Key design decisions:
- riscv64 is non-blocking: continue-on-error prevents workflow failure
- Per-arch jobs only push suffixed tags (-amd64, -arm64, -riscv64);
  only the manifest jobs own unsuffixed shared tags
- create-manifest publishes amd64+arm64 immediately without waiting
- update-manifest adds riscv64 to the manifest after it completes,
  guarded by digest output (not job result, which is unreliable with
  continue-on-error)
- 120-minute timeout for QEMU-emulated Node.js builds

Ref: openclaw#11977

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gounthar gounthar force-pushed the feat/riscv64-docker branch from ff51976 to 54d20bd Compare February 8, 2026 19:03
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