diff --git a/backend/.gitignore b/backend/.gitignore index 44cceecb40..b4e1c2fed7 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -31,4 +31,5 @@ target .settings .project .classpath -.factorypath \ No newline at end of file +.factorypath +*.jar \ No newline at end of file diff --git a/backend/pom.xml b/backend/pom.xml index af84159f0c..50e2ee6ea5 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -369,6 +369,16 @@ 2.6 + + org.apache.maven.plugins + maven-jar-plugin + + + **/jmeter/lib/**/*.jar + + + + org.apache.maven.plugins maven-antrun-plugin @@ -396,6 +406,35 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + copy + generate-resources + + copy + + + + + + + org.apache.jmeter + ApacheJMeter_functions + ${jmeter.version} + jar + true + src/main/resources/jmeter/lib/ext + ApacheJMeter_functions.jar + + + ${project.build.directory}/wars + false + true + + org.mybatis.generator mybatis-generator-maven-plugin diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.java index b022159557..baafe6c422 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtProjectMapper.java @@ -11,4 +11,6 @@ public interface ExtProjectMapper { List getProjectWithWorkspace(@Param("proRequest") ProjectRequest request); List getProjectIdByWorkspaceId(String workspaceId); + + int removeIssuePlatform(@Param("platform") String platform, @Param("orgId") String orgId); } 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 85589a901f..c4c9f8b821 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,9 +4,9 @@ + + update project + + + jira_key = null + + + tapd_id = null + + + where project.id in (select id from (select id + from project + where workspace_id in + (select workspace.id + from workspace + where organization_id = #{orgId})) as a) + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/RestTemplateUtils.java b/backend/src/main/java/io/metersphere/commons/utils/RestTemplateUtils.java index b4f6fdd323..0f66e13177 100644 --- a/backend/src/main/java/io/metersphere/commons/utils/RestTemplateUtils.java +++ b/backend/src/main/java/io/metersphere/commons/utils/RestTemplateUtils.java @@ -23,7 +23,8 @@ public class RestTemplateUtils { ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class); return responseEntity.getBody(); } catch (Exception e) { - MSException.throwException("接口调用失败:" + e.getMessage()); + LogUtil.error(e.getMessage(), e); + MSException.throwException("Tapd接口调用失败:" + e.getMessage()); return null; } } @@ -36,7 +37,8 @@ public class RestTemplateUtils { ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); return responseEntity.getBody(); } catch (Exception e) { - MSException.throwException("接口调用失败:" + e.getMessage()); + LogUtil.error(e.getMessage(), e); + MSException.throwException("Tapd接口调用失败:" + e.getMessage()); return null; } diff --git a/backend/src/main/java/io/metersphere/service/IntegrationService.java b/backend/src/main/java/io/metersphere/service/IntegrationService.java index 0eb7d56df6..a3522cba37 100644 --- a/backend/src/main/java/io/metersphere/service/IntegrationService.java +++ b/backend/src/main/java/io/metersphere/service/IntegrationService.java @@ -3,6 +3,7 @@ package io.metersphere.service; import io.metersphere.base.domain.ServiceIntegration; import io.metersphere.base.domain.ServiceIntegrationExample; import io.metersphere.base.mapper.ServiceIntegrationMapper; +import io.metersphere.base.mapper.ext.ExtProjectMapper; import io.metersphere.controller.request.IntegrationRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -20,6 +21,8 @@ public class IntegrationService { @Resource private ServiceIntegrationMapper serviceIntegrationMapper; + @Resource + private ExtProjectMapper extProjectMapper; public ServiceIntegration save(ServiceIntegration service) { ServiceIntegrationExample example = new ServiceIntegrationExample(); @@ -63,6 +66,8 @@ public class IntegrationService { .andOrganizationIdEqualTo(orgId) .andPlatformEqualTo(platform); serviceIntegrationMapper.deleteByExample(example); + // 删除项目关联的id/key + extProjectMapper.removeIssuePlatform(platform, orgId); } public List getAll(String orgId) { 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 a977736aa3..79a51257f5 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java @@ -1,7 +1,7 @@ package io.metersphere.track.controller; import io.metersphere.base.domain.Issues; -import io.metersphere.service.IssuesService; +import io.metersphere.track.service.IssuesService; import io.metersphere.track.request.testcase.IssuesRequest; import org.springframework.web.bind.annotation.*; @@ -30,4 +30,9 @@ public class TestCaseIssuesController { issuesService.testAuth(platform); } + @GetMapping("/close/{id}") + public void closeLocalIssue(@PathVariable String id) { + issuesService.closeLocalIssue(id); + } + } diff --git a/backend/src/main/java/io/metersphere/service/IssuesService.java b/backend/src/main/java/io/metersphere/track/service/IssuesService.java similarity index 91% rename from backend/src/main/java/io/metersphere/service/IssuesService.java rename to backend/src/main/java/io/metersphere/track/service/IssuesService.java index 73a9e4e7b3..9afc632d83 100644 --- a/backend/src/main/java/io/metersphere/service/IssuesService.java +++ b/backend/src/main/java/io/metersphere/track/service/IssuesService.java @@ -1,4 +1,4 @@ -package io.metersphere.service; +package io.metersphere.track.service; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -15,8 +15,9 @@ import io.metersphere.commons.utils.RestTemplateUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.ResultHolder; import io.metersphere.controller.request.IntegrationRequest; +import io.metersphere.service.IntegrationService; +import io.metersphere.service.ProjectService; import io.metersphere.track.request.testcase.IssuesRequest; -import io.metersphere.track.service.TestCaseService; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -26,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.apache.commons.lang3.StringUtils; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @@ -63,7 +65,6 @@ public class IssuesService { RestTemplate restTemplate = new RestTemplate(); restTemplate.exchange("https://api.tapd.cn/quickstart/testauth", HttpMethod.GET, requestEntity, String.class); } catch (Exception e) { - System.out.println(e); LogUtil.error(e.getMessage(), e); MSException.throwException("验证失败!"); } @@ -154,12 +155,6 @@ public class IssuesService { String tapdId = getTapdProjectId(issuesRequest.getTestCaseId()); String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId()); - if (tapd || jira) { - if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey)) { - MSException.throwException("集成了缺陷管理平台,但未进行项目关联!"); - } - } - if (tapd) { // 是否关联了项目 if (StringUtils.isNotBlank(tapdId)) { @@ -173,7 +168,7 @@ public class IssuesService { } } - if (!tapd && !jira) { + if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey)) { addLocalIssues(issuesRequest); } @@ -275,7 +270,14 @@ public class IssuesService { HttpEntity requestEntity = new HttpEntity<>(json, requestHeaders); RestTemplate restTemplate = new RestTemplate(); //post - ResponseEntity responseEntity = restTemplate.exchange(url + "/rest/api/2/issue", HttpMethod.POST, requestEntity, String.class); + ResponseEntity responseEntity = null; + try { + responseEntity = restTemplate.exchange(url + "/rest/api/2/issue", HttpMethod.POST, requestEntity, String.class); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + MSException.throwException("调用Jira接口创建缺陷失败"); + } + return responseEntity.getBody(); } @@ -315,7 +317,7 @@ public class IssuesService { HttpEntity requestEntity = new HttpEntity<>(headers); RestTemplate restTemplate = new RestTemplate(); //post - ResponseEntity responseEntity = null; + ResponseEntity responseEntity; Issues issues = new Issues(); try { responseEntity = restTemplate.exchange(url + "/rest/api/2/issue/" + issuesId, HttpMethod.GET, requestEntity, String.class); @@ -336,8 +338,15 @@ public class IssuesService { issues.setDescription(description); issues.setStatus(status); issues.setPlatform(IssuesManagePlatform.Jira.toString()); - } catch (Exception e) { + } catch (HttpClientErrorException.NotFound e) { + LogUtil.error(e.getStackTrace(), e); return new Issues(); + } catch (HttpClientErrorException.Unauthorized e) { + LogUtil.error(e.getStackTrace(), e); + MSException.throwException("获取Jira缺陷失败,检查Jira配置信息"); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + MSException.throwException("调用Jira接口获取缺陷失败"); } return issues; @@ -381,7 +390,7 @@ public class IssuesService { List issues = extIssuesMapper.getIssues(caseId, IssuesManagePlatform.Tapd.toString()); - List issuesIds = issues.stream().map(issue -> issue.getId()).collect(Collectors.toList()); + List issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList()); issuesIds.forEach(issuesId -> { Issues dto = getTapdIssues(tapdId, issuesId); if (StringUtils.isBlank(dto.getId())) { @@ -423,7 +432,7 @@ public class IssuesService { List issues = extIssuesMapper.getIssues(caseId, IssuesManagePlatform.Jira.toString()); - List issuesIds = issues.stream().map(issue -> issue.getId()).collect(Collectors.toList()); + List issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList()); issuesIds.forEach(issuesId -> { Issues dto = getJiraIssues(headers, url, issuesId); if (StringUtils.isBlank(dto.getId())) { @@ -445,7 +454,11 @@ public class IssuesService { } public List getLocalIssues(String caseId) { - return extIssuesMapper.getIssues(caseId, IssuesManagePlatform.Local.toString()); + List list = extIssuesMapper.getIssues(caseId, IssuesManagePlatform.Local.toString()); + List issues = list.stream() + .filter(l -> !StringUtils.equals(l.getStatus(), "closed")) + .collect(Collectors.toList()); + return issues; } public String getTapdProjectId(String testCaseId) { @@ -471,4 +484,11 @@ public class IssuesService { return StringUtils.isNotBlank(integration.getId()); } + public void closeLocalIssue(String issueId) { + Issues issues = new Issues(); + issues.setId(issueId); + issues.setStatus("closed"); + issuesMapper.updateByPrimaryKeySelective(issues); + } + } diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index b86032cbbd..8eff343619 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit b86032cbbda9a9e6028308aa95a887cff2192f1c +Subproject commit 8eff343619df1572e1cded52f173257ef4b518a1 diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 6f07a9bf57..cc3c37684b 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -118,7 +118,6 @@ test_case_already_exists_excel=There are duplicate test cases in the import file test_case_module_already_exists=The module name already exists at the same level api_test_name_already_exists=Test name already exists functional_method_tip=Functional test not support auto method - #ldap ldap_url_is_null=LDAP address is empty ldap_dn_is_null=LDAP binding DN is empty @@ -136,4 +135,10 @@ login_fail_email_null=Login failed, user mailbox is empty login_fail_ou_error=Login failed, please check the user OU login_fail_filter_error=Login failed, please check the user filter check_ldap_mapping=Check LDAP attribute mapping -ldap_mapping_value_null=LDAP user attribute mapping field is empty \ No newline at end of file +ldap_mapping_value_null=LDAP user attribute mapping field is empty +#quota +quota_workspace_excess_org_api=The total number of interface tests in the workspace cannot exceed the organization's quota +quota_workspace_excess_org_performance=The total number of performance tests for the workspace cannot exceed the organization's quota +quota_workspace_excess_org_max_threads=The maximum concurrent number of workspaces cannot exceed the quota of the organization +quota_workspace_excess_org_max_duration=The stress test duration of the workspace cannot exceed the organization's quota +quota_workspace_excess_org_resource_pool=The resource pool of the workspace cannot exceed the resource pool of the organization \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index a4e890d91c..e7870873c5 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -118,7 +118,6 @@ test_case_already_exists_excel=导入文件中存在重复用例 test_case_module_already_exists=同层级下已存在该模块名称 api_test_name_already_exists=测试名称已经存在 functional_method_tip=功能测试不支持自动方式 - #ldap ldap_url_is_null=LDAP地址为空 ldap_dn_is_null=LDAP绑定DN为空 @@ -137,5 +136,12 @@ login_fail_ou_error=登录失败,请检查用户OU login_fail_filter_error=登录失败,请检查用户过滤器 check_ldap_mapping=检查LDAP属性映射 ldap_mapping_value_null=LDAP用户属性映射字段为空值 +#quota +quota_workspace_excess_org_api=工作空间的接口测试数量总和不能超过组织的配额 +quota_workspace_excess_org_performance=工作空间的性能测试数量总和不能超过组织的配额 +quota_workspace_excess_org_max_threads=工作空间的最大并发数不能超过组织的配额 +quota_workspace_excess_org_max_duration=工作空间的压测时长不能超过组织的配额 +quota_workspace_excess_org_resource_pool=工作空间的资源池不能超过组织的资源池范围 + diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index 326ed9f4f1..00aaf178ce 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -118,7 +118,6 @@ test_case_already_exists_excel=導入文件中存在重復用例 test_case_module_already_exists=同層級下已存在該模塊名稱 api_test_name_already_exists=測試名稱已經存在 functional_method_tip=功能測試不支持自動方式 - #ldap ldap_url_is_null=LDAP地址為空 ldap_dn_is_null=LDAP綁定DN為空 @@ -137,3 +136,9 @@ login_fail_ou_error=登錄失敗,請檢查用戶OU login_fail_filter_error=登錄失敗,請檢查用戶過濾器 check_ldap_mapping=檢查LDAP屬性映射 ldap_mapping_value_null=LDAP用戶屬性映射預設為空值 +#quota +quota_workspace_excess_org_api=工作空間的接口測試數量總和不能超過組織的配額 +quota_workspace_excess_org_performance=工作空間的性能測試數量總和不能超過組織的配額 +quota_workspace_excess_org_max_threads=工作空間的最大並發數不能超過組織的配額 +quota_workspace_excess_org_max_duration=工作空間的壓測時長不能超過組織的配額 +quota_workspace_excess_org_resource_pool=工作空間的資源池不能超過組織的資源池範圍 diff --git a/frontend/src/business/components/settings/organization/DefectManagement.vue b/frontend/src/business/components/settings/organization/IssuesManagement.vue similarity index 90% rename from frontend/src/business/components/settings/organization/DefectManagement.vue rename to frontend/src/business/components/settings/organization/IssuesManagement.vue index 8b5b25ebac..7192c130d8 100644 --- a/frontend/src/business/components/settings/organization/DefectManagement.vue +++ b/frontend/src/business/components/settings/organization/IssuesManagement.vue @@ -1,6 +1,6 @@