diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eff0319..1c19395 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,39 @@ jobs: - name: Test run: go test -v ./... + windows-build: + name: Windows Build & Test + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.25.6' + cache: true + + - name: Download dependencies + run: go mod download + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v ./... + + - name: Validate PowerShell installer + shell: pwsh + run: | + $tokens = $null + $errors = $null + [System.Management.Automation.Language.Parser]::ParseFile("install.ps1", [ref]$tokens, [ref]$errors) | Out-Null + if ($errors.Count -gt 0) { + $errors | Format-List * + exit 1 + } + lint: name: Lint runs-on: ubuntu-latest diff --git a/.goreleaser.yaml b/.goreleaser.yaml index b0a4d5e..26f508c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -117,3 +117,7 @@ release: ```bash curl -fsSL https://raw.githubusercontent.com/AndroidPoet/playconsole-cli/main/install.sh | bash ``` + On Windows (PowerShell): + ```powershell + irm https://raw.githubusercontent.com/AndroidPoet/playconsole-cli/main/install.ps1 | iex + ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a59eb0f..64b53a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,16 @@ make build ./playconsole-cli version ``` +On Windows, use PowerShell instead of `make`: + +```powershell +git clone https://github.com/AndroidPoet/playconsole-cli.git +Set-Location playconsole-cli +go build -o bin/playconsole-cli.exe ./cmd/playconsole-cli +go test ./... +.\bin\playconsole-cli.exe version +``` + ## Code Style - Run `go fmt` before committing diff --git a/README.md b/README.md index 7acbf00..046a905 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ gpc bundles upload --file app.aab --track production ## 📦 Installation ```bash -# Homebrew (recommended) +# Homebrew (macOS) brew tap AndroidPoet/tap && brew install playconsole-cli # Install script (Linux/macOS) @@ -52,6 +52,25 @@ git clone https://github.com/AndroidPoet/playconsole-cli.git cd playconsole-cli && make build ``` +### Windows + +From PowerShell, install the latest pre-built release for your Windows architecture: + +```powershell +irm https://raw.githubusercontent.com/AndroidPoet/playconsole-cli/main/install.ps1 | iex +``` + +The installer places `playconsole-cli.exe` and the `gpc.exe` alias in +`%LOCALAPPDATA%\Programs\playconsole-cli` and adds that directory to your user `PATH`. +Open a new terminal after installation. To install a specific release or choose another +directory, set `GPC_VERSION` or `GPC_INSTALL_DIR` before running the command. + +To build from source on Windows, install Go and run: + +```powershell +go install github.com/AndroidPoet/playconsole-cli/cmd/playconsole-cli@latest +``` + After install, you can use either `playconsole-cli` or the shorter alias `gpc`. --- @@ -65,7 +84,7 @@ gpc setup --auto ``` That's it. This will: -- Install `gcloud` if needed (via Homebrew on macOS, or curl on Linux) +- Install `gcloud` if needed (via Homebrew on macOS, curl on Linux, or winget on Windows; Windows may show a UAC prompt) - Log you into Google Cloud - Create a service account and download credentials - Open Play Console for the one manual step (granting access) diff --git a/cmd/playconsole-cli/commands/setup/setup.go b/cmd/playconsole-cli/commands/setup/setup.go index 322bb41..d63dc00 100644 --- a/cmd/playconsole-cli/commands/setup/setup.go +++ b/cmd/playconsole-cli/commands/setup/setup.go @@ -430,6 +430,31 @@ func installGcloud() bool { fmt.Println(" ✓ gcloud installed") return true + case "windows": + if _, err := exec.LookPath("winget"); err != nil { + fmt.Println(" winget was not found.") + fmt.Println(" Install Google Cloud CLI manually: https://cloud.google.com/sdk/docs/install-sdk#windows") + return false + } + + fmt.Println(" Installing via winget...") + cmd := exec.Command("winget", "install", + "--id", "Google.CloudSDK", + "--exact", + "--source", "winget", + "--silent", + "--accept-source-agreements", + "--accept-package-agreements") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Printf(" winget install failed: %v\n", err) + fmt.Println(" Install Google Cloud CLI manually: https://cloud.google.com/sdk/docs/install-sdk#windows") + return false + } + fmt.Println(" ✓ gcloud installed via winget") + return true + default: fmt.Println(" Auto-install not supported on this platform.") fmt.Println(" Install manually: https://cloud.google.com/sdk/install") diff --git a/docs/commands.md b/docs/commands.md index 3504823..b642d93 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -364,8 +364,8 @@ gpc auth login --credentials path/to/service-account.json gpc auth login --credentials-b64 "base64_string" gpc auth list # List profiles gpc auth current # Show active profile -gpc auth switch --profile production # Switch profile -gpc auth delete --profile old-profile +gpc auth switch --name production # Switch profile +gpc auth delete --name old-profile ``` ### setup diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..34eeab4 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,97 @@ +[CmdletBinding()] +param() + +$ErrorActionPreference = "Stop" + +$repo = if ($env:GPC_REPO) { $env:GPC_REPO } else { "AndroidPoet/playconsole-cli" } +$version = if ($env:GPC_VERSION) { $env:GPC_VERSION } else { "latest" } +$installDir = if ($env:GPC_INSTALL_DIR) { + $env:GPC_INSTALL_DIR +} elseif ($env:LOCALAPPDATA) { + Join-Path $env:LOCALAPPDATA "Programs\playconsole-cli" +} else { + Join-Path $env:USERPROFILE "bin\playconsole-cli" +} + +if ($repo -notmatch "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$") { + throw "Invalid GPC_REPO value. Expected owner/repository." +} +if ($version -ne "latest" -and $version -notmatch "^[A-Za-z0-9._-]+$") { + throw "Invalid GPC_VERSION value." +} + +$machineArch = if ($env:PROCESSOR_ARCHITEW6432) { + $env:PROCESSOR_ARCHITEW6432 +} else { + $env:PROCESSOR_ARCHITECTURE +} +$arch = switch ($machineArch.ToUpperInvariant()) { + "AMD64" { "amd64"; break } + "ARM64" { "arm64"; break } + default { throw "Unsupported Windows architecture: $machineArch (supported: amd64, arm64)." } +} + +$releaseEndpoint = if ($version -eq "latest") { + "https://api.github.com/repos/$repo/releases/latest" +} else { + "https://api.github.com/repos/$repo/releases/tags/$version" +} + +$headers = @{ Accept = "application/vnd.github+json" } +if ($env:GITHUB_TOKEN) { + $headers.Authorization = "Bearer $($env:GITHUB_TOKEN)" +} + +$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "playconsole-cli-$([guid]::NewGuid().ToString('N'))" +$archivePath = Join-Path $tempRoot "archive.zip" +$extractDir = Join-Path $tempRoot "extract" + +try { + New-Item -ItemType Directory -Path $tempRoot -Force | Out-Null + Write-Host "==> Fetching playconsole-cli release ($repo, windows/$arch)..." -ForegroundColor Green + + $release = Invoke-RestMethod -Uri $releaseEndpoint -Headers $headers + $asset = @($release.assets | Where-Object { + $_.name -match "^playconsole-cli_.*_windows_${arch}\.zip$" + }) | Select-Object -First 1 + + if (-not $asset) { + throw "No pre-built Windows/$arch asset was found for release '$version'. Install Go and build from source with: go install github.com/$repo/cmd/playconsole-cli@latest" + } + + Write-Host "==> Downloading $($asset.name)..." -ForegroundColor Green + Invoke-WebRequest -Uri $asset.browser_download_url -Headers $headers -OutFile $archivePath + Expand-Archive -LiteralPath $archivePath -DestinationPath $extractDir -Force + + $binary = Get-ChildItem -LiteralPath $extractDir -Filter "playconsole-cli.exe" -File -Recurse | Select-Object -First 1 + if (-not $binary) { + throw "The downloaded archive does not contain playconsole-cli.exe." + } + + New-Item -ItemType Directory -Path $installDir -Force | Out-Null + $target = Join-Path $installDir "playconsole-cli.exe" + Copy-Item -LiteralPath $binary.FullName -Destination $target -Force + + # Windows has no portable user-level symlink equivalent. A copy keeps the + # gpc alias usable without requiring Developer Mode or administrator rights. + Copy-Item -LiteralPath $target -Destination (Join-Path $installDir "gpc.exe") -Force + + $userPath = [Environment]::GetEnvironmentVariable("Path", "User") + $pathEntries = @() + if ($userPath) { + $pathEntries = @($userPath -split ';' | Where-Object { $_ }) + } + if (-not ($pathEntries | Where-Object { $_.TrimEnd('\') -ieq $installDir.TrimEnd('\') })) { + [Environment]::SetEnvironmentVariable("Path", (($pathEntries + $installDir) -join ';'), "User") + $env:Path = "$installDir;$env:Path" + Write-Host "==> Added $installDir to the user PATH." -ForegroundColor Green + } + + Write-Host "==> Installed playconsole-cli to $target" -ForegroundColor Green + & $target version + Write-Host "Installation complete. Open a new terminal, then use 'gpc' or 'playconsole-cli'." -ForegroundColor Green +} finally { + if (Test-Path -LiteralPath $tempRoot) { + Remove-Item -LiteralPath $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } +} diff --git a/install.sh b/install.sh index ae1149b..52dd65c 100755 --- a/install.sh +++ b/install.sh @@ -20,10 +20,11 @@ error() { echo -e "${RED}Error:${NC} $1"; exit 1; } # Detect OS OS=$(uname -s | tr '[:upper:]' '[:lower:]') +WINDOWS_INSTALL=false case "$OS" in darwin) OS="darwin" ;; linux) OS="linux" ;; - mingw*|msys*|cygwin*) OS="windows" ;; + mingw*|msys*|cygwin*) OS="windows"; WINDOWS_INSTALL=true ;; *) error "Unsupported OS: $OS" ;; esac @@ -86,9 +87,17 @@ if [ -z "$DOWNLOAD_URL" ]; then fi cd playconsole-cli - go build -o playconsole-cli ./cmd/playconsole-cli + if [ "$WINDOWS_INSTALL" = true ]; then + go build -o playconsole-cli.exe ./cmd/playconsole-cli + else + go build -o playconsole-cli ./cmd/playconsole-cli + fi mkdir -p "$INSTALL_DIR" - mv playconsole-cli "$INSTALL_DIR/playconsole-cli" + if [ "$WINDOWS_INSTALL" = true ]; then + mv playconsole-cli.exe "$INSTALL_DIR/playconsole-cli.exe" + else + mv playconsole-cli "$INSTALL_DIR/playconsole-cli" + fi cd / rm -rf "$TMPDIR" else @@ -112,19 +121,30 @@ else # Install mkdir -p "$INSTALL_DIR" - mv playconsole-cli "$INSTALL_DIR/playconsole-cli" + if [ "$WINDOWS_INSTALL" = true ]; then + mv playconsole-cli.exe "$INSTALL_DIR/playconsole-cli.exe" + else + mv playconsole-cli "$INSTALL_DIR/playconsole-cli" + fi cd / rm -rf "$TMPDIR" fi -chmod +x "$INSTALL_DIR/playconsole-cli" - -# Create gpc alias -ln -sf "$INSTALL_DIR/playconsole-cli" "$INSTALL_DIR/gpc" - -info "Installed playconsole-cli to $INSTALL_DIR/playconsole-cli" -info "Created alias: gpc -> playconsole-cli" +if [ "$WINDOWS_INSTALL" = true ]; then + # Symlinks may require Developer Mode or elevation on Windows. A copy works + # in Git Bash without changing the user's system policy. + cp "$INSTALL_DIR/playconsole-cli.exe" "$INSTALL_DIR/gpc.exe" + BINARY_PATH="$INSTALL_DIR/playconsole-cli.exe" + info "Installed playconsole-cli to $BINARY_PATH" + info "Created alias: gpc.exe" +else + chmod +x "$INSTALL_DIR/playconsole-cli" + ln -sf "$INSTALL_DIR/playconsole-cli" "$INSTALL_DIR/gpc" + BINARY_PATH="$INSTALL_DIR/playconsole-cli" + info "Installed playconsole-cli to $BINARY_PATH" + info "Created alias: gpc -> playconsole-cli" +fi # Check PATH if ! echo "$PATH" | tr ':' '\n' | grep -q "^$INSTALL_DIR$"; then @@ -135,10 +155,10 @@ if ! echo "$PATH" | tr ':' '\n' | grep -q "^$INSTALL_DIR$"; then fi # Verify installation -if "$INSTALL_DIR/playconsole-cli" version &>/dev/null; then +if "$BINARY_PATH" version &>/dev/null; then info "Installation complete!" echo "" - "$INSTALL_DIR/playconsole-cli" version + "$BINARY_PATH" version else - warn "Installed but could not verify. Try running: $INSTALL_DIR/playconsole-cli --help" + warn "Installed but could not verify. Try running: $BINARY_PATH --help" fi