Skip to content

ci(release): publish desktop releases directly to OSS #3995

ci(release): publish desktop releases directly to OSS

ci(release): publish desktop releases directly to OSS #3995

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
# A newer PR head supersedes its older checks. Keep main runs complete so every
# merged commit still receives a full CI result.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
check:
name: check (${{ matrix.moonbit-channel }}, ${{ matrix.target }})
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
# Run pre-release targets independently (fail-fast: false), while the
# native/JS split lets the two test suites run in parallel.
fail-fast: false
matrix:
moonbit-channel: [pre-release]
target: [native, js]
include:
- moonbit-channel: pre-release
moonbit-version: pre-release
deny-warn: "--deny-warn"
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up MoonBit (${{ matrix.moonbit-channel }})
run: |
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s -- "${{ matrix.moonbit-version }}"
echo "$HOME/.moon/bin" >> $GITHUB_PATH
- name: Show MoonBit version
run: |
moon version --all
- name: Update MoonBit package registry
run: moon update
# Proton comes from the registry, so the version it is pinned to lives in
# desktop/moon.mod and nowhere else. Read it back here rather than
# repeating it, and reuse it for both the CEF cache key and the CLI.
- name: Resolve pinned Proton version
id: proton
run: |
version="$(sed -n 's/.*"moonbit-community\/proton@\([^"]*\)".*/\1/p' desktop/moon.mod)"
test -n "$version"
echo "version=$version" >> "$GITHUB_OUTPUT"
# Pull requests may restore the default branch's cache, but their own
# merge-ref caches are private to that PR and cannot warm other branches.
- name: Restore CEF distribution
if: matrix.target == 'native'
id: cef-cache
uses: actions/cache/restore@v4
with:
# Proton shares downloaded CEF distributions between projects here,
# then copies the selected version into the project-local runtime.
path: ~/.proton/cache/cef
key: cef-${{ runner.os }}-${{ runner.arch }}-proton-${{ steps.proton.outputs.version }}
- name: Check formatting
# Pre-release only, for the same reason as `--deny-warn` below. `moon fmt` is
# a moving target on nightly: its output for markdown `mbt` blocks
# changed between 2026-07-15 and 2026-07-25, which red-lined this step
# for a file no one had touched. And because the step ran on both
# channels, the repo could only ever satisfy it while the two
# formatters agreed — once they disagree there is no committed form
# that passes, which is not a state CI should be able to reach.
if: matrix.moonbit-channel == 'pre-release' && matrix.target == 'native'
run: moon fmt --check
- name: Check ${{ matrix.target }} target
# This is the local-dependency integration check: desktop must compile
# against the editor member from this checkout. Keeping the target
# explicit also makes each matrix row own one complete check/test pair;
# pre-release denies warnings across the complete integrated workspace.
run: moon check --target ${{ matrix.target }} ${{ matrix.deny-warn }}
- name: Check generated interfaces
# `moon info` formats abstract types differently across toolchain
# versions (`type X` on pre-release vs `pub struct X { // private fields }`
# on stable), and the committed `.mbti` are pre-release-generated — so
# this consistency check is only meaningful on pre-release. This covers
# the editor's public interfaces from the same checkout too. Ignore
# blank-only formatter drift, but still reject content changes and new
# `.mbti`.
if: matrix.target == 'native'
run: |
moon info
untracked_mbti="$(git ls-files --others --exclude-standard -- '*.mbti')"
if [ -n "$untracked_mbti" ] ||
! git diff --quiet --ignore-blank-lines -- '*.mbti'; then
git status --short -- '*.mbti'
git diff --ignore-blank-lines -- '*.mbti'
exit 1
fi
# Only now: `cef setup` reads the Proton package's platform prebuilt out
# of .mooncakes, and nothing before the check steps above materializes
# it — `moon update` only refreshes the registry index. The checks
# themselves need no runtime because they never link. Setup runs at the
# repository root, which is both where Moon resolves .mooncakes and
# where Proton's link config looks for the .proton/runtime.json it
# writes; `moonx` runs the published CLI straight from the registry
# cache, so there is nothing to install.
#
# The test binaries below do link libproton.so, whose DT_NEEDED names
# libcef.so, libgtk-3.so.0 and libX11.so.6 — the loader resolves all
# three before main runs, so even a test that never opens a window
# cannot start without them. GTK and X11 are already on the runner
# image; libcef.so is the one the Proton package does not ship, and is
# what this step assembles beside libproton.so.
- name: Assemble Proton CEF runtime
if: matrix.target == 'native'
run: |
moonx "moonbit-community/proton_cli@${{ steps.proton.outputs.version }}" \
-C "$PWD" cef setup
test -f .proton/runtime.json
# The pre-release/native main job is the sole Linux writer. PR jobs remain
# restore-only, and no second channel races to reserve the same key.
- name: Save CEF distribution
if: >-
github.event_name == 'push' &&
matrix.moonbit-channel == 'pre-release' &&
matrix.target == 'native' &&
steps.cef-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.proton/cache/cef
key: ${{ steps.cef-cache.outputs.cache-primary-key }}
- name: Test native target
# No Xvfb: nothing here initializes CEF or opens a window. That was
# Proton's own windowed test suite, which left this workspace when
# Proton became a registry dependency; loading libproton needs the
# libraries above, not a display.
if: matrix.target == 'native'
run: moon test --target native
- name: Test JS target
# Run JS-only package tests from the same root workspace. These do not
# create Proton windows and therefore do not need Xvfb.
if: matrix.target == 'js'
run: moon test --target js
- name: Cram (offline CLI docs)
if: matrix.target == 'native'
run: moon cram test tests/cram