Skip to content

Commit cd89843

Browse files
committed
feat: add install.ps1
Mirrors install.sh: pinned version bumped by release-please, sha256 from checksums.txt, ~\.local\bin, PATH edited unless told otherwise. Two Windows-specific wrinkles. PATH goes through the HKCU\Environment registry key as ExpandString, because [Environment]::SetEnvironmentVariable rewrites REG_EXPAND_SZ as REG_SZ and would break any %VAR% already in PATH; a dummy User-scope write then broadcasts WM_SETTINGCHANGE so open shells reread it. And `iex` cannot pass arguments, so the parameters are backed by the same FLAGSMITH_* environment variables and the docs show the scriptblock form. Add-CiPath appends the install dir to $GITHUB_PATH, so a GitHub Actions step after the install finds the CLI on PATH — which is what the release smoke job relies on. beep boop
1 parent bf91455 commit cd89843

5 files changed

Lines changed: 206 additions & 1 deletion

File tree

.github/workflows/pull-request.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ jobs:
4444
version: v2.11.4 # keep in step with the hook rev in .pre-commit-config.yaml
4545
- run: go mod tidy -diff
4646

47+
install-ps1:
48+
name: install.ps1 lint
49+
runs-on: windows-latest
50+
steps:
51+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52+
with:
53+
persist-credentials: false
54+
- name: PSScriptAnalyzer
55+
shell: pwsh
56+
run: |
57+
Install-Module PSScriptAnalyzer -Force -Scope CurrentUser -SkipPublisherCheck
58+
$found = Invoke-ScriptAnalyzer -Path ./install.ps1 -Severity Warning, Error
59+
$found | Format-Table -AutoSize
60+
if ($found) { exit 1 }
61+
- run: ./install.ps1 -DryRun
62+
shell: pwsh
63+
4764
cross-compile:
4865
runs-on: ubuntu-latest
4966
steps:

.github/workflows/release.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,16 @@ jobs:
6464
persist-credentials: false
6565
- run: sh install.sh --version "$GITHUB_REF_NAME" --bin-dir "$RUNNER_TEMP/bin"
6666
- run: flagsmith --version
67+
68+
install-script-windows:
69+
name: install.ps1
70+
needs: goreleaser
71+
runs-on: windows-latest
72+
steps:
73+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
74+
with:
75+
persist-credentials: false
76+
- run: ./install.ps1 -Version $env:GITHUB_REF_NAME
77+
shell: pwsh
78+
- run: flagsmith --version
79+
shell: pwsh

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ To pin the installer itself, fetch it at a commit you trust: `raw.githubusercont
2121

2222
Alternatively, `go install github.com/Flagsmith/flagsmith-cli@latest`, or grab an archive from [Releases](https://github.com/Flagsmith/flagsmith-cli/releases).
2323

24+
On Windows:
25+
26+
```powershell
27+
irm https://raw.githubusercontent.com/Flagsmith/flagsmith-cli/main/install.ps1 | iex
28+
```
29+
2430
## Build
2531

2632
```sh

install.ps1

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#Requires -Version 5.1
2+
<#
3+
.SYNOPSIS
4+
Install the Flagsmith CLI.
5+
.DESCRIPTION
6+
irm https://get.flagsmith.com/install.ps1 | iex
7+
8+
`iex` cannot pass arguments, so either set the environment variables below
9+
first, or invoke a script block:
10+
11+
&([scriptblock]::Create((irm https://get.flagsmith.com/install.ps1))) -Version <tag>
12+
.PARAMETER Version
13+
Version to install. Defaults to $env:FLAGSMITH_CLI_VERSION, else the version
14+
this script shipped with.
15+
.PARAMETER BinDir
16+
Where to install. Defaults to $env:FLAGSMITH_INSTALL_DIR, else ~\.local\bin.
17+
.PARAMETER NoModifyPath
18+
Leave the user PATH alone. Also $env:FLAGSMITH_NO_MODIFY_PATH.
19+
.PARAMETER DryRun
20+
Report what would be installed, then stop.
21+
#>
22+
param(
23+
[string]$Version,
24+
[string]$BinDir,
25+
[switch]$NoModifyPath,
26+
[switch]$DryRun
27+
)
28+
29+
$ErrorActionPreference = 'Stop'
30+
# Invoke-WebRequest spends most of its time drawing the progress bar.
31+
$ProgressPreference = 'SilentlyContinue'
32+
33+
$DefaultVersion = 'v2.0.0-beta.1' # x-release-please-version
34+
35+
$Repo = 'Flagsmith/flagsmith-cli'
36+
$ExeName = 'flagsmith.exe'
37+
$BaseUrl = if ($env:FLAGSMITH_CLI_BASE_URL) {
38+
$env:FLAGSMITH_CLI_BASE_URL
39+
} else {
40+
"https://github.com/$Repo/releases/download"
41+
}
42+
43+
function Get-TargetArch {
44+
$arch = try {
45+
[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()
46+
} catch {
47+
# PROCESSOR_ARCHITECTURE from the registry, not the environment: a 32-bit
48+
# PowerShell under WOW64 reports x86 for its own process.
49+
(Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment').PROCESSOR_ARCHITECTURE
50+
}
51+
switch -Regex ($arch) {
52+
'^(X64|AMD64)$' { return 'amd64' }
53+
'^ARM64$' { return 'arm64' }
54+
default { throw "unsupported architecture '$arch'" }
55+
}
56+
}
57+
58+
function Get-Checksum {
59+
param([string]$SumsFile, [string]$Name)
60+
61+
$pattern = '\s\*?' + [regex]::Escape($Name) + '$'
62+
$lines = @(Get-Content -LiteralPath $SumsFile | Where-Object { $_ -match $pattern })
63+
if ($lines.Count -ne 1) {
64+
throw "expected exactly one checksum for $Name in checksums.txt, found $($lines.Count)"
65+
}
66+
return ($lines[0] -split '\s+')[0]
67+
}
68+
69+
# Add-UserPath adds to the user PATH through the registry rather than
70+
# [Environment]::SetEnvironmentVariable, which rewrites REG_EXPAND_SZ as REG_SZ
71+
# and so breaks any %VAR% already in PATH.
72+
function Add-UserPath {
73+
param([string]$Dir)
74+
75+
$key = 'registry::HKEY_CURRENT_USER\Environment'
76+
$current = (Get-Item -LiteralPath $key).GetValue('Path', '', 'DoNotExpandEnvironmentNames') -split ';' -ne ''
77+
if ($Dir -in $current) { return $false }
78+
79+
Set-ItemProperty -LiteralPath $key -Name Path -Type ExpandString -Value ((, $Dir + $current) -join ';')
80+
# Tell running shells and Explorer to reread the environment.
81+
$dummy = 'flagsmith-' + [guid]::NewGuid().ToString()
82+
[Environment]::SetEnvironmentVariable($dummy, 'x', 'User')
83+
[Environment]::SetEnvironmentVariable($dummy, [NullString]::Value, 'User')
84+
return $true
85+
}
86+
87+
# Add-CiPath makes the CLI available to later steps of a GitHub Actions job.
88+
function Add-CiPath {
89+
param([string]$Dir)
90+
91+
if ($env:GITHUB_PATH) {
92+
Write-Output $Dir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
93+
}
94+
}
95+
96+
if (-not $Version) {
97+
$Version = if ($env:FLAGSMITH_CLI_VERSION) { $env:FLAGSMITH_CLI_VERSION } else { $DefaultVersion }
98+
}
99+
if ($Version -notlike 'v*') { $Version = "v$Version" }
100+
101+
if (-not $BinDir) {
102+
$BinDir = if ($env:FLAGSMITH_INSTALL_DIR) {
103+
$env:FLAGSMITH_INSTALL_DIR
104+
} else {
105+
Join-Path $env:USERPROFILE '.local\bin'
106+
}
107+
}
108+
if ($env:FLAGSMITH_NO_MODIFY_PATH) { $NoModifyPath = $true }
109+
110+
$arch = Get-TargetArch
111+
$archive = "flagsmith_$($Version.TrimStart('v'))_windows_$arch.zip"
112+
$archiveUrl = "$BaseUrl/$Version/$archive"
113+
$sumsUrl = "$BaseUrl/$Version/checksums.txt"
114+
115+
if ($DryRun) {
116+
Write-Output "would install flagsmith $Version (windows/$arch) to $BinDir"
117+
Write-Output " archive: $archiveUrl"
118+
Write-Output " checksums: $sumsUrl"
119+
return
120+
}
121+
122+
# PowerShell 5.1 still defaults to TLS 1.0, which github.com refuses.
123+
if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') {
124+
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
125+
}
126+
127+
$tmp = New-Item -ItemType Directory -Path (Join-Path ([System.IO.Path]::GetTempPath()) ([guid]::NewGuid()))
128+
try {
129+
Write-Output "downloading flagsmith $Version (windows/$arch)"
130+
$zip = Join-Path $tmp $archive
131+
$sums = Join-Path $tmp 'checksums.txt'
132+
try {
133+
Invoke-WebRequest -Uri $archiveUrl -OutFile $zip -UseBasicParsing
134+
} catch {
135+
throw "cannot download $archiveUrl`nIf $Version was released moments ago its archives may still be uploading - retry shortly, or choose a version with -Version."
136+
}
137+
Invoke-WebRequest -Uri $sumsUrl -OutFile $sums -UseBasicParsing
138+
139+
$expected = Get-Checksum -SumsFile $sums -Name $archive
140+
$actual = (Get-FileHash -LiteralPath $zip -Algorithm SHA256).Hash
141+
if ($actual -ne $expected.ToUpperInvariant()) {
142+
throw "checksum mismatch for ${archive}: expected $expected, got $actual"
143+
}
144+
145+
Expand-Archive -LiteralPath $zip -DestinationPath $tmp -Force
146+
New-Item -ItemType Directory -Force -Path $BinDir | Out-Null
147+
Move-Item -Force -LiteralPath (Join-Path $tmp $ExeName) -Destination (Join-Path $BinDir $ExeName)
148+
} finally {
149+
Remove-Item -Recurse -Force -LiteralPath $tmp
150+
}
151+
152+
$exe = Join-Path $BinDir $ExeName
153+
$installed = & $exe --version
154+
if ($LASTEXITCODE -ne 0) { throw "$exe was installed but will not run" }
155+
Write-Output "installed $installed to $exe"
156+
157+
$pathAdded = $false
158+
if (-not $NoModifyPath) {
159+
$pathAdded = Add-UserPath -Dir $BinDir
160+
Add-CiPath -Dir $BinDir
161+
}
162+
163+
Write-Output ''
164+
if ($pathAdded) {
165+
Write-Output "Open a new terminal, then run 'flagsmith init' to get started."
166+
} else {
167+
Write-Output "Run 'flagsmith init' to get started."
168+
}

release-please-config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"draft": false,
1111
"include-component-in-tag": false,
1212
"extra-files": [
13-
"install.sh"
13+
"install.sh",
14+
"install.ps1"
1415
]
1516
}
1617
},

0 commit comments

Comments
 (0)