diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7f9f8aa --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,191 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + PYTHON_VERSION: "3.12" + +jobs: + # エミュレータ本体と src32_testbench。testbench は後続ジョブで使うので artifact にする。 + rust: + name: Rust (testbench build + integration tests) + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - name: Install system packages + run: sudo apt-get update && sudo apt-get install -y libasound2-dev libudev-dev + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Build src32_testbench + run: cargo build --bin src32_testbench + - uses: actions/upload-artifact@v4 + with: + name: src32_testbench + path: target/debug/src32_testbench + retention-days: 7 + - name: Build sol guest images used by integration tests + run: | + set -e + mkdir -p target/guests + build() { + python3 tools/solc/solc.py compile "$1" -o "target/guests/$2.a" + python3 tools/asm/asm.py "target/guests/$2.a" -o "$2.bin" + } + build dos.sol dos + build tinybasic.sol tinybasic + build tools/dsfs/dsfs_smoke.sol dsfs_guest + # lib の単体テストは外部リポジトリ (s3w2_core) の golden ファイルを include するため + # CI ではビルドできない。tests/ の統合テストだけを実行する。 + # strek_* と tb_load_live は既知の失敗/外部ファイル依存なので known-failures ジョブへ回す。 + - name: Integration tests + run: | + set -e + args=() + for f in tests/*.rs; do + name=$(basename "$f" .rs) + case "$name" in + strek_micro|strek_smoke|strek_verify|tb_load_live) continue ;; + esac + args+=(--test "$name") + done + cargo test --no-fail-fast "${args[@]}" -- \ + --skip dos_hex_returns_to_shell_at_800_cycles_per_frame + + # 失敗が既知のテスト。ステップ単位の continue-on-error なので PR のチェックは緑のまま、 + # 結果はこのジョブのログ (Known-failing tests ステップ) で確認できる。 + known-failures: + name: Rust known failures (non-blocking) + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - name: Install system packages + run: sudo apt-get update && sudo apt-get install -y libasound2-dev libudev-dev + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Build sol guest images + run: | + set -e + mkdir -p target/guests + python3 tools/solc/solc.py compile dos.sol -o target/guests/dos.a + python3 tools/asm/asm.py target/guests/dos.a -o dos.bin + python3 tools/solc/solc.py compile tinybasic.sol -o target/guests/tinybasic.a + python3 tools/asm/asm.py target/guests/tinybasic.a -o tinybasic.bin + - name: Known-failing tests + continue-on-error: true + run: | + cargo test --no-fail-fast --test strek_micro --test strek_smoke --test tb_load_live + cargo test --test dos_smoke dos_hex_returns_to_shell_at_800_cycles_per_frame + + # LLVM/SRC32 ツールチェーンと Foundation の受け入れテスト (test_toolchain.py)。 + # Clang は llvmlite が組み込んでいる LLVM と同じメジャーバージョンを使う + # (ずれると -O1/-O2 で "icmp constexprs" エラーになる)。 + toolchain: + name: LLVM toolchain + Foundation tests + needs: rust + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: pip + cache-dependency-path: tools/llvm-src32/requirements.txt + - name: Install Python packages + run: pip install -r tools/llvm-src32/requirements.txt + - name: Install Clang matching llvmlite + run: | + set -e + major=$(python -c "import llvmlite.binding as l; print(l.llvm_version_info[0])") + echo "llvmlite uses LLVM $major" + wget -q https://apt.llvm.org/llvm.sh + sudo bash llvm.sh "$major" + echo "CLANG=/usr/bin/clang-$major" >> "$GITHUB_ENV" + - uses: actions/download-artifact@v4 + with: + name: src32_testbench + path: target/debug + - name: Prepare testbench + run: | + chmod +x target/debug/src32_testbench + echo "SRC32_TESTBENCH=$PWD/target/debug/src32_testbench" >> "$GITHUB_ENV" + - name: Toolchain tests + run: | + "$CLANG" --version + python -m unittest discover -s tools/llvm-src32 -p 'test_*.py' -v + + # sol コンパイラ / VM / LSP、WAX ツール、Foundation WAX ローダのホストテスト。 + # sol の Foundation 実行テストは testbench を使う。 + solc: + name: sol compiler + WAX tests + needs: rust + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - run: pip install pytest + - uses: actions/download-artifact@v4 + with: + name: src32_testbench + path: target/debug + - name: Prepare testbench + run: | + chmod +x target/debug/src32_testbench + echo "SRC32_TESTBENCH=$PWD/target/debug/src32_testbench" >> "$GITHUB_ENV" + - name: pytest + run: python -m pytest tools/solc tools/wax -q + - name: Foundation WAX loader (host) + run: python -m unittest discover -s foundation/tests/wax -v + + wasm-sdk: + name: WASM expansion card SDK + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Package builder tests + run: python -m unittest discover -s sdk/wasm-expansion-card -p 'test_*.py' -v + + # VS Code 拡張 (sol / SRC32 アセンブリ) の .vsix を作って artifact に残す。 + vscode-extensions: + name: VS Code extensions + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: 22 + cache: npm + cache-dependency-path: tools/vscode-sol-syntax/package-lock.json + - name: Package vscode-sol-syntax + working-directory: tools/vscode-sol-syntax + run: | + npm ci + npm run compile + npx vsce package --no-dependencies + - name: Package vscode-src32-asm-syntax + working-directory: tools/vscode-src32-asm-syntax + run: npx --yes @vscode/vsce@3 package --no-dependencies + - uses: actions/upload-artifact@v4 + with: + name: vscode-extensions + path: tools/*/*.vsix + retention-days: 7 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c381d1e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,115 @@ +name: Release + +# v で始まるタグ (例: v0.1.0) を push すると、各 OS の cpt32 バイナリと +# VS Code 拡張の .vsix を GitHub Releases に公開する。 +# 手動実行 (workflow_dispatch) と、このファイルを変更した PR では Release を作らず、 +# 成果物を artifact に残すだけ (ビルドの確認用)。 +on: + push: + tags: ["v*"] + pull_request: + paths: [".github/workflows/release.yml"] + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +jobs: + binaries: + name: Binaries (${{ matrix.name }}) + strategy: + fail-fast: false + matrix: + include: + - name: linux-x86_64 + os: ubuntu-24.04 + ext: "" + - name: windows-x86_64 + os: windows-latest + ext: ".exe" + - name: macos-arm64 + os: macos-latest + ext: "" + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v5 + - name: Install system packages + if: runner.os == 'Linux' + run: sudo apt-get update && sudo apt-get install -y libasound2-dev libudev-dev + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + key: release + - name: Build + run: cargo build --release --bin cpt32 --bin cpt32-tool --bin src32_testbench + - name: Stage files + shell: bash + run: | + set -e + name="cpt32-${GITHUB_REF_NAME//\//-}-${{ matrix.name }}" + dir="dist/$name" + mkdir -p "$dir/assets" + for bin in cpt32 cpt32-tool src32_testbench; do + cp "target/release/$bin${{ matrix.ext }}" "$dir/" + done + cp README.md LICENSE THIRD_PARTY_NOTICES.txt ACKNOWLEDGEMENTS.md config.example.yaml "$dir/" + cp -r licenses "$dir/" + cp assets/bios.rom "$dir/assets/" + echo "PKG_NAME=$name" >> "$GITHUB_ENV" + - name: Archive (zip) + if: runner.os == 'Windows' + shell: pwsh + run: Compress-Archive -Path "dist/$env:PKG_NAME" -DestinationPath "dist/$env:PKG_NAME.zip" + - name: Archive (tar.gz) + if: runner.os != 'Windows' + run: tar -C dist -czf "dist/$PKG_NAME.tar.gz" "$PKG_NAME" + - uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.name }} + path: | + dist/*.zip + dist/*.tar.gz + if-no-files-found: error + + vscode-extensions: + name: VS Code extensions + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: 22 + cache: npm + cache-dependency-path: tools/vscode-sol-syntax/package-lock.json + - name: Package vscode-sol-syntax + working-directory: tools/vscode-sol-syntax + run: | + npm ci + npm run compile + npx vsce package --no-dependencies + - name: Package vscode-src32-asm-syntax + working-directory: tools/vscode-src32-asm-syntax + run: npx --yes @vscode/vsce@3 package --no-dependencies + - uses: actions/upload-artifact@v4 + with: + name: vscode-extensions + path: tools/*/*.vsix + if-no-files-found: error + + release: + name: Publish GitHub Release + if: startsWith(github.ref, 'refs/tags/v') + needs: [binaries, vscode-extensions] + runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + - uses: softprops/action-gh-release@v2 + with: + files: dist/* + generate_release_notes: true + prerelease: ${{ contains(github.ref_name, '-') }} diff --git a/MEMORY.md b/MEMORY.md index 1d0fe10..177f816 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -1050,3 +1050,9 @@ - Fixed llvm-src32 bug: LLVM prints a backslash byte inside c"..." (and quoted names) as `\\`, every other escape as `\XX`; data.py `_quoted_bytes` only knew `\XX`, so any constant byte array or string literal with 0x5C (e.g. "C:\\dir") failed with "invalid LLVM byte escape". Regression: test_backslash_bytes_in_constants. - src32_testbench runs all frames and then treats a non-running CPU as halted, so the idle thread's HALT (all processes exited/blocked) at the end of the budget reads as R1=0 or "did not halt". tests/wax keeps a never-yielding `spin` process. Spawning is slow with interrupts off (11 spawns ~16M cycles at -O0 Scalar), hence --frames 90. - Mutations that the testbench test catches: descriptor origin +4, UGP = 0, regions granted RWX. Zeroing BSS is only caught by the host test (testbench RAM starts zero and exits zero it). + +## GitHub Actions CI (2026-10-22) +- .github/workflows/ci.yml: `rust` builds src32_testbench (debug, uploaded as artifact) and runs the `tests/*.rs` integration tests only; lib unit tests cannot build without the external `s3w2_core` golden .inc files. Guest images dos.bin / tinybasic.bin / dsfs_guest.bin are gitignored, so CI builds them from dos.sol, tinybasic.sol and tools/dsfs/dsfs_smoke.sol (solc.py compile -> asm.py) into the repo root before `cargo test`. +- Known failures run in the `known-failures` job with step-level continue-on-error (PR check stays green, results in the step log): strek_micro, strek_smoke, tb_load_live, and dos_smoke `dos_hex_returns_to_shell_at_800_cycles_per_frame`. strek_verify needs a sibling Tiny-Basic checkout and is not run. When one of these is fixed, move it back into the blocking job. +- `toolchain` installs Clang of the same LLVM major as llvmlite (`llvmlite.binding.llvm_version_info`) via apt.llvm.org and sets CLANG; a mismatched Clang (e.g. Ubuntu's Clang 18 vs llvmlite's LLVM 20+) fails -O1/-O2 with "icmp constexprs". It also needs cmake + ninja (present on ubuntu-24.04 runners). +- Release (CD): .github/workflows/release.yml. Pushing a `v*` tag builds cpt32 / cpt32-tool / src32_testbench in release mode for linux-x86_64, windows-x86_64 and macos-arm64 (archive also carries README, licenses, config.example.yaml, assets/bios.rom) plus both VS Code .vsix files, and publishes them with softprops/action-gh-release (tags containing `-` become prereleases). PRs touching release.yml and workflow_dispatch run the builds without publishing. CI's `vscode-extensions` job also packages the .vsix on every PR.