Remove Probe build jobs and release paths. Transfer Gitea publishing credentials to both Agent architecture jobs, publish each platform archive once, and run slow tests after development images are published.
205 lines
8.3 KiB
Bash
205 lines
8.3 KiB
Bash
#!/usr/bin/env bash
|
|
# Build and push one architecture-specific development image (main push with [CI]) to moshiro-dev.
|
|
set -euo pipefail
|
|
|
|
[[ "${CI_PIPELINE_EVENT:-}" == push && "${CI_COMMIT_BRANCH:-}" == main && "${CI_COMMIT_MESSAGE:-}" == *"[CI]"* ]] || {
|
|
echo "development image builds require a main push with [CI] in the commit message" >&2
|
|
exit 2
|
|
}
|
|
|
|
component="${1:?usage: build-dev-image.sh <backend|agent> [amd64|arm64]}"
|
|
arch="${2:-amd64}"
|
|
case "$component" in
|
|
backend|agent) ;;
|
|
*) echo "unsupported component: $component" >&2; exit 2 ;;
|
|
esac
|
|
case "$arch" in
|
|
amd64|arm64) ;;
|
|
*) echo "unsupported architecture: $arch" >&2; exit 2 ;;
|
|
esac
|
|
if [[ "$component" == backend && "$arch" != amd64 ]]; then
|
|
echo "the main development pipeline currently builds Backend for amd64 only" >&2
|
|
exit 2
|
|
fi
|
|
[[ -n "${ZOT_USERNAME:-}" && -n "${ZOT_SECRET:-}" ]] || {
|
|
echo "Zot credentials are required" >&2
|
|
exit 2
|
|
}
|
|
[[ "${CI_COMMIT_SHA:-}" =~ ^[0-9a-fA-F]{40}$ ]] || {
|
|
echo "CI_COMMIT_SHA must be a full commit SHA" >&2
|
|
exit 2
|
|
}
|
|
|
|
active_command_pid=""
|
|
cancel_active_command() {
|
|
local pid="${active_command_pid:-}"
|
|
[[ -n "$pid" ]] || return 0
|
|
|
|
kill -TERM -- "-$pid" 2>/dev/null || true
|
|
kill -TERM "$pid" 2>/dev/null || true
|
|
for _ in {1..10}; do
|
|
kill -0 -- "-$pid" 2>/dev/null || break
|
|
sleep 1
|
|
done
|
|
kill -KILL -- "-$pid" 2>/dev/null || true
|
|
kill -KILL "$pid" 2>/dev/null || true
|
|
wait "$pid" 2>/dev/null || true
|
|
active_command_pid=""
|
|
}
|
|
|
|
handle_cancel() {
|
|
trap - TERM INT HUP
|
|
cancel_active_command
|
|
exit 143
|
|
}
|
|
|
|
trap handle_cancel TERM INT HUP
|
|
|
|
run_bounded() {
|
|
local duration="$1" status=0
|
|
shift
|
|
|
|
# setsid gives the command its own process group so a cancel signal can
|
|
# terminate Buildah and its children even when the local backend only signals
|
|
# the shell process. timeout is the fallback if cancellation is lost entirely.
|
|
setsid timeout --foreground --signal=TERM --kill-after=30s "$duration" "$@" <&0 &
|
|
active_command_pid=$!
|
|
if wait "$active_command_pid"; then
|
|
status=0
|
|
else
|
|
status=$?
|
|
fi
|
|
active_command_pid=""
|
|
return "$status"
|
|
}
|
|
|
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
# 版本:v<下一个补丁版本>-dev.<自最近 tag 的提交数>-<提交前 7 位>(见 ci/version.sh);写进工作区的 Directory.Build.props,镜像标签、构建信息、签名清单都用它
|
|
source "$root/ci/version.sh"
|
|
moshiro_apply_version
|
|
registry="${ZOT_REGISTRY:-registry.oeo.one}"
|
|
repository="$registry/moshiro-dev/moshiro-$component"
|
|
work="$root/.release/dev-image-build/$component-$arch"
|
|
base_home="/home/justme/woodpecker/buildah-home/dev-image-build-noble-aot-v1-$component-$arch"
|
|
# 镜像标签不带 v(和正式版一致):latest 和 <版本>;构建信息和清单里的 tag 带 v
|
|
image_version="$MOSHIRO_VERSION"
|
|
mkdir -p "$work" "$base_home"
|
|
export REGISTRY_AUTH_FILE="$work/$component-auth.json"
|
|
if [[ ! -s "$REGISTRY_AUTH_FILE" ]]; then
|
|
printf '{"auths":{}}\n' > "$REGISTRY_AUTH_FILE"
|
|
chmod 600 "$REGISTRY_AUTH_FILE"
|
|
fi
|
|
|
|
if [[ "$component" == backend ]]; then
|
|
BUILDAH_HOME="$base_home" \
|
|
ZOT_REGISTRY="$registry" \
|
|
ZOT_IMAGE_REPOSITORY="$repository" \
|
|
IMAGE_TAGS="latest,$image_version" \
|
|
IMAGE_PUBLISH=true \
|
|
MOSHIRO_PUSH_GATE="$root/ci/wait-for-checks.sh" \
|
|
run_bounded 30m bash "$root/ci/release-linux.sh" "$arch" backend
|
|
exit 0
|
|
fi
|
|
|
|
export HOME="$base_home"
|
|
export BUILDAH_HOME="$base_home"
|
|
source "$root/ci/buildah-env.sh"
|
|
moshiro_setup_buildah "$base_home"
|
|
context="$work/$component"
|
|
local_image="localhost/moshiro-$component:dev-$arch-check"
|
|
node_rid="linux-musl-x64"
|
|
[[ "$arch" == arm64 ]] && node_rid="linux-musl-arm64"
|
|
# Build a dedicated .NET 10 NativeAOT/AotAnywhere environment in this isolated
|
|
# Buildah store. Keeping NuGet inside image layers avoids a shared writable
|
|
# package mount being corrupted by canceled or parallel builds.
|
|
builder_image="localhost/moshiro-dotnet10-nativeaot-aotanywhere:ci"
|
|
source "$root/ci/nativeaot-toolchain.sh"
|
|
moshiro_nativeaot_settings "$root"
|
|
builder_cache="${MOSHIRO_RUNNER_IMAGE_CACHE:-/home/justme/woodpecker/cache/runner-image}"
|
|
cached_key="$(cat "$builder_cache/nativeaot-builder.key" 2>/dev/null || true)"
|
|
builder_id="$(cat "$builder_cache/nativeaot-builder.id" 2>/dev/null || true)"
|
|
if [[ "$cached_key" == "$MOSHIRO_NATIVEAOT_BUILDER_KEY" && "$builder_id" =~ ^[0-9a-f]{64}$ && -f "$builder_cache/nativeaot-builder-$builder_id.oci" ]]; then
|
|
local_builder_id="$(buildah images --noheading --no-trunc --format '{{.ID}}' "$builder_image" 2>/dev/null || true)"
|
|
if [[ "${local_builder_id#sha256:}" != "$builder_id" ]]; then
|
|
run_bounded 10m buildah pull "oci-archive:$builder_cache/nativeaot-builder-$builder_id.oci"
|
|
buildah tag "$builder_id" "$builder_image"
|
|
fi
|
|
echo "using cached NativeAOT toolchain $builder_id"
|
|
else
|
|
builder_context="$work/nativeaot-builder"
|
|
mkdir -p "$builder_context"
|
|
tr -d '\r' < "$root/global.json" > "$builder_context/global.json"
|
|
run_bounded 30m buildah bud --layers --network host --tls-verify=true --arch amd64 \
|
|
--build-arg "AOTANYWHERE_VERSION=$MOSHIRO_AOTANYWHERE_VERSION" \
|
|
--build-arg "ZIG_TOOLSET_VERSION=$MOSHIRO_ZIG_TOOLSET_VERSION" \
|
|
-f "$root/packaging/container/NativeAot.Builder.Containerfile" \
|
|
-t "$builder_image" "$builder_context"
|
|
fi
|
|
|
|
# A stable timestamp lets a retry of the same commit reuse the publish layer.
|
|
commit_epoch="$(git -C "$root" show -s --format=%ct "$CI_COMMIT_SHA")"
|
|
built_at="$(date -u -d "@$commit_epoch" +%Y-%m-%dT%H:%M:%SZ)"
|
|
|
|
python3 "$root/ci/stage-node-image.py" "$component" "$node_rid" "$context"
|
|
# Zig compiles musl libc by spawning many compiler processes. Buildah's default
|
|
# nofile limit (1024) makes Zig fail with ProcessFdQuotaExceeded while linking.
|
|
run_bounded 30m buildah bud --layers --network host --tls-verify=true --ulimit nofile=65536:65536 --arch "$arch" \
|
|
--build-arg "NATIVEAOT_BUILDER_IMAGE=$builder_image" \
|
|
--build-arg "APP_VERSION=$image_version" \
|
|
--build-arg "NODE_RID=$node_rid" \
|
|
--build-arg "MOSHIRO_TAG=$MOSHIRO_TAG" --build-arg "MOSHIRO_COMMIT=${CI_COMMIT_SHA:0:10}" --build-arg "MOSHIRO_BUILT_AT=$built_at" \
|
|
-f "$context/Containerfile" \
|
|
-t "$local_image" "$context"
|
|
|
|
# 构建和测试是并行的:镜像已经好了,推送之前等 verify 和 web-build 都过(任何一个失败就不推)
|
|
bash "$root/ci/wait-for-checks.sh"
|
|
|
|
logged_in=false
|
|
for attempt in 1 2 3 4; do
|
|
if run_bounded 2m 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; }
|
|
|
|
for tag in "$image_version-$arch"; do
|
|
pushed=false
|
|
for attempt in 1 2 3; do
|
|
if run_bounded 10m buildah push --tls-verify=true --digestfile "$work/$component.digest" "$local_image" "docker://$repository:$tag"; then
|
|
pushed=true
|
|
break
|
|
fi
|
|
if [[ "$attempt" -lt 3 ]]; then
|
|
echo "Zot push for $component:$tag attempt $attempt failed; retrying in 5 seconds" >&2
|
|
sleep 5
|
|
fi
|
|
done
|
|
[[ "$pushed" == true ]] || { echo "could not push $repository:$tag after 3 attempts" >&2; exit 1; }
|
|
echo "pushed development image $repository:$tag"
|
|
done
|
|
|
|
# Reuse the static Agent/enrollment binaries already built above; do not compile again.
|
|
# Publish before the multi-arch image offer wakes online native nodes.
|
|
if [[ "$component" == agent ]]; then
|
|
buildah rm "moshiro-openwrt-extract-$arch" >/dev/null 2>&1 || true
|
|
native_container="$(buildah from --arch "$arch" --name "moshiro-openwrt-extract-$arch" "$local_image")"
|
|
native_dir="$work/openwrt"
|
|
mkdir -p "$native_dir"
|
|
native_mount="$(buildah mount "$native_container")"
|
|
cp "$native_mount/usr/local/bin/moshiro-agent" "$native_mount/usr/local/bin/fleet-enroll" "$native_dir/"
|
|
buildah unmount "$native_container" >/dev/null
|
|
buildah rm "$native_container" >/dev/null
|
|
bash "$root/ci/publish-openwrt.sh" dev "$node_rid" "$native_dir"
|
|
fi
|
|
|
|
# Agent manifests are signed after both architecture-specific images
|
|
# have been pushed. Backend is still a single-architecture development image.
|
|
if [[ "$component" == backend && -n "${RELEASE_SIGNING_KEY:-}" ]]; then
|
|
bash "$root/ci/publish-release-offer.sh" "$component" "$repository" "$(cat "$work/$component.digest")" "$MOSHIRO_TAG" dev "$work/$component-release"
|
|
fi
|