From d49087027e8c788cd32b253f02ef21b64954c1b0 Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Wed, 8 Jul 2026 23:24:32 +0800 Subject: [PATCH] chore(release): include cli install scripts --- .github/workflows/rust-release.yml | 49 +++++++++++++++++ RELEASE_NOTES/v0.8.0.md | 15 ++++++ scripts/install-op.ps1 | 84 ++++++++++++++++++++++++++++++ scripts/install-op.sh | 75 ++++++++++++++++++-------- 4 files changed, 201 insertions(+), 22 deletions(-) create mode 100644 scripts/install-op.ps1 diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml index 872136124..f8c08333e 100644 --- a/.github/workflows/rust-release.yml +++ b/.github/workflows/rust-release.yml @@ -444,6 +444,7 @@ jobs: echo "::error::NPM_TOKEN is required to publish web SDK packages" exit 1 fi + echo "::notice::NPM_TOKEN must be scoped for @zseven-w packages and have bypass 2FA enabled" printf '//registry.npmjs.org/:_authToken=%s\n' "$NPM_TOKEN" > ~/.npmrc npm whoami - name: Build wasm-backed SDK packages @@ -529,6 +530,54 @@ jobs: echo "::error::expected 3 SDK tarballs, found ${#sdk[@]}" exit 1 fi + - name: Generate CLI install scripts + shell: bash + run: | + set -euo pipefail + tag="$GITHUB_REF_NAME" + version="${tag#v}" + + sha_file() { + sha256sum "release-files/$1" | awk '{print $1}' + } + + cli_mac_arm_sha="$(sha_file "op-cli-macos-aarch64.tar.gz")" + cli_mac_x64_sha="$(sha_file "op-cli-macos-x86_64.tar.gz")" + cli_linux_arm_sha="$(sha_file "op-cli-linux-aarch64.tar.gz")" + cli_linux_x64_sha="$(sha_file "op-cli-linux-x86_64.tar.gz")" + cli_win_arm_sha="$(sha_file "op-cli-windows-aarch64.zip")" + cli_win_x64_sha="$(sha_file "op-cli-windows-x86_64.zip")" + + cp scripts/install-op.sh release-files/install-op.sh + cp scripts/install-op.ps1 release-files/install-op.ps1 + OP_INSTALLER_VERSION="$version" \ + OP_SHA_MACOS_AARCH64="$cli_mac_arm_sha" \ + OP_SHA_MACOS_X86_64="$cli_mac_x64_sha" \ + OP_SHA_LINUX_AARCH64="$cli_linux_arm_sha" \ + OP_SHA_LINUX_X86_64="$cli_linux_x64_sha" \ + perl -0pi -e ' + s/^DEFAULT_OP_VERSION=.*/DEFAULT_OP_VERSION="$ENV{OP_INSTALLER_VERSION}"/m; + s/^DEFAULT_SHA_MACOS_AARCH64=.*/DEFAULT_SHA_MACOS_AARCH64="$ENV{OP_SHA_MACOS_AARCH64}"/m; + s/^DEFAULT_SHA_MACOS_X86_64=.*/DEFAULT_SHA_MACOS_X86_64="$ENV{OP_SHA_MACOS_X86_64}"/m; + s/^DEFAULT_SHA_LINUX_AARCH64=.*/DEFAULT_SHA_LINUX_AARCH64="$ENV{OP_SHA_LINUX_AARCH64}"/m; + s/^DEFAULT_SHA_LINUX_X86_64=.*/DEFAULT_SHA_LINUX_X86_64="$ENV{OP_SHA_LINUX_X86_64}"/m; + ' release-files/install-op.sh + OP_INSTALLER_VERSION="$version" \ + OP_SHA_WINDOWS_AARCH64="$cli_win_arm_sha" \ + OP_SHA_WINDOWS_X86_64="$cli_win_x64_sha" \ + perl -0pi -e ' + s/^\$DefaultOpVersion = .*/\$DefaultOpVersion = "$ENV{OP_INSTALLER_VERSION}"/m; + s/^\$DefaultShaWindowsAarch64 = .*/\$DefaultShaWindowsAarch64 = "$ENV{OP_SHA_WINDOWS_AARCH64}"/m; + s/^\$DefaultShaWindowsX86_64 = .*/\$DefaultShaWindowsX86_64 = "$ENV{OP_SHA_WINDOWS_X86_64}"/m; + ' release-files/install-op.ps1 + chmod +x release-files/install-op.sh + if grep -E 'DEFAULT_OP_VERSION=""|DEFAULT_SHA_(MACOS|LINUX)_[A-Z0-9_]+=""|\$Default(OpVersion|ShaWindows[A-Za-z0-9_]+) = ""' \ + release-files/install-op.sh release-files/install-op.ps1; then + echo "::error::CLI install scripts still contain unstamped release metadata" + exit 1 + fi + grep -q "$version" release-files/install-op.sh + grep -q "$version" release-files/install-op.ps1 - name: Prepare release body shell: bash run: | diff --git a/RELEASE_NOTES/v0.8.0.md b/RELEASE_NOTES/v0.8.0.md index f4150e083..2e7d49a32 100644 --- a/RELEASE_NOTES/v0.8.0.md +++ b/RELEASE_NOTES/v0.8.0.md @@ -18,6 +18,21 @@ - Linux: `OpenPencil-0.8.0--linux.AppImage`, `OpenPencil-0.8.0--linux.deb`, plus raw desktop and `op` CLI archives. - Web SDK: published npm packages and attached npm tarballs for the base SDK, React adapter, and Vue adapter. - Package managers: Homebrew cask/formula and Scoop desktop/CLI manifests. +- CLI installers: `install-op.sh` and `install-op.ps1`. + +## CLI Install + +macOS / Linux: + +```sh +curl -fsSL https://raw.githubusercontent.com/ZSeven-W/openpencil/main/scripts/install-op.sh | bash +``` + +Windows PowerShell: + +```powershell +irm https://raw.githubusercontent.com/ZSeven-W/openpencil/main/scripts/install-op.ps1 | iex +``` ## Docker diff --git a/scripts/install-op.ps1 b/scripts/install-op.ps1 new file mode 100644 index 000000000..b035400d4 --- /dev/null +++ b/scripts/install-op.ps1 @@ -0,0 +1,84 @@ +param( + [string]$OpVersion = $env:OP_VERSION, + [string]$InstallDir = $(if ($env:INSTALL_DIR) { $env:INSTALL_DIR } else { Join-Path $env:USERPROFILE ".openpencil\bin" }) +) + +$ErrorActionPreference = "Stop" + +$Owner = "ZSeven-W" +$Repo = "openpencil" +$DefaultOpVersion = "" +$DefaultShaWindowsAarch64 = "" +$DefaultShaWindowsX86_64 = "" + +function Resolve-Version { + if (-not [string]::IsNullOrWhiteSpace($OpVersion)) { + return $OpVersion.TrimStart("v") + } + if (-not [string]::IsNullOrWhiteSpace($DefaultOpVersion)) { + return $DefaultOpVersion.TrimStart("v") + } + + $Latest = Invoke-RestMethod -Uri "https://api.github.com/repos/$Owner/$Repo/releases/latest" + if (-not $Latest.tag_name) { + throw "install-op: could not resolve latest release tag; set OP_VERSION explicitly" + } + return $Latest.tag_name.TrimStart("v") +} + +switch ($env:PROCESSOR_ARCHITECTURE) { + "AMD64" { + $Label = "windows-x86_64" + $ExpectedSha = $DefaultShaWindowsX86_64 + } + "ARM64" { + $Label = "windows-aarch64" + $ExpectedSha = $DefaultShaWindowsAarch64 + } + default { + throw "install-op: unsupported Windows architecture $env:PROCESSOR_ARCHITECTURE" + } +} + +$Version = Resolve-Version +$Asset = "op-cli-$Label.zip" +$Url = "https://github.com/$Owner/$Repo/releases/download/v$Version/$Asset" + +Write-Host "==> Installing op $Version ($Label)" +Write-Host " from $Url" + +$Temp = Join-Path ([System.IO.Path]::GetTempPath()) ("openpencil-op-install-" + [System.Guid]::NewGuid().ToString("N")) +New-Item -ItemType Directory -Path $Temp | Out-Null +try { + $Archive = Join-Path $Temp $Asset + Invoke-WebRequest -Uri $Url -OutFile $Archive -UseBasicParsing + + if (-not [string]::IsNullOrWhiteSpace($ExpectedSha)) { + $ActualSha = (Get-FileHash -Algorithm SHA256 $Archive).Hash.ToLowerInvariant() + if ($ActualSha -ne $ExpectedSha) { + throw "install-op: checksum mismatch for $Asset. Expected $ExpectedSha, got $ActualSha" + } + } + + Expand-Archive -Path $Archive -DestinationPath $Temp -Force + $Source = Get-ChildItem -Path $Temp -Filter "op.exe" -Recurse | Select-Object -First 1 + if (-not $Source) { + throw "install-op: op.exe was not found in $Asset" + } + + New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null + $Target = Join-Path $InstallDir "op.exe" + Copy-Item -Path $Source.FullName -Destination $Target -Force + + $UserPath = [Environment]::GetEnvironmentVariable("Path", "User") + $PathEntries = @($UserPath -split ";" | Where-Object { $_ }) + if ($PathEntries -notcontains $InstallDir) { + [Environment]::SetEnvironmentVariable("Path", (($PathEntries + $InstallDir) -join ";"), "User") + Write-Host "Added $InstallDir to the user PATH. Restart the shell to use op globally." + } + + Write-Host "==> Done. Run 'op --version' to verify." + & $Target --version +} finally { + Remove-Item -Path $Temp -Recurse -Force -ErrorAction SilentlyContinue +} diff --git a/scripts/install-op.sh b/scripts/install-op.sh index 241ece87c..672864584 100755 --- a/scripts/install-op.sh +++ b/scripts/install-op.sh @@ -6,13 +6,13 @@ # and installs the `op` binary into a bin directory on PATH. # # Usage: -# ./install-op.sh # install the latest release -# OP_VERSION=0.8.0 ./install-op.sh # pin a specific version -# INSTALL_DIR=$HOME/.local/bin ./install-op.sh # custom install dir +# ./install-op.sh # install the latest stable release +# OP_VERSION=0.8.0 ./install-op.sh # pin a specific version +# INSTALL_DIR=$HOME/.local/bin ./install-op.sh # -# Environment overrides: -# OP_VERSION release version WITHOUT the leading "v" (default: latest) -# INSTALL_DIR install target directory (default: /usr/local/bin) +# The release workflow stamps DEFAULT_OP_VERSION and DEFAULT_SHA_* in the copy +# uploaded to GitHub Releases, so the release asset installs that exact tag and +# verifies the CLI archive checksum. set -euo pipefail @@ -20,22 +20,25 @@ OWNER="ZSeven-W" REPO="openpencil" INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}" -# Resolve the asset "label" token rust-release.yml uses in -# op-cli-