301 lines
9.8 KiB
Python
301 lines
9.8 KiB
Python
"""
|
|
流水线执行对话框
|
|
"""
|
|
from PyQt5.QtWidgets import (
|
|
QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QTextEdit, QPushButton, QProgressBar, QFrame, QMessageBox
|
|
)
|
|
from PyQt5.QtCore import Qt, QTimer
|
|
from datetime import datetime
|
|
|
|
|
|
class PipelineDialog(QDialog):
|
|
"""流水线执行对话框"""
|
|
|
|
def __init__(self, project, parent=None):
|
|
"""
|
|
初始化对话框
|
|
|
|
Args:
|
|
project: 项目对象
|
|
parent: 父窗口
|
|
"""
|
|
super().__init__(parent)
|
|
self.project = project
|
|
self.current_step = 0
|
|
self.timer = None
|
|
self._setup_ui()
|
|
|
|
def _setup_ui(self):
|
|
"""设置UI"""
|
|
self.setWindowTitle(f"流水线 - {self.project.name}")
|
|
self.resize(1000, 600)
|
|
|
|
layout = QVBoxLayout(self)
|
|
layout.setSpacing(15)
|
|
|
|
# 标题
|
|
title_label = QLabel(f"<h2>🚀 项目流水线 - {self.project.name}</h2>")
|
|
layout.addWidget(title_label)
|
|
|
|
# 流水线步骤
|
|
steps_layout = QHBoxLayout()
|
|
steps_layout.setSpacing(10)
|
|
|
|
self.step_widgets = []
|
|
steps = [
|
|
("🔍", "静态扫描", "SonarQube"),
|
|
("🔨", "编译构建", "Maven"),
|
|
("📦", "打包", "JAR"),
|
|
("🚀", "部署", "测试环境"),
|
|
("✅", "验证测试", "JUnit")
|
|
]
|
|
|
|
for icon, name, tool in steps:
|
|
step_widget = self._create_step_widget(icon, name, tool)
|
|
self.step_widgets.append(step_widget)
|
|
steps_layout.addWidget(step_widget)
|
|
|
|
layout.addLayout(steps_layout)
|
|
|
|
# 日志输出区域
|
|
log_label = QLabel("<b>执行日志:</b>")
|
|
layout.addWidget(log_label)
|
|
|
|
self.log_text = QTextEdit()
|
|
self.log_text.setReadOnly(True)
|
|
self.log_text.setStyleSheet("""
|
|
QTextEdit {
|
|
background: #1e293b;
|
|
color: #10b981;
|
|
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
font-size: 12px;
|
|
border: 1px solid rgba(59, 130, 246, 0.2);
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
}
|
|
""")
|
|
layout.addWidget(self.log_text)
|
|
|
|
# 总体进度条
|
|
self.progress = QProgressBar()
|
|
self.progress.setTextVisible(True)
|
|
self.progress.setFormat("%p%")
|
|
layout.addWidget(self.progress)
|
|
|
|
# 按钮区域
|
|
button_layout = QHBoxLayout()
|
|
button_layout.addStretch()
|
|
|
|
self.start_btn = QPushButton("▶ 启动流水线")
|
|
self.start_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
|
stop:0 #10b981, stop:1 #059669);
|
|
}
|
|
""")
|
|
self.start_btn.setMinimumWidth(120)
|
|
self.start_btn.clicked.connect(self._start_pipeline)
|
|
button_layout.addWidget(self.start_btn)
|
|
|
|
self.stop_btn = QPushButton("⏹ 停止")
|
|
self.stop_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
|
stop:0 #ef4444, stop:1 #dc2626);
|
|
}
|
|
""")
|
|
self.stop_btn.setMinimumWidth(120)
|
|
self.stop_btn.setEnabled(False)
|
|
self.stop_btn.clicked.connect(self._stop_pipeline)
|
|
button_layout.addWidget(self.stop_btn)
|
|
|
|
close_btn = QPushButton("关闭")
|
|
close_btn.setMinimumWidth(120)
|
|
close_btn.clicked.connect(self.accept)
|
|
button_layout.addWidget(close_btn)
|
|
|
|
layout.addLayout(button_layout)
|
|
|
|
def _create_step_widget(self, icon: str, name: str, tool: str) -> QFrame:
|
|
"""创建步骤组件"""
|
|
widget = QFrame()
|
|
widget.setFrameShape(QFrame.StyledPanel)
|
|
widget.setStyleSheet("""
|
|
QFrame {
|
|
background: rgba(51, 65, 85, 0.4);
|
|
border: 1px solid rgba(59, 130, 246, 0.2);
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
}
|
|
""")
|
|
|
|
layout = QVBoxLayout(widget)
|
|
layout.setAlignment(Qt.AlignCenter)
|
|
layout.setSpacing(8)
|
|
|
|
# 图标
|
|
icon_label = QLabel(icon)
|
|
icon_label.setStyleSheet("font-size: 36px;")
|
|
icon_label.setAlignment(Qt.AlignCenter)
|
|
layout.addWidget(icon_label)
|
|
|
|
# 步骤名称
|
|
name_label = QLabel(name)
|
|
name_label.setStyleSheet("""
|
|
font-weight: bold;
|
|
font-size: 14px;
|
|
color: #e0e6ed;
|
|
""")
|
|
name_label.setAlignment(Qt.AlignCenter)
|
|
layout.addWidget(name_label)
|
|
|
|
# 工具名称
|
|
tool_label = QLabel(tool)
|
|
tool_label.setStyleSheet("""
|
|
color: #94a3b8;
|
|
font-size: 11px;
|
|
""")
|
|
tool_label.setAlignment(Qt.AlignCenter)
|
|
layout.addWidget(tool_label)
|
|
|
|
# 状态标签
|
|
status_label = QLabel("就绪")
|
|
status_label.setObjectName("status_label")
|
|
status_label.setStyleSheet("""
|
|
color: #94a3b8;
|
|
font-size: 12px;
|
|
""")
|
|
status_label.setAlignment(Qt.AlignCenter)
|
|
layout.addWidget(status_label)
|
|
|
|
return widget
|
|
|
|
def _start_pipeline(self):
|
|
"""启动流水线"""
|
|
self.start_btn.setEnabled(False)
|
|
self.stop_btn.setEnabled(True)
|
|
self.current_step = 0
|
|
self.progress.setValue(0)
|
|
self.log_text.clear()
|
|
|
|
self._add_log("[INFO] ========================================")
|
|
self._add_log(f"[INFO] 流水线启动 - 项目: {self.project.name}")
|
|
self._add_log("[INFO] ========================================")
|
|
|
|
# 使用定时器模拟流水线执行
|
|
self.timer = QTimer()
|
|
self.timer.timeout.connect(self._update_pipeline)
|
|
self.timer.start(1500) # 每1.5秒执行一步
|
|
|
|
def _update_pipeline(self):
|
|
"""更新流水线状态"""
|
|
if self.current_step < len(self.step_widgets):
|
|
widget = self.step_widgets[self.current_step]
|
|
|
|
# 更新为进行中状态
|
|
widget.setStyleSheet("""
|
|
QFrame {
|
|
background: rgba(59, 130, 246, 0.3);
|
|
border: 2px solid #3b82f6;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
}
|
|
""")
|
|
|
|
# 更新状态标签
|
|
status_label = widget.findChild(QLabel, "status_label")
|
|
if status_label:
|
|
status_label.setText("进行中...")
|
|
status_label.setStyleSheet("""
|
|
color: #3b82f6;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
""")
|
|
|
|
# 添加日志
|
|
step_names = ["静态扫描", "编译构建", "打包", "部署", "验证测试"]
|
|
self._add_log(f"[INFO] 开始执行: {step_names[self.current_step]}")
|
|
self._add_log(f"[INFO] 步骤 {self.current_step + 1}/{len(self.step_widgets)}")
|
|
|
|
# 更新进度条
|
|
progress_value = int((self.current_step + 1) / len(self.step_widgets) * 100)
|
|
self.progress.setValue(progress_value)
|
|
|
|
# 延迟标记为完成
|
|
QTimer.singleShot(1000, lambda: self._complete_step(self.current_step))
|
|
|
|
self.current_step += 1
|
|
else:
|
|
self.timer.stop()
|
|
self._finish_pipeline()
|
|
|
|
def _complete_step(self, step_index: int):
|
|
"""完成步骤"""
|
|
if step_index < len(self.step_widgets):
|
|
widget = self.step_widgets[step_index]
|
|
|
|
# 更新为完成状态
|
|
widget.setStyleSheet("""
|
|
QFrame {
|
|
background: rgba(16, 185, 129, 0.2);
|
|
border: 2px solid #10b981;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
}
|
|
""")
|
|
|
|
# 更新状态标签
|
|
status_label = widget.findChild(QLabel, "status_label")
|
|
if status_label:
|
|
status_label.setText("✓ 完成")
|
|
status_label.setStyleSheet("""
|
|
color: #10b981;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
""")
|
|
|
|
# 添加完成日志
|
|
step_names = ["静态扫描", "编译构建", "打包", "部署", "验证测试"]
|
|
self._add_log(f"[SUCCESS] {step_names[step_index]} 完成")
|
|
self._add_log("")
|
|
|
|
def _finish_pipeline(self):
|
|
"""完成流水线"""
|
|
self._add_log("[INFO] ========================================")
|
|
self._add_log("[SUCCESS] 流水线执行完成!")
|
|
self._add_log(f"[INFO] 项目: {self.project.name}")
|
|
self._add_log("[INFO] 所有步骤已成功执行")
|
|
self._add_log("[INFO] ========================================")
|
|
|
|
self.start_btn.setEnabled(True)
|
|
self.stop_btn.setEnabled(False)
|
|
|
|
QMessageBox.information(
|
|
self,
|
|
"完成",
|
|
f"流水线执行完成!\n\n项目: {self.project.name}\n所有步骤已成功执行。"
|
|
)
|
|
|
|
def _stop_pipeline(self):
|
|
"""停止流水线"""
|
|
if self.timer:
|
|
self.timer.stop()
|
|
|
|
self._add_log("")
|
|
self._add_log("[WARNING] ========================================")
|
|
self._add_log("[WARNING] 流水线已被用户停止")
|
|
self._add_log("[WARNING] ========================================")
|
|
|
|
self.start_btn.setEnabled(True)
|
|
self.stop_btn.setEnabled(False)
|
|
|
|
def _add_log(self, message: str):
|
|
"""添加日志"""
|
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
|
self.log_text.append(f"[{timestamp}] {message}")
|
|
|
|
# 自动滚动到底部
|
|
scrollbar = self.log_text.verticalScrollBar()
|
|
scrollbar.setValue(scrollbar.maximum())
|