From 78163441ddb9fa07cd29e2865350e29c7414e654 Mon Sep 17 00:00:00 2001 From: Timi Date: Thu, 9 Apr 2026 13:14:20 +0800 Subject: [PATCH] v1.0.0 --- .gitea/workflows/ci.yml | 84 +++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 0956623..ba58c40 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -57,20 +57,17 @@ jobs: - name: Deploy service if: success() env: - HOST: host.docker.internal - APP_PATH: ${{ vars.APP_PATH }} - DOCKER_CONTAINER_NAME: ${{ vars.DOCKER_CONTAINER_NAME }} - SSHPASS: ${{ secrets.TIMI_SERVER_SSH_PWD }} + CONTAINER_NAME: ${{ vars.CONTAINER_NAME }} + CONTAINER_TARGET_PATH: ${{ vars.CONTAINER_TARGET_PATH }} MAX_RETRIES: 3 RETRY_DELAY: 10 run: | - if [ -z "$HOST" ] || [ -z "$APP_PATH" ] || [ -z "DOCKER_CONTAINER_NAME" ] || [ -z "$SSHPASS" ]; then + if [ -z "$CONTAINER_NAME" ] || [ -z "$CONTAINER_TARGET_PATH" ]; then echo "Missing production environment variables" - echo "Required: APP_PATH, DOCKER_CONTAINER_NAME, TIMI_SERVER_SSH_PWD" + echo "Required: CONTAINER_NAME, CONTAINER_TARGET_PATH" exit 1 fi - # 重试函数 retry_command() { local cmd="$1" local desc="$2" @@ -79,10 +76,10 @@ jobs: while [ $attempt -le $MAX_RETRIES ]; do echo "[$desc] Attempt $attempt/$MAX_RETRIES..." if eval "$cmd"; then - echo "✓ $desc succeeded" + echo "OK: $desc succeeded" return 0 fi - echo "✗ $desc failed (attempt $attempt/$MAX_RETRIES)" + echo "FAIL: $desc failed (attempt $attempt/$MAX_RETRIES)" if [ $attempt -lt $MAX_RETRIES ]; then echo "Retrying in ${RETRY_DELAY}s..." sleep $RETRY_DELAY @@ -90,16 +87,10 @@ jobs: attempt=$((attempt + 1)) done - echo "✗ $desc failed after $MAX_RETRIES attempts" + echo "FAIL: $desc failed after $MAX_RETRIES attempts" return 1 } - # SSH 配置(使用密码认证) - SSH_PORT="22" - SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=30 -o ServerAliveInterval=10 -o ServerAliveCountMax=3 -p $SSH_PORT" - SCP_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=30 -o ServerAliveInterval=10 -o ServerAliveCountMax=3 -P $SSH_PORT" - - # 获取构建产物信息 version=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version) artifact_id=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.artifactId) jar_file="target/${artifact_id}-${version}.jar" @@ -109,18 +100,26 @@ jobs: exit 1 fi - # 目标文件名(去掉版本号) - target_jar="${artifact_id}.jar" - echo "Deploying $jar_file to $HOST:$APP_PATH/$target_jar" - - # 上传文件(带重试) - if ! retry_command "sshpass -e scp $SCP_OPTS \"$jar_file\" \"root@$HOST:$APP_PATH/$target_jar\"" "SCP upload"; then + if ! command -v docker >/dev/null 2>&1; then + echo "docker command not found in runner environment" exit 1 fi - # 重启 Docker 服务(带重试) - echo "Restarting Docker service: $DOCKER_SERVICE_NAME" - if ! retry_command "sshpass -e ssh $SSH_OPTS \"root@$HOST\" \"docker restart $DOCKER_SERVICE_NAME\"" "Docker restart"; then + if ! docker inspect "$CONTAINER_NAME" >/dev/null 2>&1; then + echo "Docker container not found: $CONTAINER_NAME" + exit 1 + fi + + target_jar="${artifact_id}.jar" + container_target="${CONTAINER_TARGET_PATH%/}/$target_jar" + echo "Deploying $jar_file to container $CONTAINER_NAME:$container_target" + + if ! retry_command "docker cp \"$jar_file\" \"$CONTAINER_NAME:$container_target\"" "Docker copy"; then + exit 1 + fi + + echo "Restarting Docker container: $CONTAINER_NAME" + if ! retry_command "docker restart \"$CONTAINER_NAME\"" "Docker restart"; then exit 1 fi echo "Deployment completed successfully" @@ -142,7 +141,6 @@ jobs: exit 1 fi - # Use internal URL if available, fallback to public URL if [ -n "$GITEA_INTERNAL_URL" ]; then api_base_url="$GITEA_INTERNAL_URL" echo "Using internal Gitea URL: $api_base_url" @@ -151,7 +149,6 @@ jobs: echo "Using public Gitea URL: $api_base_url" fi - # 获取构建产物信息 version=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version) artifact_id=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.artifactId) jar_file="target/${artifact_id}-${version}.jar" @@ -179,17 +176,14 @@ jobs: echo "API URL: $api_url" echo "Target commit: $RELEASE_TARGET" - # 使用唯一临时文件避免跨 job 污染 release_response_file=$(mktemp /tmp/release_response_XXXXXX.json) trap "rm -f $release_response_file" EXIT - # 创建 release(带重试,处理幂等性) release_id="" attempt=1 while [ $attempt -le $MAX_RETRIES ] && [ -z "$release_id" ]; do echo "[Create release] Attempt $attempt/$MAX_RETRIES..." - # 清空临时文件 > "$release_response_file" http_code=$(curl -sS -w "%{http_code}" -o "$release_response_file" -X POST "$api_url" \ @@ -203,30 +197,27 @@ jobs: echo "HTTP Status: $http_code" if [ "$http_code" = "201" ]; then - # 提取第一个 id 字段的值,确保去除换行符 if command -v jq >/dev/null 2>&1; then release_id=$(echo "$response" | jq -r '.id' 2>/dev/null) else release_id=$(echo "$response" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2 | tr -d '\n\r') fi - echo "✓ Release created: id=$release_id" + echo "OK: Release created: id=$release_id" elif [ "$http_code" = "409" ]; then - # HTTP 409 Conflict: Release 已存在,获取现有的 release_id echo "Release already exists (HTTP 409), fetching existing release..." existing=$(curl -sS "$api_url" -H "Authorization: token $GITEA_TOKEN" --connect-timeout 30 2>/dev/null || echo "[]") - # 使用 jq 解析 JSON,如果没有 jq 则用 grep if command -v jq >/dev/null 2>&1; then release_id=$(echo "$existing" | jq -r ".[] | select(.tag_name==\"$RELEASE_TAG\") | .id" 2>/dev/null | head -1) else release_id=$(echo "$existing" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2 | tr -d '\n\r') fi if [ -n "$release_id" ]; then - echo "✓ Found existing release: id=$release_id" + echo "OK: Found existing release: id=$release_id" else - echo "✗ Could not find existing release id" + echo "FAIL: Could not find existing release id" fi else - echo "✗ Failed (HTTP $http_code)" + echo "FAIL: Create release failed (HTTP $http_code)" if [ $attempt -lt $MAX_RETRIES ]; then echo "Retrying in ${RETRY_DELAY}s..." sleep $RETRY_DELAY @@ -236,17 +227,15 @@ jobs: done if [ -z "$release_id" ]; then - echo "✗ Failed to create/find release after $MAX_RETRIES attempts" + echo "FAIL: Failed to create or find release after $MAX_RETRIES attempts" exit 1 fi - # 上传 fat jar(带重试) asset_name=$(basename "$jar_file") echo "Uploading asset: $asset_name (size: $file_size bytes)" upload_url="$api_url/$release_id/assets?name=$asset_name" echo "Upload URL: $upload_url" - # 使用唯一临时文件避免跨 job 污染 asset_response_file=$(mktemp /tmp/asset_response_XXXXXX.json) trap "rm -f $release_response_file $asset_response_file" EXIT @@ -255,10 +244,8 @@ jobs: while [ $attempt -le $MAX_RETRIES ] && [ "$upload_success" = "false" ]; do echo "[Upload asset] Attempt $attempt/$MAX_RETRIES..." - # 清空临时文件 > "$asset_response_file" - # Gitea API 要求使用 multipart/form-data 格式上传文件 http_code=$(curl -sS -w "%{http_code}" -o "$asset_response_file" -X POST "$upload_url" \ -H "Authorization: token $GITEA_TOKEN" \ --connect-timeout 30 \ @@ -267,9 +254,9 @@ jobs: if [ "$http_code" = "201" ]; then upload_success=true - echo "✓ Successfully uploaded: $asset_name" + echo "OK: Successfully uploaded: $asset_name" else - echo "✗ Upload failed (HTTP $http_code)" + echo "FAIL: Upload failed (HTTP $http_code)" cat "$asset_response_file" 2>/dev/null || true fi @@ -281,7 +268,7 @@ jobs: done if [ "$upload_success" = "false" ]; then - echo "✗ Failed to upload asset after $MAX_RETRIES attempts" + echo "FAIL: Failed to upload asset after $MAX_RETRIES attempts" exit 1 fi @@ -306,7 +293,6 @@ jobs: COMMIT_SHA: ${{ github.sha }} REPO: ${{ github.repository }} SERVER_URL: ${{ github.server_url }} - # 通知配置(按需启用) WEBHOOK_URL: ${{ vars.NOTIFY_WEBHOOK_URL }} run: | echo "=========================================" @@ -324,11 +310,9 @@ jobs: echo "" echo "=========================================" - # 发送 Webhook 通知(钉钉/企业微信/Slack 等) if [ -n "$WEBHOOK_URL" ]; then - message="🚨 CI 部署失败\n\nPR: #$PR_NUMBER - $PR_TITLE\n分支: $SOURCE_BRANCH\n提交者: $AUTHOR\n\n请检查并决定:\n• 重试 CI\n• 回滚合并" + message="CI 部署失败\n\nPR: #$PR_NUMBER - $PR_TITLE\n分支: $SOURCE_BRANCH\n提交者: $AUTHOR\n\n请检查并决定:\n- 重试 CI\n- 回滚合并" - # 通用 JSON 格式(适配大多数 Webhook) payload=$(cat <