From 06b434843170262cf1237bfbfe8d5fd260021bd8 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Thu, 4 Jun 2026 14:26:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?test:=20temp=20CI=20=E2=80=94=20Windows=20n?= =?UTF-8?q?o-git=20default-user=20flow=20repro=20(DO=20NOT=20MERGE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes all other workflows on this branch and adds a single windows-latest job that: - disables the runner's preinstalled Git for Windows - installs xlings via the official quick_install.ps1 one-liner - runs 'xlings install mcpp', 'mcpp new/build', 'mcpp self init --force' - probes 'git --version' with XLINGS_HOME redirected to ~/.mcpp/registry to confirm the xvm git-shim / redirected-XLINGS_HOME root cause --- .github/workflows/bootstrap-macos.yml | 146 ----- .github/workflows/ci-fresh-install.yml | 192 ------ .github/workflows/ci-linux.yml | 168 ------ .github/workflows/ci-macos.yml | 358 ------------ .github/workflows/ci-windows.yml | 257 -------- .github/workflows/release.yml | 548 ------------------ .../temp-windows-no-git-user-flow.yml | 183 ++++++ 7 files changed, 183 insertions(+), 1669 deletions(-) delete mode 100644 .github/workflows/bootstrap-macos.yml delete mode 100644 .github/workflows/ci-fresh-install.yml delete mode 100644 .github/workflows/ci-linux.yml delete mode 100644 .github/workflows/ci-macos.yml delete mode 100644 .github/workflows/ci-windows.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/temp-windows-no-git-user-flow.yml diff --git a/.github/workflows/bootstrap-macos.yml b/.github/workflows/bootstrap-macos.yml deleted file mode 100644 index 33fffc4d..00000000 --- a/.github/workflows/bootstrap-macos.yml +++ /dev/null @@ -1,146 +0,0 @@ -name: bootstrap-macos - -# One-shot workflow to produce the first macOS mcpp binary. -# Uses xmake + xlings LLVM to compile mcpp from source. -# Once a macOS binary exists, mcpp can self-host for future releases. - -on: - workflow_dispatch: - -jobs: - bootstrap: - name: Bootstrap mcpp (macOS ARM64) - runs-on: macos-15 - timeout-minutes: 30 - env: - XLINGS_NON_INTERACTIVE: '1' - XLINGS_VERSION: '0.4.30' - steps: - - uses: actions/checkout@v4 - - - name: System info - run: | - uname -a - sw_vers - xcrun --show-sdk-path - - - name: Install xlings - run: | - WORK=$(mktemp -d) - tarball="xlings-${XLINGS_VERSION}-macosx-arm64.tar.gz" - curl -fsSL -o "${WORK}/${tarball}" \ - "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}" - tar -xzf "${WORK}/${tarball}" -C "${WORK}" - "${WORK}/xlings-${XLINGS_VERSION}-macosx-arm64/subos/default/bin/xlings" self install - echo "$HOME/.xlings/subos/default/bin" >> "$GITHUB_PATH" - echo "$HOME/.xlings/bin" >> "$GITHUB_PATH" - - - name: Install LLVM + xmake - run: | - xlings install llvm -y || xlings install llvm@20.1.7 -y - brew install xmake - LLVM_ROOT=$(find "$HOME/.xlings" -path "*/xpkgs/xim-x-llvm/*/bin/clang++" | head -1 | xargs dirname | xargs dirname) - echo "LLVM_ROOT=$LLVM_ROOT" >> "$GITHUB_ENV" - "$LLVM_ROOT/bin/clang++" --version - xmake --version - - - name: Build mcpp with xmake - run: | - # Generate xmake.lua if not present - if [ ! -f xmake.lua ]; then - cat > xmake.lua << 'EOF' - add_rules("mode.release") - set_languages("c++23") - - package("cmdline") - set_homepage("https://github.com/mcpplibs/cmdline") - set_description("Modern C++ command-line parsing library") - set_license("Apache-2.0") - add_urls("https://github.com/mcpplibs/cmdline/archive/refs/tags/$(version).tar.gz") - add_versions("0.0.1", "3fb2f5495c1a144485b3cbb2e43e27059151633460f702af0f3851cbff387ef0") - on_install(function (package) - import("package.tools.xmake").install(package) - end) - package_end() - - add_requires("cmdline 0.0.1") - - target("mcpp") - set_kind("binary") - add_files("src/main.cpp") - add_files("src/**.cppm") - add_packages("cmdline") - add_includedirs("src/libs/json") - set_policy("build.c++.modules", true) - -- Static link libc++ for minimal runtime dependencies - add_ldflags("-static-libstdc++", {force = true}) - add_cxxflags("-stdlib=libc++", {force = true}) - add_ldflags("-stdlib=libc++", {force = true}) - EOF - fi - - # Configure with xlings LLVM - xmake f -y -m release --toolchain=llvm --sdk="$LLVM_ROOT" - # Build - xmake build -y mcpp - - - name: Verify built binary - run: | - MCPP=$(find build -name mcpp -type f -perm +111 | head -1) - test -x "$MCPP" - echo "=== file ===" - file "$MCPP" - echo "=== otool -L (dynamic deps) ===" - otool -L "$MCPP" - echo "=== version ===" - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - - - name: Package - id: package - run: | - VERSION=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml) - TARBALL="mcpp-${VERSION}-macosx-arm64.tar.gz" - WRAPPER="mcpp-${VERSION}-macosx-arm64" - - mkdir -p "dist/$WRAPPER/bin" - cp "$MCPP" "dist/$WRAPPER/bin/mcpp" - strip "dist/$WRAPPER/bin/mcpp" 2>/dev/null || true - cp LICENSE "dist/$WRAPPER/" 2>/dev/null || true - cp README.md "dist/$WRAPPER/" 2>/dev/null || true - - cat > "dist/$WRAPPER/mcpp" << 'LAUNCHER' - #!/bin/sh - exec "$(dirname "$0")/bin/mcpp" "$@" - LAUNCHER - chmod +x "dist/$WRAPPER/mcpp" - - # Bundle xlings - XLINGS_BIN="$HOME/.xlings/subos/default/bin/xlings" - if [ -x "$XLINGS_BIN" ]; then - mkdir -p "dist/$WRAPPER/registry/bin" - cp "$XLINGS_BIN" "dist/$WRAPPER/registry/bin/xlings" - fi - - (cd dist && tar -czf "$TARBALL" "$WRAPPER") - (cd dist && shasum -a 256 "$TARBALL" > "$TARBALL.sha256") - - echo "tarball=dist/$TARBALL" >> "$GITHUB_OUTPUT" - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - ls -la dist/ - - - name: Smoke test - run: | - SMOKE=$(mktemp -d) - tar -xzf "${{ steps.package.outputs.tarball }}" -C "$SMOKE" - VERSION="${{ steps.package.outputs.version }}" - "$SMOKE/mcpp-${VERSION}-macosx-arm64/bin/mcpp" --version - "$SMOKE/mcpp-${VERSION}-macosx-arm64/mcpp" --version - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: mcpp-macosx-arm64 - path: | - dist/mcpp-*-macosx-arm64.tar.gz - dist/mcpp-*-macosx-arm64.tar.gz.sha256 diff --git a/.github/workflows/ci-fresh-install.yml b/.github/workflows/ci-fresh-install.yml deleted file mode 100644 index d5cf6ca5..00000000 --- a/.github/workflows/ci-fresh-install.yml +++ /dev/null @@ -1,192 +0,0 @@ -name: ci-fresh-install - -# Fresh install CI — validates the released mcpp binary via xlings. -# Simulates a real first-time user on a clean machine (no caches). -# -# For each platform, tests every supported toolchain: -# 1. mcpp new hello → mcpp run (basic project) -# 2. mcpp build (build mcpp itself from source) -# -# This workflow tests released mcpp, not PR code. -# It runs on release publish, manual trigger, and daily schedule. - -on: - release: - types: [ published ] - workflow_dispatch: - schedule: - # Run daily at 06:00 UTC to catch issues from xlings/runner updates - - cron: '0 6 * * *' - -concurrency: - group: ci-fresh-install - cancel-in-progress: false # use false to test in PRs, true to only test released mcpp - -jobs: - # ────────────────────────────────────────────────────────────────── - # Linux: gcc@16.1.0, musl-gcc@15.1.0, llvm@20.1.7 - # ────────────────────────────────────────────────────────────────── - linux-fresh: - name: Linux fresh install - runs-on: ubuntu-24.04 - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - - name: Install xlings + mcpp - env: - XLINGS_NON_INTERACTIVE: '1' - run: | - curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v0.4.38 - echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - - name: Install mcpp and config mirror - run: | - xlings install mcpp -y -g # install to global - mcpp --version - mcpp self config --mirror GLOBAL - - echo "mcpp debug info:" - which mcpp - cat $HOME/.xlings/.xlings.json - - - name: "Default: mcpp new → run" - run: | - cd "$(mktemp -d)" - mcpp new hello_gcc - cd hello_gcc - mcpp run - - - name: "Default: build mcpp" - run: | - mcpp clean - mcpp run - - - name: "musl-gcc: mcpp new → run" - run: | - mcpp toolchain install gcc 15.1.0-musl - mcpp toolchain default gcc@15.1.0-musl - cd "$(mktemp -d)" - mcpp new hello_musl - cd hello_musl - mcpp run - - - name: "musl-gcc: build mcpp" - run: | - mcpp toolchain default gcc@15.1.0-musl - mcpp clean - mcpp run - - - name: "gcc 16: mcpp new → run" - run: | - mcpp toolchain install gcc 16.1.0 - mcpp toolchain default gcc@16.1.0 - cd "$(mktemp -d)" - mcpp new hello_gcc16 - cd hello_gcc16 - mcpp run - - - name: "gcc 16: build mcpp" - run: | - mcpp toolchain default gcc@16.1.0 - mcpp clean - mcpp run - - - name: "LLVM: mcpp new → run" - run: | - mcpp toolchain install llvm 20.1.7 - mcpp toolchain default llvm@20.1.7 - cd "$(mktemp -d)" - mcpp new hello_llvm - cd hello_llvm - mcpp run - - - name: "LLVM: build mcpp" - run: | - mcpp toolchain default llvm@20.1.7 - mcpp clean - mcpp run - - # ────────────────────────────────────────────────────────────────── - # macOS: llvm@20.1.7 - # ────────────────────────────────────────────────────────────────── - macos-fresh: - name: macOS fresh install - runs-on: macos-15 - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - - name: Install xlings - env: - XLINGS_NON_INTERACTIVE: '1' - run: | - curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v0.4.38 - echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - - name: Install mcpp and config mirror - run: | - xlings install mcpp -y -g # install to global - mcpp --version - mcpp self config --mirror GLOBAL - - echo "mcpp debug info:" - which mcpp - cat $HOME/.xlings/.xlings.json - - - name: "LLVM: mcpp new → run" - run: | - cd "$(mktemp -d)" - mcpp new hello_mac - cd hello_mac - mcpp run - - - name: "LLVM: build mcpp" - run: | - mcpp clean - mcpp run - - # ────────────────────────────────────────────────────────────────── - # Windows: llvm@20.1.7 + MSVC STL - # ────────────────────────────────────────────────────────────────── - windows-fresh: - name: Windows fresh install - runs-on: windows-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - - name: Install xlings - shell: pwsh - env: - XLINGS_NON_INTERACTIVE: '1' - run: | - irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex - - $xlingsbin = "$env:USERPROFILE\.xlings\subos\current\bin" - $env:PATH = "$xlingsbin;$env:PATH" - $xlingsbin | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8 - - - name: Install mcpp and config mirror - shell: pwsh - run: | - xlings install mcpp -y -g --verbose - - cat "$env:USERPROFILE\.xlings\.xlings.json" - mcpp --version - mcpp self config --mirror GLOBAL - - - name: "LLVM: mcpp new → run" - shell: pwsh - run: | - $tmp = New-TemporaryFile | ForEach-Object { Remove-Item $_; New-Item -ItemType Directory -Path $_ } - Set-Location $tmp - mcpp new hello_win - Set-Location hello_win - mcpp run - - - name: "LLVM: build mcpp" - shell: pwsh - run: | - mcpp clean - mcpp run diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml deleted file mode 100644 index fbd75d87..00000000 --- a/.github/workflows/ci-linux.yml +++ /dev/null @@ -1,168 +0,0 @@ -name: ci-linux - -# Self-host CI on Linux: mcpp builds mcpp. The bootstrap mcpp comes from -# `xlings install mcpp` (xim:mcpp in the xlings package index), so this -# workflow no longer depends on a previous-release tarball — the -# chicken-and-egg now lives upstream in the xlings index. -# -# Paired workflows: ci-macos.yml, ci-windows.yml. - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - workflow_dispatch: - -concurrency: - group: ci-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build-and-test: - name: build + test (linux x86_64, self-host) - runs-on: ubuntu-24.04 - timeout-minutes: 60 - env: - # MCPP_HOME pinned so the cache key below restores into the - # same path mcpp resolves at runtime. - MCPP_HOME: /home/runner/.mcpp - steps: - - uses: actions/checkout@v4 - - # Cache mcpp's sandbox: the toolchain (musl-gcc + binutils + - # glibc + linux-headers + patchelf + ninja) takes minutes to - # install on a cold runner. Key on the workspace manifest so a - # toolchain change in mcpp.toml refreshes the cache; restore-keys - # provide a layered fallback so near-misses still skip the slow - # toolchain installs. - - name: Cache mcpp sandbox - uses: actions/cache@v4 - with: - path: ~/.mcpp - key: mcpp-sandbox-${{ runner.os }}-${{ hashFiles('mcpp.toml', '.xlings.json') }} - restore-keys: | - mcpp-sandbox-${{ runner.os }}- - - # Cache xlings + its locally installed packages (xim:mcpp etc.). - # Saves the xlings bootstrap roundtrip + the mcpp xpkg download - # on hot runs. - - name: Cache xlings - uses: actions/cache@v4 - with: - path: ~/.xlings - key: xlings-${{ runner.os }}-v2-${{ hashFiles('.xlings.json') }} - restore-keys: | - xlings-${{ runner.os }}-v2- - - - name: Bootstrap mcpp via xlings - env: - XLINGS_NON_INTERACTIVE: '1' - XLINGS_VERSION: '0.4.30' - run: | - # Always install the pinned version — cache may hold an older - # xlings whose sysroot/packages are incompatible. - tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz" - curl -fsSL -o "/tmp/${tarball}" \ - "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}" - tar -xzf "/tmp/${tarball}" -C /tmp - "/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install - export PATH="$HOME/.xlings/subos/default/bin:$PATH" - xlings --version - # xim:mcpp — `xlings install` is idempotent so cache hits skip - # the download. - xlings install mcpp -y - MCPP="$HOME/.xlings/subos/default/bin/mcpp" - test -x "$MCPP" - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV" - - # Cache the build directory: precise key on src/ + manifest - # so a no-source-change run lands on a full hit. Layered - # restore-keys let mid-run partial hits keep BMI/dyndep state - # for proper incremental builds. - - name: Cache target/ (build artifacts + BMIs) - uses: actions/cache@v4 - with: - path: target - key: mcpp-target-${{ runner.os }}-${{ hashFiles('src/**', 'tests/**', 'mcpp.toml', 'mcpp.lock') }} - restore-keys: | - mcpp-target-${{ runner.os }}- - - - name: Configure mirror + Build mcpp from source (self-host) - run: | - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - # Set GLOBAL mirror via xlings directly (bootstrap mcpp may lack --mirror flag) - "$XLINGS_BIN" config --mirror GLOBAL 2>/dev/null || true - "$MCPP" self config --mirror GLOBAL 2>/dev/null || true - "$MCPP" build - - - name: Unit + integration tests via `mcpp test` - run: | - # Use freshly-built mcpp for test (it has --mirror support) - MCPP_FRESH=$(realpath "$(find target -type f -name mcpp -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2)") - "$MCPP_FRESH" self config --mirror GLOBAL - "$MCPP_FRESH" test - - - name: E2E suite - # Step-level guard: a single hung test (historically 10_env_command.sh - # on slow xlings/network) used to eat the full 60-min job budget. - # Cap the suite at 25 min so a hang fails fast and we still have room - # for the downstream toolchain steps. Per-test 600s timeout lives in - # tests/e2e/run_all.sh and identifies WHICH test hung. - timeout-minutes: 25 - run: | - # Point the e2e runner at the freshly-built binary, not the - # bootstrap one. Tests cd into mktemp -d, so $MCPP must be - # absolute or the relative path breaks under the temp cwd. - MCPP=$(realpath "$(find target -type f -name mcpp -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2)") - test -x "$MCPP" - export MCPP - # Tests that set MCPP_HOME to a fresh tmpdir need an xlings - # to bootstrap from; surface the xlings binary installed - # above so they don't have to reinstall the sandbox. - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - test -x "$MCPP_VENDORED_XLINGS" - # GitHub-hosted runners are outside CN; keep CI toolchain downloads on - # the global mirror while mcpp's default remains CN for fresh local - # sandboxes. E2E tests with their own MCPP_HOME read this variable. - export MCPP_E2E_TOOLCHAIN_MIRROR=GLOBAL - "$MCPP" self config --mirror "$MCPP_E2E_TOOLCHAIN_MIRROR" - "$MCPP" self config - # Pin the global default so test 28 (which exercises the - # default-toolchain path) gets a deterministic GNU answer - # instead of whatever auto-install picks on a fresh sandbox. - "$MCPP" toolchain default gcc@16.1.0 - # Warm musl once in the persistent sandbox. Fresh-home e2e tests - # inherit this payload, and the later --target musl job reuses it - # instead of downloading a second copy into another home. - "$MCPP" toolchain install gcc 15.1.0-musl - bash tests/e2e/run_all.sh - - - name: Save freshly-built mcpp for toolchain tests - run: | - MCPP=$(realpath "$(find target -type f -name mcpp -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2)") - cp "$MCPP" /tmp/mcpp-fresh - echo "MCPP=/tmp/mcpp-fresh" >> "$GITHUB_ENV" - - - name: "Toolchain: GCC — build mcpp + test" - run: | - "$MCPP" clean - "$MCPP" build 2>&1 | tee build.log; grep -q "Resolved gcc@16.1.0" build.log - "$MCPP" test - - - name: "Toolchain: musl-gcc — build mcpp (--target)" - run: | - "$MCPP" clean - "$MCPP" build --target x86_64-linux-musl 2>&1 | tee build.log; grep -q "Resolved gcc@15.1.0-musl" build.log - - - name: "Toolchain: LLVM — build mcpp" - run: | - "$MCPP" toolchain install llvm 20.1.7 - # Override project toolchain to use LLVM for this build - sed -i 's/^default = "gcc@16.1.0"/default = "llvm@20.1.7"/' mcpp.toml - "$MCPP" clean - "$MCPP" build 2>&1 | tee build.log; grep -q "Resolved llvm@20.1.7" build.log - # Restore - sed -i 's/^default = "llvm@20.1.7"/default = "gcc@16.1.0"/' mcpp.toml diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml deleted file mode 100644 index 4aa5e60c..00000000 --- a/.github/workflows/ci-macos.yml +++ /dev/null @@ -1,358 +0,0 @@ -name: ci-macos - -# macOS CI for mcpp — validates LLVM/Clang as the default macOS toolchain. -# Tests the full xlings → LLVM → C++23 import std pipeline on macOS ARM64. - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - workflow_dispatch: - -concurrency: - group: ci-macos-${{ github.ref }} - cancel-in-progress: true - -jobs: - macos-xlings-llvm: - name: macOS ARM64 — xlings LLVM end-to-end - runs-on: macos-15 - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - - name: System info - run: | - uname -a - sw_vers - xcrun --show-sdk-path - echo "SDK: $(xcrun --show-sdk-version)" - - - name: Cache xlings - uses: actions/cache@v4 - with: - path: ~/.xlings - key: xlings-macos15-arm64-v3-${{ hashFiles('.xlings.json') }} - restore-keys: | - xlings-macos15-arm64-v3- - - - name: Bootstrap xlings - env: - XLINGS_NON_INTERACTIVE: '1' - XLINGS_VERSION: '0.4.30' - run: | - WORK=$(mktemp -d) - tarball="xlings-${XLINGS_VERSION}-macosx-arm64.tar.gz" - curl -fsSL -o "${WORK}/${tarball}" \ - "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}" - tar -xzf "${WORK}/${tarball}" -C "${WORK}" - XLINGS_DIR="${WORK}/xlings-${XLINGS_VERSION}-macosx-arm64" - "$XLINGS_DIR/subos/default/bin/xlings" self install - export PATH="$HOME/.xlings/subos/default/bin:$PATH" - xlings --version - echo "PATH=$HOME/.xlings/subos/default/bin:$PATH" >> "$GITHUB_ENV" - - - name: Install LLVM via xlings - run: | - xlings install llvm -y || xlings install llvm@20.1.7 -y - # Verify clang++ is available - LLVM_ROOT=$(find "$HOME/.xlings" -path "*/xpkgs/xim-x-llvm/*/bin/clang++" | head -1 | xargs dirname | xargs dirname) - echo "LLVM_ROOT=$LLVM_ROOT" - ls "$LLVM_ROOT/bin/clang++" - "$LLVM_ROOT/bin/clang++" --version - echo "LLVM_ROOT=$LLVM_ROOT" >> "$GITHUB_ENV" - echo "CXX=$LLVM_ROOT/bin/clang++" >> "$GITHUB_ENV" - - - name: Inspect LLVM package structure - run: | - echo "=== bin/ ===" - ls "$LLVM_ROOT/bin/" | grep -E "^(clang|llvm|lld|ld)" | head -20 - echo "=== lib/ ===" - ls "$LLVM_ROOT/lib/" 2>/dev/null | head -10 - echo "=== share/libc++/ ===" - find "$LLVM_ROOT" -name "std.cppm" -o -name "std.compat.cppm" 2>/dev/null - echo "=== clang++.cfg ===" - cat "$LLVM_ROOT/bin/clang++.cfg" 2>/dev/null || echo "(no cfg file)" - echo "=== Target triple ===" - "$CXX" -dumpmachine - echo "=== Module manifest ===" - "$CXX" -print-library-module-manifest-path 2>/dev/null || echo "(not available)" - - - name: Test — non-module C++23 compilation - run: | - WORK=$(mktemp -d) - cd "$WORK" - cat > main.cpp << 'EOF' - #include - #include - int main() { - std::cout << std::format("Hello from LLVM on macOS! clang {}", __clang_version__) << std::endl; - return 0; - } - EOF - "$CXX" -std=c++23 -o hello main.cpp - ./hello - - - name: Test — import std (two-stage module compilation) - run: | - WORK=$(mktemp -d) - cd "$WORK" - - # Find std.cppm - STD_CPPM=$(find "$LLVM_ROOT" -name "std.cppm" -path "*/libc++/*" | head -1) - if [ -z "$STD_CPPM" ]; then - echo "::error::std.cppm not found in LLVM package" - find "$LLVM_ROOT" -name "*.cppm" 2>/dev/null - exit 1 - fi - echo "std.cppm at: $STD_CPPM" - - echo "=== Step 1: Precompile std module ===" - mkdir -p pcm.cache - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - --precompile "$STD_CPPM" -o pcm.cache/std.pcm - - echo "=== Step 2: Compile std.pcm → std.o ===" - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - pcm.cache/std.pcm -c -o std.o - - echo "=== Step 3: Compile main.cpp with import std ===" - cat > main.cpp << 'EOF' - import std; - int main() { - std::println("C++23 import std works on macOS via xlings LLVM!"); - return 0; - } - EOF - "$CXX" -std=c++23 -fmodule-file=std=pcm.cache/std.pcm -c main.cpp -o main.o - - echo "=== Step 4: Link ===" - "$CXX" main.o std.o -o hello_modules - echo "=== Step 5: Run ===" - ./hello_modules - - - name: Test — import std.compat - run: | - WORK=$(mktemp -d) - cd "$WORK" - - STD_CPPM=$(find "$LLVM_ROOT" -name "std.cppm" -path "*/libc++/*" | head -1) - STD_COMPAT_CPPM=$(find "$LLVM_ROOT" -name "std.compat.cppm" -path "*/libc++/*" | head -1) - - if [ -z "$STD_COMPAT_CPPM" ]; then - echo "::warning::std.compat.cppm not found, skipping" - exit 0 - fi - echo "std.compat.cppm at: $STD_COMPAT_CPPM" - - mkdir -p pcm.cache - # Build std first - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - --precompile "$STD_CPPM" -o pcm.cache/std.pcm - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - pcm.cache/std.pcm -c -o std.o - - # Build std.compat (depends on std) - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - -fmodule-file=std=pcm.cache/std.pcm \ - --precompile "$STD_COMPAT_CPPM" -o pcm.cache/std.compat.pcm - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - -fmodule-file=std=pcm.cache/std.pcm \ - pcm.cache/std.compat.pcm -c -o std.compat.o - - cat > main.cpp << 'EOF' - import std.compat; - #include - int main() { - printf("std.compat works on macOS! %s\n", "success"); - return 0; - } - EOF - "$CXX" -std=c++23 \ - -fmodule-file=std=pcm.cache/std.pcm \ - -fmodule-file=std.compat=pcm.cache/std.compat.pcm \ - -c main.cpp -o main.o - "$CXX" main.o std.o std.compat.o -o compat_test - ./compat_test - - - name: Test — multi-module project - run: | - WORK=$(mktemp -d) - cd "$WORK" - - STD_CPPM=$(find "$LLVM_ROOT" -name "std.cppm" -path "*/libc++/*" | head -1) - mkdir -p pcm.cache - - # Build std - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - --precompile "$STD_CPPM" -o pcm.cache/std.pcm - "$CXX" -std=c++23 -Wno-reserved-module-identifier \ - pcm.cache/std.pcm -c -o std.o - - # User module: greeter - cat > greeter.cppm << 'EOF' - export module greeter; - import std; - export namespace greeter { - std::string hello(std::string_view name) { - return std::format("Hello, {}! (from macOS module)", name); - } - } - EOF - "$CXX" -std=c++23 -fmodule-file=std=pcm.cache/std.pcm \ - --precompile greeter.cppm -o pcm.cache/greeter.pcm - "$CXX" -std=c++23 -fmodule-file=std=pcm.cache/std.pcm \ - pcm.cache/greeter.pcm -c -o greeter.o - - # Main - cat > main.cpp << 'EOF' - import std; - import greeter; - int main() { - std::println("{}", greeter::hello("mcpp")); - return 0; - } - EOF - "$CXX" -std=c++23 \ - -fmodule-file=std=pcm.cache/std.pcm \ - -fmodule-file=greeter=pcm.cache/greeter.pcm \ - -c main.cpp -o main.o - "$CXX" main.o greeter.o std.o -o multimod - ./multimod - - - name: Validate mcpp probe logic expectations - run: | - echo "=== Verifying mcpp's assumptions ===" - echo "1. -print-sysroot returns empty (mcpp falls back to xcrun):" - result=$("$CXX" -print-sysroot 2>/dev/null || true) - if [ -z "$result" ]; then - echo " PASS: empty (xcrun fallback needed)" - else - echo " INFO: $result" - fi - - echo "2. xcrun --show-sdk-path works:" - xcrun --show-sdk-path && echo " PASS" - - echo "3. -dumpmachine returns darwin triple:" - triple=$("$CXX" -dumpmachine) - echo " $triple" - echo "$triple" | grep -q "darwin" && echo " PASS: contains 'darwin'" - - echo "4. libc++ module manifest discoverable:" - manifest=$("$CXX" -print-library-module-manifest-path 2>/dev/null || true) - if [ -n "$manifest" ] && [ -f "$manifest" ]; then - echo " PASS: $manifest" - echo " Content:" - cat "$manifest" | head -20 - else - echo " INFO: manifest not via flag, using fallback path" - find "$LLVM_ROOT/share/libc++" -name "*.cppm" 2>/dev/null && echo " PASS: fallback exists" - fi - - echo "5. llvm-ar available:" - ls "$LLVM_ROOT/bin/llvm-ar" && echo " PASS" - - echo "6. clang-scan-deps available:" - ls "$LLVM_ROOT/bin/clang-scan-deps" && echo " PASS" || echo " WARN: not found" - - - name: Validate install.sh platform detection - run: | - uname_s=$(uname -s) - uname_m=$(uname -m) - echo "Platform: ${uname_s}-${uname_m}" - case "${uname_s}-${uname_m}" in - Darwin-arm64) echo "PASS: would select darwin-arm64" ;; - Darwin-x86_64) echo "PASS: would select darwin-x86_64" ;; - *) echo "FAIL: unexpected platform"; exit 1 ;; - esac - - - name: Bootstrap mcpp via xlings - run: | - # Same pattern as Linux CI: xlings install mcpp - xlings install mcpp -y - MCPP="$HOME/.xlings/subos/default/bin/mcpp" - test -x "$MCPP" - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV" - - - name: Configure dev mcpp sandbox to reuse xlings LLVM - run: | - LLVM_PKG="$HOME/.xlings/data/xpkgs/xim-x-llvm/20.1.7" - MCPP_LLVM_LINK="$HOME/.mcpp/registry/data/xpkgs/xim-x-llvm/20.1.7" - test -d "$LLVM_PKG" - printf '1\n' > "$LLVM_PKG/.mcpp_ok" - - mkdir -p "$HOME/.mcpp/registry/data/xpkgs/xim-x-llvm" - rm -rf "$MCPP_LLVM_LINK" - ln -s "$LLVM_PKG" "$MCPP_LLVM_LINK" - - mkdir -p "$HOME/.mcpp" - cat > "$HOME/.mcpp/config.toml" <> "$GITHUB_PATH" - xlings.exe --version - xlings.exe install mcpp -y - echo "=== Searching for mcpp binary ===" - find "$USERPROFILE/.xlings" -name "mcpp.exe" -o -name "mcpp" 2>/dev/null | head -10 - MCPP=$(find "$USERPROFILE/.xlings" -name "mcpp.exe" -path "*/bin/*" 2>/dev/null | head -1) - if [ -z "$MCPP" ]; then - MCPP=$(find "$USERPROFILE/.xlings" -name "mcpp" -path "*/bin/*" 2>/dev/null | head -1) - fi - test -n "$MCPP" || { echo "FAIL: mcpp not found after xlings install"; exit 1; } - echo "Found mcpp at: $MCPP" - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - XLINGS_BIN=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe") - echo "XLINGS_BIN=$XLINGS_BIN" >> "$GITHUB_ENV" - - - name: Build mcpp from source (self-host) - shell: bash - run: | - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - - "$MCPP" build - - MCPP_SELF=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1) - test -n "$MCPP_SELF" || { echo "FAIL: no mcpp.exe"; exit 1; } - MCPP_SELF=$(cd "$(dirname "$MCPP_SELF")" && pwd)/$(basename "$MCPP_SELF") - echo "Self-hosted binary: $MCPP_SELF" - "$MCPP_SELF" --version - echo "MCPP_SELF=$MCPP_SELF" >> "$GITHUB_ENV" - - - name: Unit + integration tests via mcpp test - shell: bash - run: | - export MCPP_VENDORED_XLINGS=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe") - "$MCPP_SELF" test - - # Regression test for the Windows first-run "press Enter to advance" hang. - # Launches mcpp with an OPEN, EMPTY, never-closing stdin pipe. Without - # seal_stdin's Windows fix, any grandchild that reads stdin would inherit - # our pipe and block forever — caught by the timeout below. With the fix, - # every subprocess stdin is redirected from NUL → no possibility of hang. - - name: "Regression: mcpp survives open-empty-stdin (Windows hang fix)" - shell: pwsh - timeout-minutes: 15 - env: - MCPP_VENDORED_XLINGS: ${{ env.XLINGS_BIN }} - run: | - $ErrorActionPreference = 'Stop' - - # MCPP_SELF was set in a bash step as an MSYS-style path - # (e.g. /d/a/mcpp/...). PowerShell can't exec that — convert it - # to a native Windows path via the git-bash cygpath that ships - # on the runner. - $mcppExe = (& 'C:\Program Files\Git\usr\bin\cygpath.exe' -w $env:MCPP_SELF).Trim() - Write-Host "Resolved MCPP_SELF (Windows form): $mcppExe" - if (-not (Test-Path $mcppExe)) { - throw "MCPP_SELF after cygpath not found: $mcppExe" - } - - $tmp = Join-Path $env:RUNNER_TEMP ("stdin-hang-test-" + [guid]::NewGuid().ToString('N')) - New-Item -ItemType Directory -Path $tmp | Out-Null - Set-Location $tmp - & $mcppExe new hello_stdin - Set-Location hello_stdin - - function Invoke-McppWithOpenStdin { - param([string]$McppPath, [string]$McppArgs, [int]$TimeoutSeconds = 300) - - $psi = [System.Diagnostics.ProcessStartInfo]::new() - $psi.FileName = $McppPath - $psi.Arguments = $McppArgs - $psi.WorkingDirectory = (Get-Location).Path - $psi.UseShellExecute = $false - $psi.RedirectStandardInput = $true # parent holds child's stdin - $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $true - # By default the child inherits the parent's env (we did not - # touch $psi.Environment) so MCPP_VENDORED_XLINGS / PATH / etc. - # propagate. - - $p = [System.Diagnostics.Process]::Start($psi) - - # Async-drain stdout/stderr so a full output buffer doesn't - # itself deadlock the child (separate failure mode from the - # stdin hang we're testing). - $stdoutTask = $p.StandardOutput.ReadToEndAsync() - $stderrTask = $p.StandardError.ReadToEndAsync() - - # NEVER write or close $p.StandardInput — the pipe stays open - # and empty for the lifetime of the child. Any grandchild that - # reads stdin will block on this pipe → caught by WaitForExit. - - if (-not $p.WaitForExit($TimeoutSeconds * 1000)) { - try { $p.Kill($true) } catch {} - Write-Host "----- captured stdout -----" - Write-Host $stdoutTask.Result - Write-Host "----- captured stderr -----" - Write-Host $stderrTask.Result - throw "REGRESSION: 'mcpp $McppArgs' HUNG with open-empty stdin after ${TimeoutSeconds}s. The Windows seal_stdin fix is not effective." - } - - Write-Host "----- stdout -----" - Write-Host $stdoutTask.Result - Write-Host "----- stderr -----" - Write-Host $stderrTask.Result - - if ($p.ExitCode -ne 0) { - throw "'mcpp $McppArgs' exited with code $($p.ExitCode) (no hang, but failed)." - } - } - - Write-Host '=== T1: mcpp --version (sanity, fast path) ===' - Invoke-McppWithOpenStdin -McppPath $mcppExe -McppArgs '--version' -TimeoutSeconds 30 - - Write-Host '=== T2: mcpp build (full bootstrap + toolchain + dep resolve + compile) ===' - Invoke-McppWithOpenStdin -McppPath $mcppExe -McppArgs 'build' -TimeoutSeconds 600 - - Write-Host '=== T3: mcpp run (post-build run path) ===' - Invoke-McppWithOpenStdin -McppPath $mcppExe -McppArgs 'run' -TimeoutSeconds 120 - - Write-Host 'SUCCESS: mcpp completes with open-empty stdin → Windows seal_stdin fix verified.' - - - name: E2E suite - shell: bash - # See ci-linux.yml — fail-fast on hung tests instead of burning the - # whole job budget. Per-test 600s timeout lives in run_all.sh. - timeout-minutes: 25 - run: | - export MCPP="$MCPP_SELF" - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - export MCPP_E2E_TOOLCHAIN_MIRROR=GLOBAL - "$MCPP_SELF" self config --mirror GLOBAL - "$MCPP_SELF" toolchain default llvm@20.1.7 - bash tests/e2e/run_all.sh - - - name: "Toolchain: LLVM — mcpp new → run" - shell: bash - run: | - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - TMP=$(mktemp -d) - cd "$TMP" - "$MCPP_SELF" new hello_win - cd hello_win - "$MCPP_SELF" run - - - name: "Toolchain: LLVM — build mcpp (self-host)" - shell: bash - run: | - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - cp "$MCPP_SELF" /tmp/mcpp-fresh.exe - MCPP=/tmp/mcpp-fresh.exe - "$MCPP" toolchain default llvm@20.1.7 - "$MCPP" clean --bmi-cache - "$MCPP" build 2>&1 | tee build.log; grep -q "Resolved llvm@20.1.7" build.log - - - name: Package Windows release zip - id: package - shell: bash - run: | - VERSION=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml) - WRAPPER="mcpp-${VERSION}-windows-x86_64" - ZIPNAME="${WRAPPER}.zip" - - MCPP_BIN=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1) - test -n "$MCPP_BIN" || { echo "FAIL: no mcpp.exe in target/"; exit 1; } - - STAGING=$(mktemp -d) - mkdir -p "$STAGING/$WRAPPER/bin" "$STAGING/$WRAPPER/registry/bin" - cp "$MCPP_BIN" "$STAGING/$WRAPPER/bin/mcpp.exe" - printf '@echo off\r\n"%%~dp0bin\\mcpp.exe" %%*\r\n' > "$STAGING/$WRAPPER/mcpp.bat" - cp README.md "$STAGING/$WRAPPER/" 2>/dev/null || true - cp LICENSE "$STAGING/$WRAPPER/" 2>/dev/null || true - XLINGS_EXE="$USERPROFILE/.xlings/subos/default/bin/xlings.exe" - [ -f "$XLINGS_EXE" ] && cp "$XLINGS_EXE" "$STAGING/$WRAPPER/registry/bin/xlings.exe" - - mkdir -p dist - (cd "$STAGING" && 7z a -tzip "$ZIPNAME" "$WRAPPER") - cp "$STAGING/$ZIPNAME" "dist/$ZIPNAME" - (cd dist && sha256sum "$ZIPNAME" > "$ZIPNAME.sha256") - echo "zipname=$ZIPNAME" >> "$GITHUB_OUTPUT" - ls -la dist/ - - - name: Smoke-test the packaged zip - shell: bash - run: | - ZIPNAME="${{ steps.package.outputs.zipname }}" - WRAPPER="${ZIPNAME%.zip}" - SMOKE=$(mktemp -d) - (cd "$SMOKE" && unzip -q "$GITHUB_WORKSPACE/dist/$ZIPNAME") - "$SMOKE/$WRAPPER/bin/mcpp.exe" --version - test -f "$SMOKE/$WRAPPER/registry/bin/xlings.exe" - test -f "$SMOKE/$WRAPPER/mcpp.bat" - echo "Smoke-test passed" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: mcpp-windows-x86_64 - path: | - dist/*.zip - dist/*.sha256 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 254f2286..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,548 +0,0 @@ -name: release - -# Self-host release: bootstrap mcpp from xlings (xim:mcpp), build the -# musl-static artefact via `mcpp pack --target x86_64-linux-musl -o ...`, -# inject xlings into the produced tarball for install.sh consumers, -# smoke-test, upload. - -on: - push: - tags: [ 'v*' ] - workflow_dispatch: - inputs: - tag: - description: 'tag to (re)build — leave blank to derive `v` from mcpp.toml and create the tag automatically' - required: false - -jobs: - build-release: - name: build + upload (linux / x86_64) - runs-on: ubuntu-24.04 - permissions: - contents: write # required to create releases + push tags - timeout-minutes: 60 - env: - # mcpp resolves MCPP_HOME from the binary's location by default, - # but here we want to share toolchains with the bootstrap sandbox, - # so we pin to a known path. - MCPP_HOME: /home/runner/.mcpp - steps: - # fetch-depth: 0 instead of fetch-tags: true — actions/checkout@v4 - # fails on push-tag triggers when both the ref'd tag and - # `fetch-tags: true` are set: - # "Cannot fetch both and refs/tags/vX.Y.Z to refs/tags/vX.Y.Z" - # Full-history fetch covers the resolve-tag step's needs without - # that contention. - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Resolve target tag + commit - id: resolve - # Three trigger shapes converge here: - # 1. push: refs/tags/vX.Y.Z → use that tag, build at its commit - # 2. workflow_dispatch with `tag` input set: - # - tag exists on remote → check it out (rebuild scenario) - # - tag doesn't exist → use current HEAD; gh-release - # creates the tag at that commit on upload - # 3. workflow_dispatch with no input → derive `v` from - # mcpp.toml's [package].version, build at current HEAD; - # gh-release creates the tag. - run: | - if [ "${{ github.event_name }}" = "push" ]; then - TAG="${{ github.ref_name }}" - elif [ -n "${{ github.event.inputs.tag }}" ]; then - TAG="${{ github.event.inputs.tag }}" - else - VER=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml) - test -n "$VER" || { echo 'failed to read [package].version from mcpp.toml'; exit 1; } - TAG="v$VER" - fi - echo "tag=$TAG" >> "$GITHUB_OUTPUT" - echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" - # If the tag exists on remote AND we're on workflow_dispatch, - # check it out so we rebuild that exact commit. push-tag runs - # already start at the tag commit. - if [ "${{ github.event_name }}" = "workflow_dispatch" ] \ - && git rev-parse --verify "refs/tags/$TAG" >/dev/null 2>&1; then - git checkout --detach "refs/tags/$TAG" - fi - echo "Resolved tag: $TAG (commit $(git rev-parse --short HEAD))" - - # Cache mcpp's sandbox: musl-gcc 15.1 + binutils + glibc + linux-headers - # + patchelf + ninja is ~800 MB on disk; without this every release - # rebuilds from cold install. Key on the workspace manifest so a - # toolchain change in mcpp.toml refreshes the cache. - - name: Cache mcpp sandbox - uses: actions/cache@v4 - with: - path: ~/.mcpp - key: mcpp-sandbox-${{ runner.os }}-release-${{ hashFiles('mcpp.toml', '.xlings.json') }} - restore-keys: | - mcpp-sandbox-${{ runner.os }}-release- - mcpp-sandbox-${{ runner.os }}- - - # Cache xlings + xim:mcpp install. - - name: Cache xlings - uses: actions/cache@v4 - with: - path: ~/.xlings - key: xlings-${{ runner.os }}-release-${{ hashFiles('.xlings.json') }} - restore-keys: | - xlings-${{ runner.os }}-release- - xlings-${{ runner.os }}- - - - name: Bootstrap mcpp via xlings - env: - XLINGS_NON_INTERACTIVE: '1' - # Pin xlings to a known-good version. The upstream install - # script always grabs `latest` (no version override), so we - # download + self-install manually to avoid broken releases. - XLINGS_VERSION: '0.4.30' - run: | - if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then - tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz" - curl -fsSL -o "/tmp/${tarball}" \ - "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}" - tar -xzf "/tmp/${tarball}" -C /tmp - "/tmp/xlings-${XLINGS_VERSION}-linux-x86_64/subos/default/bin/xlings" self install - fi - export PATH="$HOME/.xlings/subos/default/bin:$PATH" - xlings --version - xlings install mcpp -y - MCPP="$HOME/.xlings/subos/default/bin/mcpp" - test -x "$MCPP" - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV" - - - name: Build + pack release artefact (musl static) - id: stage - # Build for the musl-static target, strip the produced ELF, then - # let `mcpp pack` assemble the tarball (binary + top-level wrapper - # + README + LICENSE, contents at archive root). Inject xlings - # afterwards so install.sh consumers get a single self-contained - # bundle. - run: | - TAG="${{ steps.resolve.outputs.tag }}" - VERSION="${{ steps.resolve.outputs.version }}" - TARBALL_NAME="mcpp-${VERSION}-linux-x86_64.tar.gz" - - # Build first so we can strip the ELF before pack copies it. - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - "$MCPP" build --target x86_64-linux-musl - ARTIFACT=$(find target/x86_64-linux-musl -type f -name mcpp | head -1) - test -n "$ARTIFACT" - file "$ARTIFACT" | grep -q 'statically linked' - # Strip — debug info on a static ELF balloons it ~7×. - strip "$ARTIFACT" - - # Pack with the freshly-built mcpp (not the bootstrap) so any - # fixes to the pack code path are exercised in the same release - # they ship in. MCPP_HOME is forced so the new binary uses the - # pinned sandbox instead of resolving relative to its own - # location under target/. - MCPP_HOME="$MCPP_HOME" "$ARTIFACT" pack \ - --target x86_64-linux-musl \ - --mode static \ - -o "${TARBALL_NAME}" - - # Inject xlings: extract → add registry/bin/xlings to the wrapper - # dir → re-tar preserving the wrapper. Since 0.0.4 the bundled - # xlings lives at /registry/bin/xlings (= /bin/xlings). - TARBALL="target/dist/${TARBALL_NAME}" - WRAPPER="${TARBALL_NAME%.tar.gz}" - test -f "$TARBALL" - INJECT=$(mktemp -d) - tar -xzf "$TARBALL" -C "$INJECT" - mkdir -p "$INJECT/$WRAPPER/registry/bin" - cp "$XLINGS_BIN" "$INJECT/$WRAPPER/registry/bin/xlings" - chmod +x "$INJECT/$WRAPPER/registry/bin/xlings" - (cd "$INJECT" && tar -czf "$GITHUB_WORKSPACE/${TARBALL}" "$WRAPPER") - rm -rf "$INJECT" - - # Stage final dist/ (tarball + sidecars) for upload. - mkdir -p dist - cp "$TARBALL" "dist/${TARBALL_NAME}" - (cd dist && cp "${TARBALL_NAME}" "mcpp-linux-x86_64.tar.gz") - (cd dist && sha256sum "${TARBALL_NAME}" "mcpp-linux-x86_64.tar.gz" > SHA256SUMS) - (cd dist && sha256sum "${TARBALL_NAME}" > "${TARBALL_NAME}.sha256") - (cd dist && sha256sum "mcpp-linux-x86_64.tar.gz" > "mcpp-linux-x86_64.tar.gz.sha256") - - # Top-level install.sh — fetched by `curl | bash`. - cp install.sh dist/install.sh - chmod +x dist/install.sh - - echo "tag=$TAG" >> $GITHUB_OUTPUT - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "tarball=${TARBALL_NAME}" >> $GITHUB_OUTPUT - ls -la dist/ - - - name: Smoke-test the bundled tarball - # Extract to a scratch dir and run mcpp from there with MCPP_HOME - # unset — proves the release artefact is genuinely self-contained. - run: | - VERSION="${{ steps.stage.outputs.version }}" - TARBALL_NAME="${{ steps.stage.outputs.tarball }}" - # Wrapper dir inside the tarball matches its stem (mcpp pack - # ties the two together). - WRAPPER="${TARBALL_NAME%.tar.gz}" - SMOKE=$(mktemp -d) - tar -xzf "dist/${TARBALL_NAME}" -C "$SMOKE" - ROOT="$SMOKE/$WRAPPER" - test -x "$ROOT/bin/mcpp" - test -x "$ROOT/registry/bin/xlings" - test -x "$ROOT/mcpp" - file "$ROOT/bin/mcpp" | grep -q 'statically linked' - env -u MCPP_HOME "$ROOT/bin/mcpp" --version - env -u MCPP_HOME "$ROOT/bin/mcpp" --help | head -10 - # Top-level wrapper reports the same version we're shipping. - env -u MCPP_HOME "$ROOT/mcpp" --version | grep -q "$VERSION" - # MCPP_HOME should auto-resolve to the extracted root. - out=$(env -u MCPP_HOME "$ROOT/bin/mcpp" self env) - echo "$out" | grep -q "MCPP_HOME *= *$ROOT" - - - name: Generate source tarball + xpkg.lua via mcpp publish - # Use the freshly-built mcpp to produce the source tarball + xpkg - # descriptor for mcpp-index. The release tarball wraps its - # contents in a `/` directory so the extract path - # is $PUB/$WRAPPER/bin/mcpp. - run: | - VERSION="${{ steps.stage.outputs.version }}" - TARBALL_NAME="${{ steps.stage.outputs.tarball }}" - WRAPPER="${TARBALL_NAME%.tar.gz}" - PUB=$(mktemp -d) - tar -xzf "dist/${TARBALL_NAME}" -C "$PUB" - MCPP_BIN="$PUB/$WRAPPER/bin/mcpp" - env -u MCPP_HOME "$MCPP_BIN" publish --dry-run --allow-dirty - test -f "target/dist/mcpp-${VERSION}.tar.gz" - test -f "target/dist/mcpp.lua" - cp "target/dist/mcpp-${VERSION}.tar.gz" dist/ - cp "target/dist/mcpp.lua" dist/ - ls -la dist/ - - - name: Extract release notes from CHANGELOG - id: notes - run: | - TAG="${{ steps.stage.outputs.tag }}" - VERSION="${{ steps.stage.outputs.version }}" - awk -v v="$VERSION" ' - /^## \[/ { - if (in_section) exit - if ($0 ~ "\\[" v "\\]") { in_section=1; next } - } - in_section { print } - ' CHANGELOG.md > dist/RELEASE_NOTES.md || true - if [ ! -s dist/RELEASE_NOTES.md ]; then - echo "(no CHANGELOG entry found for $VERSION)" > dist/RELEASE_NOTES.md - fi - echo "--- RELEASE_NOTES.md ---" - cat dist/RELEASE_NOTES.md - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ steps.stage.outputs.tag }} - name: ${{ steps.stage.outputs.tag }} - body_path: dist/RELEASE_NOTES.md - draft: false - prerelease: false - files: | - dist/mcpp-${{ steps.stage.outputs.version }}-linux-x86_64.tar.gz - dist/mcpp-${{ steps.stage.outputs.version }}-linux-x86_64.tar.gz.sha256 - dist/mcpp-linux-x86_64.tar.gz - dist/mcpp-linux-x86_64.tar.gz.sha256 - dist/install.sh - dist/SHA256SUMS - dist/mcpp-${{ steps.stage.outputs.version }}.tar.gz - dist/mcpp.lua - - build-macos: - name: build (macOS / ARM64) - runs-on: macos-15 - needs: build-release - permissions: - contents: write - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Resolve tag - id: resolve - run: | - if [ "${{ github.event_name }}" = "push" ]; then - TAG="${{ github.ref_name }}" - elif [ -n "${{ github.event.inputs.tag }}" ]; then - TAG="${{ github.event.inputs.tag }}" - else - VER=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml) - TAG="v$VER" - fi - echo "tag=$TAG" >> "$GITHUB_OUTPUT" - echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" - if [ "${{ github.event_name }}" = "workflow_dispatch" ] \ - && git rev-parse --verify "refs/tags/$TAG" >/dev/null 2>&1; then - git checkout --detach "refs/tags/$TAG" - fi - - - name: Cache xlings - uses: actions/cache@v4 - with: - path: ~/.xlings - key: xlings-macos15-release-${{ hashFiles('.xlings.json') }} - restore-keys: | - xlings-macos15-release- - xlings-macos15-arm64- - - - name: Bootstrap mcpp via xlings - env: - XLINGS_NON_INTERACTIVE: '1' - XLINGS_VERSION: '0.4.30' - run: | - if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then - WORK=$(mktemp -d) - tarball="xlings-${XLINGS_VERSION}-macosx-arm64.tar.gz" - curl -fsSL -o "${WORK}/${tarball}" \ - "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}" - tar -xzf "${WORK}/${tarball}" -C "${WORK}" - "${WORK}/xlings-${XLINGS_VERSION}-macosx-arm64/subos/default/bin/xlings" self install - fi - export PATH="$HOME/.xlings/subos/default/bin:$PATH" - xlings --version - xlings install mcpp -y - MCPP="$HOME/.xlings/subos/default/bin/mcpp" - test -x "$MCPP" - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV" - - - name: Build mcpp from source (self-host) - run: | - export PATH="$HOME/.xlings/subos/default/bin:$PATH" - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - "$MCPP" build - MCPP_BIN=$(find target -path "*/bin/mcpp" | head -1) - MCPP_BIN=$(cd "$(dirname "$MCPP_BIN")" && pwd)/$(basename "$MCPP_BIN") - test -x "$MCPP_BIN" - file "$MCPP_BIN" - otool -L "$MCPP_BIN" - "$MCPP_BIN" --version - echo "MCPP_BIN=$MCPP_BIN" >> "$GITHUB_ENV" - - - name: Package macOS release - id: stage - run: | - VERSION="${{ steps.resolve.outputs.version }}" - TARBALL_NAME="mcpp-${VERSION}-macosx-arm64.tar.gz" - WRAPPER="mcpp-${VERSION}-macosx-arm64" - - # Create release layout - STAGING=$(mktemp -d) - mkdir -p "$STAGING/$WRAPPER/bin" - cp "$MCPP_BIN" "$STAGING/$WRAPPER/bin/mcpp" - # Strip (Mach-O) - strip "$STAGING/$WRAPPER/bin/mcpp" 2>/dev/null || true - # Copy metadata - cp LICENSE "$STAGING/$WRAPPER/" 2>/dev/null || true - cp README.md "$STAGING/$WRAPPER/" 2>/dev/null || true - - # Shell launcher (same as Linux) - cat > "$STAGING/$WRAPPER/mcpp" << 'LAUNCHER' - #!/bin/sh - exec "$(dirname "$0")/bin/mcpp" "$@" - LAUNCHER - chmod +x "$STAGING/$WRAPPER/mcpp" - - # Bundle xlings for install.sh consumers - XLINGS_BIN="$HOME/.xlings/subos/default/bin/xlings" - if [ -x "$XLINGS_BIN" ]; then - mkdir -p "$STAGING/$WRAPPER/registry/bin" - cp "$XLINGS_BIN" "$STAGING/$WRAPPER/registry/bin/xlings" - chmod +x "$STAGING/$WRAPPER/registry/bin/xlings" - fi - - # Create tarball - mkdir -p dist - (cd "$STAGING" && tar -czf "$GITHUB_WORKSPACE/dist/${TARBALL_NAME}" "$WRAPPER") - # Versionless alias - cp "dist/${TARBALL_NAME}" "dist/mcpp-macosx-arm64.tar.gz" - # SHA256 - (cd dist && shasum -a 256 "${TARBALL_NAME}" > "${TARBALL_NAME}.sha256") - (cd dist && shasum -a 256 "mcpp-macosx-arm64.tar.gz" > "mcpp-macosx-arm64.tar.gz.sha256") - - echo "tarball=${TARBALL_NAME}" >> "$GITHUB_OUTPUT" - ls -la dist/ - - - name: Smoke-test the tarball - run: | - VERSION="${{ steps.resolve.outputs.version }}" - TARBALL_NAME="${{ steps.stage.outputs.tarball }}" - WRAPPER="${TARBALL_NAME%.tar.gz}" - SMOKE=$(mktemp -d) - tar -xzf "dist/${TARBALL_NAME}" -C "$SMOKE" - "$SMOKE/$WRAPPER/bin/mcpp" --version - "$SMOKE/$WRAPPER/mcpp" --version | grep -q "$VERSION" - - - name: Upload macOS artifacts to release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ steps.resolve.outputs.tag }} - files: | - dist/mcpp-${{ steps.resolve.outputs.version }}-macosx-arm64.tar.gz - dist/mcpp-${{ steps.resolve.outputs.version }}-macosx-arm64.tar.gz.sha256 - dist/mcpp-macosx-arm64.tar.gz - dist/mcpp-macosx-arm64.tar.gz.sha256 - - build-windows: - name: build (Windows / x86_64) - runs-on: windows-latest - needs: build-release - permissions: - contents: write - timeout-minutes: 45 - env: - MCPP_HOME: C:\Users\runneradmin\.mcpp - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Resolve tag - id: resolve - shell: bash - run: | - if [ "${{ github.event_name }}" = "push" ]; then - TAG="${{ github.ref_name }}" - elif [ -n "${{ github.event.inputs.tag }}" ]; then - TAG="${{ github.event.inputs.tag }}" - else - VER=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml) - TAG="v$VER" - fi - echo "tag=$TAG" >> "$GITHUB_OUTPUT" - echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" - if [ "${{ github.event_name }}" = "workflow_dispatch" ] \ - && git rev-parse --verify "refs/tags/$TAG" >/dev/null 2>&1; then - git checkout --detach "refs/tags/$TAG" - fi - - - name: Cache mcpp sandbox - uses: actions/cache@v4 - with: - path: ~\.mcpp - key: mcpp-sandbox-${{ runner.os }}-release-${{ hashFiles('mcpp.toml', '.xlings.json') }} - restore-keys: | - mcpp-sandbox-${{ runner.os }}-release- - mcpp-sandbox-${{ runner.os }}- - - - name: Cache xlings - uses: actions/cache@v4 - with: - path: ~\.xlings - key: xlings-${{ runner.os }}-release-${{ hashFiles('.xlings.json') }} - restore-keys: | - xlings-${{ runner.os }}-release- - xlings-${{ runner.os }}- - - - name: Bootstrap mcpp via xlings - shell: bash - env: - XLINGS_NON_INTERACTIVE: '1' - XLINGS_VERSION: '0.4.30' - run: | - WORK=$(mktemp -d) - zipfile="xlings-${XLINGS_VERSION}-windows-x86_64.zip" - curl -fsSL -o "${WORK}/${zipfile}" \ - "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${zipfile}" - cd "${WORK}" - unzip -q "${zipfile}" - "$WORK/xlings-${XLINGS_VERSION}-windows-x86_64/subos/default/bin/xlings.exe" self install - export PATH="$USERPROFILE/.xlings/subos/default/bin:$PATH" - echo "$USERPROFILE/.xlings/subos/default/bin" >> "$GITHUB_PATH" - xlings.exe --version - xlings.exe install mcpp -y - MCPP=$(find "$USERPROFILE/.xlings" -name "mcpp.exe" -path "*/bin/*" 2>/dev/null | head -1) - if [ -z "$MCPP" ]; then - MCPP=$(find "$USERPROFILE/.xlings" -name "mcpp" -path "*/bin/*" 2>/dev/null | head -1) - fi - test -n "$MCPP" || { echo "FAIL: mcpp not found after xlings install"; exit 1; } - "$MCPP" --version - echo "MCPP=$MCPP" >> "$GITHUB_ENV" - XLINGS_BIN=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe") - echo "XLINGS_BIN=$XLINGS_BIN" >> "$GITHUB_ENV" - echo "XLINGS_BIN_UNIX=$USERPROFILE/.xlings/subos/default/bin/xlings.exe" >> "$GITHUB_ENV" - echo "XLINGS_XPKGS=$USERPROFILE/.xlings/data/xpkgs" >> "$GITHUB_ENV" - - - name: Build mcpp from source (self-host) - shell: bash - run: | - export MCPP_VENDORED_XLINGS="$XLINGS_BIN" - - "$MCPP" build - - MCPP_BIN=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1) - test -n "$MCPP_BIN" || { echo "FAIL: no mcpp.exe in target/"; exit 1; } - MCPP_BIN=$(cd "$(dirname "$MCPP_BIN")" && pwd)/$(basename "$MCPP_BIN") - echo "Self-hosted binary: $MCPP_BIN" - "$MCPP_BIN" --version - echo "MCPP_BIN=$MCPP_BIN" >> "$GITHUB_ENV" - - - name: Package Windows release zip - id: stage - shell: bash - run: | - VERSION="${{ steps.resolve.outputs.version }}" - WRAPPER="mcpp-${VERSION}-windows-x86_64" - ZIPNAME="${WRAPPER}.zip" - - STAGING=$(mktemp -d) - mkdir -p "$STAGING/$WRAPPER/bin" "$STAGING/$WRAPPER/registry/bin" - cp "$MCPP_BIN" "$STAGING/$WRAPPER/bin/mcpp.exe" - - # Windows batch launcher - printf '@echo off\r\n"%%~dp0bin\\mcpp.exe" %%*\r\n' > "$STAGING/$WRAPPER/mcpp.bat" - cp README.md "$STAGING/$WRAPPER/" 2>/dev/null || true - cp LICENSE "$STAGING/$WRAPPER/" 2>/dev/null || true - - # Bundle xlings.exe for install consumers - if [ -f "$XLINGS_BIN_UNIX" ]; then - cp "$XLINGS_BIN_UNIX" "$STAGING/$WRAPPER/registry/bin/xlings.exe" - fi - - # Pack with 7z (available on windows-latest) - mkdir -p dist - (cd "$STAGING" && 7z a -tzip "$ZIPNAME" "$WRAPPER") - cp "$STAGING/$ZIPNAME" "dist/$ZIPNAME" - # Versionless alias - cp "dist/$ZIPNAME" "dist/mcpp-windows-x86_64.zip" - # SHA256 - (cd dist && sha256sum "$ZIPNAME" > "$ZIPNAME.sha256") - (cd dist && sha256sum "mcpp-windows-x86_64.zip" > "mcpp-windows-x86_64.zip.sha256") - - echo "zipname=$ZIPNAME" >> "$GITHUB_OUTPUT" - ls -la dist/ - - - name: Smoke-test the packaged zip - shell: bash - run: | - ZIPNAME="${{ steps.stage.outputs.zipname }}" - WRAPPER="${ZIPNAME%.zip}" - SMOKE=$(mktemp -d) - (cd "$SMOKE" && unzip -q "$GITHUB_WORKSPACE/dist/$ZIPNAME") - "$SMOKE/$WRAPPER/bin/mcpp.exe" --version - "$SMOKE/$WRAPPER/bin/mcpp.exe" --help | head -5 - test -f "$SMOKE/$WRAPPER/registry/bin/xlings.exe" - test -f "$SMOKE/$WRAPPER/mcpp.bat" - echo "Smoke-test passed" - - - name: Upload Windows artifacts to release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ steps.resolve.outputs.tag }} - files: | - dist/mcpp-${{ steps.resolve.outputs.version }}-windows-x86_64.zip - dist/mcpp-${{ steps.resolve.outputs.version }}-windows-x86_64.zip.sha256 - dist/mcpp-windows-x86_64.zip - dist/mcpp-windows-x86_64.zip.sha256 diff --git a/.github/workflows/temp-windows-no-git-user-flow.yml b/.github/workflows/temp-windows-no-git-user-flow.yml new file mode 100644 index 00000000..37f3240d --- /dev/null +++ b/.github/workflows/temp-windows-no-git-user-flow.yml @@ -0,0 +1,183 @@ +# TEMPORARY workflow — reproduces the Windows "no package index / no git" +# failure chain for a DEFAULT user machine (no system git installed): +# +# 1. uninstall/disable the runner's preinstalled Git for Windows +# 2. install xlings via the official one-liner (like a normal user) +# 3. xlings install mcpp +# 4. mcpp new hello && cd hello && mcpp build (expected to fail) +# 5. mcpp self init --force (expected to fail) +# 6. root-cause probes: +# - `git --version` in the user env (xvm shim → expected OK) +# - `git --version` with XLINGS_HOME redirected to ~/.mcpp/registry +# (expected: "xlings: 'git' is not installed" — the smoking gun) +# +# DO NOT MERGE. Delete this branch after the investigation. +name: temp-windows-no-git-user-flow + +on: + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + user-flow: + name: "user flow: no system git -> xlings -> mcpp build" + runs-on: windows-latest + timeout-minutes: 60 + defaults: + run: + shell: pwsh + steps: + - name: "Stage 0: disable preinstalled git (simulate default user machine)" + run: | + Write-Host "=== git visible before disabling ===" + where.exe git 2>$null | ForEach-Object { Write-Host $_ } + + $candidates = @() + $candidates += @(where.exe git 2>$null) + $candidates += @( + "C:\Program Files\Git\cmd\git.exe", + "C:\Program Files\Git\bin\git.exe", + "C:\Program Files\Git\mingw64\bin\git.exe", + "C:\Program Files\Git\usr\bin\git.exe" + ) + foreach ($p in ($candidates | Where-Object { $_ } | Select-Object -Unique)) { + if (Test-Path -LiteralPath $p) { + try { + Rename-Item -LiteralPath $p -NewName ((Split-Path $p -Leaf) + ".disabled") + Write-Host "disabled: $p" + } catch { + Write-Host "FAILED to disable: $p -- $_" + } + } + } + + Write-Host "=== git visible after disabling ===" + $still = @(where.exe git 2>$null) + if ($still.Count -gt 0) { + $still | ForEach-Object { Write-Host "STILL VISIBLE: $_" } + exit 1 + } + Write-Host "OK: git is no longer resolvable on this machine" + exit 0 + + - name: "Stage 1: install xlings (official user one-liner)" + run: | + powershell -ExecutionPolicy Bypass -c "irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + # Simulate "open a new terminal after install": pick up the + # User-level PATH / XLINGS_HOME that `xlings self install` registered. + $userHome = [Environment]::GetEnvironmentVariable('XLINGS_HOME', 'User') + Write-Host "User XLINGS_HOME = $userHome" + if ($userHome) { "XLINGS_HOME=$userHome" | Add-Content $env:GITHUB_ENV } + + foreach ($d in @( + "$env:USERPROFILE\.xlings\subos\current\bin", + "$env:USERPROFILE\.xlings\bin" + )) { + if (Test-Path $d) { + Add-Content $env:GITHUB_PATH $d + Write-Host "added to PATH for later steps: $d" + } + } + exit 0 + + - name: "Stage 1b: xlings sanity check" + run: | + Write-Host "PATH = $env:Path" + Write-Host "XLINGS_HOME = $env:XLINGS_HOME" + xlings --version + exit $LASTEXITCODE + + - name: "Stage 2: xlings install mcpp" + id: install_mcpp + continue-on-error: true + run: | + xlings install mcpp -y + exit $LASTEXITCODE + + - name: "Stage 2b: post-install git/shim state" + if: always() + run: | + Write-Host "=== where git ===" + where.exe git 2>$null | ForEach-Object { Write-Host $_ } + Write-Host "=== git --version (user env; expected to work via xvm shim) ===" + git --version + Write-Host "git exit code: $LASTEXITCODE" + Write-Host "=== where mcpp ===" + where.exe mcpp 2>$null | ForEach-Object { Write-Host $_ } + Write-Host "=== ~/.xlings layout (top level) ===" + Get-ChildItem "$env:USERPROFILE\.xlings" -ErrorAction SilentlyContinue | Select-Object Name + Get-ChildItem "$env:USERPROFILE\.xlings\subos\current\bin" -ErrorAction SilentlyContinue | Select-Object Name + exit 0 + + - name: "Stage 3: mcpp new hello && mcpp build" + id: build + continue-on-error: true + run: | + mcpp new hello + if ($LASTEXITCODE -ne 0) { Write-Host "mcpp new failed: $LASTEXITCODE"; exit $LASTEXITCODE } + cd hello + mcpp build + exit $LASTEXITCODE + + - name: "Stage 4: mcpp self init --force" + id: selfinit + continue-on-error: true + run: | + mcpp self init --force + exit $LASTEXITCODE + + - name: "Stage 5: root-cause probe — git shim vs redirected XLINGS_HOME" + if: always() + run: | + Write-Host "=== probe A: git --version with user XLINGS_HOME ($env:XLINGS_HOME) ===" + git --version + Write-Host "exit code: $LASTEXITCODE" + + Write-Host "" + Write-Host "=== probe B: git --version with XLINGS_HOME=~/.mcpp/registry (what mcpp's subprocesses see) ===" + $env:XLINGS_HOME = "$env:USERPROFILE\.mcpp\registry" + git --version + Write-Host "exit code: $LASTEXITCODE" + exit 0 + + - name: "Stage 6: dump mcpp sandbox state" + if: always() + run: | + Write-Host "=== ~/.mcpp layout ===" + Get-ChildItem "$env:USERPROFILE\.mcpp" -Recurse -Depth 2 -ErrorAction SilentlyContinue | + Select-Object FullName | ForEach-Object { Write-Host $_.FullName } + + Write-Host "=== package index presence ===" + foreach ($d in @( + "$env:USERPROFILE\.mcpp\registry\data\xim-pkgindex\pkgs", + "$env:USERPROFILE\.mcpp\registry\data\mcpplibs\pkgs", + "$env:USERPROFILE\.xlings\data\xim-pkgindex\pkgs" + )) { + Write-Host ("{0} -> exists: {1}" -f $d, (Test-Path $d)) + } + + Write-Host "=== mcpp logs ===" + Get-ChildItem "$env:USERPROFILE\.mcpp\log" -ErrorAction SilentlyContinue | ForEach-Object { + Write-Host "---- $($_.FullName) ----" + Get-Content $_.FullName -Tail 100 -ErrorAction SilentlyContinue + } + exit 0 + + - name: "Summary" + if: always() + run: | + $lines = @( + "## temp-windows-no-git-user-flow result", + "", + "| step | outcome |", + "|------|---------|", + "| xlings install mcpp | ${{ steps.install_mcpp.outcome }} |", + "| mcpp new + build | ${{ steps.build.outcome }} |", + "| mcpp self init --force | ${{ steps.selfinit.outcome }} |" + ) + $lines | Add-Content $env:GITHUB_STEP_SUMMARY + $lines | ForEach-Object { Write-Host $_ } + exit 0 From 7ad912914b861d4ea261d0e24a8ece3e8c28cfb9 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Thu, 4 Jun 2026 14:31:51 +0800 Subject: [PATCH 2/2] test: harden git probes (cmd /c), add xim:git shim stage --- .../temp-windows-no-git-user-flow.yml | 90 +++++++++++++------ 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/.github/workflows/temp-windows-no-git-user-flow.yml b/.github/workflows/temp-windows-no-git-user-flow.yml index 37f3240d..4bdbbbb8 100644 --- a/.github/workflows/temp-windows-no-git-user-flow.yml +++ b/.github/workflows/temp-windows-no-git-user-flow.yml @@ -6,7 +6,9 @@ # 3. xlings install mcpp # 4. mcpp new hello && cd hello && mcpp build (expected to fail) # 5. mcpp self init --force (expected to fail) -# 6. root-cause probes: +# 6. install xim:git (creates the xvm git shim -> `git --version` works +# in the user env, matching the reported machine state), re-run mcpp +# 7. root-cause probes: # - `git --version` in the user env (xvm shim → expected OK) # - `git --version` with XLINGS_HOME redirected to ~/.mcpp/registry # (expected: "xlings: 'git' is not installed" — the smoking gun) @@ -85,7 +87,6 @@ jobs: - name: "Stage 1b: xlings sanity check" run: | - Write-Host "PATH = $env:Path" Write-Host "XLINGS_HOME = $env:XLINGS_HOME" xlings --version exit $LASTEXITCODE @@ -97,58 +98,93 @@ jobs: xlings install mcpp -y exit $LASTEXITCODE - - name: "Stage 2b: post-install git/shim state" + - name: "Stage 2b: post-install git/shim/mcpp state" if: always() run: | Write-Host "=== where git ===" - where.exe git 2>$null | ForEach-Object { Write-Host $_ } - Write-Host "=== git --version (user env; expected to work via xvm shim) ===" - git --version - Write-Host "git exit code: $LASTEXITCODE" + $git = @(where.exe git 2>$null) + if ($git.Count -gt 0) { + $git | ForEach-Object { Write-Host $_ } + cmd /c "git --version 2>&1" + Write-Host "git --version exit code: $LASTEXITCODE" + } else { + Write-Host "(git not resolvable)" + } Write-Host "=== where mcpp ===" where.exe mcpp 2>$null | ForEach-Object { Write-Host $_ } - Write-Host "=== ~/.xlings layout (top level) ===" - Get-ChildItem "$env:USERPROFILE\.xlings" -ErrorAction SilentlyContinue | Select-Object Name - Get-ChildItem "$env:USERPROFILE\.xlings\subos\current\bin" -ErrorAction SilentlyContinue | Select-Object Name + cmd /c "mcpp --version 2>&1" + Write-Host "mcpp --version exit code: $LASTEXITCODE" + Write-Host "=== xvm shim dir ===" + Get-ChildItem "$env:USERPROFILE\.xlings\subos\current\bin" -ErrorAction SilentlyContinue | + ForEach-Object { Write-Host $_.Name } exit 0 - - name: "Stage 3: mcpp new hello && mcpp build" + - name: "Stage 3: mcpp new hello && mcpp build (fresh machine, no git anywhere)" id: build continue-on-error: true run: | - mcpp new hello - if ($LASTEXITCODE -ne 0) { Write-Host "mcpp new failed: $LASTEXITCODE"; exit $LASTEXITCODE } + mcpp new hello 2>&1 | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) { Write-Host "mcpp new exit code: $LASTEXITCODE"; exit 1 } cd hello - mcpp build + cmd /c "mcpp build 2>&1" + Write-Host "mcpp build exit code: $LASTEXITCODE" exit $LASTEXITCODE - - name: "Stage 4: mcpp self init --force" + - name: "Stage 4: mcpp self init --force (fresh machine, no git anywhere)" id: selfinit continue-on-error: true run: | - mcpp self init --force + cmd /c "mcpp self init --force 2>&1" + Write-Host "exit code: $LASTEXITCODE" exit $LASTEXITCODE - - name: "Stage 5: root-cause probe — git shim vs redirected XLINGS_HOME" + - name: "Stage 5: install xim:git -> user now has working `git --version` (reported machine state)" + id: ximgit + continue-on-error: true + run: | + xlings install xim:git -y + Write-Host "xlings install xim:git exit code: $LASTEXITCODE" + Write-Host "=== where git (after xim:git) ===" + where.exe git 2>$null | ForEach-Object { Write-Host $_ } + cmd /c "git --version 2>&1" + Write-Host "git --version exit code: $LASTEXITCODE" + exit $LASTEXITCODE + + - name: "Stage 5b: re-run mcpp build + self init (git --version now OK in user env)" + id: rebuild + continue-on-error: true + run: | + cd hello + cmd /c "mcpp build 2>&1" + $buildRc = $LASTEXITCODE + Write-Host "mcpp build exit code: $buildRc" + cd .. + cmd /c "mcpp self init --force 2>&1" + $initRc = $LASTEXITCODE + Write-Host "mcpp self init --force exit code: $initRc" + if ($buildRc -ne 0 -or $initRc -ne 0) { exit 1 } + exit 0 + + - name: "Stage 6: root-cause probe — git shim vs redirected XLINGS_HOME" if: always() run: | Write-Host "=== probe A: git --version with user XLINGS_HOME ($env:XLINGS_HOME) ===" - git --version + cmd /c "git --version 2>&1" Write-Host "exit code: $LASTEXITCODE" Write-Host "" Write-Host "=== probe B: git --version with XLINGS_HOME=~/.mcpp/registry (what mcpp's subprocesses see) ===" $env:XLINGS_HOME = "$env:USERPROFILE\.mcpp\registry" - git --version + cmd /c "git --version 2>&1" Write-Host "exit code: $LASTEXITCODE" exit 0 - - name: "Stage 6: dump mcpp sandbox state" + - name: "Stage 7: dump mcpp sandbox state" if: always() run: | - Write-Host "=== ~/.mcpp layout ===" - Get-ChildItem "$env:USERPROFILE\.mcpp" -Recurse -Depth 2 -ErrorAction SilentlyContinue | - Select-Object FullName | ForEach-Object { Write-Host $_.FullName } + Write-Host "=== ~/.mcpp layout (depth 3) ===" + Get-ChildItem "$env:USERPROFILE\.mcpp" -Recurse -Depth 3 -ErrorAction SilentlyContinue | + ForEach-Object { Write-Host $_.FullName } Write-Host "=== package index presence ===" foreach ($d in @( @@ -174,9 +210,11 @@ jobs: "", "| step | outcome |", "|------|---------|", - "| xlings install mcpp | ${{ steps.install_mcpp.outcome }} |", - "| mcpp new + build | ${{ steps.build.outcome }} |", - "| mcpp self init --force | ${{ steps.selfinit.outcome }} |" + "| xlings install mcpp (no git) | ${{ steps.install_mcpp.outcome }} |", + "| mcpp new + build (no git) | ${{ steps.build.outcome }} |", + "| mcpp self init --force (no git) | ${{ steps.selfinit.outcome }} |", + "| xlings install xim:git (user env) | ${{ steps.ximgit.outcome }} |", + "| re-run build + self init (git shim OK) | ${{ steps.rebuild.outcome }} |" ) $lines | Add-Content $env:GITHUB_STEP_SUMMARY $lines | ForEach-Object { Write-Host $_ }