Files
faerro-kb/scripts/publish-image.sh
T

135 lines
3.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
domain="registry.gitea.faerro.it"
image="$domain/andrea/faerro-kb"
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
bump="patch"
while [[ $# -gt 0 ]]; do
case "$1" in
--major|--minor)
if [[ "$bump" != "patch" ]]; then
echo "Choose only one of --major or --minor." >&2
exit 1
fi
bump="${1#--}"
;;
*)
echo "Usage: $0 [--major | --minor]" >&2
exit 1
;;
esac
shift
done
if ! command -v docker >/dev/null 2>&1; then
echo "Docker is required to build and publish the image." >&2
exit 1
fi
if ! command -v git >/dev/null 2>&1; then
echo "Git is required to determine the release version." >&2
exit 1
fi
if [[ -n "$(git -C "$repo_root" status --porcelain)" ]]; then
echo "Commit or discard all staged, unstaged, and untracked changes before publishing." >&2
exit 1
fi
latest_version=""
while IFS= read -r candidate; do
if [[ "$candidate" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
latest_version="$candidate"
break
fi
done < <(git -C "$repo_root" tag --list --sort=-version:refname)
if [[ -z "$latest_version" ]]; then
echo "At least one MAJOR.MINOR.PATCH Git tag is required to determine the next version." >&2
exit 1
fi
commits_since_release="$(git -C "$repo_root" rev-list --count "$latest_version..HEAD")"
if [[ "$commits_since_release" -eq 0 ]]; then
echo "No new commits since Git tag $latest_version; nothing to publish." >&2
exit 1
fi
IFS=. read -r major minor patch <<< "$latest_version"
case "$bump" in
major)
major=$((10#$major + 1))
minor=0
patch=0
;;
minor)
minor=$((10#$minor + 1))
patch=0
;;
patch)
patch=$((10#$patch + 1))
;;
esac
version="$major.$minor.$patch"
if git -C "$repo_root" show-ref --verify --quiet "refs/tags/$version"; then
echo "Git tag $version already exists; refusing to move it." >&2
exit 1
fi
build_context="$(mktemp -d)"
trap 'rm -rf "$build_context"' EXIT
git -C "$repo_root" archive HEAD | tar -x -C "$build_context"
footer_file="$build_context/frontend/index.html"
footer_count="$(grep -c '<footer>' "$footer_file" || true)"
if [[ "$footer_count" -ne 1 ]]; then
echo "Expected exactly one footer in frontend/index.html." >&2
exit 1
fi
sed -E -i "/<footer>/ { s/ · v[0-9]+\.[0-9]+\.[0-9]+//; s#</p># · v$version</p>#; }" "$footer_file"
if ! grep -Fq "· v$version</p></footer>" "$footer_file"; then
echo "Could not update the footer version in the build context." >&2
exit 1
fi
git -C "$repo_root" tag --annotate "$version" --message "Release $version" HEAD
cd "$repo_root"
docker build --tag "$image:$version" --tag "$image:latest" "$build_context"
registry_username="${GITEA_USERNAME:-${DOCKER_USERNAME:-}}"
registry_token="${GITEA_TOKEN:-${DOCKER_PASSWORD:-}}"
unset GITEA_TOKEN DOCKER_PASSWORD
env_file="$repo_root/.env"
if [[ -f "$env_file" ]]; then
while IFS= read -r line || [[ -n "$line" ]]; do
line="${line%$'\r'}"
if [[ "$line" =~ ^GITEA_USERNAME=(.*)$ ]]; then
registry_username="${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^GITEA_TOKEN=(.*)$ ]]; then
registry_token="${BASH_REMATCH[1]}"
fi
done < "$env_file"
fi
if [[ -n "$registry_username" || -n "$registry_token" ]]; then
if [[ -z "$registry_username" || -z "$registry_token" ]]; then
echo "Set both GITEA_USERNAME and GITEA_TOKEN in .env to log in automatically." >&2
exit 1
fi
if ! printf '%s' "$registry_token" | docker login --username "$registry_username" --password-stdin "$domain"; then
unset registry_token
exit 1
fi
unset registry_token
fi
docker push "$image:$version"
docker push "$image:latest"
while IFS= read -r local_image; do
[[ -z "$local_image" || "$local_image" == "$image:$version" || "$local_image" == "$image:latest" ]] && continue
docker image rm "$local_image"
done < <(docker image ls --format '{{.Repository}}:{{.Tag}}' "$image")
echo "Published $image:$version and $image:latest"