diff --git a/backend/apps/models.py b/backend/apps/models.py
index ece8c15..b3527f7 100644
--- a/backend/apps/models.py
+++ b/backend/apps/models.py
@@ -225,6 +225,18 @@ class BuildTask(models.Model):
# 构建阶段
stages = models.JSONField(default=list, verbose_name='构建阶段')
+ # 构建参数配置
+ parameters = models.JSONField(default=list, verbose_name='构建参数配置', help_text='''
+ [
+ {
+ "name": "MY_SERVICES",
+ "description": "选择要部署的服务",
+ "choices": ["user-service", "order-service", "payment-service"],
+ "default_values": ["user-service"]
+ }
+ ]
+ ''')
+
# 外部脚本库配置
use_external_script = models.BooleanField(default=False, verbose_name='使用外部脚本库')
external_script_config = models.JSONField(default=dict, verbose_name='外部脚本库配置', help_text='''
@@ -287,6 +299,12 @@ class BuildHistory(models.Model):
requirement = models.TextField(null=True, blank=True, verbose_name='构建需求描述')
build_log = models.TextField(null=True, blank=True, verbose_name='构建日志')
stages = models.JSONField(default=list, verbose_name='构建阶段')
+ parameter_values = models.JSONField(default=dict, verbose_name='构建参数值', help_text='''
+ {
+ "MY_SERVICES": ["user-service", "order-service"],
+ "FEATURE_FLAGS": ["enable-cache"]
+ }
+ ''')
build_time = models.JSONField(default=dict, verbose_name='构建时间信息', help_text='''
{
"total_duration": "300", # 总耗时(秒)
diff --git a/backend/apps/utils/builder.py b/backend/apps/utils/builder.py
index a119db9..cb8588e 100644
--- a/backend/apps/utils/builder.py
+++ b/backend/apps/utils/builder.py
@@ -462,11 +462,19 @@ class Builder:
'LANG': 'POSIX',
}
- combined_env = {**os.environ, **system_variables}
+ # 添加自定义参数变量
+ custom_parameters = {}
+ if self.history.parameter_values:
+ for param_name, selected_values in self.history.parameter_values.items():
+ custom_parameters[param_name] = ','.join(selected_values)
+ self.send_log(f"设置参数变量: {param_name}={custom_parameters[param_name]}", "Parameters")
+
+ combined_env = {**os.environ, **system_variables, **custom_parameters}
stage_executor.env = combined_env
- # 保存系统变量到文件
- stage_executor._save_variables_to_file(system_variables)
+ # 保存系统变量和自定义参数到文件
+ all_variables = {**system_variables, **custom_parameters}
+ stage_executor._save_variables_to_file(all_variables)
# 执行构建阶段
success = self.execute_stages(stage_executor)
diff --git a/backend/apps/views/build.py b/backend/apps/views/build.py
index 5c6cb60..1cece72 100644
--- a/backend/apps/views/build.py
+++ b/backend/apps/views/build.py
@@ -145,6 +145,7 @@ class BuildTaskView(View):
'name': task.git_token.name
} if task.git_token else None,
'stages': task.stages,
+ 'parameters': task.parameters,
'notification_channels': task.notification_channels,
'notification_robots': notification_robots,
# 外部脚本库配置
@@ -288,7 +289,8 @@ class BuildTaskView(View):
'description': task.description,
'branch': task.branch,
'status': task.status,
- 'building_status': task.building_status, # 添加构建状态字段
+ 'building_status': task.building_status,
+ 'parameters': task.parameters,
'version': task.version,
'last_build_number': task.last_build_number,
'total_builds': task.total_builds,
@@ -334,6 +336,7 @@ class BuildTaskView(View):
branch = data.get('branch', 'main')
git_token_id = data.get('git_token_id')
stages = data.get('stages', [])
+ parameters = data.get('parameters', [])
notification_channels = data.get('notification_channels', [])
# 外部脚本库配置
@@ -379,6 +382,23 @@ class BuildTaskView(View):
'message': '任务名称、项目和环境不能为空'
})
+ # 验证参数配置格式
+ if parameters:
+ import re
+ for param in parameters:
+ if not param.get('name') or not param.get('choices'):
+ return JsonResponse({
+ 'code': 400,
+ 'message': '参数名称和可选值不能为空'
+ })
+
+ # 验证参数名格式(大写字母、数字、下划线)
+ if not re.match(r'^[A-Z_][A-Z0-9_]*$', param['name']):
+ return JsonResponse({
+ 'code': 400,
+ 'message': f'参数名"{param["name"]}"格式不正确,只能包含大写字母、数字和下划线,且必须以字母或下划线开头'
+ })
+
# 验证通知机器人是否存在
if notification_channels:
existing_robots = set(NotificationRobot.objects.filter(
@@ -431,6 +451,7 @@ class BuildTaskView(View):
branch=branch,
git_token=git_token,
stages=stages,
+ parameters=parameters,
notification_channels=notification_channels,
use_external_script=use_external_script,
external_script_config=external_script_config,
@@ -473,6 +494,7 @@ class BuildTaskView(View):
branch = data.get('branch')
git_token_id = data.get('git_token_id')
stages = data.get('stages')
+ parameters = data.get('parameters')
notification_channels = data.get('notification_channels')
status = data.get('status')
@@ -512,6 +534,23 @@ class BuildTaskView(View):
else:
external_script_config = {}
+ # 验证参数配置格式
+ if parameters:
+ import re
+ for param in parameters:
+ if not param.get('name') or not param.get('choices'):
+ return JsonResponse({
+ 'code': 400,
+ 'message': '参数名称和可选值不能为空'
+ })
+
+ # 验证参数名格式(大写字母、数字、下划线)
+ if not re.match(r'^[A-Z_][A-Z0-9_]*$', param['name']):
+ return JsonResponse({
+ 'code': 400,
+ 'message': f'参数名"{param["name"]}"格式不正确,只能包含大写字母、数字和下划线,且必须以字母或下划线开头'
+ })
+
if not task_id:
return JsonResponse({
'code': 400,
@@ -617,6 +656,8 @@ class BuildTaskView(View):
task.branch = branch
if 'stages' in data:
task.stages = stages
+ if 'parameters' in data:
+ task.parameters = parameters
if 'notification_channels' in data:
# 验证通知机器人是否存在
existing_robots = set(NotificationRobot.objects.filter(
@@ -710,6 +751,7 @@ class BuildExecuteView(View):
commit_id = data.get('commit_id')
version = data.get('version')
requirement = data.get('requirement')
+ parameter_values = data.get('parameter_values', {})
if not task_id:
return JsonResponse({
@@ -785,6 +827,23 @@ class BuildExecuteView(View):
'message': '构建需求描述不能为空'
})
+ # 验证参数值是否合法
+ if task.parameters and parameter_values:
+ task_parameters = {p['name']: p['choices'] for p in task.parameters}
+ for param_name, selected_values in parameter_values.items():
+ if param_name not in task_parameters:
+ return JsonResponse({
+ 'code': 400,
+ 'message': f'未定义的参数: {param_name}'
+ })
+
+ for value in selected_values:
+ if value not in task_parameters[param_name]:
+ return JsonResponse({
+ 'code': 400,
+ 'message': f'参数{param_name}的值"{value}"不在可选范围内'
+ })
+
# 检查任务的构建状态
if task.building_status == 'building':
return JsonResponse({
@@ -824,6 +883,7 @@ class BuildExecuteView(View):
version=version if version else None, # 对于预发布和生产环境,使用传入的版本号
status='pending', # 初始状态为等待中
requirement=requirement,
+ parameter_values=parameter_values,
operator=User.objects.get(user_id=request.user_id) # 记录构建人
)
diff --git a/web/src/views/build/BuildTaskEdit.vue b/web/src/views/build/BuildTaskEdit.vue
index c6b011d..7b97fde 100644
--- a/web/src/views/build/BuildTaskEdit.vue
+++ b/web/src/views/build/BuildTaskEdit.vue
@@ -134,6 +134,84 @@
+
+