iuna

iuna

iuna - experimental devnet protocol
git clone https://getiuna.org/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 81b7bbeae26b1ab361025495c56bac2afc8042ac
parent dd31eb76fe236f4b5eceb6f17e648b4abb0226eb
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Thu, 13 Aug 2026 09:37:35 +0200

Improve deployment script

Diffstat:
Mdeployment.sh | 69++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 64 insertions(+), 5 deletions(-)

diff --git a/deployment.sh b/deployment.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")" + usage() { echo "Usage: $0 <version>" >&2 echo "Example: $0 0.2.48" >&2 @@ -11,6 +13,25 @@ die() { exit 1 } +require_command() { + local command_name="$1" + + command -v "$command_name" >/dev/null 2>&1 || die "missing required command: ${command_name}" +} + +confirm() { + local prompt="$1" + local answer + + if ! read -r -p "$prompt" answer || [[ ! "$answer" =~ ^[Yy]$ ]]; then + return 1 + fi +} + +escape_sed_replacement() { + printf '%s' "$1" | sed -e 's/[\/&]/\\&/g' +} + replace_in_file() { local file="$1" local pattern="$2" @@ -19,12 +40,26 @@ replace_in_file() { } ensure_clean_worktree() { + require_command git + if ! git diff --quiet || ! git diff --cached --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]; then die "worktree is not clean; commit or stash changes before releasing" fi } +ensure_head_matches_tag() { + local tag="$1" + local head_commit + local tag_commit + + head_commit="$(git rev-parse HEAD)" + tag_commit="$(git rev-parse "${tag}^{commit}")" + [ "$head_commit" = "$tag_commit" ] || die "${tag} exists, but HEAD is not at ${tag}; checkout ${tag} before redeploying it" +} + ensure_tauri_cli() { + require_command cargo + if ! cargo tauri --version >/dev/null 2>&1; then cargo install tauri-cli --locked --version "^2" fi @@ -33,6 +68,9 @@ ensure_tauri_cli() { update_versions() { local version="$1" + require_command cargo + require_command perl + replace_in_file Cargo.toml '(\[package\]\nname = "iuna"\nversion = ")[^"]+' "\${1}${version}" replace_in_file src-tauri/Cargo.toml '(\[package\]\nname = "iuna-desktop"\nversion = ")[^"]+' "\${1}${version}" replace_in_file src-tauri/tauri.conf.json '("version": ")[^"]+' "\${1}${version}" @@ -49,6 +87,8 @@ commit_and_tag() { local version="$1" local tag="v${version}" + require_command git + git add Cargo.toml Cargo.lock src-tauri/Cargo.toml src-tauri/Cargo.lock src-tauri/tauri.conf.json README.md git commit -m "Release ${tag}" git tag -a "$tag" -m "Release ${tag}" @@ -62,6 +102,8 @@ build_macos_desktop_if_possible() { [ "$(uname -s)" = "Darwin" ] || return 0 [ "$(uname -m)" = "arm64" ] || die "macOS desktop artifact requires Apple silicon; expected ${artifact}" + require_command codesign + require_command ditto ensure_tauri_cli cargo build --release --locked mkdir -p src-tauri/binaries downloads @@ -178,6 +220,8 @@ build_linux_cli_archives() { mkdir -p downloads [ -f "downloads/${linux_x86_64_package}.tar.gz" ] && [ -f "downloads/${linux_aarch64_package}.tar.gz" ] && return 0 + require_command docker + docker run --rm --platform=linux/amd64 \ -e "IUNA_VERSION=${version}" \ -e "HOST_UID=$(id -u)" \ @@ -266,6 +310,8 @@ build_docker_image() { local www_image="${IUNA_WWW_IMAGE:-iuna-www:v${version}}" local node_image="${IUNA_NODE_IMAGE:-iuna-node:v${version}}" + require_command docker + docker build --platform=linux/amd64 --progress=plain -t "$www_image" . docker build --platform=linux/amd64 --progress=plain -t "$node_image" -f Dockerfile.node . echo "Built Docker images: ${www_image}, ${node_image}" @@ -278,6 +324,10 @@ import_image_to_k3s() { local remote_file="${image//[:\/]/_}.tar" local image_file="${tmp_folder}/${remote_file}" + require_command docker + require_command scp + require_command ssh + docker save "$image" -o "$image_file" scp "$image_file" "${remote_host}:~/" ssh "$remote_host" "sudo k3s ctr -n k8s.io images import ~/${remote_file} && rm ~/${remote_file}" @@ -287,10 +337,15 @@ render_manifest() { local www_image="$1" local node_image="$2" local output="$3" + local escaped_www_image + local escaped_node_image + + escaped_www_image="$(escape_sed_replacement "$www_image")" + escaped_node_image="$(escape_sed_replacement "$node_image")" sed \ - -e "s|\${IUNA_WWW_IMAGE}|${www_image}|g" \ - -e "s|\${IUNA_NODE_IMAGE}|${node_image}|g" \ + -e "s|\${IUNA_WWW_IMAGE}|${escaped_www_image}|g" \ + -e "s|\${IUNA_NODE_IMAGE}|${escaped_node_image}|g" \ config/deployment.yml > "$output" } @@ -301,6 +356,8 @@ deploy_docker_image() { local kubectl_context="${IUNA_KUBECTL_CONTEXT:-jhx-app}" local tmp_folder + require_command kubectl + tmp_folder="$(mktemp -d)" trap 'rm -rf "$tmp_folder"' RETURN @@ -330,18 +387,20 @@ main() { # Check if the tag already exists; if it does, only deploy if git rev-parse --verify "v${version}" >/dev/null 2>&1; then - echo "Tag v${version} already exists; skipping build and deploying only" - if ! read -p "Are you sure you want to deploy v${version}? (y/N) " answer || [[ ! "$answer" =~ ^[Yy]$ ]]; then + ensure_head_matches_tag "v${version}" + echo "Tag v${version} already exists; rebuilding Docker images and deploying" + if ! confirm "Are you sure you want to deploy v${version}? (y/N) "; then echo "Aborting deployment" exit 1 fi + build_docker_image "$version" deploy_docker_image "$version" exit 0 fi update_versions "$version" - commit_and_tag "$version" build_versions "$version" + commit_and_tag "$version" build_docker_image "$version" deploy_docker_image "$version" }