diff --git a/.gitignore b/.gitignore index 832cb0b18e..165db4e885 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ target .settings .project .classpath -.jython_cache \ No newline at end of file +.jython_cache +qywx.json \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0bcbd5ea2b..07f9e02988 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,9 +6,9 @@ ARG MS_VERSION=dev RUN mkdir -p /opt/apps && mkdir -p /opt/jmeter -ADD backend/target/backend-1.4.jar /opt/apps +COPY backend/target/backend-1.4.jar /opt/apps -ADD backend/target/classes/jmeter/ /opt/jmeter/ +COPY backend/target/classes/jmeter/ /opt/jmeter/ ENV JAVA_APP_JAR=/opt/apps/backend-1.4.jar diff --git a/README_EN.md b/README-EN.md old mode 100755 new mode 100644 similarity index 80% rename from README_EN.md rename to README-EN.md index e94f9ec3d1..9d0d82f374 --- a/README_EN.md +++ b/README-EN.md @@ -7,11 +7,10 @@ MeterSphere is a one-stop open-source enterprise-class continuous testing platform. It covers functions such as tests tracking, interface testing, performance testing, team collaboration and is compatible with open-source standards such as JMeter. It helps development and testing teams to conduct highly scalable automated testing, making full use of elasticity of the cloud, and accelerating the delivery process of high-quality software. -- Test Tracking: Far beyond the user experience of TestLink. -- API Testing: Similar to Postman's experience. -- Performance Testing: Compatible with JMeter. Support Kubernetes and Cloud Environment. High concurrency, distributed performance testing with ease. -- Team Collaboration: duo-levels tenants system, naturally support team co-op. - +- Test Tracking: Far beyond the user experience of TestLink. +- API Testing: Similar to Postman's experience. +- Performance Testing: Compatible with JMeter. Support Kubernetes and Cloud Environment. High concurrency, distributed performance testing with ease. +- Team Collaboration: duo-levels tenants system, naturally support team co-op. ## Quick Start @@ -26,11 +25,11 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu ``` ## Technical advantages - -- Full Life Cycle: Full coverage over all STLC phases. Starting from the Test Plan to the Report Creation phase. -- Automation & Scalable: Automation for interface and performance testings. Fully adopt the elasticity of Cloud to produce a large scale of performance testing. -- Continuous Testing: Seamlessly integrated with the CI tools. Supporting enterprises for "Shift left" testing. -- Team Collaboration: Support different proportions of teams. Capable from a group of five to a testing center of several hundred people. + +- Full Life Cycle: Full coverage over all STLC phases. Starting from the Test Plan to the Report Creation phase. +- Automation & Scalable: Automation for interface and performance testings. Fully adopt the elasticity of Cloud to produce a large scale of performance testing. +- Continuous Testing: Seamlessly integrated with the CI tools. Supporting enterprises for "Shift left" testing. +- Team Collaboration: Support different proportions of teams. Capable from a group of five to a testing center of several hundred people. ## Features List @@ -149,15 +148,13 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu - ## Technology stack -- Backend: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm) -- Frontend: [Vue.js](https://vuejs.org/) -- Middleware: [MySQL](https://www.mysql.com/), [Kafka](https://kafka.apache.org/) -- Basic infrastructure: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/) -- Test engine: [JMeter](https://jmeter.apache.org/) - +- Backend: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm) +- Frontend: [Vue.js](https://vuejs.org/) +- Middleware: [MySQL](https://www.mysql.com/), [Kafka](https://kafka.apache.org/) +- Basic infrastructure: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/) +- Test engine: [JMeter](https://jmeter.apache.org/) ## License & Copyright @@ -165,6 +162,6 @@ Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved. Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at -https://www.gnu.org/licenses/gpl-2.0.html + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/README.md b/README.md index 0bbfc8272e..b096fc70dc 100755 --- a/README.md +++ b/README.md @@ -5,41 +5,41 @@ [![GitHub All Releases](https://img.shields.io/github/downloads/metersphere/metersphere/total)](https://github.com/metersphere/metersphere/releases) [![TesterHome](https://img.shields.io/badge/TTF-TesterHome-2955C5.svg)](https://testerhome.com/github_statistics) -> [English](README_EN.md) | 中文 +> [English](README-EN.md) | 中文 -|Developer Wanted| -|----------------| -|我们正在寻找开发者,欢迎加入我们共同打造更好用、更强大的 MeterSphere。联系我们: | +| Developer Wanted | +| ------------------------------------------------------------------------------------------------------------ | +| 我们正在寻找开发者,欢迎加入我们共同打造更好用、更强大的 MeterSphere。联系我们: [metersphere@fit2cloud.com](mailto:metersphere@fit2cloud.com) | MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟踪、接口测试、性能测试、团队协作等功能,兼容JMeter 等开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量软件的交付。 -- 测试跟踪: 远超 TestLink 的使用体验; -- 接口测试: 类似 Postman 的体验; -- 性能测试: 兼容 JMeter,支持 Kubernetes 和云环境,轻松支持高并发、分布式的性能测试; -- 团队协作: 两级租户体系,天然支持团队协作。 +- 测试跟踪: 远超 TestLink 的使用体验; +- 接口测试: 类似 Postman 的体验; +- 性能测试: 兼容 JMeter,支持 Kubernetes 和云环境,轻松支持高并发、分布式的性能测试; +- 团队协作: 两级租户体系,天然支持团队协作。 ![产品定位](https://metersphere.oss-cn-hangzhou.aliyuncs.com/img/ct-devops.png) - > 如需进一步了解 MeterSphere 开源项目,推荐阅读 [MeterSphere 的初心和使命](https://mp.weixin.qq.com/s/DpCt3BNgBTlV3sJ5qtPmZw) ## 在线体验 -- 环境地址:https://demo.metersphere.com/ -- 用户名:demo -- 密码:P@ssw0rd123.. -| :warning: 注意 | -|:---------------------------| -| 该环境仅作体验目的使用,我们会定时清理、重置数据! | -| 请勿修改体验环境用户的密码! | +- 环境地址: +- 用户名:demo +- 密码:P@ssw0rd123.. + +| :warning: 注意 | +| :--------------------------- | +| 该环境仅作体验目的使用,我们会定时清理、重置数据! | +| 请勿修改体验环境用户的密码! | | 请勿在环境中添加业务生产环境地址、用户名密码等敏感信息! | ## 快速开始 仅需两步快速安装 MeterSphere: - 1. 准备一台不小于 8 G内存的 64位 Linux 主机; - 2. 以 root 用户执行如下命令一键安装 MeterSphere。 +1. 准备一台不小于 8 G内存的 64位 Linux 主机; +2. 以 root 用户执行如下命令一键安装 MeterSphere。 ```sh curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh @@ -47,34 +47,37 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu 文档和演示视频: -- [完整文档](https://metersphere.io/docs/) -- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4) +- [完整文档](https://metersphere.io/docs/) +- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4) ## MeterSphere 企业版 + [申请企业版使用](https://jinshuju.net/f/CzzAOe) + > 注: 企业版支持离线安装,申请通过后会提供高速下载链接 ## 相关工具 -- [Jenkins 插件](https://github.com/metersphere/jenkins-plugin) -- [浏览器插件](https://github.com/metersphere/chrome-extensions) +- [Jenkins 插件](https://github.com/metersphere/jenkins-plugin) +- [浏览器插件](https://github.com/metersphere/chrome-extensions) ## 版本说明 MeterSphere 版本号命名规则为:v大版本.功能版本.Bug修复版本。比如: -``` +```text v1.0.1 是 v1.0.0 之后的Bug修复版本; v1.1.0 是 v1.0.0 之后的功能版本。 ``` + 像其它优秀开源项目一样,MeterSphere 将每月发布一个功能版本。 ## 技术优势 - -- 全生命周期: 能够覆盖从测试计划到测试执行、测试报告分析的不同阶段; -- 自动化 & 扩展性: 支持接口和性能的自动化测试,可以充分利用云弹性实现超大规模的性能测试; -- 持续测试: 能够与持续集成工具无缝集成,支撑企业实现测试左移; -- 团队协作: 支持不同规模的测试团队,小到几个人的测试团队、大到数百人的测试中心。 + +- 全生命周期: 能够覆盖从测试计划到测试执行、测试报告分析的不同阶段; +- 自动化 & 扩展性: 支持接口和性能的自动化测试,可以充分利用云弹性实现超大规模的性能测试; +- 持续测试: 能够与持续集成工具无缝集成,支撑企业实现测试左移; +- 团队协作: 支持不同规模的测试团队,小到几个人的测试团队、大到数百人的测试中心。 ## 功能列表 @@ -276,17 +279,17 @@ v1.1.0 是 v1.0.0 之后的功能版本。 ## 技术栈 -- 后端: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm) -- 前端: [Vue.js](https://vuejs.org/) -- 中间件: [MySQL](https://www.mysql.com/), [Kafka](https://kafka.apache.org/) -- 基础设施: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/) -- 测试引擎: [JMeter](https://jmeter.apache.org/) +- 后端: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm) +- 前端: [Vue.js](https://vuejs.org/) +- 中间件: [MySQL](https://www.mysql.com/), [Kafka](https://kafka.apache.org/) +- 基础设施: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/) +- 测试引擎: [JMeter](https://jmeter.apache.org/) ## 致谢 -- [BlazeMeter](https://www.blazemeter.com/):感谢 BlazeMeter 提供的设计思路 -- [JMeter](https://jmeter.apache.org/):MeterSphere 使用了 JMeter 作为测试引擎 -- [Element](https://element.eleme.cn/#/):感谢 Element 提供的优秀组件库 +- [BlazeMeter](https://www.blazemeter.com/):感谢 BlazeMeter 提供的设计思路 +- [JMeter](https://jmeter.apache.org/):MeterSphere 使用了 JMeter 作为测试引擎 +- [Element](https://element.eleme.cn/#/):感谢 Element 提供的优秀组件库 ## 加入 MeterSphere 团队 @@ -304,6 +307,6 @@ Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved. Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at -https://www.gnu.org/licenses/gpl-2.0.html + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/ROADMAP.md b/ROADMAP.md index 3921fe2abb..2b9a37a03f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,61 +1,65 @@ - ## v1.1 (已发布) - -- [x] 浏览器插件支持编辑录制后的内容 -- [x] 插件录制的脚本支持用作接口测试 -- [x] 动态展示性能测试报告 -- [x] 优化性能测试稳定性及资源使用效率 -- [x] 提供 Jenkins 插件 -- [x] 提供 Swagger API 文档 -- [x] 增加针对项目的环境配置、全局变量管理功能 -- [x] 支持 JMX/Swagger 等方式导入接口测试 -- [x] 支持 LDAP 登录 -- [ ] 推出在线体验环境 +## v1.1 (已发布) + +- [x] 浏览器插件支持编辑录制后的内容 +- [x] 插件录制的脚本支持用作接口测试 +- [x] 动态展示性能测试报告 +- [x] 优化性能测试稳定性及资源使用效率 +- [x] 提供 Jenkins 插件 +- [x] 提供 Swagger API 文档 +- [x] 增加针对项目的环境配置、全局变量管理功能 +- [x] 支持 JMX/Swagger 等方式导入接口测试 +- [x] 支持 LDAP 登录 +- [ ] 推出在线体验环境 ## v1.2 (已发布) -- [x] 接口测试支持前后置脚本 -- [x] 接口测试支持常用函数 -- [x] 接口测试批量执行 -- [x] 接口测试单接口调试功能 -- [ ] 测试用例增加用例评审功能 -- [x] 测试用例与缺陷管理工具的集成 -- [x] 测试用例增加批量操作类型 -- [ ] 增加消息通知 -- [ ] 测试报告导出 -- [ ] 优化性能测试压力配置模式 +- [x] 接口测试支持前后置脚本 +- [x] 接口测试支持常用函数 +- [x] 接口测试批量执行 +- [x] 接口测试单接口调试功能 +- [ ] 测试用例增加用例评审功能 +- [x] 测试用例与缺陷管理工具的集成 +- [x] 测试用例增加批量操作类型 +- [ ] 增加消息通知 +- [ ] 测试报告导出 +- [ ] 优化性能测试压力配置模式 ## v1.3 (已发布) -- [x] 测试跟踪:用例评审机制 -- [x] 测试跟踪:测试计划关联用例支持跨项目 -- [ ] 测试跟踪:测试用例支持贴图 -- [x] 测试跟踪:支持思维导图格式导入用例 -- [x] 接口测试:增加逻辑控制环节 -- [x] 接口测试:支持场景拼接 -- [x] 接口测试:支持 SQL 类型的请求 -- [x] 接口测试:支持自定义 Hosts -- [x] 接口测试:参数增加启用禁用 -- [ ] 性能测试:增加压测模式 -- [x] 其他:消息通知 -- [x] 其他:报告导出 + +- [x] 测试跟踪:用例评审机制 +- [x] 测试跟踪:测试计划关联用例支持跨项目 +- [ ] 测试跟踪:测试用例支持贴图 +- [x] 测试跟踪:支持思维导图格式导入用例 +- [x] 接口测试:增加逻辑控制环节 +- [x] 接口测试:支持场景拼接 +- [x] 接口测试:支持 SQL 类型的请求 +- [x] 接口测试:支持自定义 Hosts +- [x] 接口测试:参数增加启用禁用 +- [ ] 性能测试:增加压测模式 +- [x] 其他:消息通知 +- [x] 其他:报告导出 ## v1.4 (已发布) -- [x] 测试跟踪模块编辑测试用例支持上传附件 -- [x] 支持上传并引用自定义Jar包 -- [x] 接口测试支持TCP协议请求 -- [x] 全新的消息通知设置,支持企业微信、钉钉机器人通知 + +- [x] 测试跟踪模块编辑测试用例支持上传附件 +- [x] 支持上传并引用自定义Jar包 +- [x] 接口测试支持TCP协议请求 +- [x] 全新的消息通知设置,支持企业微信、钉钉机器人通知 ## v1.5 (开发中) -- [ ] 性能测试:优化并发数、持续时间等压力配置方式 -- [ ] 性能测试:支持使用了额外插件的 JMX 文件 -- [ ] 性能测试:自动修改 csv 等数据文件引用路径 -- [ ] 性能测试:优化性能测试报告展示 -- [ ] 测试跟踪:支持对接禅道同步缺陷 -- [ ] 其他:Jenkins 插件支持 pipeline 方式调用 + +- [ ] 性能测试:优化并发数、持续时间等压力配置方式 +- [ ] 性能测试:支持使用了额外插件的 JMX 文件 +- [ ] 性能测试:自动修改 csv 等数据文件引用路径 +- [ ] 性能测试:优化性能测试报告展示 +- [ ] 测试跟踪:支持对接禅道同步缺陷 +- [ ] 其他:Jenkins 插件支持 pipeline 方式调用 ## 规划中 -- [ ] 接口测试支持添加 WebSocket 协议请求 -- [ ] 接口管理功能 -- [ ] 集成云平台动态管理测试资源池 -- [ ] 支持 K8s 集群作为测试资源池 -- [ ] 移动端测试支持 -- [ ] UI 功能测试支持 + +- [ ] 接口测试支持添加 WebSocket 协议请求 +- [ ] 接口管理功能 +- [ ] 集成云平台动态管理测试资源池 +- [ ] 支持 K8s 集群作为测试资源池 +- [ ] 移动端测试支持 +- [ ] UI 功能测试支持 diff --git a/backend/pom.xml b/backend/pom.xml index 28225acbca..723061e1f8 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -156,7 +156,7 @@ org.python jython-standalone - 2.7.0 + 2.7.2 diff --git a/backend/src/main/java/io/metersphere/base/domain/LoadTestReport.java b/backend/src/main/java/io/metersphere/base/domain/LoadTestReport.java index d587d581ae..9f7c9e77ba 100644 --- a/backend/src/main/java/io/metersphere/base/domain/LoadTestReport.java +++ b/backend/src/main/java/io/metersphere/base/domain/LoadTestReport.java @@ -22,5 +22,7 @@ public class LoadTestReport implements Serializable { private String triggerMode; + private String fileId; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/LoadTestReportExample.java b/backend/src/main/java/io/metersphere/base/domain/LoadTestReportExample.java index 38edf86b0b..17743bbca4 100644 --- a/backend/src/main/java/io/metersphere/base/domain/LoadTestReportExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/LoadTestReportExample.java @@ -643,6 +643,76 @@ public class LoadTestReportExample { addCriterion("trigger_mode not between", value1, value2, "triggerMode"); return (Criteria) this; } + + public Criteria andFileIdIsNull() { + addCriterion("file_id is null"); + return (Criteria) this; + } + + public Criteria andFileIdIsNotNull() { + addCriterion("file_id is not null"); + return (Criteria) this; + } + + public Criteria andFileIdEqualTo(String value) { + addCriterion("file_id =", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdNotEqualTo(String value) { + addCriterion("file_id <>", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdGreaterThan(String value) { + addCriterion("file_id >", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdGreaterThanOrEqualTo(String value) { + addCriterion("file_id >=", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdLessThan(String value) { + addCriterion("file_id <", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdLessThanOrEqualTo(String value) { + addCriterion("file_id <=", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdLike(String value) { + addCriterion("file_id like", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdNotLike(String value) { + addCriterion("file_id not like", value, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdIn(List values) { + addCriterion("file_id in", values, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdNotIn(List values) { + addCriterion("file_id not in", values, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdBetween(String value1, String value2) { + addCriterion("file_id between", value1, value2, "fileId"); + return (Criteria) this; + } + + public Criteria andFileIdNotBetween(String value1, String value2) { + addCriterion("file_id not between", value1, value2, "fileId"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/domain/Project.java b/backend/src/main/java/io/metersphere/base/domain/Project.java index 4b934ac658..25403e763e 100644 --- a/backend/src/main/java/io/metersphere/base/domain/Project.java +++ b/backend/src/main/java/io/metersphere/base/domain/Project.java @@ -21,5 +21,7 @@ public class Project implements Serializable { private String jiraKey; + private String zentaoId; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java b/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java index 7c93737e82..8f83d6ad88 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java @@ -643,6 +643,76 @@ public class ProjectExample { addCriterion("jira_key not between", value1, value2, "jiraKey"); return (Criteria) this; } + + public Criteria andZentaoIdIsNull() { + addCriterion("zentao_id is null"); + return (Criteria) this; + } + + public Criteria andZentaoIdIsNotNull() { + addCriterion("zentao_id is not null"); + return (Criteria) this; + } + + public Criteria andZentaoIdEqualTo(String value) { + addCriterion("zentao_id =", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdNotEqualTo(String value) { + addCriterion("zentao_id <>", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdGreaterThan(String value) { + addCriterion("zentao_id >", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdGreaterThanOrEqualTo(String value) { + addCriterion("zentao_id >=", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdLessThan(String value) { + addCriterion("zentao_id <", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdLessThanOrEqualTo(String value) { + addCriterion("zentao_id <=", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdLike(String value) { + addCriterion("zentao_id like", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdNotLike(String value) { + addCriterion("zentao_id not like", value, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdIn(List values) { + addCriterion("zentao_id in", values, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdNotIn(List values) { + addCriterion("zentao_id not in", values, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdBetween(String value1, String value2) { + addCriterion("zentao_id between", value1, value2, "zentaoId"); + return (Criteria) this; + } + + public Criteria andZentaoIdNotBetween(String value1, String value2) { + addCriterion("zentao_id not between", value1, value2, "zentaoId"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/mapper/LoadTestReportMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/LoadTestReportMapper.xml index 9b1b3543bc..0b238045cf 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/LoadTestReportMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/LoadTestReportMapper.xml @@ -10,6 +10,7 @@ + @@ -74,7 +75,7 @@ - id, test_id, `name`, create_time, update_time, `status`, user_id, trigger_mode + id, test_id, `name`, create_time, update_time, `status`, user_id, trigger_mode, file_id description, load_configuration @@ -130,12 +131,12 @@ INSERT INTO load_test_report (id, test_id, `name`, create_time, update_time, `status`, - user_id, trigger_mode, description, - load_configuration) + user_id, trigger_mode, file_id, + description, load_configuration) VALUES (#{id,jdbcType=VARCHAR}, #{testId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{status,jdbcType=VARCHAR}, - #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR}, - #{loadConfiguration,jdbcType=LONGVARCHAR}) + #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, + #{description,jdbcType=LONGVARCHAR}, #{loadConfiguration,jdbcType=LONGVARCHAR}) insert into load_test_report @@ -164,6 +165,9 @@ trigger_mode, + + file_id, + description, @@ -196,6 +200,9 @@ #{triggerMode,jdbcType=VARCHAR}, + + #{fileId,jdbcType=VARCHAR}, + #{description,jdbcType=LONGVARCHAR}, @@ -237,6 +244,9 @@ trigger_mode = #{record.triggerMode,jdbcType=VARCHAR}, + + file_id = #{record.fileId,jdbcType=VARCHAR}, + description = #{record.description,jdbcType=LONGVARCHAR}, @@ -258,6 +268,7 @@ `status` = #{record.status,jdbcType=VARCHAR}, user_id = #{record.userId,jdbcType=VARCHAR}, trigger_mode = #{record.triggerMode,jdbcType=VARCHAR}, + file_id = #{record.fileId,jdbcType=VARCHAR}, description = #{record.description,jdbcType=LONGVARCHAR}, load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR} @@ -273,7 +284,8 @@ update_time = #{record.updateTime,jdbcType=BIGINT}, `status` = #{record.status,jdbcType=VARCHAR}, user_id = #{record.userId,jdbcType=VARCHAR}, - trigger_mode = #{record.triggerMode,jdbcType=VARCHAR} + trigger_mode = #{record.triggerMode,jdbcType=VARCHAR}, + file_id = #{record.fileId,jdbcType=VARCHAR} @@ -302,6 +314,9 @@ trigger_mode = #{triggerMode,jdbcType=VARCHAR}, + + file_id = #{fileId,jdbcType=VARCHAR}, + description = #{description,jdbcType=LONGVARCHAR}, @@ -312,27 +327,29 @@ where id = #{id,jdbcType=VARCHAR} - update load_test_report - set test_id = #{testId,jdbcType=VARCHAR}, + UPDATE load_test_report + SET test_id = #{testId,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT}, `status` = #{status,jdbcType=VARCHAR}, user_id = #{userId,jdbcType=VARCHAR}, trigger_mode = #{triggerMode,jdbcType=VARCHAR}, + file_id = #{fileId,jdbcType=VARCHAR}, description = #{description,jdbcType=LONGVARCHAR}, load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR} - where id = #{id,jdbcType=VARCHAR} + WHERE id = #{id,jdbcType=VARCHAR} - update load_test_report - set test_id = #{testId,jdbcType=VARCHAR}, + UPDATE load_test_report + SET test_id = #{testId,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT}, `status` = #{status,jdbcType=VARCHAR}, user_id = #{userId,jdbcType=VARCHAR}, - trigger_mode = #{triggerMode,jdbcType=VARCHAR} - where id = #{id,jdbcType=VARCHAR} + trigger_mode = #{triggerMode,jdbcType=VARCHAR}, + file_id = #{fileId,jdbcType=VARCHAR} + WHERE id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml index a5939ef7bd..4ed30cebfe 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml @@ -10,6 +10,7 @@ + @@ -70,7 +71,8 @@ - id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key + id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key, + zentao_id @@ -198,6 +208,9 @@ jira_key = #{record.jiraKey,jdbcType=VARCHAR}, + + zentao_id = #{record.zentaoId,jdbcType=VARCHAR}, + @@ -212,7 +225,8 @@ create_time = #{record.createTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT}, tapd_id = #{record.tapdId,jdbcType=VARCHAR}, - jira_key = #{record.jiraKey,jdbcType=VARCHAR} + jira_key = #{record.jiraKey,jdbcType=VARCHAR}, + zentao_id = #{record.zentaoId,jdbcType=VARCHAR} @@ -241,6 +255,9 @@ jira_key = #{jiraKey,jdbcType=VARCHAR}, + + zentao_id = #{zentaoId,jdbcType=VARCHAR}, + where id = #{id,jdbcType=VARCHAR} @@ -252,7 +269,8 @@ create_time = #{createTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT}, tapd_id = #{tapdId,jdbcType=VARCHAR}, - jira_key = #{jiraKey,jdbcType=VARCHAR} + jira_key = #{jiraKey,jdbcType=VARCHAR}, + zentao_id = #{zentaoId,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.xml index c4c9f8b821..66bb7c3588 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.xml @@ -4,7 +4,7 @@ SELECT DISTINCT * FROM ( - SELECT `user`.* FROM user_role JOIN `user` ON user_role.user_id = `user`.id - WHERE user_role.source_id = #{orgMember.organizationId} + SELECT `user`.* + FROM user_role JOIN `user` + ON user_role.user_id = `user`.id + WHERE user_role.source_id in + ( + SELECT id FROM workspace w + WHERE w.organization_id = #{orgMember.organizationId} + UNION + SELECT #{orgMember.organizationId} AS id FROM dual + ) AND `user`.name like CONCAT('%', #{orgMember.name},'%') diff --git a/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java b/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java index d1ace27122..0e6540740d 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java +++ b/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum IssuesManagePlatform { - Tapd, Jira, Local + Tapd, Jira, Local, Zentao } diff --git a/backend/src/main/java/io/metersphere/commons/constants/RoleConstants.java b/backend/src/main/java/io/metersphere/commons/constants/RoleConstants.java index 19d254b23c..adb585b0d0 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/RoleConstants.java +++ b/backend/src/main/java/io/metersphere/commons/constants/RoleConstants.java @@ -3,6 +3,7 @@ package io.metersphere.commons.constants; public class RoleConstants { public final static String ADMIN = "admin"; public final static String ORG_ADMIN = "org_admin"; + public final static String ORG_MEMBER = "org_member"; public final static String TEST_VIEWER = "test_viewer"; public final static String TEST_MANAGER = "test_manager"; public final static String TEST_USER = "test_user"; diff --git a/backend/src/main/java/io/metersphere/dto/ProjectDTO.java b/backend/src/main/java/io/metersphere/dto/ProjectDTO.java index e869d8f12a..12b4c46d37 100644 --- a/backend/src/main/java/io/metersphere/dto/ProjectDTO.java +++ b/backend/src/main/java/io/metersphere/dto/ProjectDTO.java @@ -16,5 +16,5 @@ public class ProjectDTO { private Long updateTime; private String tapdId; private String jiraKey; - + private String zentaoId; } diff --git a/backend/src/main/java/io/metersphere/notice/service/MailService.java b/backend/src/main/java/io/metersphere/notice/service/MailService.java index 3efeca32ae..0cc1c5e44e 100644 --- a/backend/src/main/java/io/metersphere/notice/service/MailService.java +++ b/backend/src/main/java/io/metersphere/notice/service/MailService.java @@ -24,6 +24,7 @@ import org.apache.commons.collections4.MapUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.StringUtils; +import org.springframework.mail.MailException; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; @@ -99,10 +100,10 @@ public class MailService { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom(javaMailSender.getUsername()); if (StringUtils.equals(type, NoticeConstants.API)) { - helper.setSubject("MeterSphere平台" + Translator.get("task_notification")); + helper.setSubject("MeterSphere平台" + Translator.get("task_notification_jenkins")); } if (StringUtils.equals(type, NoticeConstants.SCHEDULE)) { - helper.setSubject("MeterSphere平台" + Translator.get("task_notification_")); + helper.setSubject("MeterSphere平台" + Translator.get("task_notification")); } String[] users; List emails = new ArrayList<>(); @@ -113,7 +114,11 @@ public class MailService { users = emails.toArray(new String[0]); helper.setText(getContent(Template, context), true); helper.setTo(users); - javaMailSender.send(mimeMessage); + try { + javaMailSender.send(mimeMessage); + } catch (MailException e) { + LogUtil.error(e); + } } //测试评审 diff --git a/backend/src/main/java/io/metersphere/performance/controller/PerformanceReportController.java b/backend/src/main/java/io/metersphere/performance/controller/PerformanceReportController.java index 2e2c5a651e..dd07e05aaa 100644 --- a/backend/src/main/java/io/metersphere/performance/controller/PerformanceReportController.java +++ b/backend/src/main/java/io/metersphere/performance/controller/PerformanceReportController.java @@ -16,6 +16,9 @@ import io.metersphere.performance.controller.request.ReportRequest; import io.metersphere.performance.service.ReportService; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -130,4 +133,13 @@ public class PerformanceReportController { public void deleteReportBatch(@RequestBody DeleteReportRequest reportRequest) { reportService.deleteReportBatch(reportRequest); } + + @GetMapping("/jtl/download/{reportId}") + public ResponseEntity downloadJtl(@PathVariable String reportId) { + byte[] bytes = reportService.downloadJtl(reportId); + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType("application/octet-stream")) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + ".jtl\"") + .body(bytes); + } } diff --git a/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java b/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java index 5b041a02b4..db8cbbd74a 100644 --- a/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java +++ b/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java @@ -39,34 +39,36 @@ public class PerformanceNoticeTask { private LoadTestReportMapper loadTestReportMapper; private final ExecutorService executorService = Executors.newFixedThreadPool(20); - private boolean isRunning = true; - @PreDestroy + private boolean isRunning=false; + + /*@PreDestroy public void preDestroy() { isRunning = false; - } + }*/ public void registerNoticeTask(LoadTestReportWithBLOBs loadTestReport) { - int count = 20; - while (count-- > 0) { - LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReport.getId()); - if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name())) { - isRunning = false; - sendSuccessNotice(loadTestReportFromDatabase); - return; + isRunning=true; + executorService.submit(() -> { + LogUtil.info("性能测试定时任务"); + while (isRunning) { + LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReport.getId()); + if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name())) { + sendSuccessNotice(loadTestReportFromDatabase); + isRunning=false; + } + if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Error.name())) { + sendFailNotice(loadTestReportFromDatabase); + isRunning=false; + } + try { + //查询定时任务是否关闭 + Thread.sleep(1000 * 30);// 每分钟检查 loadtest 的状态 + } catch (InterruptedException e) { + LogUtil.error(e); + } } - if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Error.name())) { - isRunning = false; - sendFailNotice(loadTestReportFromDatabase); - return; - } - count--; - try { - Thread.sleep(1000 * 4L);// 每分钟检查 loadtest 的状态 - } catch (InterruptedException e) { - LogUtil.error(e); - } - } + }); } public void sendSuccessNotice(LoadTestReportWithBLOBs loadTestReport) { diff --git a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java index d515b6b80b..fdfbd929ce 100644 --- a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java +++ b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java @@ -785,7 +785,9 @@ public class JmeterDocumentParser implements DocumentParser { threadGroup.appendChild(createStringProp(document, "LogFilename", "")); // bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空 // threadGroup.appendChild(createStringProp(document, "Iterations", "1")); - threadGroup.appendChild(createStringProp(document, "Unit", "M")); +// threadGroup.appendChild(createStringProp(document, "Unit", "M")); + // 单位改成秒 + threadGroup.appendChild(createStringProp(document, "Unit", "S")); } private void processCheckoutTimer(Element element) { @@ -878,6 +880,24 @@ public class JmeterDocumentParser implements DocumentParser { } private void processVariableThroughputTimer(Element variableThroughputTimer) { + Object durations = context.getProperty("duration"); + Integer duration; + if (durations instanceof List) { + Object o = ((List) durations).get(0); + duration = (Integer) o; + ((List) durations).remove(0); + } else { + duration = (Integer) durations; + } + Object rpsLimits = context.getProperty("rpsLimit"); + String rpsLimit; + if (rpsLimits instanceof List) { + Object o = ((List) rpsLimits).get(0); + ((List) rpsLimits).remove(0); + rpsLimit = o.toString(); + } else { + rpsLimit = rpsLimits.toString(); + } if (variableThroughputTimer.getChildNodes().getLength() > 0) { final NodeList childNodes = variableThroughputTimer.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { @@ -903,27 +923,9 @@ public class JmeterDocumentParser implements DocumentParser { stringPropCount++; } else { stringPropCount = 0; - Object durations = context.getProperty("duration");// 传入的是分钟数, 需要转化成秒数 - Integer duration; - if (durations instanceof List) { - Object o = ((List) durations).get(0); - duration = (Integer) o; - ((List) durations).remove(0); - } else { - duration = (Integer) durations; - } - prop.getFirstChild().setNodeValue(String.valueOf(duration * 60)); + prop.getFirstChild().setNodeValue(String.valueOf(duration)); continue; } - Object rpsLimits = context.getProperty("rpsLimit"); - String rpsLimit; - if (rpsLimits instanceof List) { - Object o = ((List) rpsLimits).get(0); - ((List) rpsLimits).remove(0); - rpsLimit = o.toString(); - } else { - rpsLimit = rpsLimits.toString(); - } prop.getFirstChild().setNodeValue(rpsLimit); } } diff --git a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java index 1dc40dfe1d..fe338d2858 100644 --- a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java +++ b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java @@ -207,6 +207,7 @@ public class PerformanceTestService { @Transactional(noRollbackFor = MSException.class)// 保存失败的信息 public String run(RunTestPlanRequest request) { + LogUtil.info("性能测试run测试"); final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId()); if (request.getUserId() != null) { loadTest.setUserId(request.getUserId()); diff --git a/backend/src/main/java/io/metersphere/performance/service/ReportService.java b/backend/src/main/java/io/metersphere/performance/service/ReportService.java index b50f6d4c23..3bc2fabaf6 100644 --- a/backend/src/main/java/io/metersphere/performance/service/ReportService.java +++ b/backend/src/main/java/io/metersphere/performance/service/ReportService.java @@ -13,11 +13,13 @@ import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.controller.request.OrderRequest; import io.metersphere.dto.LogDetailDTO; import io.metersphere.dto.ReportDTO; +import io.metersphere.i18n.Translator; import io.metersphere.performance.base.*; import io.metersphere.performance.controller.request.DeleteReportRequest; import io.metersphere.performance.controller.request.ReportRequest; import io.metersphere.performance.engine.Engine; import io.metersphere.performance.engine.EngineFactory; +import io.metersphere.service.FileService; import io.metersphere.service.TestResourceService; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -47,6 +49,8 @@ public class ReportService { private TestResourceService testResourceService; @Resource private LoadTestReportDetailMapper loadTestReportDetailMapper; + @Resource + private FileService fileService; public List getRecentReportList(ReportRequest request) { List orders = new ArrayList<>(); @@ -168,7 +172,10 @@ public class ReportService { public void checkReportStatus(String reportId) { LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId); - String reportStatus = loadTestReport.getStatus(); + String reportStatus = ""; + if (loadTestReport != null) { + reportStatus = loadTestReport.getStatus(); + } if (StringUtils.equals(PerformanceTestStatus.Error.name(), reportStatus)) { MSException.throwException("Report generation error!"); } @@ -268,4 +275,12 @@ public class ReportService { String content = getContent(id, ReportKeys.ResponseCodeChart); return JSON.parseArray(content, ChartsData.class); } + + public byte[] downloadJtl(String reportId) { + LoadTestReportWithBLOBs report = getReport(reportId); + if (StringUtils.isBlank(report.getFileId())) { + throw new RuntimeException(Translator.get("load_test_report_file_not_exist")); + } + return fileService.loadFileAsBytes(report.getFileId()); + } } diff --git a/backend/src/main/java/io/metersphere/service/OrganizationService.java b/backend/src/main/java/io/metersphere/service/OrganizationService.java index a88e4f7b31..71f89263d4 100644 --- a/backend/src/main/java/io/metersphere/service/OrganizationService.java +++ b/backend/src/main/java/io/metersphere/service/OrganizationService.java @@ -171,12 +171,11 @@ public class OrganizationService { SessionUser sessionUser = SessionUtils.getUser(); UserDTO user = userService.getUserDTO(sessionUser.getId()); List collect = user.getUserRoles().stream() - .filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId())) + .filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId()) || RoleConstants.ORG_MEMBER.equals(ur.getRoleId())) .map(UserRole::getSourceId) .collect(Collectors.toList()); if (!collect.contains(organizationId)) { MSException.throwException(Translator.get("organization_does_not_belong_to_user")); } - } } diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java index 18357447da..6b279c0d4a 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java @@ -2,6 +2,7 @@ package io.metersphere.track.controller; import io.metersphere.base.domain.Issues; import io.metersphere.track.issue.PlatformUser; +import io.metersphere.track.issue.ZentaoBuild; import io.metersphere.track.service.IssuesService; import io.metersphere.track.request.testcase.IssuesRequest; import org.springframework.web.bind.annotation.*; @@ -42,8 +43,19 @@ public class TestCaseIssuesController { } @GetMapping("/tapd/user/{caseId}") - public List getPlatformUsers(@PathVariable String caseId) { + public List getTapdUsers(@PathVariable String caseId) { return issuesService.getTapdProjectUsers(caseId); } + @GetMapping("/zentao/user/{caseId}") + public List getZentaoUsers(@PathVariable String caseId) { + return issuesService.getZentaoUsers(caseId); + } + + @GetMapping("/zentao/builds/{caseId}") + public List getZentaoBuilds(@PathVariable String caseId) { + return issuesService.getZentaoBuilds(caseId); + } + + } diff --git a/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java b/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java index 3592094890..b578caac05 100644 --- a/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java +++ b/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java @@ -10,11 +10,13 @@ import java.util.List; public class IssueFactory { public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) { if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) { - return new TapdIssue(addIssueRequest); + return new TapdPlatform(addIssueRequest); } else if (StringUtils.equals(IssuesManagePlatform.Jira.toString(), platform)) { - return new JiraIssue(addIssueRequest); - } else if (StringUtils.equals("LOCAL", platform)) { - return new LocalIssue(addIssueRequest); + return new JiraPlatform(addIssueRequest); + } else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) { + return new ZentaoPlatform(addIssueRequest); + } else if (StringUtils.equals("LOCAL", platform)) { + return new LocalPlatform(addIssueRequest); } return null; } diff --git a/backend/src/main/java/io/metersphere/track/issue/JiraIssue.java b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java similarity index 98% rename from backend/src/main/java/io/metersphere/track/issue/JiraIssue.java rename to backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java index 40a1277f90..981b76e2ef 100644 --- a/backend/src/main/java/io/metersphere/track/issue/JiraIssue.java +++ b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java @@ -28,10 +28,10 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; -public class JiraIssue extends AbstractIssuePlatform { +public class JiraPlatform extends AbstractIssuePlatform { - public JiraIssue(IssuesRequest issuesRequest) { + public JiraPlatform(IssuesRequest issuesRequest) { super(issuesRequest); } diff --git a/backend/src/main/java/io/metersphere/track/issue/LocalIssue.java b/backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java similarity index 94% rename from backend/src/main/java/io/metersphere/track/issue/LocalIssue.java rename to backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java index b75946b726..bbbd12df8f 100644 --- a/backend/src/main/java/io/metersphere/track/issue/LocalIssue.java +++ b/backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java @@ -10,9 +10,9 @@ import io.metersphere.track.request.testcase.IssuesRequest; import java.util.List; import java.util.UUID; -public class LocalIssue extends AbstractIssuePlatform { +public class LocalPlatform extends AbstractIssuePlatform { - public LocalIssue(IssuesRequest issuesRequest) { + public LocalPlatform(IssuesRequest issuesRequest) { super(issuesRequest); } diff --git a/backend/src/main/java/io/metersphere/track/issue/TapdIssue.java b/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java similarity index 98% rename from backend/src/main/java/io/metersphere/track/issue/TapdIssue.java rename to backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java index 3df46f4291..2b01f5b468 100644 --- a/backend/src/main/java/io/metersphere/track/issue/TapdIssue.java +++ b/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java @@ -24,10 +24,10 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; -public class TapdIssue extends AbstractIssuePlatform { +public class TapdPlatform extends AbstractIssuePlatform { - public TapdIssue(IssuesRequest issueRequest) { + public TapdPlatform(IssuesRequest issueRequest) { super(issueRequest); } diff --git a/backend/src/main/java/io/metersphere/track/issue/ZentaoBuild.java b/backend/src/main/java/io/metersphere/track/issue/ZentaoBuild.java new file mode 100644 index 0000000000..fa6dc42b67 --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/issue/ZentaoBuild.java @@ -0,0 +1,9 @@ +package io.metersphere.track.issue; + +import lombok.Data; + +@Data +public class ZentaoBuild { + private String id; + private String name; +} diff --git a/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java b/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java new file mode 100644 index 0000000000..1d0196651e --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java @@ -0,0 +1,300 @@ +package io.metersphere.track.issue; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import io.metersphere.base.domain.*; +import io.metersphere.commons.constants.IssuesManagePlatform; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.track.request.testcase.IssuesRequest; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.util.*; +import java.util.stream.Collectors; + +public class ZentaoPlatform extends AbstractIssuePlatform { + /** + * zentao account + */ + private final String account; + /** + * zentao password + */ + private final String password; + /** + * zentao url eg:http://x.x.x.x/zentao + */ + private final String url; + + public ZentaoPlatform(IssuesRequest issuesRequest) { + super(issuesRequest); + String config = getPlatformConfig(IssuesManagePlatform.Zentao.toString()); + JSONObject object = JSON.parseObject(config); + this.account = object.getString("account"); + this.password = object.getString("password"); + this.url = object.getString("url"); + } + + @Override + String getProjectId() { + TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); + Project project = projectService.getProjectById(testCase.getProjectId()); + return project.getZentaoId(); + } + + @Override + public List getIssue() { + List list = new ArrayList<>(); + + TestCaseIssuesExample example = new TestCaseIssuesExample(); + example.createCriteria().andTestCaseIdEqualTo(testCaseId); + + List issues = extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Zentao.toString()); + + List issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList()); + issuesIds.forEach(issuesId -> { + Issues dto = getZentaoIssues(issuesId); + if (StringUtils.isBlank(dto.getId())) { + // 缺陷不存在,解除用例和缺陷的关联 + TestCaseIssuesExample issuesExample = new TestCaseIssuesExample(); + issuesExample.createCriteria() + .andTestCaseIdEqualTo(testCaseId) + .andIssuesIdEqualTo(issuesId); + testCaseIssuesMapper.deleteByExample(issuesExample); + issuesMapper.deleteByPrimaryKey(issuesId); + } else { + dto.setPlatform(IssuesManagePlatform.Zentao.toString()); + // 缺陷状态为 关闭,则不显示 + if (!StringUtils.equals("closed", dto.getStatus())) { + list.add(dto); + } + } + }); + return list; + + } + + private Issues getZentaoIssues(String bugId) { + String session = login(); + HttpEntity requestEntity = new HttpEntity<>(new HttpHeaders()); + RestTemplate restTemplate = new RestTemplate(); + try { + ResponseEntity responseEntity = restTemplate.exchange(url + "api-getModel-bug-getById-bugID={bugId}?zentaosid=" + session, + HttpMethod.POST, requestEntity, String.class, bugId); + String body = responseEntity.getBody(); + JSONObject obj = JSONObject.parseObject(body); + + LogUtil.info("bug id is " + bugId + obj); + + if (obj != null) { + JSONObject bug = obj.getJSONObject("data"); + String id = bug.getString("id"); + String title = bug.getString("title"); + String description = bug.getString("steps"); + Long createTime = bug.getLong("openedDate"); + String status = bug.getString("status"); + String reporter = bug.getString("openedBy"); + int deleted = bug.getInteger("deleted"); + if (deleted == 1) { + return new Issues(); + } + Issues issues = new Issues(); + issues.setId(id); + issues.setTitle(title); + issues.setDescription(description); + issues.setCreateTime(createTime); + issues.setStatus(status); + issues.setReporter(reporter); + return issues; + } + } catch (Exception e) { + LogUtil.error("get zentao bug fail " + e.getMessage()); + } + + return new Issues(); + } + + @Override + public void addIssue(IssuesRequest issuesRequest) { + + String session = login(); + String projectId = getProjectId(); + + if (StringUtils.isBlank(projectId)) { + MSException.throwException("add zentao bug fail, project zentao id is null"); + } + + if (StringUtils.isBlank(session)) { + MSException.throwException("session is null"); + } + + MultiValueMap paramMap = new LinkedMultiValueMap<>(); + paramMap.add("product", projectId); + paramMap.add("title", issuesRequest.getTitle()); + paramMap.add("steps", issuesRequest.getContent()); + if (!CollectionUtils.isEmpty(issuesRequest.getZentaoBuilds())) { + List builds = issuesRequest.getZentaoBuilds(); + builds.forEach(build -> { + paramMap.add("openedBuild[]", build); + }); + } else { + paramMap.add("openedBuild", "trunk"); + } + if (StringUtils.isNotBlank(issuesRequest.getZentaoUser())) { + paramMap.add("assignedTo", issuesRequest.getZentaoUser()); + } + + HttpEntity requestEntity = new HttpEntity<>(paramMap, new HttpHeaders()); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(url + "api-getModel-bug-create.json?zentaosid=" + session, HttpMethod.POST, requestEntity, String.class); + String body = responseEntity.getBody(); + JSONObject obj = JSONObject.parseObject(body); + + LogUtil.info("add zentao bug " + obj); + + if (obj != null) { + JSONObject data = obj.getJSONObject("data"); + String id = data.getString("id"); + if (StringUtils.isNotBlank(id)) { + // 用例与第三方缺陷平台中的缺陷关联 + TestCaseIssues testCaseIssues = new TestCaseIssues(); + testCaseIssues.setId(UUID.randomUUID().toString()); + testCaseIssues.setIssuesId(id); + testCaseIssues.setTestCaseId(testCaseId); + testCaseIssuesMapper.insert(testCaseIssues); + + IssuesExample issuesExample = new IssuesExample(); + issuesExample.createCriteria().andIdEqualTo(id) + .andPlatformEqualTo(IssuesManagePlatform.Zentao.toString()); + if (issuesMapper.selectByExample(issuesExample).size() <= 0) { + // 插入缺陷表 + Issues issues = new Issues(); + issues.setId(id); + issues.setPlatform(IssuesManagePlatform.Zentao.toString()); + issuesMapper.insert(issues); + } + } + } + } + + @Override + public void deleteIssue(String id) { + + } + + @Override + public void testAuth() { + try { + login(); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + MSException.throwException("验证失败!"); + } + + } + + + private String login() { + String session = getSession(); + String loginUrl = url + "user-login.json?zentaosid=" + session; + MultiValueMap paramMap = new LinkedMultiValueMap<>(); + paramMap.add("account", account); + paramMap.add("password", password); + HttpEntity requestEntity = new HttpEntity<>(paramMap, new HttpHeaders()); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(loginUrl, HttpMethod.POST, requestEntity, String.class); + String body = responseEntity.getBody(); + JSONObject obj = JSONObject.parseObject(body); + JSONObject user = obj.getJSONObject("user"); + if (user == null) { + LogUtil.error("login fail"); + LogUtil.error(obj); + // 登录失败,获取的session无效,置空session + MSException.throwException("zentao login fail"); + } + String username = user.getString("account"); + if (!StringUtils.equals(username, account)) { + LogUtil.error("login fail,inconsistent users"); + MSException.throwException("zentao login fail"); + } + return session; + } + + private String getSession() { + RestTemplate restTemplate = new RestTemplate(); + HttpEntity requestEntity = new HttpEntity<>(new HttpHeaders()); + ResponseEntity responseEntity = restTemplate.exchange(url + "api-getsessionid.json", HttpMethod.GET, requestEntity, String.class); + String body = responseEntity.getBody(); + JSONObject obj = JSONObject.parseObject(body); + JSONObject data = obj.getJSONObject("data"); + String session = data.getString("sessionID"); + return session; + } + + @Override + public List getPlatformUser() { + + String session = login(); + HttpHeaders httpHeaders = new HttpHeaders(); + HttpEntity requestEntity = new HttpEntity<>(httpHeaders); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(url + "api-getModel-user-getList?zentaosid=" + session, + HttpMethod.GET, requestEntity, String.class); + String body = responseEntity.getBody(); + JSONObject obj = JSONObject.parseObject(body); + + LogUtil.info("zentao user " + obj); + + JSONArray data = obj.getJSONArray("data"); + + List users = new ArrayList<>(); + for (int i = 0; i < data.size(); i++) { + JSONObject o = data.getJSONObject(i); + PlatformUser platformUser = new PlatformUser(); + String account = o.getString("account"); + String username = o.getString("realname"); + platformUser.setName(username); + platformUser.setUser(account); + users.add(platformUser); + } + return users; + } + + public List getBuilds() { + String session = login(); + String projectId = getProjectId(); + HttpHeaders httpHeaders = new HttpHeaders(); + HttpEntity requestEntity = new HttpEntity<>(httpHeaders); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(url + "api-getModel-build-getProductBuildPairs-productID={projectId}?zentaosid=" + session, + HttpMethod.GET, requestEntity, String.class, projectId); + String body = responseEntity.getBody(); + JSONObject obj = JSONObject.parseObject(body); + + LogUtil.info("zentao builds" + obj); + + JSONObject data = obj.getJSONObject("data"); + Map maps = data.getInnerMap(); + + List list = new ArrayList<>(); + for (Map.Entry map : maps.entrySet()) { + ZentaoBuild build = new ZentaoBuild(); + String id = (String) map.getKey(); + if (StringUtils.isNotBlank(id)) { + build.setId((String) map.getKey()); + build.setName((String) map.getValue()); + list.add(build); + } + } + return list; + } +} diff --git a/backend/src/main/java/io/metersphere/track/issue/ZentaoUtils.java b/backend/src/main/java/io/metersphere/track/issue/ZentaoUtils.java new file mode 100644 index 0000000000..fa34a39224 --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/issue/ZentaoUtils.java @@ -0,0 +1,26 @@ +package io.metersphere.track.issue; + +import io.metersphere.commons.utils.EncryptUtils; + +public class ZentaoUtils { + + /** + * @param code Zentao 应用代号 + * @param key Zentao 密钥 + * @return token + */ + public static String getToken(String code, String key, String time) { + return (String) EncryptUtils.md5Encrypt(code + key + time); + } + + /** + * @param url Zentao url + * @param code Zentao 应用代号 + * @param key Zentao 密钥 + * @return url + */ + public static String getUrl(String url, String code, String key) { + String time = String.valueOf(System.currentTimeMillis());; + return url + "api.php?" + "code=" + code + "&time=" + time + "&token=" + getToken(code, key, time); + } +} diff --git a/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java b/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java index 88fb097185..a1ea0ad74a 100644 --- a/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java +++ b/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java @@ -13,4 +13,12 @@ public class IssuesRequest { private String projectId; private String testCaseId; private List tapdUsers; + /** + * zentao bug 处理人 + */ + private String zentaoUser; + /** + * zentao bug 影响版本 + */ + private List zentaoBuilds; } diff --git a/backend/src/main/java/io/metersphere/track/service/IssuesService.java b/backend/src/main/java/io/metersphere/track/service/IssuesService.java index 6353e08bfd..dc84ad5bf8 100644 --- a/backend/src/main/java/io/metersphere/track/service/IssuesService.java +++ b/backend/src/main/java/io/metersphere/track/service/IssuesService.java @@ -19,9 +19,7 @@ import io.metersphere.notice.service.NoticeService; import io.metersphere.notice.service.WxChatTaskService; import io.metersphere.service.IntegrationService; import io.metersphere.service.ProjectService; -import io.metersphere.track.issue.AbstractIssuePlatform; -import io.metersphere.track.issue.IssueFactory; -import io.metersphere.track.issue.PlatformUser; +import io.metersphere.track.issue.*; import io.metersphere.track.request.testcase.IssuesRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -63,9 +61,11 @@ public class IssuesService { boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); + boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString()); String tapdId = getTapdProjectId(issuesRequest.getTestCaseId()); String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId()); + String zentaoId = getZentaoProjectId(issuesRequest.getTestCaseId()); List platforms = new ArrayList<>(); @@ -82,7 +82,13 @@ public class IssuesService { } } - if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey)) { + if (zentao) { + if (StringUtils.isNotBlank(zentaoId)) { + platforms.add(IssuesManagePlatform.Zentao.name()); + } + } + + if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey) && StringUtils.isBlank(zentaoId)) { platforms.add("LOCAL"); } @@ -122,6 +128,7 @@ public class IssuesService { boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); + boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString()); List platforms = new ArrayList<>(); if (tapd) { @@ -140,6 +147,13 @@ public class IssuesService { } } + if (zentao) { + String zentaoId = getZentaoProjectId(caseId); + if (StringUtils.isNotBlank(zentaoId)) { + platforms.add(IssuesManagePlatform.Zentao.name()); + } + } + platforms.add("LOCAL"); IssuesRequest issueRequest = new IssuesRequest(); issueRequest.setTestCaseId(caseId); @@ -152,18 +166,24 @@ public class IssuesService { return list; } - public String getTapdProjectId(String testCaseId) { + private String getTapdProjectId(String testCaseId) { TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); Project project = projectService.getProjectById(testCase.getProjectId()); return project.getTapdId(); } - public String getJiraProjectKey(String testCaseId) { + private String getJiraProjectKey(String testCaseId) { TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); Project project = projectService.getProjectById(testCase.getProjectId()); return project.getJiraKey(); } + private String getZentaoProjectId(String testCaseId) { + TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); + Project project = projectService.getProjectById(testCase.getProjectId()); + return project.getZentaoId(); + } + /** * 是否关联平台 */ @@ -189,6 +209,13 @@ public class IssuesService { return platform.getPlatformUser(); } + public List getZentaoUsers(String caseId) { + IssuesRequest issueRequest = new IssuesRequest(); + issueRequest.setTestCaseId(caseId); + AbstractIssuePlatform platform = IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issueRequest); + return platform.getPlatformUser(); + } + public void deleteIssue(String id) { issuesMapper.deleteByPrimaryKey(id); } @@ -200,4 +227,11 @@ public class IssuesService { } return context; } + + public List getZentaoBuilds(String caseId) { + IssuesRequest issueRequest = new IssuesRequest(); + issueRequest.setTestCaseId(caseId); + ZentaoPlatform platform = (ZentaoPlatform) IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issueRequest); + return platform.getBuilds(); + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java index 82c99bff35..ca463ab9b0 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java @@ -457,12 +457,19 @@ public class TestCaseService { if (t.getMethod().equals("manual")) { String steps = t.getSteps(); String setp = ""; - if (steps.contains("null") && !steps.contains("\"null\"")) { - setp = steps.replace("null", "\"\""); - } else { - setp = steps; + setp = steps; + JSONArray jsonArray = null; + + //解决旧版本保存用例导出报错 + try { + jsonArray = JSON.parseArray(setp); + } catch (Exception e) { + if (steps.contains("null") && !steps.contains("\"null\"")) { + setp = steps.replace("null", "\"\""); + jsonArray = JSON.parseArray(setp); + } } - JSONArray jsonArray = JSON.parseArray(setp); + for (int j = 0; j < jsonArray.size(); j++) { int num = j + 1; step.append(num + "." + jsonArray.getJSONObject(j).getString("desc") + "\n"); diff --git a/backend/src/main/resources/db/migration/V42__modify_load_test_report.sql b/backend/src/main/resources/db/migration/V42__modify_load_test_report.sql new file mode 100644 index 0000000000..77ad67bd9a --- /dev/null +++ b/backend/src/main/resources/db/migration/V42__modify_load_test_report.sql @@ -0,0 +1,2 @@ +ALTER TABLE load_test_report + ADD file_id VARCHAR(50) NULL; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V43__add_role.sql b/backend/src/main/resources/db/migration/V43__add_role.sql new file mode 100644 index 0000000000..7b6ba33c6f --- /dev/null +++ b/backend/src/main/resources/db/migration/V43__add_role.sql @@ -0,0 +1,2 @@ +INSERT INTO role (id, name, description, type, create_time, update_time) +VALUES ('org_member', '组织成员', NULL, NULL, unix_timestamp() * 1000, unix_timestamp() * 1000); \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V44__project_add_zentao_id.sql b/backend/src/main/resources/db/migration/V44__project_add_zentao_id.sql new file mode 100644 index 0000000000..11e373adc8 --- /dev/null +++ b/backend/src/main/resources/db/migration/V44__project_add_zentao_id.sql @@ -0,0 +1 @@ +alter table project add zentao_id varchar(50) null; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V45__modify_issues.sql b/backend/src/main/resources/db/migration/V45__modify_issues.sql new file mode 100644 index 0000000000..0617627ced --- /dev/null +++ b/backend/src/main/resources/db/migration/V45__modify_issues.sql @@ -0,0 +1,4 @@ +alter table issues drop primary key; +alter table issues + add constraint issues_pk + primary key (id, platform); \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 237b90b7fe..5dc4f84212 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -170,6 +170,8 @@ task_defect_notification=Task defect notification task_notification=Jenkins Task notification task_notification_=Timing task result notification api_definition_url_not_repeating=The interface request address already exists +task_notification_jenkins=Jenkins Task notification +task_notification=Result notification diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index 9fb9533080..bc3e719677 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -170,4 +170,6 @@ test_plan_notification=测试计划通知 task_defect_notification=缺陷任务通知 task_notification=jenkins任务通知 task_notification_=定时任务结果通知 -api_definition_url_not_repeating=接口请求地址已经存在 \ No newline at end of file +api_definition_url_not_repeating=接口请求地址已经存在 +task_notification_jenkins=jenkins任务通知 +task_notification=任务通知 \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index b6c0d4e3ba..b0be5d2483 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -169,6 +169,9 @@ check_owner_comment=當前用戶沒有操作此評論的權限 upload_content_is_null=導入內容為空 test_plan_notification=測試計畫通知 task_defect_notification=缺陷任務通知 +task_notification_jenkins=jenkins任務通知 +task_notification=任務通知 + task_notification=jenkins任務通知 task_notification_=定時任務通知 api_definition_url_not_repeating=接口請求地址已經存在 diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue index 3cdb8af86a..41cb26562f 100644 --- a/frontend/src/business/App.vue +++ b/frontend/src/business/App.vue @@ -57,9 +57,9 @@ export default { if (header.default !== undefined) { this.licenseHeader = "LicenseMessage"; } - // 是否显示校验信息 + if (display.default !== undefined) { - display.default.valid(this); + display.default.showHome(this); } } else { window.location.href = "/login" diff --git a/frontend/src/business/components/api/report/ApiReportViewDetail.vue b/frontend/src/business/components/api/report/ApiReportViewDetail.vue index 8184192e82..a00b2b446a 100644 --- a/frontend/src/business/components/api/report/ApiReportViewDetail.vue +++ b/frontend/src/business/components/api/report/ApiReportViewDetail.vue @@ -1,5 +1,5 @@