Skip to content

0.2.0: native CLion views, shared editor services, and openkal 0.23.3 #55

0.2.0: native CLion views, shared editor services, and openkal 0.23.3

0.2.0: native CLion views, shared editor services, and openkal 0.23.3 #55

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
workflow_call:
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
XLINGS_NON_INTERACTIVE: '1'
NODE_VERSION: 22
jobs:
# The backend on each system the editors run on: build every program (the backend, the mock mcpp,
# the dev tool), run the tests -- the protocol against its schema and the fixtures against mcpp's
# contract among them -- and check the translations. The `pack` leg then packs the backend as the
# editor packages carry it (mcpp design 2026-10-28 part 2 §15): the ok-image bundle, and the
# universal self-contained package (both images; okrun for Linux, macOS and Windows, each built
# over the platform's hosted arrangement) whose okrun the packages take. The `host-platform` row
# builds and tests with the build programs (build.mcpp, the spec/ generators) as ok images run by
# okrun.
backend:
name: backend (${{ matrix.platform }}${{ matrix.host-platform && format(', host platform {0}', matrix.host-platform) || '' }})
runs-on: ${{ matrix.os }}
timeout-minutes: 75
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: true }
- { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false' }
- { os: macos-14, platform: darwin-arm64, llvm: 'true' }
- { os: windows-2022, platform: win32-x64, llvm: 'true' }
- { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', host-platform: 'openkal-platform@0.18.0' }
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-mcpp
with:
llvm: ${{ matrix.llvm }}
- name: The host graph's platform
if: matrix.host-platform
run: echo "MCPP_HOST_PLATFORM=${{ matrix.host-platform }}" >> "$GITHUB_ENV"
- name: Build
run: mcpp build
- name: Test
run: mcpp test
- name: Every string has its translation
run: mcpp run mcpp-ide-dev -- check-i18n
- name: The backend as the editor packages carry it
if: matrix.pack
run: |
set -euo pipefail
version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)"
mcpp pack mcpp-ide --target openkal --mode self-contained --systems all --pkg-format tar,okb -o target/dist/
# The tree's name carries the mode (`mcpp-ide-<version>-openkal-bundle-all`, mcpp SPEC-014).
tarball="$(ls target/dist/mcpp-ide-"$version"-openkal*.tar.gz)"
package="$(basename "$tarball" .tar.gz)"
mkdir -p backend unpacked
cp "target/dist/$package.tar.gz" backend/
cp "target/dist/mcpp-ide-$version.okb" backend/mcpp-ide.okb
tar -xzf "backend/$package.tar.gz" -C unpacked
cp -R "unpacked/$package/libexec/okrun" backend/okrun
python3 - "unpacked/$package/mcpp-package.json" <<'PY'
import json, sys
d = json.load(open(sys.argv[1]))
print("legs", d["legs"], "runs_on", d["runs_on"])
want = {"linux-x86_64", "linux-aarch64", "macos-aarch64", "windows-x86_64"}
assert want <= set(d["runs_on"]["self"]), d["runs_on"]
PY
"unpacked/$package/bin/mcpp-ide" --version
backend/okrun/linux-x86_64/okrun backend/mcpp-ide.okb --version
ls -lR backend
- uses: actions/upload-artifact@v5
if: matrix.pack
with:
name: backend
path: backend
# The VS Code extension (mide-plugins/vscode), mcpp-vscode 0.9.0 over the backend. Its gates
# (the registry, the translations, the unit suite) on the three desktop systems; the manifest
# generated from spec/ with no drift, and the snapshots generated from mcpp's source; the parity
# gates against 0.9.0; the package with the bundle and every system's okrun; the Extension Host
# suite against every mcppls variant on the three systems, over the bundled backend; an isolated
# install that resolves the language service; the graph page in Chromium.
vscode-gates:
name: VS Code gates (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
defaults:
run:
working-directory: mide-plugins/vscode
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- run: npm ci
- name: Registry, translation and unit gates
run: npm test
vscode-drift:
name: VS Code manifest and settings documentation
runs-on: ubuntu-24.04
timeout-minutes: 45
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-mcpp
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- name: The manifest, its strings and the settings registry are spec/'s
run: |
mcpp run mcpp-ide-dev -- gen vscode
git diff --exit-code -- mide-plugins/vscode spec
- run: npm ci
working-directory: mide-plugins/vscode
- name: The settings documentation matches the registry
working-directory: mide-plugins/vscode
run: |
npm run gen:docs
git diff --exit-code docs/settings.md
vscode:
name: VS Code extension
needs: backend
runs-on: ubuntu-24.04
timeout-minutes: 45
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-mcpp
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- uses: actions/download-artifact@v5
with:
name: backend
path: backend
- name: Build the backend and its test programs
run: |
chmod +x backend/okrun/*/okrun*
mcpp build
{
echo "MCPP_IDE_OKB=$GITHUB_WORKSPACE/backend/mcpp-ide.okb"
echo "MCPP_IDE_OKRUN=$GITHUB_WORKSPACE/backend/okrun"
} >> "$GITHUB_ENV"
- run: npm ci
working-directory: mide-plugins/vscode
- name: Unit tests, with the backend built here
working-directory: mide-plugins/vscode
run: npm test
- name: Parity with 0.9.0 (the manifest and strings, every page's document)
working-directory: mide-plugins/vscode
run: npm run test:parity
- name: Package, with the bundle and every system's okrun
working-directory: mide-plugins/vscode
run: npm run package
- name: Verify the VSIX archive
working-directory: mide-plugins/vscode
run: unzip -t mcpp-vscode-*.vsix
- name: The manifest keeps its promises
working-directory: mide-plugins/vscode
run: |
node -e '
const p = require("./package.json");
const fail = (message) => { console.error(message); process.exit(1); };
if (p.extensionDependencies?.[0] !== "sunrisepeak.mcpp-language-server") fail("the dependency moved");
if (p.extensionDependencies.some((id) => id.includes("clangd"))) fail("clangd is back in the dependency list");
// The language client of the backend is bundled into dist/vendor; nothing is a runtime dependency.
if (Object.keys(p.dependencies ?? {}).length) fail("a runtime dependency crept in: the VSIX carries no node_modules");
if ((p.activationEvents ?? []).some((event) => event.startsWith("onCommand:"))) fail("onCommand activations are derived since 1.74");
if (!p.contributes?.viewsContainers?.activitybar?.length) fail("the view container disappeared");
console.log("manifest ok");
'
- name: The VSIX carries the runtime artefacts and the backend
working-directory: mide-plugins/vscode
run: |
set -euo pipefail
VSIX=$(ls mcpp-vscode-*.vsix)
for entry in \
extension/l10n/bundle.l10n.zh-cn.json \
extension/package.nls.json \
extension/package.nls.zh-cn.json \
extension/dist/data/config-registry.json \
extension/media/settings.css \
extension/backend/mcpp-ide.okb \
extension/backend/okrun/linux-x86_64/okrun \
extension/backend/okrun/linux-aarch64/okrun \
extension/backend/okrun/macos-aarch64/okrun \
extension/backend/okrun/windows-x86_64/okrun.exe; do
unzip -l "$VSIX" | grep -q "$entry" || { echo "missing from the VSIX: $entry"; exit 1; }
done
echo "VSIX contents ok"
- name: The VSIX stays small and free of local state
working-directory: mide-plugins/vscode
run: |
set -euo pipefail
VSIX=$(ls mcpp-vscode-*.vsix)
SIZE=$(stat -c %s "$VSIX")
COUNT=$(unzip -l "$VSIX" | tail -1 | awk '{print $2}')
echo "VSIX: $COUNT files, $((SIZE / 1024)) KiB"
if [ "$COUNT" -gt 220 ]; then echo "the VSIX has $COUNT files; something local leaked in"; exit 1; fi
# Offline Mermaid, the pinned official tests, the backend bundle (two images) and four okruns.
if [ "$SIZE" -gt 12582912 ]; then echo "the VSIX is over 12 MiB ($SIZE bytes)"; exit 1; fi
for required in dist/vendor/mermaid.js dist/vendor/MERMAID-LICENSE dist/data/library-examples.json; do
unzip -p "$VSIX" "extension/$required" > /dev/null
done
for forbidden in .dev-profile/ .agents/ .agnets/ test/ tools/ src/ node_modules/; do
if unzip -l "$VSIX" | grep -q "extension/$forbidden"; then
echo "leaked into the VSIX: $forbidden"
exit 1
fi
done
- name: One language client, the backend's, bundled
working-directory: mide-plugins/vscode
run: |
test ! -e dist/src/languageClient.js
! grep -rqsE "require\(['\"]vscode-languageclient['\"]\)|from ['\"]vscode-languageclient['\"]" dist/src package.json
test "$(grep -rlE "vendor/languageclient" dist/src)" = "dist/src/ide/session.js"
test -s dist/vendor/languageclient.js
- uses: actions/upload-artifact@v5
with:
name: mcpp-vscode-vsix
path: mide-plugins/vscode/mcpp-vscode-*.vsix
if-no-files-found: error
# One Extension Host run per mcppls variant, on the three desktop systems, over the backend the
# package carries (staged into the extension): the spawn and path handling the suite exercises is
# exactly what differs between them.
vscode-e2e:
name: VS Code Extension Host (${{ matrix.os }})
needs: backend
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 45
defaults:
run:
shell: bash
working-directory: mide-plugins/vscode
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- uses: actions/download-artifact@v5
with:
name: backend
path: backend
- run: npm ci
- run: npm run compile
- name: The backend the package carries
run: MCPP_IDE_OKB="$GITHUB_WORKSPACE/backend/mcpp-ide.okb" MCPP_IDE_OKRUN="$GITHUB_WORKSPACE/backend/okrun" npm run stage:backend
- name: Cache the pinned VS Code download
uses: actions/cache@v5
with:
path: mide-plugins/vscode/.vscode-test
key: vscode-1.91.0-${{ runner.os }}-${{ runner.arch }}
- name: Extension Host smoke tests against every mcppls variant
run: |
if [ "$(uname)" = "Linux" ]; then
xvfb-run -a npm run test:e2e:one
else
npm run test:e2e:one
fi
# The declared degraded mode (part 2 §8, F15): the bundle without a runner for this system,
# as on a platform okrun does not cover.
- name: Extension Host without its backend
env:
MCPP_E2E_NO_BACKEND: "1"
run: |
if [ "$(uname)" = "Linux" ]; then
xvfb-run -a npm run test:e2e:one
else
npm run test:e2e:one
fi
# The only check that proves the dependency resolves end to end: install the packed VSIX into a
# private profile and let VS Code pull the platform build of the language service.
vscode-isolated-install:
name: VS Code isolated install (${{ matrix.os }})
needs: vscode
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
defaults:
run:
shell: bash
working-directory: mide-plugins/vscode
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- run: npm ci
- uses: actions/download-artifact@v5
with:
name: mcpp-vscode-vsix
path: mide-plugins/vscode
- name: Cache the pinned VS Code download
uses: actions/cache@v5
with:
path: mide-plugins/vscode/.vscode-test
key: vscode-1.91.0-${{ runner.os }}-${{ runner.arch }}
- name: Download the VS Code CLI
run: |
set -euo pipefail
CODE=$(node tools/ci-vscode-cli.mjs | tr '\\' '/')
"$CODE" --version
echo "CODE=$CODE" >> "$GITHUB_ENV"
- name: Install into a private profile
run: |
set -euo pipefail
"$CODE" --extensions-dir "$PWD/.ci-extensions" --user-data-dir "$PWD/.ci-user" \
--install-extension mcpp-vscode-*.vsix --force
"$CODE" --extensions-dir "$PWD/.ci-extensions" --user-data-dir "$PWD/.ci-user" \
--install-extension sunrisepeak.mcpp-language-server
- name: The dependency resolved, with a version
run: |
set -euo pipefail
LIST=$("$CODE" --extensions-dir "$PWD/.ci-extensions" --user-data-dir "$PWD/.ci-user" \
--list-extensions --show-versions | tr -d '\r')
echo "$LIST"
echo "$LIST" | grep -q "^mcpp-community.mcpp-vscode@" || { echo "the extension is missing"; exit 1; }
echo "$LIST" | grep -q "^sunrisepeak.mcpp-language-server@" || { echo "the dependency did not resolve"; exit 1; }
VERSION=$(printf '%s\n' "$LIST" | sed -n 's/^sunrisepeak\.mcpp-language-server@//p')
echo "resolved mcppls $VERSION"
echo "resolved mcppls \`$VERSION\`" >> "$GITHUB_STEP_SUMMARY"
vscode-graph-browser:
name: VS Code graph page in Chromium
runs-on: ubuntu-latest
timeout-minutes: 30
defaults:
run:
working-directory: mide-plugins/vscode
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- run: npm ci
- run: npx playwright install --with-deps chromium
- name: Render and interact with the shipped graph in Chromium
run: npm run test:graphs-ui
- uses: actions/upload-artifact@v5
if: always()
with:
name: graph-browser-evidence
path: mide-plugins/vscode/.dev-profile/graph-ui-artifacts
if-no-files-found: warn
# The CLion plugin (mide-plugins/clion; the protocol's editor `jetbrains`, the IntelliJ platform):
# its tests (the wire and a session over the mock mcpp), the workbench it shows (mcpp-vscode's pages,
# bundled by the extension's tools) in Chromium over the backend built here, the archive carrying
# the workbench, the bundle and every system's okrun, and the Plugin Verifier against the oldest
# CLion it claims (2026.1) and the one it is built on.
clion:
name: CLion plugin
needs: backend
runs-on: ubuntu-24.04
timeout-minutes: 90
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-mcpp
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: mide-plugins/vscode/package-lock.json
- name: The extension's dependencies (the workbench's bundler)
working-directory: mide-plugins/vscode
run: npm ci
- name: Gradle (xim:gradle brings its JDK)
run: xlings install gradle -y -g
- uses: actions/cache@v5
with:
path: ~/.gradle/caches/modules-2
key: gradle-clion-${{ hashFiles('mide-plugins/clion/gradle.properties', 'mide-plugins/clion/build.gradle.kts', 'mide-plugins/clion/settings.gradle.kts') }}
- uses: actions/download-artifact@v5
with:
name: backend
path: backend
- name: Build the backend and its test programs
run: |
chmod +x backend/okrun/*/okrun*
mcpp build
# Every Gradle run of this job packages the same plugin: the variables hold for all of them.
bin="$(cd "$(dirname "$(ls -t target/*/*/bin/mcpp-ide | head -1)")" && pwd)"
{
echo "MCPP_IDE_DEV=$bin/mcpp-ide-dev"
echo "MCPP_IDE_BACKEND=$bin/mcpp-ide"
echo "MCPP_IDE_MOCK_MCPP=$bin/mcpp-ide-mock-mcpp"
echo "MCPP_IDE_OKB=$GITHUB_WORKSPACE/backend/mcpp-ide.okb"
echo "MCPP_IDE_OKRUN=$GITHUB_WORKSPACE/backend/okrun"
} >> "$GITHUB_ENV"
- name: The graph page in Chromium, over the backend
working-directory: mide-plugins/vscode
run: |
npx playwright install --with-deps chromium
npm run test:webui
- name: Test and package
working-directory: mide-plugins/clion
run: gradle --no-daemon test buildPlugin
- name: Plugin Verifier
working-directory: mide-plugins/clion
run: gradle --no-daemon verifyPlugin
- name: The archive carries the bundle and every system's okrun
working-directory: mide-plugins/clion
run: |
unzip -l build/distributions/mcpp-clion-*.zip | tee files.txt
grep -q "mcpp-clion/backend/mcpp-ide.okb" files.txt
for p in linux-x86_64/okrun linux-aarch64/okrun macos-aarch64/okrun windows-x86_64/okrun.exe; do grep -q "mcpp-clion/backend/okrun/$p" files.txt; done
[ "$(grep -c '\.okb$' files.txt)" = 1 ]
jar="$(grep -o 'mcpp-clion/lib/mcpp-clion-[^ ]*\.jar' files.txt | head -1)"
unzip -p build/distributions/mcpp-clion-*.zip "$jar" > plugin.jar
unzip -l plugin.jar | tee jar.txt | grep -q "webui/files.txt"
for f in $(unzip -p plugin.jar webui/files.txt); do grep -q " webui/$f$" jar.txt; done
ls -l build/distributions/*.zip
# The plugin's icon and its tool window's are the mcpp logo, an embedded image (design 2026-10-29
# §10.4), not text; the VS Code extension's logo is mcpp-vscode 0.9.0's, byte for byte.
- name: The icons are the mcpp logo
run: |
[ "$(md5sum < mide-plugins/vscode/media/logo.png | cut -d' ' -f1)" = f94579030616a45ca26694120daba050 ] \
|| { echo "::error::media/logo.png is not the mcpp logo"; exit 1; }
cd mide-plugins/clion
for f in META-INF/pluginIcon.svg icons/mcpp.svg; do
svg="$(unzip -p plugin.jar "$f")"
grep -q 'data:image/png;base64,' <<< "$svg" || { echo "::error::$f embeds no image of the logo"; exit 1; }
! grep -q '<text' <<< "$svg" || { echo "::error::$f is text, not the logo"; exit 1; }
done
- uses: actions/upload-artifact@v5
with:
name: mcpp-clion-zip
path: mide-plugins/clion/build/distributions/*.zip
# The Neovim plugin (mide-plugins/nvim) in a headless Neovim, against the backend built here: over
# the mock mcpp on the oldest and the newest Neovim it supports, then over the real mcpp, which
# builds the test's project. Neovim comes from xlings (`nvim` in xim-pkgindex), each version
# installed and selected with `xlings use`, as mcppls's CI provisions it.
nvim:
name: Neovim plugin
runs-on: ubuntu-24.04
timeout-minutes: 45
env:
NVIM_VERSIONS: 0.10.4 0.12.5
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/setup-mcpp
- name: Build the backend and the mock mcpp
run: mcpp build
- name: Neovim from xlings
run: |
set -euo pipefail
for version in $NVIM_VERSIONS; do
for attempt in 1 2 3; do
if xlings install "nvim@$version" -y -g; then break; fi
[ "$attempt" = 3 ] && { echo "::error::nvim@$version could not be installed"; exit 1; }
sleep 30
done
done
# Neovim runs outside the repository: inside it, xlings resolves tools through the project's
# own subos (.xlings.json), which holds mcpp only. The suite finds the backend by its own path.
- name: The plugin on each Neovim, over the mock mcpp
working-directory: ${{ runner.temp }}
run: |
set -euo pipefail
failed=''
for version in $NVIM_VERSIONS; do
xlings use nvim "$version"
nvim --version | head -1 | tee said.txt
grep -qF "v$version" said.txt
echo "::group::Neovim $version"
nvim --headless --clean -l "$GITHUB_WORKSPACE/mide-plugins/nvim/tests/smoke.lua" || failed="$failed $version"
echo "::endgroup::"
done
if [ -n "$failed" ]; then echo "::error::the Neovim plugin failed on:$failed"; exit 1; fi
- name: The plugin over the real mcpp
working-directory: ${{ runner.temp }}
run: MCPP_NVIM_MCPP="$(command -v mcpp)" nvim --headless --clean -l "$GITHUB_WORKSPACE/mide-plugins/nvim/tests/smoke.lua"
# The packages, opened on every system they serve: the one bundle each editor package carries,
# started by the okrun it carries for that system (scripts/check-package.sh), and the backend's own
# universal package started by its launcher.
packages:
name: packages on ${{ matrix.os }}
needs: [vscode, clion]
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14, windows-2022]
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
- uses: actions/download-artifact@v5
with:
pattern: mcpp-*
path: packages
merge-multiple: true
- uses: actions/download-artifact@v5
with:
name: backend
path: backend
- name: The VS Code extension
run: .github/scripts/check-package.sh packages/mcpp-vscode-*.vsix extension
- name: The CLion plugin
run: .github/scripts/check-package.sh packages/mcpp-clion-*.zip mcpp-clion
- name: The backend's universal package
run: |
set -euo pipefail
dir="$(mktemp -d)"
tar -xzf backend/mcpp-ide-*-openkal*.tar.gz -C "$dir"
root="$(echo "$dir"/mcpp-ide-*-openkal*)"
"$root/bin/mcpp-ide" --version | tee said.txt
grep -q '^mcpp-ide ' said.txt