linguo 1.3.0

Cross-platform, multi-language runtime, package, and project manager
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy
      - uses: Swatinem/rust-cache@v2
      # An invalid workflow file silently loses its triggers on GitHub;
      # fail loudly here instead.
      - name: Workflow files parse
        run: |
          python3 - <<'PY'
          import glob, yaml
          for f in glob.glob('.github/workflows/*.yml'):
              d = yaml.safe_load(open(f))
              assert 'jobs' in d and (True in d or 'on' in d), f
              print(f, 'ok:', list(d['jobs']))
          PY
      - run: cargo fmt --all -- --check
      - run: cargo clippy --all-targets -- -D warnings
      - run: cargo test
      # Keep the release packaging honest on every push, not just release day.
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-deb,cargo-generate-rpm
      - name: Package deb and rpm
        run: |
          cargo build --release
          cargo deb --no-build
          cargo generate-rpm
          ls target/debian/*.deb target/generate-rpm/*.rpm
      # Keeps the Launchpad PPA source packaging honest: assembles the
      # vendored orig tarball and runs dpkg-buildpackage -S unsigned.
      - name: PPA source package builds
        run: |
          sudo apt-get update && sudo apt-get install -y devscripts debhelper
          version=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
          ./packaging/ppa/build-source.sh "$version" noble
      # Exercises the curl installer's Linux path against the latest release.
      - name: Install script smoke test
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          LINGUO_INSTALL_DIR="$RUNNER_TEMP/install-sh-bin" sh install.sh
          "$RUNNER_TEMP/install-sh-bin/linguo" --version

  test-musl:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-unknown-linux-musl
      - uses: Swatinem/rust-cache@v2
      - run: sudo apt-get update && sudo apt-get install -y musl-tools
      # Static musl test binaries run fine on the glibc host.
      - run: cargo test --target x86_64-unknown-linux-musl
      - run: cargo build --release --target x86_64-unknown-linux-musl
      # The real thing: the static binary inside a vanilla Alpine container.
      - name: Alpine smoke test
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          docker run --rm -e GITHUB_TOKEN \
            -v "$PWD/target/x86_64-unknown-linux-musl/release/linguo:/usr/local/bin/linguo:ro" \
            alpine:latest sh -ec '
              export LINGUO_ROOT=/tmp/linguo-root
              linguo python install 3.12
              mkdir /tmp/py && cd /tmp/py
              linguo python init demo
              linguo python run -- python -c "print(\"python on musl ok\")"

              linguo ruby install 3.4
              mkdir /tmp/rb && cd /tmp/rb
              linguo ruby use 3.4
              linguo ruby run -- ruby -e "puts \"ruby on musl ok\""

              linguo tf install 1.13
              mkdir /tmp/tf && cd /tmp/tf
              linguo tf use 1.13
              linguo tf run -- terraform version

              linguo zig install 0.16
              mkdir /tmp/zg && cd /tmp/zg
              linguo zig use 0.16
              linguo zig run -- zig version

              linguo php install 8.5
              mkdir /tmp/ph && cd /tmp/ph
              linguo php init
              linguo php run -- php -r "echo \"php on musl ok\n\";"
              linguo php run -- composer --version

              linguo jvm install 21
              mkdir /tmp/jv && cd /tmp/jv
              linguo jvm use 21
              linguo jvm run -- java -version
              linguo groovy install
              linguo groovy use 5
              linguo groovy run -- groovy -e "println \"groovy on musl ok\""

              # node and go have no official musl builds: expect honest errors
              linguo node install 2>/dev/null && exit 1 || echo "node bails as expected"
              linguo go install 2>/dev/null && exit 1 || echo "go bails as expected"

              linguo status
            '

  test-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo test
      - run: cargo build
      # Real end-to-end exercise of every Windows-supported backend:
      # install, project init, and running a command through the toolchain.
      - name: Smoke test (python, node, go, terraform)
        shell: bash
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          set -euo pipefail
          export LINGUO_ROOT="$RUNNER_TEMP/linguo-root"
          linguo() { "$GITHUB_WORKSPACE/target/debug/linguo.exe" "$@"; }

          linguo python install 3.12
          mkdir "$RUNNER_TEMP/py-demo" && cd "$RUNNER_TEMP/py-demo"
          linguo python init demo
          linguo python add requests
          linguo python run -- python -c "import requests; print('python ok')"
          linguo python which

          linguo node install 24
          mkdir "$RUNNER_TEMP/node-demo" && cd "$RUNNER_TEMP/node-demo"
          linguo node init demo
          linguo node add left-pad
          linguo node run -- node -e "require('left-pad'); console.log('node ok')"
          linguo node which

          linguo go install
          mkdir "$RUNNER_TEMP/go-demo" && cd "$RUNNER_TEMP/go-demo"
          linguo go init demo
          linguo go run -- go version
          linguo go which

          linguo tf install 1.13
          mkdir "$RUNNER_TEMP/tf-demo" && cd "$RUNNER_TEMP/tf-demo"
          linguo tf use 1.13
          linguo tf run -- terraform version
          linguo tf which

          linguo ruby install 3.4
          mkdir "$RUNNER_TEMP/rb-demo" && cd "$RUNNER_TEMP/rb-demo"
          linguo ruby use 3.4
          linguo ruby run -- ruby -e "puts 'ruby on windows ok'"
          linguo ruby init
          linguo ruby add rake
          linguo ruby which rake

          linguo php install 8.5
          mkdir "$RUNNER_TEMP/php-demo" && cd "$RUNNER_TEMP/php-demo"
          linguo php init
          linguo php run -- php -r "echo 'php on windows ok';"
          linguo php run -- composer --version
          linguo php which

          linguo jvm install 21
          mkdir "$RUNNER_TEMP/jvm-demo" && cd "$RUNNER_TEMP/jvm-demo"
          linguo jvm use 21
          linguo jvm run -- java -version
          linguo groovy install
          linguo groovy use 5
          linguo groovy run -- groovy -e "println 'groovy on windows ok'"
          linguo groovy which

          linguo zig install 0.16
          mkdir "$RUNNER_TEMP/zig-demo" && cd "$RUNNER_TEMP/zig-demo"
          linguo zig use 0.16
          linguo zig run -- zig version
          linguo zig which

          linguo rust install 1.96
          mkdir "$RUNNER_TEMP/rust-demo" && cd "$RUNNER_TEMP/rust-demo"
          linguo rust init demo
          linguo rust run -- cargo run --quiet
          linguo rust which

          linguo status
      - name: Smoke test (PowerShell hook)
        shell: pwsh
        run: |
          $env:LINGUO_ROOT = Join-Path $env:RUNNER_TEMP "linguo-root"
          # The emitted hook re-invokes `linguo`, so it must be on PATH.
          $env:PATH = "$env:GITHUB_WORKSPACE\target\debug;$env:PATH"
          linguo activate powershell | Out-String | Invoke-Expression
          Set-Location (Join-Path $env:RUNNER_TEMP "py-demo")
          _linguo_hook
          $py = (Get-Command python).Source
          if ($py -notlike "*py-demo*") { throw "hook did not activate venv python: $py" }
          python -c "print('powershell hook ok')"
      - name: Package MSI
        shell: bash
        run: |
          cargo install cargo-wix --locked
          cargo wix --nocapture
          ls target/wix/*.msi
      # Keeps the Chocolatey packaging honest: render and pack (no push).
      - name: Chocolatey package builds
        shell: bash
        run: |
          version=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
          ./packaging/chocolatey/generate.sh "$version" \
            0000000000000000000000000000000000000000000000000000000000000000 choco-out
          choco pack choco-out/linguo.nuspec --outputdirectory choco-out
          ls choco-out/*.nupkg