diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0861abe..b5468cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,12 @@ env: jobs: test: - runs-on: macos-latest + name: Test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 @@ -40,6 +45,23 @@ jobs: - name: Run tests run: cargo test + lint: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-lint-${{ hashFiles('**/Cargo.lock') }} + - name: Check formatting run: cargo fmt -- --check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 390d9d4..4667b51 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,6 +41,12 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest archive: tar.gz + - target: x86_64-pc-windows-msvc + os: windows-latest + archive: zip + - target: aarch64-pc-windows-msvc + os: windows-latest + archive: zip steps: - name: Checkout @@ -67,12 +73,19 @@ jobs: if: matrix.target != 'aarch64-unknown-linux-gnu' run: cargo build --release --target ${{ matrix.target }} -p icm-cli - - name: Package + - name: Package (Unix) + if: matrix.archive == 'tar.gz' run: | cd target/${{ matrix.target }}/release tar -czvf ../../../icm-${{ matrix.target }}.${{ matrix.archive }} icm cd ../../.. + - name: Package (Windows) + if: matrix.archive == 'zip' + shell: pwsh + run: | + Compress-Archive -Path "target/${{ matrix.target }}/release/icm.exe" -DestinationPath "icm-${{ matrix.target }}.zip" + - name: Upload artifact uses: actions/upload-artifact@v4 with: @@ -106,7 +119,7 @@ jobs: - name: Flatten artifacts run: | mkdir -p release - find artifacts -type f -name "*.tar.gz" -exec cp {} release/ \; + find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" \) -exec cp {} release/ \; - name: Create checksums run: | diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..c5212d5 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,57 @@ +# icm installer for Windows - https://github.com/rtk-ai/icm +# Usage: irm https://raw.githubusercontent.com/rtk-ai/icm/main/install.ps1 | iex + +$ErrorActionPreference = "Stop" + +$Repo = "rtk-ai/icm" +$BinaryName = "icm" + +function Get-Arch { + $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture + switch ($arch) { + "X64" { return "x86_64" } + "Arm64" { return "aarch64" } + default { throw "Unsupported architecture: $arch" } + } +} + +function Get-LatestVersion { + $release = Invoke-RestMethod "https://api.github.com/repos/$Repo/releases/latest" + return $release.tag_name +} + +$Arch = Get-Arch +$Version = Get-LatestVersion +$Target = "$Arch-pc-windows-msvc" +$InstallDir = Join-Path $env:LOCALAPPDATA "icm\bin" + +Write-Host "[INFO] Installing $BinaryName $Version ($Arch)..." -ForegroundColor Green + +# Create install directory +New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null + +# Download +$Url = "https://github.com/$Repo/releases/download/$Version/$BinaryName-$Target.zip" +$TempZip = Join-Path $env:TEMP "$BinaryName.zip" +Write-Host "[INFO] Downloading from: $Url" -ForegroundColor Green +Invoke-WebRequest -Uri $Url -OutFile $TempZip + +# Extract +$TempDir = Join-Path $env:TEMP "$BinaryName-extract" +if (Test-Path $TempDir) { Remove-Item -Recurse -Force $TempDir } +Expand-Archive -Path $TempZip -DestinationPath $TempDir +Copy-Item (Join-Path $TempDir "$BinaryName.exe") -Destination $InstallDir -Force + +# Cleanup +Remove-Item $TempZip -Force +Remove-Item $TempDir -Recurse -Force + +# Add to PATH if not already there +$UserPath = [Environment]::GetEnvironmentVariable("Path", "User") +if ($UserPath -notlike "*$InstallDir*") { + [Environment]::SetEnvironmentVariable("Path", "$UserPath;$InstallDir", "User") + Write-Host "[INFO] Added $InstallDir to user PATH (restart terminal to apply)" -ForegroundColor Yellow +} + +Write-Host "[INFO] Successfully installed to $InstallDir\$BinaryName.exe" -ForegroundColor Green +Write-Host "[INFO] Run '$BinaryName --help' to get started." -ForegroundColor Green diff --git a/install.sh b/install.sh index 50683ec..6662087 100755 --- a/install.sh +++ b/install.sh @@ -21,7 +21,8 @@ detect_os() { case "$(uname -s)" in Darwin*) OS="darwin"; TARGET_SUFFIX="apple-darwin";; Linux*) OS="linux"; TARGET_SUFFIX="unknown-linux-gnu";; - *) error "Unsupported OS: $(uname -s). icm supports macOS and Linux.";; + MINGW*|MSYS*|CYGWIN*) OS="windows"; TARGET_SUFFIX="pc-windows-msvc";; + *) error "Unsupported OS: $(uname -s). icm supports macOS, Linux and Windows.";; esac } @@ -45,9 +46,17 @@ install() { info "Detected: ${OS} ${ARCH}" info "Version: ${VERSION}" - DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/${BINARY_NAME}-${TARGET}.tar.gz" + if [ "$OS" = "windows" ]; then + EXT="zip" + INSTALL_DIR="${LOCALAPPDATA:-$HOME}/icm/bin" + mkdir -p "$INSTALL_DIR" + else + EXT="tar.gz" + fi + + DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/${BINARY_NAME}-${TARGET}.${EXT}" TEMP_DIR=$(mktemp -d) - ARCHIVE="${TEMP_DIR}/${BINARY_NAME}.tar.gz" + ARCHIVE="${TEMP_DIR}/${BINARY_NAME}.${EXT}" info "Downloading from: ${DOWNLOAD_URL}" if ! curl -fsSL "$DOWNLOAD_URL" -o "$ARCHIVE"; then @@ -55,18 +64,21 @@ install() { fi info "Extracting..." - tar -xzf "$ARCHIVE" -C "$TEMP_DIR" - - if [ -w "$INSTALL_DIR" ]; then - mv "${TEMP_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/" + if [ "$OS" = "windows" ]; then + unzip -o "$ARCHIVE" -d "$TEMP_DIR" + mv "${TEMP_DIR}/${BINARY_NAME}.exe" "${INSTALL_DIR}/" else - info "Requesting sudo to install to ${INSTALL_DIR}" - sudo mv "${TEMP_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/" + tar -xzf "$ARCHIVE" -C "$TEMP_DIR" + if [ -w "$INSTALL_DIR" ]; then + mv "${TEMP_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/" + else + info "Requesting sudo to install to ${INSTALL_DIR}" + sudo mv "${TEMP_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/" + fi + chmod +x "${INSTALL_DIR}/${BINARY_NAME}" fi - chmod +x "${INSTALL_DIR}/${BINARY_NAME}" rm -rf "$TEMP_DIR" - info "Successfully installed ${BINARY_NAME} to ${INSTALL_DIR}/${BINARY_NAME}" }