Namespaces, assemblies, projects and directories, the solution, binaries, images, systemd units, config paths, environment variables, protocol method names, the media type and the raw chunk magic all move to MoShiro/moshiro. Existing data and deployments are not compatible and must be recreated. Also fix the architecture tests after the solution layout change and make the update tests independent of their order.
126 lines
4.9 KiB
Bash
126 lines
4.9 KiB
Bash
#!/usr/bin/env bash
|
||
# Build a musl NativeAOT Backend OCI image with statically linked SQLite; publishing is optional.
|
||
set -euo pipefail
|
||
|
||
arch="${1:?usage: release-linux.sh <amd64|arm64>}"
|
||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
tag="${CI_COMMIT_TAG:-}"
|
||
if [[ -n "$tag" ]]; then
|
||
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || {
|
||
echo "release must run from a vMAJOR.MINOR.PATCH tag" >&2
|
||
exit 2
|
||
}
|
||
version="${tag#v}"
|
||
else
|
||
[[ "${CI_PIPELINE_EVENT:-}" == push && "${CI_COMMIT_BRANCH:-}" == main && "${CI_COMMIT_MESSAGE:-}" == *"[CI]"* ]] || {
|
||
echo "untagged backend builds require a main push with [CI] in the commit message" >&2
|
||
exit 2
|
||
}
|
||
version=main
|
||
fi
|
||
image_publish="${IMAGE_PUBLISH:-true}"
|
||
[[ "$image_publish" == true || "$image_publish" == false ]] || {
|
||
echo "IMAGE_PUBLISH must be true or false" >&2; exit 2;
|
||
}
|
||
if [[ "$image_publish" == true ]]; then
|
||
[[ -n "${ZOT_USERNAME:-}" && -n "${ZOT_SECRET:-}" ]] || {
|
||
echo "Zot credentials are required" >&2; exit 2;
|
||
}
|
||
fi
|
||
case "$arch" in
|
||
amd64) rid=linux-musl-x64 ;;
|
||
arm64) rid=linux-musl-arm64 ;;
|
||
*) echo "unsupported architecture: $arch" >&2; exit 2 ;;
|
||
esac
|
||
|
||
project_version="$(sed -n 's#.*<Version>\(.*\)</Version>.*#\1#p' "$root/backend/Directory.Build.props" | head -1)"
|
||
if [[ -n "$tag" && "$version" != "$project_version" ]]; then
|
||
echo "tag version $version does not match project version $project_version" >&2
|
||
exit 1
|
||
fi
|
||
|
||
registry="${ZOT_REGISTRY:-registry.oeo.one}"
|
||
image="${ZOT_IMAGE_REPOSITORY:-$registry/moshiro/moshiro-backend}"
|
||
output="$root/.release/linux-$arch/backend"
|
||
build_root="$root/.release/build/linux-$arch-backend"
|
||
container_context="$root/.release/container/linux-$arch"
|
||
mkdir -p "$output" "$build_root" "$container_context/app" "$container_context/data"
|
||
|
||
# 构建信息:tag 发布用 tag,main 构建用 main-<提交>
|
||
export MOSHIRO_TAG="${MOSHIRO_TAG:-${tag:-main-${CI_COMMIT_SHA:0:10}}}"
|
||
export MOSHIRO_COMMIT="${MOSHIRO_COMMIT:-${CI_COMMIT_SHA:0:10}}"
|
||
export MOSHIRO_BUILT_AT="${MOSHIRO_BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}"
|
||
|
||
(cd "$root/backend" && dotnet publish src/MoShiro.Backend \
|
||
-m:3 -c Release -r "$rid" --self-contained true \
|
||
-p:DebugType=none -p:DebugSymbols=false \
|
||
-p:PublishAot=true -p:UseAotAnywhere=true -p:SqliteStaticLink=true -p:OpenApiGenerateDocuments=false \
|
||
--artifacts-path "$build_root" -o "$output")
|
||
[[ -x "$output/moshiro-backend" ]] || { echo "NativeAOT Backend executable is missing" >&2; exit 1; }
|
||
[[ "$(wc -c < "$output/moshiro-backend")" -gt 2000000 ]] || { echo "Backend output is an apphost, not a NativeAOT executable" >&2; exit 1; }
|
||
install -m 0755 "$output/moshiro-backend" "$container_context/app/moshiro-backend"
|
||
: > "$container_context/data/.keep"
|
||
|
||
# Woodpecker's local backend isolates HOME per workflow. Keep Buildah's image
|
||
# store outside that temporary directory so the runtime base image is reusable
|
||
# across releases. Separate stores avoid concurrent amd64/arm64 writers.
|
||
buildah_home="${BUILDAH_HOME:-/home/justme/woodpecker/buildah-home/$arch}"
|
||
mkdir -p "$buildah_home"
|
||
export HOME="$buildah_home"
|
||
|
||
local_image="localhost/moshiro-backend:$version-$arch"
|
||
buildah bud --tls-verify=true --arch "$arch" \
|
||
--build-arg "APP_VERSION=$version" \
|
||
-f "$root/packaging/container/Backend.Containerfile" \
|
||
-t "$local_image" "$container_context"
|
||
if [[ "$image_publish" == false ]]; then
|
||
echo "built local Backend image for $arch; not publishing it"
|
||
exit 0
|
||
fi
|
||
export REGISTRY_AUTH_FILE="$root/.release/auth/zot-linux-$arch.json"
|
||
mkdir -p "$(dirname "$REGISTRY_AUTH_FILE")"
|
||
logged_in=false
|
||
for attempt in 1 2 3 4; do
|
||
if buildah login --tls-verify=true --username "$ZOT_USERNAME" --password-stdin "$registry" <<< "$ZOT_SECRET" >/dev/null; then
|
||
logged_in=true
|
||
break
|
||
fi
|
||
if [[ "$attempt" -lt 4 ]]; then
|
||
echo "Zot login attempt $attempt failed; retrying in 3 seconds" >&2
|
||
sleep 3
|
||
fi
|
||
done
|
||
[[ "$logged_in" == true ]] || { echo "could not authenticate to Zot after 4 attempts" >&2; exit 1; }
|
||
push_tag() {
|
||
local target_tag="$1" pushed=false
|
||
for attempt in 1 2 3; do
|
||
if buildah push --tls-verify=true "$local_image" "docker://$image:$target_tag"; then
|
||
pushed=true
|
||
break
|
||
fi
|
||
if [[ "$attempt" -lt 3 ]]; then
|
||
echo "Zot push attempt $attempt failed; retrying in 5 seconds" >&2
|
||
sleep 5
|
||
fi
|
||
done
|
||
[[ "$pushed" == true ]] || { echo "could not push image to Zot after 3 attempts" >&2; return 1; }
|
||
echo "pushed Zot image $image:$target_tag"
|
||
}
|
||
|
||
if [[ -n "${IMAGE_TAGS:-}" ]]; then
|
||
IFS=',' read -r -a image_tags <<< "$IMAGE_TAGS"
|
||
((${#image_tags[@]} > 0)) || { echo "IMAGE_TAGS must contain at least one tag" >&2; exit 2; }
|
||
for image_tag in "${image_tags[@]}"; do
|
||
[[ "$image_tag" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]] || {
|
||
echo "invalid image tag: $image_tag" >&2
|
||
exit 2
|
||
}
|
||
push_tag "$image_tag"
|
||
done
|
||
else
|
||
push_tag "$version-$arch"
|
||
if [[ -z "$tag" ]]; then
|
||
push_tag "$version"
|
||
fi
|
||
fi
|