From 7f7cd9b33348a59afcaf0850cdae8bc00398afa6 Mon Sep 17 00:00:00 2001 From: hukdoesn Date: Tue, 15 Jul 2025 16:03:25 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=96=B0=E5=A2=9Egitlab=20?= =?UTF-8?q?push=E4=BA=8B=E4=BB=B6=E8=A7=A6=E5=8F=91webhooks=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=9E=84=E5=BB=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 22 +-- backend/apps/models.py | 64 ++----- backend/apps/views/build.py | 41 +++++ backend/apps/views/webhook.py | 229 ++++++++++++++++++++++++++ backend/backend/urls.py | 4 + backend/conf/config.txt | 2 +- liteops_init.sql | 123 +++----------- web/src/views/build/BuildTaskEdit.vue | 121 +++++++++++++- 8 files changed, 436 insertions(+), 170 deletions(-) create mode 100644 backend/apps/views/webhook.py diff --git a/Dockerfile b/Dockerfile index 50e307e..b87363b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,14 +52,14 @@ RUN set -eux; \ # SSH客户端基础配置 mkdir -p /root/.ssh && \ chmod 700 /root/.ssh && \ - # 轻量化安装NVM + # 安装NVM curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash && \ echo 'export NVM_DIR="$HOME/.nvm"' >> /root/.bashrc && \ echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> /root/.bashrc && \ echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" --no-use' >> /root/.profile && \ # 创建Java和Maven安装目录 mkdir -p /usr/local/java /usr/local/maven && \ - # 安装精简版Docker Engine + # 安装Docker Engine (curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null) || \ (curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ @@ -75,7 +75,7 @@ RUN set -eux; \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/cache/apt/* /root/.cache/* # ============================================================================= -# 精简Java环境安装 +# Java环境安装 # ============================================================================= COPY jdk-8u211-linux-x64.tar.gz apache-maven-3.8.8-bin.tar.gz /tmp/ @@ -85,12 +85,12 @@ RUN set -eux; \ tar -xzf /tmp/apache-maven-3.8.8-bin.tar.gz -C /usr/local/maven && \ # 立即清理压缩包 rm -f /tmp/jdk-8u211-linux-x64.tar.gz /tmp/apache-maven-3.8.8-bin.tar.gz && \ - # 极度精简JDK - 删除所有不必要的文件 + # 删除所有不必要的文件 cd /usr/local/java/jdk1.8.0_211 && \ rm -rf src.zip javafx-src.zip man sample demo \ COPYRIGHT LICENSE README.html THIRDPARTYLICENSEREADME.txt \ release ASSEMBLY_EXCEPTION && \ - # 删除不常用的JDK工具(保留核心编译和运行工具) + # 删除不常用的JDK工具 cd bin && \ rm -f appletviewer extcheck jarsigner java-rmi.cgi \ javadoc javah javap javaws jcmd jconsole jdb jhat \ @@ -105,7 +105,7 @@ RUN set -eux; \ cd bin && \ rm -f javaws jvisualvm orbd policytool rmid \ rmiregistry servertool tnameserv && \ - # 精简Maven安装,删除文档和示例 + # Maven安装,删除文档和示例 cd /usr/local/maven/apache-maven-3.8.8 && \ rm -rf LICENSE NOTICE README.txt @@ -166,7 +166,7 @@ RUN set -eux; \ # 配置pip镜像源 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && \ pip config set install.trusted-host mirrors.aliyun.com && \ - # 安装精简版Docker Engine + # 安装Docker Engine (curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null) || \ (curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ @@ -194,17 +194,17 @@ RUN set -eux; \ /usr/share/man/* /usr/share/locale/* /usr/share/info/* # ============================================================================= -# 从构建阶段复制精简的文件 +# 从构建阶段复制文件 # ============================================================================= # 复制SSH配置 COPY --from=builder /root/.ssh /root/.ssh -# 复制精简的NVM环境 +# 复制NVM环境 COPY --from=builder /root/.nvm /root/.nvm COPY --from=builder /root/.bashrc /root/.bashrc COPY --from=builder /root/.profile /root/.profile -# 复制精简后的Java环境 +# 复制Java环境 COPY --from=builder /usr/local/java /usr/local/java COPY --from=builder /usr/local/maven /usr/local/maven @@ -223,7 +223,7 @@ RUN ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default # 复制前端构建文件到Nginx静态文件目录 COPY web/dist/ /usr/share/nginx/html/ -# 优化Python依赖安装 +# Python依赖安装 COPY backend/requirements.txt /app/ RUN pip install --no-cache-dir -r requirements.txt && \ # 清理pip缓存和不必要的文件 diff --git a/backend/apps/models.py b/backend/apps/models.py index b3527f7..d07481a 100644 --- a/backend/apps/models.py +++ b/backend/apps/models.py @@ -226,47 +226,23 @@ 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"] - } - ] - ''') + parameters = models.JSONField(default=list, verbose_name='构建参数配置') # 外部脚本库配置 use_external_script = models.BooleanField(default=False, verbose_name='使用外部脚本库') - external_script_config = models.JSONField(default=dict, verbose_name='外部脚本库配置', help_text=''' - { - "repo_url": "https://github.com/example/scripts.git", # Git仓库地址 - "directory": "/data/scripts", # 存放目录 - "branch": "main", # 分支名称(可选) - "token_id": "credential_id" # Git Token凭证ID(私有仓库) - } - ''') + external_script_config = models.JSONField(default=dict, verbose_name='外部脚本库配置') # 构建时间信息(使用JSON存储) - build_time = models.JSONField(default=dict, verbose_name='构建时间信息', help_text=''' - { - "total_duration": "300", # 总耗时(秒) - "start_time": "2024-03-06 12:00:00", # 开始时间 - "end_time": "2024-03-06 12:05:00", # 结束时间 - "stages_time": [ # 各阶段时间信息 - { - "name": "代码拉取", - "start_time": "2024-03-06 12:00:00", - "duration": "60" # 耗时(秒) - } - ] - } - ''') + build_time = models.JSONField(default=dict, verbose_name='构建时间信息') # 构建后操作 notification_channels = models.JSONField(default=list, verbose_name='通知方式') + # 自动构建配置 + auto_build_enabled = models.BooleanField(default=False, verbose_name='启用自动构建') + auto_build_branches = models.JSONField(default=list, verbose_name='自动构建分支') + webhook_token = models.CharField(max_length=64, null=True, blank=True, verbose_name='Webhook验证Token') + # 状态和统计 status = models.CharField(max_length=20, default='created', null=True, verbose_name='任务状态') # created, disabled building_status = models.CharField(max_length=20, default='idle', null=True, verbose_name='构建状态') # idle, building @@ -299,26 +275,8 @@ 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", # 总耗时(秒) - "start_time": "2024-03-06 12:00:00", # 开始时间 - "end_time": "2024-03-06 12:05:00", # 结束时间 - "stages_time": [ # 各阶段时间信息 - { - "name": "代码拉取", - "start_time": "2024-03-06 12:00:00", - "duration": "60" # 耗时(秒) - } - ] - } - ''') + parameter_values = models.JSONField(default=dict, verbose_name='构建参数值') + build_time = models.JSONField(default=dict, verbose_name='构建时间信息') operator = models.ForeignKey('User', on_delete=models.SET_NULL, to_field='user_id', null=True, verbose_name='构建人') create_time = models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间') @@ -329,7 +287,7 @@ class BuildHistory(models.Model): verbose_name = '构建历史' verbose_name_plural = verbose_name ordering = ['-create_time'] - unique_together = ['task', 'build_number'] # 确保任务和构建号的组合唯一 + unique_together = ['task', 'build_number'] def __str__(self): return f"{self.task.name} #{self.build_number}" diff --git a/backend/apps/views/build.py b/backend/apps/views/build.py index 1dfca71..6a228ff 100644 --- a/backend/apps/views/build.py +++ b/backend/apps/views/build.py @@ -154,6 +154,10 @@ class BuildTaskView(View): 'external_script_directory': task.external_script_config.get('directory', '') if task.external_script_config else '', 'external_script_branch': task.external_script_config.get('branch', '') if task.external_script_config else '', 'external_script_token_id': task.external_script_config.get('token_id') if task.external_script_config else None, + # 自动构建配置 + 'auto_build_enabled': task.auto_build_enabled, + 'auto_build_branches': task.auto_build_branches, + 'webhook_token': task.webhook_token, 'status': task.status, 'building_status': task.building_status, # 添加构建状态字段 'version': task.version, @@ -339,6 +343,11 @@ class BuildTaskView(View): parameters = data.get('parameters', []) notification_channels = data.get('notification_channels', []) + # 自动构建配置 + auto_build_enabled = data.get('auto_build_enabled', False) + auto_build_branches = data.get('auto_build_branches', []) + webhook_token = data.get('webhook_token', '') + # 外部脚本库配置 use_external_script = data.get('use_external_script') external_script_config = None @@ -447,6 +456,11 @@ class BuildTaskView(View): 'message': 'GitLab Token凭证不存在' }) + # 如果启用自动构建但没有webhook_token,生成一个 + if auto_build_enabled and not webhook_token: + import secrets + webhook_token = secrets.token_urlsafe(32) + # 创建构建任务 creator = User.objects.get(user_id=request.user_id) task = BuildTask.objects.create( @@ -462,6 +476,9 @@ class BuildTaskView(View): notification_channels=notification_channels, use_external_script=use_external_script, external_script_config=external_script_config, + auto_build_enabled=auto_build_enabled, + auto_build_branches=auto_build_branches, + webhook_token=webhook_token, creator=creator ) @@ -505,6 +522,11 @@ class BuildTaskView(View): notification_channels = data.get('notification_channels') status = data.get('status') + # 自动构建配置 + auto_build_enabled = data.get('auto_build_enabled') + auto_build_branches = data.get('auto_build_branches') + webhook_token = data.get('webhook_token') + # 外部脚本库配置 use_external_script = data.get('use_external_script') external_script_config = None @@ -691,6 +713,25 @@ class BuildTaskView(View): task.use_external_script = use_external_script task.external_script_config = external_script_config + # 更新自动构建配置 + if 'auto_build_enabled' in data: + task.auto_build_enabled = auto_build_enabled + + if auto_build_enabled: + # 如果启用自动构建但没有webhook_token,生成一个 + if not task.webhook_token and not webhook_token: + import secrets + task.webhook_token = secrets.token_urlsafe(32) + elif webhook_token is not None: + task.webhook_token = webhook_token + else: + # 如果取消自动构建,清除所有相关配置 + task.auto_build_branches = [] + task.webhook_token = '' + + if 'auto_build_branches' in data and auto_build_enabled: + task.auto_build_branches = auto_build_branches + task.save() return JsonResponse({ diff --git a/backend/apps/views/webhook.py b/backend/apps/views/webhook.py new file mode 100644 index 0000000..61441fc --- /dev/null +++ b/backend/apps/views/webhook.py @@ -0,0 +1,229 @@ +import json +import logging +from django.http import JsonResponse +from django.views import View +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt +from ..models import BuildTask, BuildHistory, User +from ..utils.builder import Builder +import threading + +logger = logging.getLogger('apps') + +def execute_auto_build(task, branch, commit_id, commit_message, commit_author): + """执行自动构建任务""" + try: + # 生成构建号 + from django.db.models import F + from ..views.build import generate_id + + # 更新任务构建号并获取新的构建号 + task.last_build_number = F('last_build_number') + 1 + task.total_builds = F('total_builds') + 1 + task.building_status = 'building' + task.save() + + # 重新获取任务以获取更新后的构建号 + task.refresh_from_db() + build_number = task.last_build_number + + # 创建构建历史记录 + history = BuildHistory.objects.create( + history_id=generate_id(), + task=task, + build_number=build_number, + branch=branch, + commit_id=commit_id, + status='pending', + requirement=f"自动构建: {commit_message[:200]} (by {commit_author})", # 使用提交信息作为构建需求 + parameter_values=get_default_parameter_values(task.parameters), # 使用默认参数值 + operator=None # 自动构建没有操作人 + ) + + builder = Builder(task, build_number, commit_id, history) + builder.execute() + + except Exception as e: + logger.error(f"自动构建执行失败: {str(e)}", exc_info=True) + finally: + # 无论构建成功、失败或异常,都将构建状态重置为空闲 + from django.db import transaction + with transaction.atomic(): + BuildTask.objects.filter(task_id=task.task_id).update(building_status='idle') + logger.info(f"任务 [{task.task_id}] 自动构建状态已重置为空闲") + +def get_default_parameter_values(parameters): + """获取参数的默认值""" + if not parameters: + return {} + + default_values = {} + for param in parameters: + param_name = param.get('name') + default_list = param.get('default_values', []) + if param_name and default_list: + default_values[param_name] = default_list + + return default_values + +def is_branch_matched(branch_name, branch_list): + """检查分支是否在配置的分支列表中""" + return branch_name in branch_list + +@method_decorator(csrf_exempt, name='dispatch') +class GitLabWebhookView(View): + """GitLab Webhook处理视图""" + + def post(self, request, task_id): + """处理GitLab Push Events""" + try: + # 验证token + token = request.GET.get('token') + if not token: + logger.warning(f"Webhook请求缺少token: task_id={task_id}") + return JsonResponse({ + 'error': 'Missing token' + }, status=401) + + # 查找对应的构建任务 + try: + task = BuildTask.objects.get(task_id=task_id, webhook_token=token) + except BuildTask.DoesNotExist: + logger.warning(f"Webhook token验证失败: task_id={task_id}, token={token}") + return JsonResponse({ + 'error': 'Invalid task or token' + }, status=404) + + # 检查任务是否启用自动构建 + if not task.auto_build_enabled: + logger.info(f"任务[{task_id}]未启用自动构建,忽略webhook") + return JsonResponse({ + 'message': 'Auto build is not enabled for this task' + }) + + # 检查任务状态 + if task.status == 'disabled': + logger.info(f"任务[{task_id}]已禁用,忽略webhook") + return JsonResponse({ + 'message': 'Task is disabled' + }) + + # 是否有正在进行的构建 + if task.building_status == 'building': + logger.info(f"任务[{task_id}]正在构建中,忽略webhook") + return JsonResponse({ + 'message': 'Build is already in progress' + }) + + # 解析webhook数据 + try: + webhook_data = json.loads(request.body) + except json.JSONDecodeError: + logger.error(f"Webhook数据解析失败: task_id={task_id}") + return JsonResponse({ + 'error': 'Invalid JSON data' + }, status=400) + + # 是否是push事件 + event_name = request.headers.get('X-Gitlab-Event', '') + if event_name != 'Push Hook': + logger.info(f"忽略非Push事件: {event_name}, task_id={task_id}") + return JsonResponse({ + 'message': f'Ignored event: {event_name}' + }) + + # 提取分支信息 + ref = webhook_data.get('ref', '') + if not ref.startswith('refs/heads/'): + logger.info(f"忽略非分支推送: {ref}, task_id={task_id}") + return JsonResponse({ + 'message': f'Ignored non-branch push: {ref}' + }) + + branch = ref.replace('refs/heads/', '') + + # 检查分支是否在自动构建配置中 + if not is_branch_matched(branch, task.auto_build_branches): + logger.info(f"分支[{branch}]不在自动构建配置中,忽略webhook: task_id={task_id}") + return JsonResponse({ + 'message': f'Branch {branch} is not configured for auto build' + }) + + # 提取提交信息 + commits = webhook_data.get('commits', []) + if not commits: + logger.warning(f"Webhook数据中没有提交信息: task_id={task_id}") + return JsonResponse({ + 'error': 'No commits found in webhook data' + }, status=400) + + # 使用最新的提交 + latest_commit = commits[-1] + commit_id = latest_commit.get('id', '') + commit_message = latest_commit.get('message', '').strip() + commit_author = latest_commit.get('author', {}).get('name', 'Unknown') + + if not commit_id: + logger.error(f"提交ID为空: task_id={task_id}") + return JsonResponse({ + 'error': 'Commit ID is empty' + }, status=400) + + env_type = task.environment.type if task.environment else None + if env_type not in ['development', 'testing']: + logger.warning(f"环境类型[{env_type}]不支持自动构建: task_id={task_id}") + return JsonResponse({ + 'message': f'Environment type {env_type} does not support auto build' + }) + + logger.info(f"触发自动构建: task_id={task_id}, branch={branch}, commit={commit_id[:8]}, author={commit_author}") + + # 在新线程中执行自动构建 + build_thread = threading.Thread( + target=execute_auto_build, + args=(task, branch, commit_id, commit_message, commit_author) + ) + build_thread.start() + + return JsonResponse({ + 'message': 'Auto build triggered successfully', + 'task_id': task_id, + 'branch': branch, + 'commit_id': commit_id[:8], + 'commit_message': commit_message[:100] + }) + + except Exception as e: + logger.error(f"Webhook处理失败: {str(e)}", exc_info=True) + return JsonResponse({ + 'error': f'Internal server error: {str(e)}' + }, status=500) + + def get(self, request, task_id): + """用于测试webhook配置""" + try: + token = request.GET.get('token') + if not token: + return JsonResponse({ + 'error': 'Missing token' + }, status=401) + + try: + task = BuildTask.objects.get(task_id=task_id, webhook_token=token) + except BuildTask.DoesNotExist: + return JsonResponse({ + 'error': 'Invalid task or token' + }, status=404) + + return JsonResponse({ + 'message': 'Webhook configuration is valid', + 'task_name': task.name, + 'auto_build_enabled': task.auto_build_enabled, + 'auto_build_branches': task.auto_build_branches + }) + + except Exception as e: + logger.error(f"Webhook测试失败: {str(e)}", exc_info=True) + return JsonResponse({ + 'error': f'Internal server error: {str(e)}' + }, status=500) \ No newline at end of file diff --git a/backend/backend/urls.py b/backend/backend/urls.py index 527503f..c6cf673 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -13,6 +13,7 @@ from apps.views.user import UserView, UserProfileView from apps.views.role import RoleView, UserPermissionView from apps.views.logs import login_logs_list, login_log_detail from apps.views.dashboard import DashboardStatsView, BuildTrendView, BuildDetailView, RecentBuildsView, ProjectDistributionView +from apps.views.webhook import GitLabWebhookView from apps.views.security import SecurityConfigView @@ -40,6 +41,9 @@ urlpatterns = [ # SSE构建日志流 path('api/build/logs/stream///', BuildLogSSEView.as_view(), name='build-log-sse'), + # GitLab Webhook + path('api/webhook/gitlab//', GitLabWebhookView.as_view(), name='gitlab-webhook'), + # 通知机器人相关路由 path('api/notification/robots/', NotificationRobotView.as_view(), name='notification-robots'), path('api/notification/robots/test/', NotificationTestView.as_view(), name='notification-robot-test'), diff --git a/backend/conf/config.txt b/backend/conf/config.txt index 41a1f92..166d1f2 100644 --- a/backend/conf/config.txt +++ b/backend/conf/config.txt @@ -3,7 +3,7 @@ host = 127.0.0.1 #host = mysql #host = liteops-mysql port = 3306 -database = liteops +database = liteops_dev user = root password = 1234567xx default-character-set = utf8mb4 \ No newline at end of file diff --git a/liteops_init.sql b/liteops_init.sql index 02d643c..691ad40 100644 --- a/liteops_init.sql +++ b/liteops_init.sql @@ -43,7 +43,7 @@ CREATE TABLE `build_history` ( KEY `build_history_operator_id_f43bdff4_fk_user_user_id` (`operator_id`), CONSTRAINT `build_history_operator_id_f43bdff4_fk_user_user_id` FOREIGN KEY (`operator_id`) REFERENCES `user` (`user_id`), CONSTRAINT `build_history_task_id_dfb7725d_fk_build_task_task_id` FOREIGN KEY (`task_id`) REFERENCES `build_task` (`task_id`) -) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for build_task @@ -71,10 +71,13 @@ CREATE TABLE `build_task` ( `version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, `build_time` json NOT NULL DEFAULT (_utf8mb3'{}'), `requirement` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, - `building_status` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL, + `building_status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, `external_script_config` json NOT NULL DEFAULT (_utf8mb3'{}'), `use_external_script` tinyint(1) NOT NULL, `parameters` json NOT NULL DEFAULT (_utf8mb3'[]'), + `auto_build_branches` json NOT NULL DEFAULT (_utf8mb3'[]'), + `auto_build_enabled` tinyint(1) NOT NULL, + `webhook_token` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `task_id` (`task_id`), KEY `build_task_creator_id_e702c745_fk_user_user_id` (`creator_id`), @@ -85,95 +88,7 @@ CREATE TABLE `build_task` ( CONSTRAINT `build_task_environment_id_8f5e7798_fk_environment_environment_id` FOREIGN KEY (`environment_id`) REFERENCES `environment` (`environment_id`), CONSTRAINT `build_task_git_token_id_813ab2b1_fk_gitlab_to` FOREIGN KEY (`git_token_id`) REFERENCES `gitlab_token_credential` (`credential_id`), CONSTRAINT `build_task_project_id_f92c80ac_fk_project_project_id` FOREIGN KEY (`project_id`) REFERENCES `project` (`project_id`) -) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; - --- ---------------------------- --- Table structure for django_admin_log --- ---------------------------- -DROP TABLE IF EXISTS `django_admin_log`; -CREATE TABLE `django_admin_log` ( - `id` int NOT NULL AUTO_INCREMENT, - `action_time` datetime(6) NOT NULL, - `object_id` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, - `object_repr` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `action_flag` smallint unsigned NOT NULL, - `change_message` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `content_type_id` int DEFAULT NULL, - `user_id` int NOT NULL, - PRIMARY KEY (`id`), - KEY `django_admin_log_content_type_id_c4bce8eb_fk_django_co` (`content_type_id`), - KEY `django_admin_log_user_id_c564eba6_fk_auth_user_id` (`user_id`), - CONSTRAINT `django_admin_log_content_type_id_c4bce8eb_fk_django_co` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`), - CONSTRAINT `django_admin_log_user_id_c564eba6_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`), - CONSTRAINT `django_admin_log_chk_1` CHECK ((`action_flag` >= 0)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; - --- ---------------------------- --- Table structure for django_apscheduler_djangojob --- ---------------------------- -DROP TABLE IF EXISTS `django_apscheduler_djangojob`; -CREATE TABLE `django_apscheduler_djangojob` ( - `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `next_run_time` datetime(6) DEFAULT NULL, - `job_state` longblob NOT NULL, - PRIMARY KEY (`id`), - KEY `django_apscheduler_djangojob_next_run_time_2f022619` (`next_run_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; - --- ---------------------------- --- Table structure for django_apscheduler_djangojobexecution --- ---------------------------- -DROP TABLE IF EXISTS `django_apscheduler_djangojobexecution`; -CREATE TABLE `django_apscheduler_djangojobexecution` ( - `id` bigint NOT NULL AUTO_INCREMENT, - `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `run_time` datetime(6) NOT NULL, - `duration` decimal(15,2) DEFAULT NULL, - `finished` decimal(15,2) DEFAULT NULL, - `exception` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, - `traceback` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, - `job_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `unique_job_executions` (`job_id`,`run_time`), - KEY `django_apscheduler_djangojobexecution_run_time_16edd96b` (`run_time`), - CONSTRAINT `django_apscheduler_djangojobexecution_job_id_daf5090a_fk` FOREIGN KEY (`job_id`) REFERENCES `django_apscheduler_djangojob` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; - --- ---------------------------- --- Table structure for django_content_type --- ---------------------------- -DROP TABLE IF EXISTS `django_content_type`; -CREATE TABLE `django_content_type` ( - `id` int NOT NULL AUTO_INCREMENT, - `app_label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `django_content_type_app_label_model_76bd3d3b_uniq` (`app_label`,`model`) -) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; - --- ---------------------------- --- Table structure for django_migrations --- ---------------------------- -DROP TABLE IF EXISTS `django_migrations`; -CREATE TABLE `django_migrations` ( - `id` bigint NOT NULL AUTO_INCREMENT, - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `applied` datetime(6) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=81 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; - --- ---------------------------- --- Table structure for django_session --- ---------------------------- -DROP TABLE IF EXISTS `django_session`; -CREATE TABLE `django_session` ( - `session_key` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `session_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `expire_date` datetime(6) NOT NULL, - PRIMARY KEY (`session_key`), - KEY `django_session_expire_date_a5c62663` (`expire_date`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for environment @@ -192,7 +107,7 @@ CREATE TABLE `environment` ( UNIQUE KEY `environment_id` (`environment_id`), KEY `environment_creator_id_2f30820a_fk_user_user_id` (`creator_id`), CONSTRAINT `environment_creator_id_2f30820a_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for gitlab_token_credential @@ -211,7 +126,7 @@ CREATE TABLE `gitlab_token_credential` ( UNIQUE KEY `credential_id` (`credential_id`), KEY `gitlab_token_credential_creator_id_d53c3666_fk_user_user_id` (`creator_id`), CONSTRAINT `gitlab_token_credential_creator_id_d53c3666_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for kubeconfig_credential @@ -232,7 +147,7 @@ CREATE TABLE `kubeconfig_credential` ( UNIQUE KEY `credential_id` (`credential_id`), KEY `kubeconfig_credential_creator_id_a3490ac1_fk_user_user_id` (`creator_id`), CONSTRAINT `kubeconfig_credential_creator_id_a3490ac1_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for login_attempt @@ -249,7 +164,7 @@ CREATE TABLE `login_attempt` ( PRIMARY KEY (`id`), UNIQUE KEY `login_attempt_user_id_ip_address_a69098a0_uniq` (`user_id`,`ip_address`), CONSTRAINT `login_attempt_user_id_0f42fcb7_fk_user_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for login_log @@ -268,7 +183,7 @@ CREATE TABLE `login_log` ( UNIQUE KEY `log_id` (`log_id`), KEY `login_log_user_id_69642132_fk_user_user_id` (`user_id`), CONSTRAINT `login_log_user_id_69642132_fk_user_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for notification_robot @@ -292,7 +207,7 @@ CREATE TABLE `notification_robot` ( UNIQUE KEY `robot_id` (`robot_id`), KEY `notification_robot_creator_id_de406276_fk_user_user_id` (`creator_id`), CONSTRAINT `notification_robot_creator_id_de406276_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for project @@ -312,7 +227,7 @@ CREATE TABLE `project` ( UNIQUE KEY `project_id` (`project_id`), KEY `project_creator_id_e70918ae_fk_user_user_id` (`creator_id`), CONSTRAINT `project_creator_id_e70918ae_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for role @@ -332,7 +247,7 @@ CREATE TABLE `role` ( UNIQUE KEY `name` (`name`), KEY `role_creator_id_37780e7e_fk_user_user_id` (`creator_id`), CONSTRAINT `role_creator_id_37780e7e_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for security_config @@ -348,7 +263,7 @@ CREATE TABLE `security_config` ( `enable_2fa` tinyint(1) NOT NULL, `update_time` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for ssh_key_credential @@ -368,7 +283,7 @@ CREATE TABLE `ssh_key_credential` ( UNIQUE KEY `credential_id` (`credential_id`), KEY `ssh_key_credential_creator_id_c7396682_fk_user_user_id` (`creator_id`), CONSTRAINT `ssh_key_credential_creator_id_c7396682_fk_user_user_id` FOREIGN KEY (`creator_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for user @@ -389,7 +304,7 @@ CREATE TABLE `user` ( UNIQUE KEY `user_id` (`user_id`), UNIQUE KEY `username` (`username`), UNIQUE KEY `email` (`email`) -) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for user_role @@ -406,7 +321,7 @@ CREATE TABLE `user_role` ( KEY `user_role_role_id_6a11361a_fk_role_role_id` (`role_id`), CONSTRAINT `user_role_role_id_6a11361a_fk_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`), CONSTRAINT `user_role_user_id_12d84374_fk_user_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- Table structure for user_token @@ -423,7 +338,7 @@ CREATE TABLE `user_token` ( UNIQUE KEY `token_id` (`token_id`), KEY `user_token_user_id_69e1f632_fk_user_user_id` (`user_id`), CONSTRAINT `user_token_user_id_69e1f632_fk_user_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -- ---------------------------- -- 初始化数据 diff --git a/web/src/views/build/BuildTaskEdit.vue b/web/src/views/build/BuildTaskEdit.vue index ec06fdc..1df0773 100644 --- a/web/src/views/build/BuildTaskEdit.vue +++ b/web/src/views/build/BuildTaskEdit.vue @@ -211,6 +211,59 @@ + 自动构建配置 +
+ + + + 启用自动构建 + +
当代码推送到配置的分支时,自动触发构建任务
+
+ +
+ + + main + master + develop + +
请输入精确的分支名称,多个分支用逗号或空格分隔
+
+ + + + + +
将此URL配置到GitLab项目的Webhook中,触发事件选择"Push events"
+
+ + +
+
+ 构建阶段
@@ -389,7 +442,7 @@