release.yml 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. name: Auto Release Pipeline
  2. on:
  3. push:
  4. branches:
  5. - main
  6. workflow_dispatch:
  7. inputs:
  8. version_type:
  9. description: 'Release type'
  10. required: true
  11. default: 'patch'
  12. type: choice
  13. options:
  14. - patch
  15. - minor
  16. - major
  17. - beta
  18. - rc
  19. - release
  20. prerelease_number:
  21. description: 'Beta/RC number (only for beta/rc types)'
  22. required: false
  23. default: '1'
  24. permissions:
  25. contents: write
  26. packages: write
  27. jobs:
  28. release-pipeline:
  29. runs-on: ubuntu-latest
  30. # 跳过由GitHub Actions创建的提交,避免死循环 (仅对push事件生效)
  31. if: |
  32. github.event_name == 'workflow_dispatch' ||
  33. (github.event.pusher.name != 'github-actions[bot]' && !contains(github.event.head_commit.message, '[skip ci]'))
  34. steps:
  35. - name: Checkout code
  36. uses: actions/checkout@v5
  37. with:
  38. fetch-depth: 0
  39. token: ${{ secrets.GITHUB_TOKEN }}
  40. - name: Check if version bump is needed
  41. id: check
  42. run: |
  43. # 检测是否是合并提交
  44. PARENT_COUNT=$(git rev-list --parents -n 1 HEAD | wc -w)
  45. PARENT_COUNT=$((PARENT_COUNT - 1))
  46. echo "Parent count: $PARENT_COUNT"
  47. if [ "$PARENT_COUNT" -gt 1 ]; then
  48. # 合并提交:获取合并进来的所有文件变更
  49. echo "Detected merge commit, getting all merged changes"
  50. # 获取合并基准点
  51. MERGE_BASE=$(git merge-base HEAD^1 HEAD^2 2>/dev/null || echo "")
  52. if [ -n "$MERGE_BASE" ]; then
  53. # 获取从合并基准到 HEAD 的所有变更
  54. CHANGED_FILES=$(git diff --name-only $MERGE_BASE..HEAD)
  55. else
  56. # 如果无法获取合并基准,使用第二个父提交
  57. CHANGED_FILES=$(git diff --name-only HEAD^2..HEAD)
  58. fi
  59. else
  60. # 普通提交:获取相对于上一个提交的变更
  61. CHANGED_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null || git diff --name-only $(git rev-list --max-parents=0 HEAD)..HEAD)
  62. fi
  63. echo "Changed files:"
  64. echo "$CHANGED_FILES"
  65. # 检查是否只有无关文件(.md, docs/, .github/等)
  66. SIGNIFICANT_CHANGES=false
  67. while IFS= read -r file; do
  68. # 跳过空行
  69. [ -z "$file" ] && continue
  70. # 检查是否是需要忽略的文件
  71. if [[ ! "$file" =~ \.(md|txt)$ ]] &&
  72. [[ ! "$file" =~ ^docs/ ]] &&
  73. [[ ! "$file" =~ ^\.github/workflows/ ]] &&
  74. [[ "$file" != "VERSION" ]] &&
  75. [[ "$file" != ".gitignore" ]] &&
  76. [[ "$file" != "LICENSE" ]]; then
  77. echo "Found significant change in: $file"
  78. SIGNIFICANT_CHANGES=true
  79. break
  80. fi
  81. done <<< "$CHANGED_FILES"
  82. if [ "$SIGNIFICANT_CHANGES" = true ]; then
  83. echo "Significant changes detected, version bump needed"
  84. echo "needs_bump=true" >> $GITHUB_OUTPUT
  85. else
  86. echo "No significant changes, skipping version bump"
  87. echo "needs_bump=false" >> $GITHUB_OUTPUT
  88. fi
  89. - name: Get current version
  90. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  91. id: get_version
  92. run: |
  93. # 获取最新的tag版本
  94. LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
  95. echo "Latest tag: $LATEST_TAG"
  96. TAG_VERSION=${LATEST_TAG#v}
  97. # 获取VERSION文件中的版本
  98. FILE_VERSION=$(cat VERSION | tr -d '[:space:]')
  99. echo "VERSION file: $FILE_VERSION"
  100. # 比较tag版本和文件版本,取较大值
  101. function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
  102. if version_gt "$FILE_VERSION" "$TAG_VERSION"; then
  103. VERSION="$FILE_VERSION"
  104. echo "Using VERSION file: $VERSION (newer than tag)"
  105. else
  106. VERSION="$TAG_VERSION"
  107. echo "Using tag version: $VERSION (newer or equal to file)"
  108. fi
  109. echo "Current version: $VERSION"
  110. echo "current_version=$VERSION" >> $GITHUB_OUTPUT
  111. - name: Calculate next version
  112. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  113. id: next_version
  114. env:
  115. VERSION_TYPE: ${{ github.event.inputs.version_type || 'patch' }}
  116. PRERELEASE_NUM: ${{ github.event.inputs.prerelease_number || '1' }}
  117. run: |
  118. VERSION="${{ steps.get_version.outputs.current_version }}"
  119. # 移除可能存在的 prerelease 后缀以获取基础版本
  120. BASE_VERSION=$(echo "$VERSION" | sed 's/-.*$//')
  121. # 分割版本号
  122. IFS='.' read -r -a version_parts <<< "$BASE_VERSION"
  123. MAJOR="${version_parts[0]:-0}"
  124. MINOR="${version_parts[1]:-0}"
  125. PATCH="${version_parts[2]:-0}"
  126. echo "Base version: $MAJOR.$MINOR.$PATCH"
  127. echo "Version type: $VERSION_TYPE"
  128. case "$VERSION_TYPE" in
  129. major)
  130. NEW_VERSION="$((MAJOR + 1)).0.0"
  131. IS_PRERELEASE=false
  132. ;;
  133. minor)
  134. NEW_VERSION="${MAJOR}.$((MINOR + 1)).0"
  135. IS_PRERELEASE=false
  136. ;;
  137. patch)
  138. NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
  139. IS_PRERELEASE=false
  140. ;;
  141. beta)
  142. NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))-beta.${PRERELEASE_NUM}"
  143. IS_PRERELEASE=true
  144. ;;
  145. rc)
  146. NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))-rc.${PRERELEASE_NUM}"
  147. IS_PRERELEASE=true
  148. ;;
  149. release)
  150. # Convert prerelease to stable release (e.g., 0.4.1-rc.1 -> 0.4.1)
  151. NEW_VERSION="${BASE_VERSION}"
  152. IS_PRERELEASE=false
  153. ;;
  154. *)
  155. # 默认 patch
  156. NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
  157. IS_PRERELEASE=false
  158. ;;
  159. esac
  160. echo "New version: $NEW_VERSION"
  161. echo "Is prerelease: $IS_PRERELEASE"
  162. echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
  163. echo "new_tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
  164. echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT
  165. - name: Update VERSION file
  166. if: (steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch') && steps.next_version.outputs.is_prerelease != 'true'
  167. run: |
  168. echo "${{ steps.next_version.outputs.new_version }}" > VERSION
  169. - name: Setup Node.js for formatting
  170. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  171. uses: actions/setup-node@v4
  172. with:
  173. node-version: "20"
  174. - name: Setup Bun
  175. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  176. uses: oven-sh/setup-bun@v2
  177. - name: Install dependencies and format code
  178. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  179. run: |
  180. bun install
  181. bun run format
  182. - name: Commit VERSION and formatted code
  183. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  184. run: |
  185. # 配置git
  186. git config user.name "github-actions[bot]"
  187. git config user.email "github-actions[bot]@users.noreply.github.com"
  188. # 添加所有更改(VERSION文件 + 格式化后的代码)
  189. git add -A
  190. # 排除 .github/ 目录的更改(workflow 文件不需要自动提交,且需要特殊权限)
  191. git restore --staged .github/ 2>/dev/null || true
  192. # 检查是否有更改需要提交
  193. if git diff --cached --quiet; then
  194. echo "No changes to commit"
  195. else
  196. # 提交所有更改 - 添加 [skip ci] 以避免再次触发
  197. git commit -m "chore: sync VERSION file with release ${{ steps.next_version.outputs.new_tag }} [skip ci]"
  198. fi
  199. - name: Create and push tag
  200. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  201. run: |
  202. NEW_TAG="${{ steps.next_version.outputs.new_tag }}"
  203. git tag -a "$NEW_TAG" -m "Release $NEW_TAG"
  204. git push origin HEAD:main "$NEW_TAG"
  205. - name: Prepare image names
  206. id: image_names
  207. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  208. run: |
  209. GHCR_IMAGE=$(echo "ghcr.io/${{ github.repository_owner }}/claude-code-hub" | tr '[:upper:]' '[:lower:]')
  210. echo "ghcr_image=${GHCR_IMAGE}" >> "$GITHUB_OUTPUT"
  211. - name: Create GitHub Release
  212. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  213. uses: softprops/action-gh-release@v2
  214. with:
  215. tag_name: ${{ steps.next_version.outputs.new_tag }}
  216. name: Release ${{ steps.next_version.outputs.new_version }}
  217. body: |
  218. ## Docker
  219. ```bash
  220. docker pull ${{ steps.image_names.outputs.ghcr_image }}:${{ steps.next_version.outputs.new_tag }}
  221. ${{ steps.next_version.outputs.is_prerelease != 'true' && format('docker pull {0}:latest', steps.image_names.outputs.ghcr_image) || '' }}
  222. ```
  223. ---
  224. Release notes will be auto-generated...
  225. draft: false
  226. prerelease: ${{ steps.next_version.outputs.is_prerelease == 'true' }}
  227. generate_release_notes: false
  228. # 自清理旧的tags和releases(保持最近50个) - 仅清理正式版本
  229. - name: Cleanup old tags and releases
  230. if: (steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch') && steps.next_version.outputs.is_prerelease != 'true'
  231. continue-on-error: true
  232. env:
  233. TAGS_TO_KEEP: 50
  234. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  235. run: |
  236. echo "🧹 自动清理旧版本,保持最近 $TAGS_TO_KEEP 个tag..."
  237. # 获取所有版本tag并按版本号排序(从旧到新)
  238. echo "正在获取所有tags..."
  239. ALL_TAGS=$(git ls-remote --tags origin | grep -E 'refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' | awk '{print $2}' | sed 's|refs/tags/||' | sort -V)
  240. # 检查是否获取到tags
  241. if [ -z "$ALL_TAGS" ]; then
  242. echo "⚠️ 未找到任何版本tag"
  243. exit 0
  244. fi
  245. TOTAL_COUNT=$(echo "$ALL_TAGS" | wc -l)
  246. echo "📊 当前tag统计:"
  247. echo "- 总数: $TOTAL_COUNT"
  248. echo "- 配置保留: $TAGS_TO_KEEP"
  249. if [ "$TOTAL_COUNT" -gt "$TAGS_TO_KEEP" ]; then
  250. DELETE_COUNT=$((TOTAL_COUNT - TAGS_TO_KEEP))
  251. echo "- 将要删除: $DELETE_COUNT 个最旧的tag"
  252. # 获取要删除的tags(最老的)
  253. TAGS_TO_DELETE=$(echo "$ALL_TAGS" | head -n "$DELETE_COUNT")
  254. # 显示将要删除的版本范围
  255. OLDEST_TO_DELETE=$(echo "$TAGS_TO_DELETE" | head -1)
  256. NEWEST_TO_DELETE=$(echo "$TAGS_TO_DELETE" | tail -1)
  257. echo ""
  258. echo "🗑️ 将要删除的版本范围:"
  259. echo "- 从: $OLDEST_TO_DELETE"
  260. echo "- 到: $NEWEST_TO_DELETE"
  261. echo ""
  262. echo "开始执行删除..."
  263. SUCCESS_COUNT=0
  264. FAIL_COUNT=0
  265. for tag in $TAGS_TO_DELETE; do
  266. echo -n " 删除 $tag ... "
  267. # 先检查release是否存在
  268. if gh release view "$tag" >/dev/null 2>&1; then
  269. # Release存在,删除release会同时删除tag
  270. if gh release delete "$tag" --yes --cleanup-tag 2>/dev/null; then
  271. echo "(release+tag)"
  272. SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
  273. else
  274. echo "❌ (release删除失败)"
  275. FAIL_COUNT=$((FAIL_COUNT + 1))
  276. fi
  277. else
  278. # Release不存在,只删除tag
  279. if git push origin --delete "$tag" 2>/dev/null; then
  280. echo "(仅tag)"
  281. SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
  282. else
  283. echo "⏭️ (已不存在)"
  284. FAIL_COUNT=$((FAIL_COUNT + 1))
  285. fi
  286. fi
  287. done
  288. echo ""
  289. echo "📊 清理结果:"
  290. echo "- 成功删除: $SUCCESS_COUNT"
  291. echo "- 失败/跳过: $FAIL_COUNT"
  292. # 重新获取并显示保留的版本范围
  293. echo ""
  294. echo "正在验证清理结果..."
  295. REMAINING_TAGS=$(git ls-remote --tags origin | grep -E 'refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' | awk '{print $2}' | sed 's|refs/tags/||' | sort -V)
  296. REMAINING_COUNT=$(echo "$REMAINING_TAGS" | wc -l)
  297. OLDEST=$(echo "$REMAINING_TAGS" | head -1)
  298. NEWEST=$(echo "$REMAINING_TAGS" | tail -1)
  299. echo "清理完成!"
  300. echo ""
  301. echo "📌 当前保留的版本:"
  302. echo "- 最旧版本: $OLDEST"
  303. echo "- 最新版本: $NEWEST"
  304. echo "- 版本总数: $REMAINING_COUNT"
  305. # 验证是否达到预期
  306. if [ "$REMAINING_COUNT" -le "$TAGS_TO_KEEP" ]; then
  307. echo "- 状态: 符合预期(≤$TAGS_TO_KEEP)"
  308. else
  309. echo "- 状态: ⚠️ 超出预期(某些tag可能删除失败)"
  310. fi
  311. else
  312. echo "当前tag数量($TOTAL_COUNT)未超过限制($TAGS_TO_KEEP),无需清理"
  313. fi
  314. # Docker构建步骤
  315. - name: Set up QEMU
  316. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  317. uses: docker/setup-qemu-action@v3
  318. - name: Set up Docker Buildx
  319. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  320. uses: docker/setup-buildx-action@v3
  321. - name: Log in to GitHub Container Registry
  322. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  323. uses: docker/login-action@v3
  324. with:
  325. registry: ghcr.io
  326. username: ${{ github.repository_owner }}
  327. password: ${{ secrets.GITHUB_TOKEN }}
  328. - name: Build and push Docker image
  329. if: steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch'
  330. uses: docker/build-push-action@v6
  331. with:
  332. context: .
  333. file: ./deploy/Dockerfile
  334. platforms: linux/amd64,linux/arm64
  335. push: true
  336. build-args: |
  337. APP_VERSION=${{ steps.next_version.outputs.new_version }}
  338. tags: |
  339. ${{ steps.image_names.outputs.ghcr_image }}:${{ steps.next_version.outputs.new_tag }}
  340. ${{ steps.next_version.outputs.is_prerelease != 'true' && format('{0}:latest', steps.image_names.outputs.ghcr_image) || '' }}
  341. ${{ steps.image_names.outputs.ghcr_image }}:${{ steps.next_version.outputs.new_version }}
  342. labels: |
  343. org.opencontainers.image.version=${{ steps.next_version.outputs.new_version }}
  344. org.opencontainers.image.revision=${{ github.sha }}
  345. org.opencontainers.image.source=https://github.com/${{ github.repository }}
  346. cache-from: type=gha
  347. cache-to: type=gha,mode=max
  348. # 同步 main 分支到 dev 分支 (rebase dev onto main) - 仅正式版本触发
  349. - name: Sync main to dev branch
  350. if: (steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch') && steps.next_version.outputs.is_prerelease != 'true'
  351. id: sync_dev
  352. continue-on-error: true
  353. env:
  354. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  355. run: |
  356. set -e
  357. echo "=========================================="
  358. echo "Starting dev branch sync after release..."
  359. echo "=========================================="
  360. # 配置 git
  361. git config user.name "github-actions[bot]"
  362. git config user.email "github-actions[bot]@users.noreply.github.com"
  363. # 确保在 main 分支的最新状态
  364. git fetch origin main
  365. git checkout main
  366. git reset --hard origin/main
  367. # 获取 dev 分支
  368. echo "Fetching dev branch..."
  369. if ! git fetch origin dev:dev 2>/dev/null; then
  370. echo "::warning::dev branch not found, skipping sync"
  371. echo "sync_status=skipped" >> $GITHUB_OUTPUT
  372. echo "sync_reason=dev branch not found" >> $GITHUB_OUTPUT
  373. exit 0
  374. fi
  375. # 检查 dev 是否有领先于 main 的 commit
  376. git checkout dev
  377. AHEAD_COUNT=$(git rev-list --count main..dev)
  378. BEHIND_COUNT=$(git rev-list --count dev..main)
  379. echo "Dev branch status:"
  380. echo " - Ahead of main: $AHEAD_COUNT commits"
  381. echo " - Behind main: $BEHIND_COUNT commits"
  382. # 如果 dev 没有落后于 main,跳过同步
  383. if [ "$BEHIND_COUNT" -eq 0 ]; then
  384. echo "::notice::dev branch is already up to date with main"
  385. echo "sync_status=skipped" >> $GITHUB_OUTPUT
  386. echo "sync_reason=already up to date" >> $GITHUB_OUTPUT
  387. exit 0
  388. fi
  389. echo ""
  390. echo "Attempting to rebase dev onto main..."
  391. echo "This will preserve $AHEAD_COUNT commits from dev"
  392. # 尝试 rebase
  393. if git rebase main; then
  394. echo "Rebase successful!"
  395. # 使用 --force-with-lease 安全推送
  396. echo "Pushing rebased dev branch..."
  397. if git push origin dev --force-with-lease; then
  398. echo "::notice::Successfully synced main to dev branch (rebased $AHEAD_COUNT commits)"
  399. echo "sync_status=success" >> $GITHUB_OUTPUT
  400. echo "ahead_count=$AHEAD_COUNT" >> $GITHUB_OUTPUT
  401. else
  402. echo "::error::Failed to push rebased dev branch"
  403. echo "sync_status=push_failed" >> $GITHUB_OUTPUT
  404. echo "sync_reason=push failed, possibly due to concurrent changes" >> $GITHUB_OUTPUT
  405. exit 1
  406. fi
  407. else
  408. echo "::warning::Rebase failed due to conflicts, will trigger autofix"
  409. git rebase --abort
  410. echo "sync_status=conflict" >> $GITHUB_OUTPUT
  411. echo "sync_reason=merge conflicts detected" >> $GITHUB_OUTPUT
  412. exit 1
  413. fi
  414. # 如果同步失败(冲突),触发 autofix workflow
  415. - name: Trigger autofix for sync conflicts
  416. if: (steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch') && steps.sync_dev.outputs.sync_status == 'conflict'
  417. env:
  418. GH_TOKEN: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
  419. run: |
  420. echo "Triggering Claude CI Auto-Fix workflow for dev sync..."
  421. # 使用 workflow 文件名而非名称,避免重命名后触发失败
  422. if gh workflow run claude-ci-autofix.yml \
  423. --field task_type=sync-dev \
  424. --field target_branch=dev \
  425. --field source_branch=main \
  426. --field release_tag=${{ steps.next_version.outputs.new_tag }}; then
  427. echo "::notice::Autofix workflow triggered to resolve conflicts"
  428. else
  429. echo "::error::Failed to trigger autofix workflow. Manual intervention required."
  430. echo "::error::Please run: gh workflow run claude-ci-autofix.yml --field task_type=sync-dev --field target_branch=dev --field source_branch=main"
  431. exit 1
  432. fi
  433. # 同步结果汇总 - 仅正式版本显示
  434. - name: Sync summary
  435. if: (steps.check.outputs.needs_bump == 'true' || github.event_name == 'workflow_dispatch') && steps.next_version.outputs.is_prerelease != 'true' && always()
  436. run: |
  437. echo "=========================================="
  438. echo "Dev Branch Sync Summary"
  439. echo "=========================================="
  440. SYNC_STATUS="${{ steps.sync_dev.outputs.sync_status }}"
  441. SYNC_REASON="${{ steps.sync_dev.outputs.sync_reason }}"
  442. AHEAD_COUNT="${{ steps.sync_dev.outputs.ahead_count }}"
  443. case "$SYNC_STATUS" in
  444. "success")
  445. echo "Status: SUCCESS"
  446. echo "Preserved $AHEAD_COUNT commits from dev branch"
  447. ;;
  448. "skipped")
  449. echo "Status: SKIPPED"
  450. echo "Reason: $SYNC_REASON"
  451. ;;
  452. "conflict")
  453. echo "Status: CONFLICT - Autofix triggered"
  454. echo "Reason: $SYNC_REASON"
  455. echo "The Claude CI Auto-Fix workflow has been triggered to resolve conflicts"
  456. ;;
  457. "push_failed")
  458. echo "Status: PUSH FAILED"
  459. echo "Reason: $SYNC_REASON"
  460. echo "Manual intervention may be required"
  461. ;;
  462. *)
  463. echo "Status: UNKNOWN ($SYNC_STATUS)"
  464. ;;
  465. esac
  466. echo "=========================================="