From e7eea8c6cc50ef0e7e2997cfdd6be790889b8d7a Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 19 Jan 2026 05:12:39 +0000 Subject: [PATCH] chore: add itom-platform auto build workflow --- .gitea/workflows/itom-platform-auto-build.yml | 329 ++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 .gitea/workflows/itom-platform-auto-build.yml diff --git a/.gitea/workflows/itom-platform-auto-build.yml b/.gitea/workflows/itom-platform-auto-build.yml new file mode 100644 index 0000000..509d2e4 --- /dev/null +++ b/.gitea/workflows/itom-platform-auto-build.yml @@ -0,0 +1,329 @@ +name: itom-platform auto build image +# itom-platform:auto-ci-managed +# 自动生成:如需自定义并阻止覆盖,请删除上一行标记 + +on: + push: + branches: + - main + workflow_dispatch: {} + +permissions: + contents: read + packages: write + +env: + # CI 触发模式:优先仓库变量,其次 Secrets(默认 dispatch) + CI_TRIGGER_MODE_VAR: ${{ vars.CI_TRIGGER_MODE }} + CI_TRIGGER_MODE_SECRET: ${{ secrets.CI_TRIGGER_MODE }} + +jobs: + build: + runs-on: ubuntu-latest + + env: + REGISTRY: docker.io + IMAGE: docker.io/kim6789/chat-deploy + steps: + - name: Check trigger mode + env: + # 兼容 Gitea/Forgejo:优先仓库变量,其次 Secrets + CI_TRIGGER_MODE_VAR: ${{ vars.CI_TRIGGER_MODE }} + CI_TRIGGER_MODE_SECRET: ${{ secrets.CI_TRIGGER_MODE }} + shell: sh + run: | + set -eu + MODE="${CI_TRIGGER_MODE:-${CI_TRIGGER_MODE_VAR:-${CI_TRIGGER_MODE_SECRET:-dispatch}}}" + MODE="$(printf 'git.imall.cloud' "$MODE" | tr 'A-Z' 'a-z')" + EVENT="${GITHUB_EVENT_NAME:-${GITEA_EVENT_NAME:-${GITEA_EVENT:-}}}" + EVENT="$(printf '' "$EVENT" | tr 'A-Z' 'a-z')" + if [ -z "$EVENT" ]; then + # 兼容重跑场景:部分运行器不会传递事件名 + EVENT="workflow_dispatch" + fi + ALLOW="false" + case "$EVENT" in + workflow_dispatch|manual|workflow_run) + if [ "$MODE" = "dispatch" ] || [ "$MODE" = "both" ]; then + ALLOW="true" + fi + ;; + push) + if [ "$MODE" = "push" ] || [ "$MODE" = "both" ]; then + ALLOW="true" + fi + ;; + *) + # 未知事件默认走 dispatch 逻辑,避免误跳过 + if [ "$MODE" = "dispatch" ] || [ "$MODE" = "both" ]; then + ALLOW="true" + fi + ;; + esac + echo "CI_TRIGGER_MODE=$MODE" >> "$GITHUB_ENV" + echo "CI_TRIGGER_ALLOWED=$ALLOW" >> "$GITHUB_ENV" + if [ "$ALLOW" != "true" ]; then + echo "Skip build: event=$EVENT mode=$MODE" + fi + + - name: Install git + if: ${{ env.CI_TRIGGER_ALLOWED == 'true' }} + shell: sh + run: | + set -eu + if ! command -v git >/dev/null 2>&1; then + apk add --no-cache git openssh-client ca-certificates + fi + + - name: Checkout + if: ${{ env.CI_TRIGGER_ALLOWED == 'true' }} + shell: sh + env: + GIT_USER: ${{ secrets.GIT_USER }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} + REGISTRY_USER: ${{ secrets.REGISTRY_USER }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + run: | + set -eu + WORKDIR="${GITHUB_WORKSPACE:-/workspace}" + mkdir -p "$WORKDIR" + REPO="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" + SERVER="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-https://}}" + if [ -z "$REPO" ]; then + echo "ERROR: missing repository info." + exit 1 + fi + USER="" + TOKEN="" + if [ -n "${GIT_USER:-}" ] && [ -n "${GIT_TOKEN:-}" ]; then + USER="$GIT_USER" + TOKEN="$GIT_TOKEN" + elif [ -n "${GITEA_TOKEN:-}" ]; then + USER="${GITEA_ACTOR:-${FORGEJO_ACTOR:-${GITHUB_ACTOR:-}}}" + TOKEN="$GITEA_TOKEN" + elif [ -n "${FORGEJO_TOKEN:-}" ]; then + USER="${FORGEJO_ACTOR:-${GITHUB_ACTOR:-}}" + TOKEN="$FORGEJO_TOKEN" + elif [ -n "${GITHUB_TOKEN:-}" ]; then + USER="${GITHUB_ACTOR:-}" + TOKEN="$GITHUB_TOKEN" + elif [ -n "${REGISTRY_USER:-}" ] && [ -n "${REGISTRY_PASSWORD:-}" ]; then + USER="$REGISTRY_USER" + TOKEN="$REGISTRY_PASSWORD" + fi + if [ -n "$TOKEN" ]; then + if [ -z "$USER" ]; then + echo "ERROR: missing git username for token auth." + exit 1 + fi + AUTH_HOST="${SERVER#https://}" + AUTH_HOST="${AUTH_HOST#http://}" + git clone "https://${USER}:${TOKEN}@${AUTH_HOST}/${REPO}.git" "$WORKDIR" + else + git clone "${SERVER}/${REPO}.git" "$WORKDIR" + fi + cd "$WORKDIR" + SHA="${GITHUB_SHA:-${GITEA_SHA:-}}" + if [ -n "$SHA" ]; then + git checkout "$SHA" + fi + + - name: Prepare tags + if: ${{ env.CI_TRIGGER_ALLOWED == 'true' }} + shell: sh + run: | + set -eu + BRANCH="${GITHUB_REF_NAME:-${GITEA_REF_NAME:-}}" + if [ -z "$BRANCH" ]; then + BRANCH="$(echo "${GITHUB_REF:-${GITEA_REF:-}}" | sed 's#.*/##')" + fi + BRANCH="$(echo "$BRANCH" | tr '/' '-')" + SHA="${GITHUB_SHA:-${GITEA_SHA:-}}" + SHA_SHORT="$(printf '%s' "$SHA" | cut -c1-7)" + echo "BRANCH=$BRANCH" >> "$GITHUB_ENV" + echo "SHA_SHORT=$SHA_SHORT" >> "$GITHUB_ENV" + + - name: Resolve Dockerfile + if: ${{ env.CI_TRIGGER_ALLOWED == 'true' }} + shell: sh + run: | + set -eu + DOCKERFILE_PATH="${DOCKERFILE_PATH:-}" + BUILD_CONTEXT="${BUILD_CONTEXT:-.}" + if [ -z "$DOCKERFILE_PATH" ]; then + for candidate in Dockerfile docker/Dockerfile .docker/Dockerfile build/Dockerfile api/Dockerfile api/docker/Dockerfile; do + if [ -f "$candidate" ]; then + DOCKERFILE_PATH="$candidate" + break + fi + done + fi + if [ -z "$DOCKERFILE_PATH" ]; then + echo "ERROR: Dockerfile not found. Set DOCKERFILE_PATH or add Dockerfile." + exit 1 + fi + echo "DOCKERFILE_PATH=$DOCKERFILE_PATH" >> "$GITHUB_ENV" + echo "BUILD_CONTEXT=$BUILD_CONTEXT" >> "$GITHUB_ENV" + + + - name: Login registry + if: ${{ env.CI_TRIGGER_ALLOWED == 'true' }} + shell: sh + env: + GIT_USER: ${{ secrets.GIT_USER }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} + REGISTRY_USER: ${{ secrets.REGISTRY_USER }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} +%!s(MISSING) + run: | + set -eu + # 带重试的登录函数(解决 Docker Hub 网络超时问题) + login_try() { + local user="$1" + local pass="$2" + local label="$3" + local max_retries=5 + local retry_delay=10 + if [ -z "$user" ] || [ -z "$pass" ]; then + return 1 + fi + for attempt in $(seq 1 $max_retries); do + echo "Registry login attempt $attempt/$max_retries ($label)..." + if echo "$pass" | docker login "$REGISTRY" -u "$user" --password-stdin 2>&1; then + echo "Registry login ok ($label)" + return 0 + fi + if [ $attempt -lt $max_retries ]; then + echo "Login failed, waiting ${retry_delay}s before retry..." + sleep $retry_delay + retry_delay=$((retry_delay * 2)) + fi + done + return 1 + } + + if login_try "$DOCKER_USERNAME" "$DOCKER_PASSWORD" "DOCKER"; then + exit 0 + fi + if login_try "$REGISTRY_USER" "$REGISTRY_PASSWORD" "REGISTRY_USER"; then + exit 0 + fi + if login_try "$GIT_USER" "$GIT_TOKEN" "GIT_USER"; then + exit 0 + fi + if login_try "${AUTO_REGISTRY_USER:-}" "${AUTO_REGISTRY_PASS:-}" "AUTO_REGISTRY"; then + exit 0 + fi + + ACTOR="${GITEA_ACTOR:-${FORGEJO_ACTOR:-${GITHUB_ACTOR:-}}}" + JOB_TOKEN="${GITEA_TOKEN:-${FORGEJO_TOKEN:-${GITHUB_TOKEN:-}}}" + if login_try "$ACTOR" "$JOB_TOKEN" "JOB_TOKEN"; then + exit 0 + fi + + echo "ERROR: registry login failed after retries. Provide REGISTRY_USER/REGISTRY_PASSWORD or GIT_USER/GIT_TOKEN with packages write permission." + exit 1 + + - name: Build and push images + if: ${{ env.CI_TRIGGER_ALLOWED == 'true' }} + shell: sh + env: + GIT_USER: ${{ secrets.GIT_USER }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} + REGISTRY_USER: ${{ secrets.REGISTRY_USER }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} +%!s(MISSING) + run: | + set -eu + cd "${GITHUB_WORKSPACE:-/workspace}" + IMAGE_BRANCH_TAG="$IMAGE:${BRANCH}" + IMAGE_SHA_TAG="$IMAGE:sha-${SHA_SHORT}" + git_user="${GIT_USER:-}" + git_token="${GIT_TOKEN:-}" + registry_user="${REGISTRY_USER:-}" + registry_pass="${REGISTRY_PASSWORD:-}" + if [ -z "$registry_user" ] && [ -n "${DOCKER_USERNAME:-}" ]; then + registry_user="$DOCKER_USERNAME" + registry_pass="${DOCKER_PASSWORD:-}" + fi + if [ -z "$registry_user" ] && [ -n "${AUTO_REGISTRY_USER:-}" ]; then + registry_user="$AUTO_REGISTRY_USER" + registry_pass="${AUTO_REGISTRY_PASS:-}" + fi + set -- docker build + if [ -n "$git_user" ] && [ -n "$git_token" ]; then + set -- "$@" --build-arg "GIT_USER=$git_user" --build-arg "GIT_TOKEN=$git_token" + fi + if [ -n "$registry_user" ] && [ -n "$registry_pass" ]; then + set -- "$@" --build-arg "REGISTRY_USER=$registry_user" --build-arg "REGISTRY_PASSWORD=$registry_pass" + fi + set -- "$@" -t "$IMAGE_BRANCH_TAG" -t "$IMAGE_SHA_TAG" -f "$DOCKERFILE_PATH" "$BUILD_CONTEXT" + "$@" + + log_image() { + local tag="$1" + echo "== Image info: $tag ==" + docker image inspect --format 'Image ID: {{.Id}} Size: {{.Size}}' "$tag" || true + } + + log_layers() { + local tag="$1" + echo "== RootFS layers (base -> top): $tag ==" + docker image inspect --format '{{range $i, $layer := .RootFS.Layers}}{{println $i $layer}}{{end}}' "$tag" || true + } + + log_history() { + local tag="$1" + echo "== Image history (top -> base): $tag ==" + docker history --no-trunc "$tag" | head -n 80 || true + echo "== (history truncated to 80 lines) ==" + } + + log_image "$IMAGE_BRANCH_TAG" + log_layers "$IMAGE_BRANCH_TAG" + log_history "$IMAGE_BRANCH_TAG" + + # 带重试的 push 函数(解决 Docker Hub 网络超时问题) + push_with_diag() { + local tag="$1" + local safe_tag + safe_tag=$(echo "$tag" | tr '/:' '__') + local log_file="/tmp/docker-push-${safe_tag}.log" + local max_retries=3 + local retry_delay=15 + + for attempt in $(seq 1 $max_retries); do + echo "== docker push $tag (attempt $attempt/$max_retries) ==" + if docker push "$tag" >"$log_file" 2>&1; then + tail -n 5 "$log_file" || true + return 0 + fi + echo "Push attempt $attempt failed." + if [ $attempt -lt $max_retries ]; then + echo "Waiting ${retry_delay}s before retry..." + sleep $retry_delay + retry_delay=$((retry_delay * 2)) + fi + done + + # 所有重试失败后,输出诊断信息 + log_image "$tag" + log_layers "$tag" + log_history "$tag" + echo "== Docker system info ==" + docker info || true + echo "== Disk usage (df -h) ==" + df -h || true + echo "== Docker disk usage ==" + docker system df -v | head -n 200 || true + echo "== Push failed (tail) for $tag ==" + tail -n 200 "$log_file" || true + exit 1 + } + + push_with_diag "$IMAGE_BRANCH_TAG" + push_with_diag "$IMAGE_SHA_TAG"