From f0671c06adda0d0cf05102b573cf9d2449ecd639 Mon Sep 17 00:00:00 2001 From: Yoshihiro OKUMURA Date: Mon, 20 Apr 2026 11:44:22 +0900 Subject: [PATCH] feat: add manual release build scripts for macOS and Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI does not have macOS or Windows runners, so provide scripts to build and optionally upload release archives locally. - scripts/build-release-macos.sh — builds x86_64 and aarch64-apple-darwin - scripts/build-release-windows.ps1 — builds x86_64-pc-windows-msvc - scripts/.env.example — template for Gitea credentials Both scripts read GITEA_TOKEN, GITEA_SERVER_URL, and GITEA_REPOSITORY from the environment or from scripts/.env (which is gitignored). Upload to Gitea is skipped when GITEA_TOKEN is not set. Use curl.exe for multipart upload in the PowerShell script to support Windows PowerShell 5.1 (Invoke-RestMethod -Form requires PS 6.1+). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- scripts/.env.example | 7 +++ scripts/build-release-macos.sh | 92 +++++++++++++++++++++++++++ scripts/build-release-windows.ps1 | 100 ++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 scripts/.env.example create mode 100755 scripts/build-release-macos.sh create mode 100644 scripts/build-release-windows.ps1 diff --git a/scripts/.env.example b/scripts/.env.example new file mode 100644 index 0000000..b129adb --- /dev/null +++ b/scripts/.env.example @@ -0,0 +1,7 @@ +# Copy this file to .env and fill in your values. +# .env is loaded automatically by the build-release scripts. +# Environment variables already set in your shell take precedence. + +GITEA_SERVER_URL=https://git.example.com +GITEA_REPOSITORY=owner/mdrs-client-rust +GITEA_TOKEN=your_token_here diff --git a/scripts/build-release-macos.sh b/scripts/build-release-macos.sh new file mode 100755 index 0000000..51f222c --- /dev/null +++ b/scripts/build-release-macos.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# Build release archives for macOS (x86_64 and aarch64). +# +# Usage: +# ./scripts/build-release-macos.sh [VERSION] +# +# If VERSION is not provided, it is read from Cargo.toml. +# Set GITEA_TOKEN (and optionally GITEA_SERVER_URL / GITEA_REPOSITORY) +# to upload the archives to a Gitea release automatically. +# These can be provided via scripts/.env. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +# Load .env if present (existing env vars take precedence) +if [[ -f "${SCRIPT_DIR}/.env" ]]; then + while IFS='=' read -r key value; do + [[ "${key}" =~ ^#.*$ || -z "${key}" ]] && continue + key="${key%%[[:space:]]}" + value="${value##[[:space:]]}" + [[ -z "${!key+x}" ]] && export "${key}=${value}" + done < "${SCRIPT_DIR}/.env" +fi + +# Determine version +if [[ $# -ge 1 ]]; then + VERSION="$1" +else + VERSION="$(grep -m1 '^version' "${REPO_ROOT}/Cargo.toml" | sed 's/.*= *"\(.*\)"/\1/')" +fi + +TAG="v${VERSION}" +TARGETS=(x86_64-apple-darwin aarch64-apple-darwin) + +cd "${REPO_ROOT}" + +echo "==> Building mdrs ${VERSION} for macOS" + +ARCHIVES=() +for TARGET in "${TARGETS[@]}"; do + echo "--- Target: ${TARGET}" + rustup target add "${TARGET}" + cargo build --release --target "${TARGET}" + + ARCHIVE="mdrs-${VERSION}-${TARGET}.tar.gz" + tar -czf "${ARCHIVE}" -C "target/${TARGET}/release" mdrs + ARCHIVES+=("${ARCHIVE}") + echo " Created: ${ARCHIVE}" +done + +echo "" +echo "==> Archives ready:" +for A in "${ARCHIVES[@]}"; do echo " ${A}"; done + +# Upload to Gitea if token is provided +if [[ -z "${GITEA_TOKEN:-}" ]]; then + echo "" + echo "GITEA_TOKEN not set — skipping upload." + echo "Set GITEA_TOKEN (and GITEA_SERVER_URL, GITEA_REPOSITORY) in scripts/.env to enable upload." + exit 0 +fi + +: "${GITEA_SERVER_URL:?GITEA_SERVER_URL is required for upload}" +: "${GITEA_REPOSITORY:?GITEA_REPOSITORY is required for upload}" + +echo "" +echo "==> Creating Gitea release ${TAG} ..." +curl -sf -X POST \ + -H "Authorization: Bearer ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + "${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases" \ + -d "{\"tag_name\": \"${TAG}\", \"name\": \"${TAG}\"}" > /dev/null || true + +RELEASE_ID="$(curl -sf \ + -H "Authorization: Bearer ${GITEA_TOKEN}" \ + "${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/tags/${TAG}" \ + | python3 -c 'import sys,json; print(json.load(sys.stdin)["id"])')" + +echo "==> Uploading assets (release id: ${RELEASE_ID}) ..." +for ARCHIVE in "${ARCHIVES[@]}"; do + echo " Uploading ${ARCHIVE} ..." + curl -sf -X POST \ + -H "Authorization: Bearer ${GITEA_TOKEN}" \ + -F "attachment=@${ARCHIVE}" \ + "${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/${RELEASE_ID}/assets" > /dev/null + echo " Done." +done + +echo "" +echo "==> Upload complete: ${GITEA_SERVER_URL}/${GITEA_REPOSITORY}/releases/tag/${TAG}" diff --git a/scripts/build-release-windows.ps1 b/scripts/build-release-windows.ps1 new file mode 100644 index 0000000..cf8ca98 --- /dev/null +++ b/scripts/build-release-windows.ps1 @@ -0,0 +1,100 @@ +# Build release archive for Windows (x86_64-pc-windows-msvc). +# +# Usage: +# .\scripts\build-release-windows.ps1 [-Version ] +# +# If -Version is not provided, it is read from Cargo.toml. +# Set GITEA_TOKEN (and optionally GITEA_SERVER_URL / GITEA_REPOSITORY) +# to upload the archive to a Gitea release automatically. +# These can be provided via scripts\.env. + +param( + [string]$Version = "" +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$RepoRoot = Split-Path -Parent $ScriptDir + +# Load .env if present (existing env vars take precedence) +$EnvFile = Join-Path $ScriptDir ".env" +if (Test-Path $EnvFile) { + Get-Content $EnvFile | ForEach-Object { + if ($_ -match '^\s*#' -or $_ -match '^\s*$') { return } + $parts = $_ -split '=', 2 + $key = $parts[0].Trim() + $value = $parts[1].Trim() + if (-not [System.Environment]::GetEnvironmentVariable($key)) { + [System.Environment]::SetEnvironmentVariable($key, $value, "Process") + } + } +} + +# Determine version +if (-not $Version) { + $cargoToml = Get-Content (Join-Path $RepoRoot "Cargo.toml") -Raw + if ($cargoToml -match 'version\s*=\s*"([^"]+)"') { + $Version = $Matches[1] + } else { + Write-Error "Could not determine version from Cargo.toml" + exit 1 + } +} + +$Tag = "v$Version" +$Target = "x86_64-pc-windows-msvc" + +Set-Location $RepoRoot + +Write-Host "==> Building mdrs $Version for Windows ($Target)" + +rustup target add $Target +cargo build --release --target $Target + +$Archive = "mdrs-$Version-$Target.zip" +Compress-Archive -Force -Path "target\$Target\release\mdrs.exe" -DestinationPath $Archive +Write-Host " Created: $Archive" + +# Upload to Gitea if token is provided +$GiteaToken = [System.Environment]::GetEnvironmentVariable("GITEA_TOKEN") +if (-not $GiteaToken) { + Write-Host "" + Write-Host "GITEA_TOKEN not set -- skipping upload." + Write-Host "Set GITEA_TOKEN (and GITEA_SERVER_URL, GITEA_REPOSITORY) in scripts\.env to enable upload." + exit 0 +} + +$ServerUrl = [System.Environment]::GetEnvironmentVariable("GITEA_SERVER_URL") +$Repository = [System.Environment]::GetEnvironmentVariable("GITEA_REPOSITORY") +if (-not $ServerUrl) { Write-Error "GITEA_SERVER_URL is required for upload"; exit 1 } +if (-not $Repository) { Write-Error "GITEA_REPOSITORY is required for upload"; exit 1 } + +$Headers = @{ Authorization = "Bearer $GiteaToken"; "Content-Type" = "application/json" } + +Write-Host "" +Write-Host "==> Creating Gitea release $Tag ..." +try { + Invoke-RestMethod -Method Post -Uri "$ServerUrl/api/v1/repos/$Repository/releases" ` + -Headers $Headers ` + -Body (ConvertTo-Json @{ tag_name = $Tag; name = $Tag }) | Out-Null +} catch { + # Release may already exist; continue +} + +$Release = Invoke-RestMethod -Method Get -Uri "$ServerUrl/api/v1/repos/$Repository/releases/tags/$Tag" ` + -Headers @{ Authorization = "Bearer $GiteaToken" } +$ReleaseId = $Release.id + +Write-Host "==> Uploading $Archive (release id: $ReleaseId) ..." +$ArchivePath = Join-Path $RepoRoot $Archive +& curl.exe -sf -X POST ` + -H "Authorization: Bearer $GiteaToken" ` + -F "attachment=@$ArchivePath" ` + "$ServerUrl/api/v1/repos/$Repository/releases/$ReleaseId/assets" | Out-Null +if ($LASTEXITCODE -ne 0) { Write-Error "Upload failed (exit code $LASTEXITCODE)"; exit 1 } +Write-Host " Done." + +Write-Host "" +Write-Host "==> Upload complete: $ServerUrl/$Repository/releases/tag/$Tag"