chore(release): bump version to 1.17.0 #38
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v[0-9]+.[0-9]+.[0-9]+' | |
| - 'v[0-9]+.[0-9]+.[0-9]+-*' # prerelease タグ(v1.5.0-beta.1 等) | |
| env: | |
| CARGO_TERM_COLOR: always | |
| # GitHub Release への書き込み権限 + SLSA Provenance 生成(attestations) | |
| permissions: | |
| contents: write | |
| id-token: write # OIDC トークン(attest-build-provenance に必須) | |
| attestations: write # SLSA Provenance アテステーション | |
| jobs: | |
| # ── Step 1: Release ページを先に作成する ────────────────────────── | |
| create-release: | |
| name: Create GitHub Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag: ${{ github.ref_name }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| - name: Create Release | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 | |
| with: | |
| generate_release_notes: true | |
| draft: false | |
| # タグ名に `-` が含まれていれば prerelease として扱う(v1.5.0-beta.1 等) | |
| prerelease: ${{ contains(github.ref_name, '-') }} | |
| # ── Step 2: 各プラットフォームのバイナリをビルドして添付する ────── | |
| build: | |
| name: Build (${{ matrix.name }}) | |
| needs: create-release | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux x86_64 | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| name: linux-x86_64 | |
| archive_ext: tar.gz | |
| # macOS Apple Silicon (M1/M2/M3) | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| name: macos-arm64 | |
| archive_ext: tar.gz | |
| # macOS Intel | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| name: macos-x86_64 | |
| archive_ext: tar.gz | |
| # Windows x86_64 | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| name: windows-x86_64 | |
| archive_ext: zip | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| - name: Set up Rust toolchain | |
| uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Cache Cargo artifacts | |
| uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| - name: Install Linux system dependencies | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libx11-dev libxkbcommon-dev libwayland-dev \ | |
| libasound2-dev libpulse-dev \ | |
| libudev-dev \ | |
| libfuse2 | |
| - name: Build release binaries | |
| # nexterm-client-gpu は v0.9.3 でバイナリ名を nexterm に変更し、 | |
| # サーバーを内部起動するシングルバイナリとなった。旧 nexterm-launcher は | |
| # 役目を終え v1.4.0 で削除済み。 | |
| # NEXTERM_MINISIGN_PUBLIC_KEY (Sprint 3-4): 設定されている場合は signature_verify | |
| # モジュールに公開鍵が埋め込まれ、自動更新時の minisign 検証が有効化される。 | |
| env: | |
| NEXTERM_MINISIGN_PUBLIC_KEY: ${{ vars.NEXTERM_MINISIGN_PUBLIC_KEY }} | |
| run: > | |
| cargo build --release --target ${{ matrix.target }} | |
| -p nexterm-server | |
| -p nexterm-client-gpu | |
| -p nexterm-client-tui | |
| -p nexterm-ctl | |
| # ── macOS: .app バンドル作成 ── | |
| - name: Create macOS .app bundle | |
| if: runner.os == 'macOS' | |
| run: | | |
| APP=dist/Nexterm.app | |
| mkdir -p "$APP/Contents/MacOS" | |
| # 全バイナリを .app バンドル内に配置 | |
| for bin in nexterm nexterm-server nexterm-client-tui nexterm-ctl; do | |
| BIN_PATH="target/${{ matrix.target }}/release/$bin" | |
| if [ -f "$BIN_PATH" ]; then | |
| cp "$BIN_PATH" "$APP/Contents/MacOS/" | |
| fi | |
| done | |
| # Info.plist のバージョンを置換して配置 | |
| VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*= "\(.*\)"/\1/') | |
| sed "s/BUNDLE_VERSION/${VERSION}/g" macos/Info.plist > "$APP/Contents/Info.plist" | |
| # ── macOS: ad-hoc コード署名(Gatekeeper の quarantine 除去後に起動可能にする)── | |
| - name: Ad-hoc code sign (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| # --deep でバンドル内の全バイナリを再帰的に一括署名する | |
| # (個別署名後にバンドルを署名すると subcomponent エラーになるため) | |
| codesign --force --deep --sign - dist/Nexterm.app | |
| # ── Unix 向けパッケージング ── | |
| - name: Package (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| mkdir -p dist | |
| # 個別バイナリも dist/ に配置(CLI 利用・Homebrew 向け) | |
| for bin in nexterm nexterm-server nexterm-client-tui nexterm-ctl; do | |
| BIN_PATH="target/${{ matrix.target }}/release/$bin" | |
| if [ -f "$BIN_PATH" ]; then | |
| cp "$BIN_PATH" dist/ | |
| fi | |
| done | |
| # Linux のみ: .desktop ファイルとインストールスクリプトを同梱 | |
| if [ "${{ runner.os }}" = "Linux" ]; then | |
| cp linux/nexterm.desktop dist/ | |
| cp linux/install.sh dist/ | |
| fi | |
| tar -czf nexterm-${{ github.ref_name }}-${{ matrix.name }}.tar.gz -C dist . | |
| # ── Linux AppImage ビルド ── | |
| - name: Build AppImage (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| # appimagetool をダウンロードする | |
| APPIMAGETOOL_URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" | |
| curl -sSL "$APPIMAGETOOL_URL" -o /tmp/appimagetool | |
| chmod +x /tmp/appimagetool | |
| # AppDir を組み立てる | |
| APPDIR=/tmp/Nexterm.AppDir | |
| mkdir -p "${APPDIR}/usr/bin" | |
| # バイナリを配置する | |
| for bin in nexterm nexterm-server nexterm-client-tui nexterm-ctl; do | |
| BIN_PATH="target/${{ matrix.target }}/release/$bin" | |
| if [ -f "$BIN_PATH" ]; then | |
| cp "$BIN_PATH" "${APPDIR}/usr/bin/" | |
| fi | |
| done | |
| # AppRun スクリプト(エントリーポイント) | |
| cp linux/AppRun "${APPDIR}/AppRun" | |
| chmod +x "${APPDIR}/AppRun" | |
| # .desktop ファイルを AppDir にコピーし、Icon= を "nexterm" に書き換える | |
| # (appimagetool は AppDir 内の <Icon>.png を探すため、Icon 名とファイル名を一致させる) | |
| sed 's/^Icon=.*/Icon=nexterm/' linux/nexterm.desktop > "${APPDIR}/nexterm.desktop" | |
| # アイコンを nexterm.png として配置する | |
| if [ -f "assets/icon.png" ]; then | |
| cp assets/icon.png "${APPDIR}/nexterm.png" | |
| else | |
| # ダミーアイコン(1x1 透過 PNG)を生成する | |
| printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01\r\n-\xb4\x00\x00\x00\x00IEND\xaeB`\x82' > "${APPDIR}/nexterm.png" | |
| fi | |
| # appimagetool でパッケージ化(libfuse2 が入っているので直接実行可能) | |
| ARCH=x86_64 /tmp/appimagetool \ | |
| "${APPDIR}" \ | |
| "nexterm-${{ github.ref_name }}-${{ matrix.name }}.AppImage" | |
| - name: Upload AppImage to GitHub Release | |
| if: runner.os == 'Linux' | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 | |
| with: | |
| files: nexterm-${{ github.ref_name }}-${{ matrix.name }}.AppImage | |
| # ── Windows 向けパッケージング(ZIP)── | |
| - name: Package (Windows ZIP) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Path dist | Out-Null | |
| # nexterm.exe = GPU クライアント + サーバー統合バイナリ(v0.9.3〜) | |
| Copy-Item target/${{ matrix.target }}/release/nexterm.exe dist/ | |
| Copy-Item target/${{ matrix.target }}/release/nexterm-server.exe dist/ | |
| Copy-Item target/${{ matrix.target }}/release/nexterm-client-tui.exe dist/ | |
| Copy-Item target/${{ matrix.target }}/release/nexterm-ctl.exe dist/ | |
| Copy-Item scripts/install-service.ps1 dist/ | |
| Copy-Item scripts/uninstall-service.ps1 dist/ | |
| Compress-Archive -Path dist/* -DestinationPath nexterm-${{ github.ref_name }}-${{ matrix.name }}.zip | |
| # ── Windows コード署名(証明書が Secrets に設定されている場合のみ)── | |
| - name: Sign binaries (Windows) | |
| if: runner.os == 'Windows' && env.WINDOWS_CERTIFICATE != '' | |
| env: | |
| WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} | |
| WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} | |
| shell: pwsh | |
| run: | | |
| # Base64 エンコードされた PFX 証明書をデコードしてファイルに保存 | |
| $certBytes = [System.Convert]::FromBase64String($env:WINDOWS_CERTIFICATE) | |
| $certPath = Join-Path $env:RUNNER_TEMP "nexterm-sign.pfx" | |
| [System.IO.File]::WriteAllBytes($certPath, $certBytes) | |
| # signtool.exe でバイナリを署名 | |
| $signtool = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe" | |
| $targets = @( | |
| "dist\nexterm.exe", | |
| "dist\nexterm-server.exe", | |
| "dist\nexterm-client-tui.exe", | |
| "dist\nexterm-ctl.exe" | |
| ) | |
| foreach ($t in $targets) { | |
| & $signtool sign ` | |
| /f $certPath ` | |
| /p $env:WINDOWS_CERTIFICATE_PASSWORD ` | |
| /tr http://timestamp.digicert.com ` | |
| /td sha256 /fd sha256 ` | |
| $t | |
| } | |
| # 証明書ファイルを削除 | |
| Remove-Item $certPath -Force | |
| # ── Windows MSI インストーラービルド ── | |
| - name: Build MSI installer (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| # WiX Toolset v3 のインストール(未インストールの場合のみ) | |
| if (-not (Get-Command candle.exe -ErrorAction SilentlyContinue)) { | |
| choco install wixtoolset -y --no-progress | |
| } | |
| $wixInstalled = Get-ChildItem "C:\Program Files (x86)\WiX Toolset*" -Directory -ErrorAction SilentlyContinue | | |
| Sort-Object Name -Descending | Select-Object -First 1 | |
| if (-not $wixInstalled) { throw "WiX Toolset not found" } | |
| $env:Path += ";$($wixInstalled.FullName)\bin" | |
| # MSI のバージョンを Cargo.toml から取得 | |
| $matchResult = Select-String -Path Cargo.toml -Pattern '^version\s*=\s*"([^"]+)"' | | |
| Select-Object -First 1 | |
| $version = $matchResult.Matches[0].Groups[1].Value | |
| if ([string]::IsNullOrEmpty($version)) { throw "Cannot extract version from Cargo.toml" } | |
| # WiX v3 の Product/Version 属性は a.b.c.d 数値形式のみ許容するため、 | |
| # prerelease suffix(例: "1.5.0-beta.1" → "1.5.0")を除去する。 | |
| # GitHub Release のタイトル(${{ github.ref_name }})には beta.1 が残る。 | |
| if ($version -match '^([0-9]+\.[0-9]+\.[0-9]+)') { | |
| $version = $Matches[1] | |
| } | |
| Write-Host "MSI version: $version" | |
| # candle.exe + light.exe でMSIをビルド(-d フラグでバージョンをプリプロセッサ変数として渡す) | |
| $wixDir = "$($wixInstalled.FullName)\bin" | |
| $wixPath = "wix\main.wxs" | |
| New-Item -ItemType Directory -Path build -Force | Out-Null | |
| & "$wixDir\candle.exe" -arch x64 "-dVersion=$version" -out "build\" $wixPath | |
| if ($LASTEXITCODE -ne 0) { throw "candle.exe failed" } | |
| & "$wixDir\light.exe" ` | |
| -out "nexterm-${{ github.ref_name }}-${{ matrix.name }}.msi" ` | |
| "build\main.wixobj" | |
| if ($LASTEXITCODE -ne 0) { throw "light.exe failed" } | |
| # ── MSI 署名(証明書が設定されている場合)── | |
| - name: Sign MSI (Windows) | |
| if: runner.os == 'Windows' && env.WINDOWS_CERTIFICATE != '' | |
| env: | |
| WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} | |
| WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} | |
| shell: pwsh | |
| run: | | |
| $certBytes = [System.Convert]::FromBase64String($env:WINDOWS_CERTIFICATE) | |
| $certPath = Join-Path $env:RUNNER_TEMP "nexterm-sign.pfx" | |
| [System.IO.File]::WriteAllBytes($certPath, $certBytes) | |
| $signtool = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe" | |
| & $signtool sign ` | |
| /f $certPath ` | |
| /p $env:WINDOWS_CERTIFICATE_PASSWORD ` | |
| /tr http://timestamp.digicert.com ` | |
| /td sha256 /fd sha256 ` | |
| "nexterm-${{ github.ref_name }}-${{ matrix.name }}.msi" | |
| Remove-Item $certPath -Force | |
| # ── Sprint 3-4: minisign 署名(秘密鍵が Secrets に設定されている場合のみ)── | |
| # MINISIGN_SECRET_KEY: minisign -G で生成した秘密鍵ファイルの内容(複数行) | |
| # MINISIGN_PASSWORD: 秘密鍵のパスワード(鍵生成時に設定したもの) | |
| - name: Set up minisign (Linux) | |
| if: runner.os == 'Linux' && env.MINISIGN_SECRET_KEY != '' | |
| env: | |
| MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} | |
| run: | | |
| sudo apt-get install -y minisign | |
| - name: Set up minisign (macOS) | |
| if: runner.os == 'macOS' && env.MINISIGN_SECRET_KEY != '' | |
| env: | |
| MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} | |
| run: | | |
| brew install minisign | |
| - name: Set up minisign (Windows) | |
| if: runner.os == 'Windows' && env.MINISIGN_SECRET_KEY != '' | |
| env: | |
| MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} | |
| shell: pwsh | |
| run: | | |
| choco install minisign -y --no-progress | |
| - name: Sign release archives with minisign (Unix) | |
| if: runner.os != 'Windows' && env.MINISIGN_SECRET_KEY != '' | |
| env: | |
| MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} | |
| MINISIGN_PASSWORD: ${{ secrets.MINISIGN_PASSWORD }} | |
| run: | | |
| # 秘密鍵を一時ファイルに書き出す | |
| KEY_FILE="$RUNNER_TEMP/nexterm-minisign.key" | |
| printf '%s' "$MINISIGN_SECRET_KEY" > "$KEY_FILE" | |
| chmod 600 "$KEY_FILE" | |
| # tar.gz および AppImage(Linux のみ)を署名 | |
| for archive in \ | |
| "nexterm-${{ github.ref_name }}-${{ matrix.name }}.tar.gz" \ | |
| "nexterm-${{ github.ref_name }}-${{ matrix.name }}.AppImage"; do | |
| if [ -f "$archive" ]; then | |
| echo "$MINISIGN_PASSWORD" | minisign -S -s "$KEY_FILE" -m "$archive" | |
| echo "Signed: $archive -> $archive.minisig" | |
| fi | |
| done | |
| # 秘密鍵を削除 | |
| rm -f "$KEY_FILE" | |
| - name: Sign release archives with minisign (Windows) | |
| if: runner.os == 'Windows' && env.MINISIGN_SECRET_KEY != '' | |
| env: | |
| MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} | |
| MINISIGN_PASSWORD: ${{ secrets.MINISIGN_PASSWORD }} | |
| shell: pwsh | |
| run: | | |
| $keyFile = Join-Path $env:RUNNER_TEMP "nexterm-minisign.key" | |
| [System.IO.File]::WriteAllText($keyFile, $env:MINISIGN_SECRET_KEY) | |
| $targets = @( | |
| "nexterm-${{ github.ref_name }}-${{ matrix.name }}.zip", | |
| "nexterm-${{ github.ref_name }}-${{ matrix.name }}.msi" | |
| ) | |
| foreach ($archive in $targets) { | |
| if (Test-Path $archive) { | |
| $env:MINISIGN_PASSWORD | minisign -S -s $keyFile -m $archive | |
| Write-Host "Signed: $archive -> $archive.minisig" | |
| } | |
| } | |
| Remove-Item $keyFile -Force | |
| # ── Sprint 3-4: SLSA Build Provenance(全リリースアーティファクト)── | |
| # 検証コマンド: gh attestation verify <archive> -R mizu-jun/Nexterm | |
| - name: Generate SLSA Provenance | |
| uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 | |
| with: | |
| subject-path: | | |
| nexterm-${{ github.ref_name }}-${{ matrix.name }}.${{ matrix.archive_ext }} | |
| - name: Generate SLSA Provenance (MSI) | |
| if: runner.os == 'Windows' | |
| uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 | |
| with: | |
| subject-path: nexterm-${{ github.ref_name }}-${{ matrix.name }}.msi | |
| - name: Generate SLSA Provenance (AppImage) | |
| if: runner.os == 'Linux' | |
| uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 | |
| with: | |
| subject-path: nexterm-${{ github.ref_name }}-${{ matrix.name }}.AppImage | |
| # ── GitHub Release にアーカイブを添付 ── | |
| - name: Upload ZIP to GitHub Release | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 | |
| with: | |
| files: | | |
| nexterm-${{ github.ref_name }}-${{ matrix.name }}.${{ matrix.archive_ext }} | |
| nexterm-${{ github.ref_name }}-${{ matrix.name }}.${{ matrix.archive_ext }}.minisig | |
| - name: Upload MSI to GitHub Release | |
| if: runner.os == 'Windows' | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 | |
| with: | |
| files: | | |
| nexterm-${{ github.ref_name }}-${{ matrix.name }}.msi | |
| nexterm-${{ github.ref_name }}-${{ matrix.name }}.msi.minisig | |
| - name: Upload AppImage minisig to GitHub Release | |
| if: runner.os == 'Linux' | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 | |
| with: | |
| files: nexterm-${{ github.ref_name }}-${{ matrix.name }}.AppImage.minisig |