Files
base-workflow/.gitea/workflows/common-trigger.yml
2026-06-22 14:28:06 +08:00

270 lines
9.9 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: Build Any Repository Docker Image
on:
workflow_dispatch:
inputs:
repo_url:
description: '要构建的仓库地址支持相对路径如xc-workflows/engine-demo或完整 URL 如https://dev.modelhub.org.cn/xc-workflows/engine-demo'
required: true
type: string
ref:
description: '分支/tag/commit'
required: true
default: 'main'
type: string
dry_run:
description: '仅构建不推送'
required: false
default: 'false'
type: choice
options:
- 'true'
- 'false'
job_id:
description: '任务ID'
required: true
type: string
submission_id:
description: '提交ID'
required: true
type: string
callback_url:
description: '回调地址'
required: false
default: ''
type: string
callback_token:
description: '回调Token'
required: false
default: ''
type: string
startup_params:
description: '启动参数JSON格式'
required: false
default: '{}'
type: string
jobs:
build:
runs-on: amd64-ubuntu-24.04
steps:
- name: Debug URL info
run: |
echo "Server URL: ${{ gitea.server_url }}"
echo "Repo URL input: ${{ github.event.inputs.repo_url }}"
echo "Ref: ${{ github.event.inputs.ref }}"
echo "Dry run: ${{ github.event.inputs.dry_run }}"
echo "Job ID: ${{ github.event.inputs.job_id }}"
echo "Submission ID: ${{ github.event.inputs.submission_id }}"
echo "Callback URL: ${{ github.event.inputs.callback_url }}"
echo "Startup Params: ${{ github.event.inputs.startup_params }}"
- name: Clone target repository
run: |
REPO_URL="${{ github.event.inputs.repo_url }}"
# 判断是否完整 URL
if [[ "$REPO_URL" == http://* || "$REPO_URL" == https://* ]]; then
CLONE_URL="$REPO_URL"
# 如果没有 .git 后缀,加上
[[ "$CLONE_URL" != *.git ]] && CLONE_URL="${CLONE_URL}.git"
# 提取路径部分用于生成镜像名
REPO_PATH="$(echo "$REPO_URL" | sed 's|https\?://[^/]*/||' | sed 's|\.git$||')"
else
# 拼接完整的 clone URLgitea.server_url 已包含协议)
CLONE_URL="${{ gitea.server_url }}/$REPO_URL.git"
REPO_PATH="$REPO_URL"
fi
echo "正在克隆: $CLONE_URL"
git clone "$CLONE_URL" target_repo
cd target_repo
git checkout "${{ github.event.inputs.ref }}"
# 打 tag
TAG_NAME="build-submission${{ github.event.inputs.submission_id }}-job${{ github.event.inputs.job_id }}"
git tag "$TAG_NAME"
echo "已打 tag: $TAG_NAME"
# 保存仓库信息供后续步骤使用
echo "TARGET_REPO_PATH=$(pwd)" >> "$GITEA_ENV"
echo "TARGET_REPO_NAME=$(basename "$REPO_PATH")" >> "$GITEA_ENV"
echo "REPO_PATH=$REPO_PATH" >> "$GITEA_ENV"
echo "TAG_NAME=$TAG_NAME" >> "$GITEA_ENV"
echo "克隆完成,当前目录: $(pwd)"
- name: Set image metadata
run: |
cd target_repo
# 生成镜像名称(将仓库路径中的 / 替换为 -,并统一归到 judge-flows 命名空间下)
IMAGE_NAME="judge-flows/$(echo "$REPO_PATH" | tr '[:upper:]' '[:lower:]' | tr '/' '-')"
SAFE_TAG="${TAG_NAME}"
IMAGE="${DOCKER_REGISTRY}/${DOCKER_USERNAME}/${IMAGE_NAME}:${SAFE_TAG}"
echo "IMAGE_NAME=${IMAGE_NAME}" >> "$GITEA_ENV"
echo "IMAGE=${IMAGE}" >> "$GITEA_ENV"
echo "SAFE_TAG=${SAFE_TAG}" >> "$GITEA_ENV"
echo "镜像名称: ${IMAGE}"
- name: Check Dockerfile exists
id: check-dockerfile
run: |
cd target_repo
if [ ! -f "Dockerfile" ]; then
echo "错误: 仓库根目录下未找到 Dockerfile"
exit 1
fi
echo "Dockerfile 存在"
- name: Login to Docker Registry
id: login-registry
if: github.event.inputs.dry_run != 'true'
run: |
echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" \
-u "$DOCKER_USERNAME" \
--password-stdin
echo "Docker 登录成功"
- name: Build Docker Image
id: build-image
run: |
cd target_repo
echo "开始构建镜像: ${IMAGE}"
set -o pipefail
docker build -t "${IMAGE}" . 2>&1 | tee build.log
echo "镜像构建完成"
- name: List built image
run: |
docker images | grep "${IMAGE_NAME}" || echo "镜像列表查看完成"
- name: Push Docker Image
id: push-image
if: github.event.inputs.dry_run != 'true'
run: |
set -o pipefail
{
for attempt in 1 2 3; do
echo "Starting docker push attempt ${attempt}/3 for ${IMAGE}"
if docker push "${IMAGE}"; then
echo "docker push completed successfully"
exit 0
fi
echo "docker push failed on attempt ${attempt}/3"
if [ $attempt -lt 3 ]; then
echo "等待 30 秒后重试..."
sleep 30
fi
done
echo "docker push failed after 3 attempts"
exit 1
} 2>&1 | tee push.log
- name: Dry Run Summary
if: github.event.inputs.dry_run == 'true'
run: |
echo "=========================================="
echo "✅ 仅构建模式完成(未推送)"
echo "=========================================="
echo "源仓库: ${{ github.event.inputs.repo_url }}"
echo "分支: ${{ github.event.inputs.ref }}"
echo "镜像名称: ${IMAGE}"
echo "镜像标签: ${SAFE_TAG}"
echo "=========================================="
echo "如需完整发布(推送镜像),请使用 dry_run=false 重新触发"
- name: Full Build Summary
if: github.event.inputs.dry_run != 'true'
run: |
echo "=========================================="
echo "✅ 完整构建完成(已推送)"
echo "=========================================="
echo "源仓库: ${{ github.event.inputs.repo_url }}"
echo "分支: ${{ github.event.inputs.ref }}"
echo "镜像名称: ${IMAGE}"
echo "镜像标签: ${SAFE_TAG}"
echo "=========================================="
- name: Callback notification
if: always() && github.event.inputs.callback_url != ''
run: |
echo "正在发送回调通知..."
# 构造回调请求体
CALLBACK_URL="${{ github.event.inputs.callback_url }}"
CALLBACK_TOKEN="${{ github.event.inputs.callback_token }}"
JOB_ID="${{ github.event.inputs.job_id }}"
STARTUP_PARAMS='${{ github.event.inputs.startup_params }}'
# 判断状态与错误信息
STATUS="SUCCESS"
ERR_MESSAGE=""
if [ "${{ steps.check-dockerfile.outcome }}" == "failure" ]; then
STATUS="FAILED"
ERR_MESSAGE="仓库根目录下未找到 Dockerfile"
elif [ "${{ steps.login-registry.outcome }}" == "failure" ]; then
STATUS="FAILED"
ERR_MESSAGE="Docker 镜像仓库登录失败"
elif [ "${{ steps.build-image.outcome }}" == "failure" ]; then
STATUS="FAILED"
ERR_MESSAGE=$(tail -n 20 build.log 2>/dev/null || echo "Docker 镜像构建失败")
elif [ "${{ steps.push-image.outcome }}" == "failure" ]; then
STATUS="FAILED"
ERR_MESSAGE=$(tail -n 20 push.log 2>/dev/null || echo "Docker 镜像推送失败")
fi
# dry_run 为 true 时,回调使用固定镜像地址
if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then
IMAGE_URL="harbor-contest.4pd.io/luopingyi/enginex-iluvatar-bi150/vllm:0.8.3"
else
IMAGE_URL="$IMAGE"
fi
# 使用 jq 构造 JSON 请求体
if [ -n "$ERR_MESSAGE" ]; then
BODY=$(jq -n \
--arg jobId "$JOB_ID" \
--arg imageUrl "$IMAGE_URL" \
--arg status "$STATUS" \
--arg errMessage "$ERR_MESSAGE" \
--argjson startupParams "$STARTUP_PARAMS" \
'{jobId: $jobId, imageUrl: $imageUrl, status: $status, errMessage: $errMessage, startupParams: $startupParams}')
else
BODY=$(jq -n \
--arg jobId "$JOB_ID" \
--arg imageUrl "$IMAGE_URL" \
--arg status "$STATUS" \
--argjson startupParams "$STARTUP_PARAMS" \
'{jobId: $jobId, imageUrl: $imageUrl, status: $status, startupParams: $startupParams}')
fi
echo "回调请求体: $BODY"
# 发送 POST 请求
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-H "X-Callback-Token: $CALLBACK_TOKEN" \
-d "$BODY" \
"$CALLBACK_URL" || true)
# 去除空白并校验 HTTP_CODE 是否为数字
HTTP_CODE=$(echo "$HTTP_CODE" | tr -d '[:space:]')
if ! [[ "$HTTP_CODE" =~ ^[0-9]+$ ]]; then
HTTP_CODE="000"
fi
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "✅ 回调通知发送成功HTTP 状态码: $HTTP_CODE"
else
echo "❌ 回调通知发送失败HTTP 状态码: $HTTP_CODE"
exit 1
fi