Files
dingMCP/distribution/bootstrap-windows.template.ps1
T
gitea-admin 40c5021c85
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
fix: make client installation observable
2026-08-18 14:16:17 +00:00

128 lines
6.6 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
$PSNativeCommandUseErrorActionPreference = $false
}
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
$dingSourceBases = @({{NODE_SOURCE_BASES_POWERSHELL}})
$dingInstallerUrl = "{{INSTALLER_URL}}"
$dingInstallerSha256 = "{{INSTALLER_SHA256}}"
$dingPublicKeyUrl = "{{PUBLIC_KEY_URL}}"
$dingPublicKeySha256 = "{{PUBLIC_KEY_SHA256}}"
$dingManifestUrl = "{{MANIFEST_URL}}"
function Write-DingProgress([string] $dingMessage) {
[Console]::Error.WriteLine("[dingtalk-approval] $dingMessage")
}
function Get-DingSha256([string] $dingPath) {
return (Get-FileHash -Algorithm SHA256 -LiteralPath $dingPath).Hash.ToLowerInvariant()
}
function Save-DingDownload([string[]] $dingUrls, [string] $dingTarget, [string] $dingExpectedSha256) {
$dingLastError = $null
foreach ($dingUrl in $dingUrls) {
Write-DingProgress "正在下载并校验:$dingUrl"
try {
if (Test-Path -LiteralPath $dingTarget) { Remove-Item -LiteralPath $dingTarget -Force }
Invoke-WebRequest -UseBasicParsing -Uri $dingUrl -OutFile $dingTarget -TimeoutSec 300
} catch {
$dingLastError = $_.Exception.Message
$dingStatusCode = $null
if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
try { $dingStatusCode = [int]$_.Exception.Response.StatusCode } catch { $dingStatusCode = $null }
}
if ($null -eq $dingStatusCode -or $dingStatusCode -eq 404) { continue }
throw "下载失败且不允许换源(HTTP $dingStatusCode):$dingUrl;$dingLastError"
}
$dingActualSha256 = Get-DingSha256 $dingTarget
if ($dingActualSha256 -ne $dingExpectedSha256) {
throw "下载文件 SHA-256 不匹配,停止安装:$dingUrl"
}
return
}
throw "所有下载源均不可用:$dingLastError"
}
function Test-DingNode([string] $dingNodePath, [bool] $dingRequireAdjacentNpm) {
if (-not $dingNodePath -or -not (Test-Path -LiteralPath $dingNodePath -PathType Leaf)) { return $false }
try {
& $dingNodePath -e 'const [a,b]=process.versions.node.split(".").map(Number);process.exit(a>22||(a===22&&b>=13)?0:1)'
if ($LASTEXITCODE -ne 0) { return $false }
if ($dingRequireAdjacentNpm) {
$dingNpmCli = Join-Path (Split-Path -Parent $dingNodePath) "node_modules\npm\bin\npm-cli.js"
return Test-Path -LiteralPath $dingNpmCli -PathType Leaf
}
return $null -ne (Get-Command npm -ErrorAction SilentlyContinue)
} catch { return $false }
}
$dingArchitecture = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant()
switch ($dingArchitecture) {
"x64" { $dingNodeFile = "{{NODE_WIN32_X64_FILE}}"; $dingNodeSha256 = "{{NODE_WIN32_X64_SHA256}}" }
"arm64" { $dingNodeFile = "{{NODE_WIN32_ARM64_FILE}}"; $dingNodeSha256 = "{{NODE_WIN32_ARM64_SHA256}}" }
default { throw "不支持的 Windows CPU 架构:$dingArchitecture" }
}
Write-DingProgress "1/4 检查 Windows-$dingArchitecture 的 Node/npm 运行环境"
$dingSystemNode = Get-Command node -ErrorAction SilentlyContinue
$dingNodePath = if ($dingSystemNode) { $dingSystemNode.Source } else { $null }
if (-not (Test-DingNode $dingNodePath $false)) {
if (-not $env:LOCALAPPDATA -and -not $env:DINGTALK_APPROVAL_CLIENT_HOME) {
throw "无法确定当前用户数据目录:LOCALAPPDATA 为空"
}
$dingClientRoot = if ($env:DINGTALK_APPROVAL_CLIENT_HOME) {
[IO.Path]::GetFullPath($env:DINGTALK_APPROVAL_CLIENT_HOME)
} else {
Join-Path $env:LOCALAPPDATA "DingTalkApproval"
}
$dingRuntimeParent = Join-Path $dingClientRoot "node"
$dingRuntimeName = [IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetFileNameWithoutExtension($dingNodeFile))
$dingRuntimeDir = Join-Path $dingRuntimeParent $dingRuntimeName
$dingNodePath = Join-Path $dingRuntimeDir "node.exe"
if (-not (Test-DingNode $dingNodePath $true)) {
Write-DingProgress "2/4 系统 Node 不可用,准备插件私有 Node;下载可能需要一些时间"
New-Item -ItemType Directory -Path $dingRuntimeParent -Force | Out-Null
$dingRuntimeTemp = Join-Path ([IO.Path]::GetTempPath()) ("dingmcp-node-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingRuntimeTemp -Force | Out-Null
try {
$dingRuntimeArchive = Join-Path $dingRuntimeTemp $dingNodeFile
$dingRuntimeUrls = @($dingSourceBases | ForEach-Object { $_ + $dingNodeFile })
Save-DingDownload $dingRuntimeUrls $dingRuntimeArchive $dingNodeSha256
$dingExtractRoot = Join-Path $dingRuntimeTemp "extract"
Expand-Archive -LiteralPath $dingRuntimeArchive -DestinationPath $dingExtractRoot -Force
$dingExtractedDir = Join-Path $dingExtractRoot $dingRuntimeName
$dingExtractedNode = Join-Path $dingExtractedDir "node.exe"
if (-not (Test-DingNode $dingExtractedNode $true)) { throw "便携 Node 归档缺少可用的 node.exe 或 npm-cli.js" }
if (Test-Path -LiteralPath $dingRuntimeDir) { Remove-Item -LiteralPath $dingRuntimeDir -Recurse -Force }
Move-Item -LiteralPath $dingExtractedDir -Destination $dingRuntimeDir
} finally {
if (Test-Path -LiteralPath $dingRuntimeTemp) { Remove-Item -LiteralPath $dingRuntimeTemp -Recurse -Force }
}
} else {
Write-DingProgress "2/4 复用已安装的插件私有 Node"
}
} else {
Write-DingProgress "2/4 复用兼容的系统 Node"
}
Write-DingProgress "3/4 下载并校验签名安装器与发布公钥"
$dingInstallTemp = Join-Path ([IO.Path]::GetTempPath()) ("dingmcp-install-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingInstallTemp -Force | Out-Null
try {
$dingInstaller = Join-Path $dingInstallTemp "installer.mjs"
$dingPublicKey = Join-Path $dingInstallTemp "release-signing-public.pem"
Save-DingDownload @($dingInstallerUrl) $dingInstaller $dingInstallerSha256
Save-DingDownload @($dingPublicKeyUrl) $dingPublicKey $dingPublicKeySha256
Write-DingProgress "4/4 执行安装器;最终 JSON 输出到 stdout,阶段进度输出到 stderr"
$dingInstallOutput = & $dingNodePath $dingInstaller install --manifest-url $dingManifestUrl --public-key $dingPublicKey --json
$dingInstallExit = $LASTEXITCODE
if ($dingInstallExit -ne 0) { throw "钉钉审批安装器执行失败:$dingInstallOutput" }
$dingResult = $dingInstallOutput | ConvertFrom-Json
if ($dingResult.ok -ne $true) { throw "钉钉审批安装失败:$($dingResult.error)" }
$dingResult | ConvertTo-Json -Depth 20 -Compress
} finally {
if (Test-Path -LiteralPath $dingInstallTemp) { Remove-Item -LiteralPath $dingInstallTemp -Recurse -Force }
}