diff --git a/README.md b/README.md index 183b105..ef9e5fd 100644 --- a/README.md +++ b/README.md @@ -154,10 +154,10 @@ chmod +x start-containers.sh ``` #### 5. 不使用一键部署方式,自定义数据库 -##### 方案A:配置文件挂载方式(推荐) +##### 方案A:配置文件挂载方式 ```bash -# 1. 先启动MySQL容器(可选) +# 1. 先启动MySQL容器(可自定义mysql) docker run -d \ --name liteops-mysql \ -e MYSQL_ROOT_PASSWORD=your_password \ @@ -246,14 +246,14 @@ docker logs liteops-mysql - **用户名**:admin - **密码**:admin123 (初始密码,可自行修改) -## 📋 手动部署(源码启动) +## 📋 源码部署 如果你想从源码运行 LiteOps,可以按照以下步骤操作: ### 环境要求 -- **Python**:3.8+ -- **Node.js**:16+ +- **Python**:3.9+ +- **Node.js**:18+ - **MySQL**:8.0+ - **Git**:用于克隆源码 @@ -304,7 +304,7 @@ npm install # 开发模式启动 npm run dev -# 生产环境构建 +# 生产环境构建(dist静态文件) npm run build ``` @@ -316,7 +316,7 @@ npm run build - **生产模式**: - 配置 Nginx Web 服务器托管前端构建文件 - - 后端继续使用 http://localhost:8900 + - 后端接口 http://localhost:8900 ### 注意事项 diff --git a/backend/apps/utils/builder.py b/backend/apps/utils/builder.py index 66e8276..13a5a43 100644 --- a/backend/apps/utils/builder.py +++ b/backend/apps/utils/builder.py @@ -358,9 +358,15 @@ class Builder: # 获取环境类型 environment_type = self.task.environment.type if self.task.environment else None - # 根据环境类型决定是否需要克隆代码 - if environment_type in ['development', 'testing']: - # 只在开发和测试环境克隆代码 + # 根据是否有分支信息决定是否需要克隆代码 + should_clone_code = ( + environment_type in ['development', 'testing'] or + (environment_type in ['staging', 'production'] and self.history.branch) + ) + + if should_clone_code: + # 克隆代码 + self.send_log(f"开始克隆代码,分支: {self.history.branch}", "Git Clone") clone_start_time = time.time() if not self.clone_repository(): self._update_build_stats(False) # 更新失败统计 @@ -377,9 +383,8 @@ class Builder: 'duration': str(int(time.time() - clone_start_time)) }) else: - pass - # self.send_log(f"预发布/生产环境构建,跳过代码克隆,直接使用版本: {self.version}", "Environment") - + # 预发布/生产环境使用版本模式,不克隆代码 + # self.send_log(f"预发布/生产环境版本模式,使用版本: {self.history.version}", "Environment") # 创建构建目录 os.makedirs(self.build_path, exist_ok=True) diff --git a/backend/apps/views/build.py b/backend/apps/views/build.py index 6a228ff..4174917 100644 --- a/backend/apps/views/build.py +++ b/backend/apps/views/build.py @@ -861,18 +861,21 @@ class BuildExecuteView(View): 'message': 'Commit ID不能为空' }) elif env_type in ['staging', 'production']: - if not version: - return JsonResponse({ - 'code': 400, - 'message': '版本号不能为空' - }) - parts = version.split('_') - if len(parts) == 2 and len(parts[1]) >= 8: - commit_id = parts[1] + if version: + parts = version.split('_') + if len(parts) == 2 and len(parts[1]) >= 8: + commit_id = parts[1] + else: + return JsonResponse({ + 'code': 400, + 'message': '版本号格式不正确,应为:YYYYMMDDHHmmSS_commitId' + }) + elif branch and commit_id: + pass # 参数验证通过,继续执行 else: return JsonResponse({ 'code': 400, - 'message': '版本号格式不正确,应为:YYYYMMDDHHmmSS_commitId' + 'message': '预发布和生产环境请选择构建方式:输入版本号或选择分支进行重新构建' }) if not requirement: @@ -932,9 +935,9 @@ class BuildExecuteView(View): history_id=generate_id(), task=task, build_number=build_number, - branch=branch if branch else '', # 对于预发布和生产环境,分支为空 + branch=branch if branch else '', commit_id=commit_id, - version=version if version else None, # 对于预发布和生产环境,使用传入的版本号 + version=version if version else None, status='pending', # 初始状态为等待中 requirement=requirement, parameter_values=parameter_values, diff --git a/web/src/views/build/BuildTasks.vue b/web/src/views/build/BuildTasks.vue index d22456b..a9eb7ee 100644 --- a/web/src/views/build/BuildTasks.vue +++ b/web/src/views/build/BuildTasks.vue @@ -338,12 +338,34 @@ + + + + 现有版本 + 重新构建 + +
+
+ + 使用已在其它环境验证通过的版本进行部署,适用于可通过环境变量切换接口的项目 +
+
+ + 重新从代码构建,适用于构建时需要指定不同环境接口配置的项目(如前端项目需要env指定) +
+
+
+
- 提示: 可以去 构建历史 页面查找测试环境最新的构建版本 + 提示: 可以去 构建历史 页面查找其它环境最新的构建版本
+ + + + + {{ branch.name }} + + {{ branch.commit.author_name }} + {{ branch.commit.title }} + + + + + + + + +
+ + + +
+
+
+
构建参数 @@ -448,6 +530,7 @@ const buildForm = reactive({ commit_id: '', requirement: '', version: '', + buildType: 'existing_version', parameterValues: {}, }); @@ -726,6 +809,7 @@ const handleBuild = async (record) => { buildForm.commit_id = ''; buildForm.requirement = ''; buildForm.version = ''; + buildForm.buildType = 'existing_version'; buildForm.parameterValues = {}; // 初始化参数默认值 @@ -1050,6 +1134,21 @@ const handleBranchChange = async (branch) => { } }; +// 处理构建方式变更 +const handleBuildTypeChange = async () => { + if (buildForm.buildType === 'rebuild') { + buildForm.version = ''; + if (isStagingOrProdEnv.value) { + await loadBranches(); + } + } else { + buildForm.branch = ''; + buildForm.commit_id = ''; + branchList.value = []; + commitList.value = []; + } +}; + // 连接SSE const connectSSE = (taskId, buildNumber, preserveLog = false) => { const protocol = window.location.protocol; @@ -1218,16 +1317,24 @@ const confirmBuild = async () => { return; } - // 预发布和生产环境需要输入版本号 + // 预发布和生产环境的验证逻辑 if (isStagingOrProdEnv.value) { - if (!buildForm.version) { - message.warning('请输入版本号'); - return; - } + if (buildForm.buildType === 'existing_version') { + // 使用已验证版本,需要输入版本号 + if (!buildForm.version) { + message.warning('请输入版本号'); + return; + } - if (!validateVersion(buildForm.version)) { - message.warning('版本号格式不正确,请输入类似 "20250320112507_029e149e" 的格式(年月日时分秒_提交ID前8位)'); - return; + if (!validateVersion(buildForm.version)) { + message.warning('版本号格式不正确,请输入类似 "20250320112507_029e149e" 的格式(年月日时分秒_提交ID前8位)'); + return; + } + } else if (buildForm.buildType === 'rebuild') { + if (!buildForm.branch) { + message.warning('请选择分支'); + return; + } } } @@ -1256,7 +1363,12 @@ const confirmBuild = async () => { requestData.branch = buildForm.branch; requestData.commit_id = buildForm.commit_id; } else if (isStagingOrProdEnv.value) { - requestData.version = buildForm.version; + if (buildForm.buildType === 'existing_version') { + requestData.version = buildForm.version; + } else if (buildForm.buildType === 'rebuild') { + requestData.branch = buildForm.branch; + requestData.commit_id = buildForm.commit_id; + } } const response = await axios.post('/api/build/tasks/build', requestData, { @@ -1274,6 +1386,8 @@ const confirmBuild = async () => { status: 'running' }; + selectedHistoryId.value = response.data.data.history_id; + // 使用返回的build_number连接SSE connectSSE(selectedTask.value.task_id, response.data.data.build_number); @@ -1759,4 +1873,16 @@ const handleViewBuildDetail = (record) => { color: rgba(0, 0, 0, 0.45); margin-top: 4px; } + +.build-type-description { + margin-top: 8px; + font-size: 12px; + color: rgba(0, 0, 0, 0.45); +} + +.description-text { + display: flex; + align-items: center; + gap: 4px; +} \ No newline at end of file diff --git a/web/src/views/environments/EnvironmentList.vue b/web/src/views/environments/EnvironmentList.vue index bd3bf77..eb21df6 100644 --- a/web/src/views/environments/EnvironmentList.vue +++ b/web/src/views/environments/EnvironmentList.vue @@ -75,12 +75,7 @@ 查看 - - 删除 - + 删除 @@ -142,7 +137,7 @@