Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
branches:
- master

concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
run-tests:
runs-on: blacksmith-4vcpu-ubuntu-2404
Expand Down Expand Up @@ -37,3 +41,115 @@ jobs:
run: |
curl -fsSL https://cli.deepsource.com/install | BINDIR=./bin sh
./bin/deepsource report --analyzer test-coverage --key go --value-file ./coverage.out --use-oidc

# Windows AMD64 coverage: release-equivalent (CGO_ENABLED=0) build, smoke
# tests, installer tests, and PE architecture verification.
windows-amd64:
runs-on: windows-latest
permissions:
contents: read
steps:
- name: Check out code
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Set up Go 1.x
uses: actions/setup-go@v5
with:
go-version: '1.25'

- name: Build release-equivalent binary
env:
CGO_ENABLED: '0'
GOOS: windows
GOARCH: amd64
run: |
cd cmd/deepsource
go build -tags static_all -ldflags "-X 'main.version=0.0.0-ci' -X 'main.buildMode=dev'" -o deepsource-ci.exe .

- name: Smoke test
run: |
& .\cmd\deepsource\deepsource-ci.exe --version
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\cmd\deepsource\deepsource-ci.exe --help
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Verify PE architecture
run: go run ./scripts/verify-pe-arch -arch amd64 cmd/deepsource/deepsource-ci.exe

- name: Run installer tests
shell: pwsh
env:
DEEPSOURCE_EXPECTED_PLATFORM: windows_amd64
run: ./scripts/tests/Run-Tests.ps1

- name: Run Windows-specific Go tests
run: |
go test ./scripts/verify-pe-arch
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
go test ./internal/update -run '^TestWindowsPlatformKey$'
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

# Windows ARM64 coverage on a native ARM64 GitHub-hosted runner
# (windows-11-arm). Host and Go toolchain architecture are asserted to be
# genuinely arm64 before building and smoke-testing a native binary.
windows-arm64:
runs-on: windows-11-arm
permissions:
contents: read
steps:
- name: Check out code
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Set up Go 1.x
uses: actions/setup-go@v5
with:
go-version: '1.25'

- name: Assert native ARM64 host and Go toolchain
shell: pwsh
run: |
$hostArch = $env:PROCESSOR_ARCHITECTURE
if ($hostArch -ne 'ARM64') {
throw "Expected a native ARM64 runner (PROCESSOR_ARCHITECTURE=ARM64), got '$hostArch'"
}
$goHostArch = (go env GOHOSTARCH).Trim()
if ($goHostArch -ne 'arm64') {
throw "Expected Go GOHOSTARCH=arm64, got '$goHostArch'"
}
Write-Host "Verified native ARM64 host: PROCESSOR_ARCHITECTURE=$hostArch, GOHOSTARCH=$goHostArch"

- name: Build release-equivalent binary
env:
CGO_ENABLED: '0'
GOOS: windows
GOARCH: arm64
run: |
cd cmd/deepsource
go build -tags static_all -ldflags "-X 'main.version=0.0.0-ci' -X 'main.buildMode=dev'" -o deepsource-ci.exe .

- name: Smoke test
run: |
& .\cmd\deepsource\deepsource-ci.exe --version
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\cmd\deepsource\deepsource-ci.exe --help
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Verify PE architecture
run: go run ./scripts/verify-pe-arch -arch arm64 cmd/deepsource/deepsource-ci.exe

- name: Run installer tests
shell: pwsh
env:
DEEPSOURCE_EXPECTED_PLATFORM: windows_arm64
run: ./scripts/tests/Run-Tests.ps1

- name: Run Windows-specific Go tests
run: |
go test ./scripts/verify-pe-arch
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
go test ./internal/update -run '^TestWindowsPlatformKey$'
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
31 changes: 22 additions & 9 deletions .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,38 +177,47 @@ jobs:
build-windows:
needs: resolve-env
runs-on: blacksmith-4vcpu-ubuntu-2404
strategy:
matrix:
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}

- name: Install cross-compiler
run: sudo apt-get update && sudo apt-get install -y gcc-mingw-w64-x86-64

- name: Build
env:
CGO_ENABLED: '1'
CGO_ENABLED: '0'
GOOS: windows
GOARCH: amd64
CC: x86_64-w64-mingw32-gcc
CXX: x86_64-w64-mingw32-g++
GOARCH: ${{ matrix.goarch }}
run: |
BINARY_NAME="${{ needs.resolve-env.outputs.binary_name }}"
cd cmd/deepsource && go build -tags static_all \
-ldflags "-X 'main.version=${{ needs.resolve-env.outputs.version }}' -X 'main.Date=$(date -u +%Y-%m-%dT%H:%M:%SZ)' -X 'main.SentryDSN=${{ secrets.SENTRY_DSN }}' -X 'main.buildMode=${{ needs.resolve-env.outputs.environment }}'" \
-o "${BINARY_NAME}.exe" .

- name: Verify PE architecture (raw binary)
run: |
BINARY_NAME="${{ needs.resolve-env.outputs.binary_name }}"
go run ./scripts/verify-pe-arch -arch ${{ matrix.goarch }} "cmd/deepsource/${BINARY_NAME}.exe"

- name: Package
run: |
BINARY_NAME="${{ needs.resolve-env.outputs.binary_name }}"
ARCHIVE="${BINARY_NAME}_${{ needs.resolve-env.outputs.version }}_windows_amd64.zip"
ARCHIVE="${BINARY_NAME}_${{ needs.resolve-env.outputs.version }}_windows_${{ matrix.goarch }}.zip"
zip "$ARCHIVE" -j "cmd/deepsource/${BINARY_NAME}.exe"
sha256sum "$ARCHIVE" > "${ARCHIVE}.sha256"

- name: Verify PE architecture (packaged archive)
run: |
BINARY_NAME="${{ needs.resolve-env.outputs.binary_name }}"
ARCHIVE="${BINARY_NAME}_${{ needs.resolve-env.outputs.version }}_windows_${{ matrix.goarch }}.zip"
go run ./scripts/verify-pe-arch -arch ${{ matrix.goarch }} "$ARCHIVE"

- uses: actions/upload-artifact@v4
with:
name: build-windows-amd64
name: build-windows-${{ matrix.goarch }}
path: |
${{ needs.resolve-env.outputs.binary_name }}_*.zip
${{ needs.resolve-env.outputs.binary_name }}_*.zip.sha256
Expand Down Expand Up @@ -258,6 +267,10 @@ jobs:
"windows_amd64": {
"archive": "${BINARY_NAME}_${VERSION}_windows_amd64.zip",
"sha256": "$(get_sha "${BINARY_NAME}_${VERSION}_windows_amd64.zip")"
},
"windows_arm64": {
"archive": "${BINARY_NAME}_${VERSION}_windows_arm64.zip",
"sha256": "$(get_sha "${BINARY_NAME}_${VERSION}_windows_arm64.zip")"
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ All commands support JSON output for scripting and automation.
curl -sfL https://cli.deepsource.com/install | sh
```

On Windows, use PowerShell:

```powershell
irm https://cli.deepsource.com/install.ps1 | iex
```

The Windows installer selects the native AMD64 or ARM64 artifact advertised by the release
manifest. Native Windows ARM64 availability begins with the first release that includes the
`windows_arm64` artifact.

## Documentation

- [Installation](https://docs.deepsource.com/docs/cli#installation)
Expand Down
23 changes: 23 additions & 0 deletions internal/update/manifest_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//go:build windows

package update

import (
"runtime"
"testing"
)

func TestWindowsPlatformKey(t *testing.T) {
expected := map[string]string{
"amd64": "windows_amd64",
"arm64": "windows_arm64",
}

want, ok := expected[runtime.GOARCH]
if !ok {
t.Skipf("no Windows release artifact for GOARCH=%s", runtime.GOARCH)
}
if got := PlatformKey(); got != want {
t.Fatalf("PlatformKey() = %q, want %q", got, want)
}
}
97 changes: 85 additions & 12 deletions scripts/install.ps1.template
Original file line number Diff line number Diff line change
@@ -1,17 +1,84 @@
# DeepSource CLI installer for Windows
# Wrapped in a scriptblock so that 'return' does not close the host when run via `irm | iex`
# Wrapped in a scriptblock so helper functions do not leak into the host when run via `irm | iex`

$InstallScript = {
param([switch]$SkipInstall)

$BaseUrl = "__BASE_URL__"
$BinaryName = "__BINARY_NAME__"

function Pass($msg) { Write-Host "✓ $msg" -ForegroundColor Green }
function Fail($msg) { Write-Host "✗ $msg" -ForegroundColor Red; return }
function Info($msg) { Write-Host "→ $msg" -ForegroundColor Cyan }

# Get-DeepSourcePlatformKey detects the running architecture and maps it to a
# manifest platform key (e.g. "windows_arm64").
#
# PROCESSOR_ARCHITEW6432 is checked first: it is set by Windows only when the
# current process is running under WOW64 emulation (e.g. an x86/x64 PowerShell
# host launched on an ARM64 machine), and always reflects the *native* host
# architecture in that case. PROCESSOR_ARCHITECTURE reflects the architecture
# of the current process itself, so it is used as the fallback for the common
# (non-emulated) case.
#
# The Architew6432/Architecture parameters default to the real environment
# variables but can be overridden by callers (tests) without mutating process
# environment state.
function Get-DeepSourcePlatformKey {
param(
[string]$Architew6432 = $env:PROCESSOR_ARCHITEW6432,
[string]$Architecture = $env:PROCESSOR_ARCHITECTURE
)

$rawArch = $Architew6432
if ([string]::IsNullOrEmpty($rawArch)) {
$rawArch = $Architecture
}

& {
$ErrorActionPreference = "Stop"
if ([string]::IsNullOrEmpty($rawArch)) {
throw "Unable to determine processor architecture: neither PROCESSOR_ARCHITEW6432 nor PROCESSOR_ARCHITECTURE is set"
}

$BaseUrl = "__BASE_URL__"
$BinaryName = "__BINARY_NAME__"
switch ($rawArch.ToUpperInvariant()) {
"AMD64" { return "windows_amd64" }
"X86_64" { return "windows_amd64" }
"ARM64" { return "windows_arm64" }
"AARCH64" { return "windows_arm64" }
default {
throw "Unsupported architecture '$rawArch': DeepSource CLI does not provide a Windows build for this architecture"
}
}
}

function Pass($msg) { Write-Host "✓ $msg" -ForegroundColor Green }
function Fail($msg) { Write-Host "✗ $msg" -ForegroundColor Red; return }
function Info($msg) { Write-Host "→ $msg" -ForegroundColor Cyan }
# Install-DeepSourceCli runs the full install flow. It is a function (rather
# than inline script) so that 'return' exits only the install routine, not the
# host, when the script is invoked via 'irm | iex'.
#
# BaseUrl/BinaryName/InstallDir/Architew6432/Architecture parameters default to
# the real script-level values / environment variables and only need to be
# overridden by tests.
function Install-DeepSourceCli {
param(
[string]$BaseUrl = $BaseUrl,
[string]$BinaryName = $BinaryName,
[string]$InstallDir = (Join-Path $env:LOCALAPPDATA "DeepSource\bin"),
[string]$Architew6432 = $env:PROCESSOR_ARCHITEW6432,
[string]$Architecture = $env:PROCESSOR_ARCHITECTURE,
# PathScope defaults to User (real, persisted behavior). Tests may pass
# 'Process' so PATH assertions only touch the current process's
# in-memory environment and never persist to the real user profile.
[System.EnvironmentVariableTarget]$PathScope = [System.EnvironmentVariableTarget]::User
)

$PlatformKey = "windows_amd64"
$ErrorActionPreference = "Stop"

try {
$PlatformKey = Get-DeepSourcePlatformKey -Architew6432 $Architew6432 -Architecture $Architecture
} catch {
Fail "$_"
return
}
Pass "Platform: $PlatformKey"

# Fetch manifest
try {
Expand Down Expand Up @@ -58,7 +125,6 @@
Pass "Checksum verified"

# Extract binary
$InstallDir = Join-Path $env:LOCALAPPDATA "DeepSource\bin"
if (-not (Test-Path $InstallDir)) {
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
}
Expand All @@ -83,9 +149,9 @@
Pass "Installed to $InstallDir\$BinaryName.exe"

# Add to user PATH if not already present
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
$UserPath = [Environment]::GetEnvironmentVariable("Path", $PathScope)
if ($UserPath -notlike "*$InstallDir*") {
[Environment]::SetEnvironmentVariable("Path", "$InstallDir;$UserPath", "User")
[Environment]::SetEnvironmentVariable("Path", "$InstallDir;$UserPath", $PathScope)
Pass "Added $InstallDir to user PATH"
Info "Restart your terminal for PATH changes to take effect"
} else {
Expand All @@ -95,3 +161,10 @@
Write-Host ""
Info "Run '$BinaryName' to get started"
}

if (-not $SkipInstall) {
Install-DeepSourceCli
}
}

& $InstallScript
Loading