diff --git a/.gitea/scripts/gui_version_creator.py b/.gitea/scripts/gui_version_creator.py index 14769e0..546d804 100644 --- a/.gitea/scripts/gui_version_creator.py +++ b/.gitea/scripts/gui_version_creator.py @@ -167,7 +167,7 @@ class DatabaseVersionManager: try: cursor = self.conn.cursor() cursor.execute(""" - SELECT version FROM web_versionhistory + SELECT version FROM web_version_history WHERE type = '水滴智能通讯插件' AND is_delete = FALSE ORDER BY release_time DESC LIMIT 1 """) @@ -211,7 +211,7 @@ class DatabaseVersionManager: try: cursor = self.conn.cursor() cursor.execute(""" - SELECT version FROM web_versionhistory + SELECT version FROM web_version_history WHERE content LIKE %s AND type = '水滴智能通讯插件' ORDER BY release_time DESC LIMIT 1 """, (f'%{commit_id}%',)) @@ -241,7 +241,7 @@ class DatabaseVersionManager: cursor = self.conn.cursor() cursor.execute(""" - INSERT INTO web_versionhistory + INSERT INTO web_version_history (id, version, type, content, download_url, release_time, is_delete) VALUES (%s, %s, %s, %s, %s, %s, %s) """, ( diff --git a/.gitea/workflows/gui-version-release.yml b/.gitea/workflows/gui-version-release.yml index 6805686..5364a79 100644 --- a/.gitea/workflows/gui-version-release.yml +++ b/.gitea/workflows/gui-version-release.yml @@ -8,29 +8,29 @@ jobs: gui-version-release: runs-on: windows - defaults: - run: - working-directory: E:\shuidrop_gui - steps: - # Step 1: Clone repository manually - - name: Clone repository + # Step 1: Checkout repository (使用 Gitea 自动检出,适配所有路径) + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: ${{ github.ref_name }} # 动态分支(master 或 develop) + fetch-depth: 0 # 获取完整历史(用于版本号计算) + + # Step 1.5: Verify checkout + - name: Verify checkout shell: powershell run: | - Write-Host "Cloning repository..." - - # Change to workspace directory - cd E:\shuidrop_gui - + Write-Host "==========================================" + Write-Host "Repository Information" + Write-Host "==========================================" Write-Host "Current directory: $(Get-Location)" + Write-Host "Branch: ${{ github.ref_name }}" + Write-Host "Commit: ${{ github.sha }}" + Write-Host "Author: ${{ github.actor }}" + Write-Host "" Write-Host "Git status:" git status - - Write-Host "Fetching latest changes..." - git fetch origin - git reset --hard origin/master - - Write-Host "Repository ready" + Write-Host "==========================================" # Step 2: Check Python environment - name: Check Python environment @@ -137,21 +137,27 @@ jobs: } } - git config user.name "Gitea Actions" - git config user.email "actions@gitea.local" + # 配置 Git 用户(自动化提交) + git config user.name "Gitea Actions Bot" + git config user.email "bot@gitea.local" + # 添加修改的文件 git add config.py git add version_history.json + # 检查是否有变更 $hasChanges = git diff --staged --quiet if ($LASTEXITCODE -ne 0) { - # 动态获取当前分支名 (用于测试使用) - $BRANCH = git rev-parse --abbrev-ref HEAD - git commit -m "[skip ci] Update version to $VERSION" + # 动态获取当前分支名(兼容 master 和 develop) + $BRANCH = "${{ github.ref_name }}" + Write-Host "Committing to branch: $BRANCH" + + git commit -m "[skip ci] 🤖 自动更新版本到 v$VERSION" git push origin $BRANCH - Write-Host "Version changes committed and pushed to $BRANCH" + + Write-Host "✅ Version changes committed and pushed to $BRANCH" } else { - Write-Host "No changes to commit" + Write-Host "ℹ️ No changes to commit" } # Step 6: Display summary diff --git a/main.py b/main.py index 861d0de..bad78c5 100644 --- a/main.py +++ b/main.py @@ -718,6 +718,23 @@ class LoginWindow(QMainWindow): def show_update_notification(self, latest_version, download_url): """显示版本更新通知""" try: + self.add_log(f"🔔 准备显示更新通知: v{latest_version}", "INFO") + self.add_log(f" 下载地址: {download_url if download_url else '(空)'}", "INFO") + + # 检查下载地址 + if not download_url or download_url.strip() == "": + # 下载地址为空,只显示通知,不提供下载 + QMessageBox.information( + self, + "版本更新", + f"发现新版本 {latest_version}!\n\n" + f"下载地址暂未配置,请稍后再试或联系管理员。", + QMessageBox.Ok + ) + self.add_log(f"⚠️ 新版本 {latest_version} 的下载地址为空,已通知用户", "WARNING") + return # 安全返回,不崩溃 + + # 下载地址有效,显示更新对话框 reply = QMessageBox.question( self, "版本更新", @@ -727,7 +744,12 @@ class LoginWindow(QMainWindow): ) if reply == QMessageBox.Yes: + self.add_log("用户选择立即更新", "INFO") self.trigger_update(download_url, latest_version) + else: + self.add_log("用户选择稍后更新", "INFO") + # 用户点击"否",不做任何操作,程序继续运行 + except Exception as e: self.add_log(f"❌ 显示更新通知失败: {e}", "ERROR") import traceback diff --git a/version_checker.py b/version_checker.py new file mode 100644 index 0000000..69d5c10 --- /dev/null +++ b/version_checker.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +版本检查器 +定期检查后端是否有新版本,并通知GUI更新 +""" + +import threading +import time +import logging +from typing import Callable, Optional + +logger = logging.getLogger(__name__) + + +class VersionChecker: + """ + 版本检查器 + 定期向后端发送版本检查请求,如果有新版本则触发更新回调 + """ + + def __init__(self, backend_client, update_callback: Optional[Callable] = None): + """ + 初始化版本检查器 + + Args: + backend_client: 后端WebSocket客户端实例 + update_callback: 发现新版本时的回调函数 callback(latest_version, download_url) + """ + self.backend_client = backend_client + self.update_callback = update_callback + self.is_running = False + self.check_interval = 600 # 10分钟检查一次 + self.thread = None + + # 从config获取当前版本 + try: + from config import APP_VERSION + self.current_version = APP_VERSION + logger.info(f"✅ 版本检查器初始化成功,当前版本: v{self.current_version}") + except ImportError: + self.current_version = "1.0.0" + logger.warning("⚠️ 无法从config读取APP_VERSION,使用默认版本: 1.0.0") + + def start(self): + """启动版本检查线程""" + if self.is_running: + logger.warning("版本检查器已在运行中") + return + + self.is_running = True + self.thread = threading.Thread(target=self._check_loop, daemon=True) + self.thread.start() + logger.info(f"✅ 版本检查器已启动,每{self.check_interval}秒检查一次更新") + + def stop(self): + """停止版本检查""" + self.is_running = False + if self.thread: + self.thread.join(timeout=2) + logger.info("版本检查器已停止") + + def _check_loop(self): + """版本检查循环""" + # 等待5秒后首次检查(避免启动时立即检查) + time.sleep(5) + + while self.is_running: + try: + self._perform_version_check() + except Exception as e: + logger.error(f"版本检查失败: {e}") + + # 等待下次检查 + time.sleep(self.check_interval) + + def _perform_version_check(self): + """执行版本检查""" + try: + if not self.backend_client or not self.backend_client.is_connected: + logger.debug("后端未连接,跳过版本检查") + return + + # 向后端发送版本检查请求 + message = { + 'type': 'version_check', + 'current_version': self.current_version, + 'client_type': 'gui' + } + + logger.debug(f"发送版本检查请求: v{self.current_version}") + self.backend_client.send_message(message) + + except Exception as e: + logger.error(f"发送版本检查请求失败: {e}") + + def handle_version_response(self, response: dict): + """ + 处理后端返回的版本检查响应 + + Args: + response: 后端响应消息 + { + "type": "version_response", + "has_update": true, + "latest_version": "1.5.0", + "current_version": "1.4.7", + "download_url": "https://example.com/download/v1.5.0", + "update_content": "修复了若干Bug" + } + """ + try: + has_update = response.get('has_update', None) # 改为 None,便于后续判断 + latest_version = response.get('latest_version', '') + current_version = response.get('current_version', self.current_version) + download_url = response.get('download_url', '') + update_content = response.get('update_content', '') + + logger.info(f"📡 收到版本检查响应: 当前v{current_version}, 最新v{latest_version}") + + # 如果后端没有返回 has_update 字段,自动通过版本比较判断 + if has_update is None and latest_version: + # 自动比较版本号 + compare_result = self.compare_versions(latest_version, current_version) + has_update = compare_result > 0 # latest > current 表示有更新 + logger.info(f"🔍 后端未返回has_update字段,通过版本比较判断: {has_update}") + + if has_update and latest_version: + logger.info(f"🔔 发现新版本: v{latest_version}") + if update_content: + logger.info(f"📝 更新内容: {update_content[:100]}") + + # 触发更新回调 + if self.update_callback: + try: + self.update_callback(latest_version, download_url) + except Exception as e: + logger.error(f"执行更新回调失败: {e}") + else: + logger.debug(f"✅ 当前已是最新版本: v{current_version}") + + except Exception as e: + logger.error(f"处理版本响应失败: {e}") + + def compare_versions(self, version1: str, version2: str) -> int: + """ + 比较两个版本号 + + Args: + version1: 版本1 (如 "1.4.7") + version2: 版本2 (如 "1.5.0") + + Returns: + 1: version1 > version2 + 0: version1 == version2 + -1: version1 < version2 + """ + try: + v1_parts = [int(x) for x in version1.split('.')] + v2_parts = [int(x) for x in version2.split('.')] + + # 补齐长度 + max_len = max(len(v1_parts), len(v2_parts)) + v1_parts.extend([0] * (max_len - len(v1_parts))) + v2_parts.extend([0] * (max_len - len(v2_parts))) + + # 逐位比较 + for v1, v2 in zip(v1_parts, v2_parts): + if v1 > v2: + return 1 + elif v1 < v2: + return -1 + + return 0 + + except Exception as e: + logger.error(f"版本比较失败: {e}") + return 0 + + +# 使用示例 +if __name__ == '__main__': + # 配置日志 + logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s [%(levelname)s] %(message)s' + ) + + # 模拟使用 + class MockBackendClient: + is_connected = True + def send_message(self, msg): + print(f"发送消息: {msg}") + + def on_update_available(version, url): + print(f"🔔 发现新版本: {version}, 下载地址: {url}") + + client = MockBackendClient() + checker = VersionChecker(client, on_update_available) + checker.start() + + # 模拟接收后端响应 + time.sleep(2) + response = { + "type": "version_response", + "has_update": True, + "latest_version": "1.5.0", + "current_version": "1.4.7", + "download_url": "https://example.com/download", + "update_content": "修复了若干Bug" + } + checker.handle_version_response(response) + + time.sleep(2) + checker.stop() + diff --git a/version_history.json b/version_history.json new file mode 100644 index 0000000..852f62b --- /dev/null +++ b/version_history.json @@ -0,0 +1,18 @@ +[ + { + "version": "1.4.7", + "update_type": "patch", + "content": "当前版本 - 多平台客服智能助手", + "author": "开发团队", + "commit_hash": "", + "commit_short_hash": "", + "branch": "develop", + "release_time": "2025-10-10 00:00:00", + "stats": { + "files_changed": 0, + "lines_added": 0, + "lines_deleted": 0 + } + } +] +