feat(系统设置): 全局前后置脚本新增变更历史

--story=1005618 --user=周骏弘 全局前后置脚本新增变更历史 https://www.tapd.cn/55049933/s/1103617
This commit is contained in:
junhong 2022-02-14 17:37:39 +08:00 committed by john1298308460
parent 3e2f492e83
commit f0ea497d0d
10 changed files with 325 additions and 14 deletions

View File

@ -0,0 +1,58 @@
package io.metersphere.log.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.LinkedHashMap;
import java.util.Map;
public class ApiTestEnvironmentDiffUtil {
public static String diff(String newValue, String oldValue) {
try {
JSONObject bloBsNew = JSON.parseObject(newValue);
JSONObject bloBsOld = JSON.parseObject(oldValue);
Map<String, String> diffMap = new LinkedHashMap<>();
diffMap.put("type", "preAndPostScript");
// 对比全局脚本配置参数
if (!StringUtils.equals(bloBsNew.getString("globalScriptConfig"), bloBsOld.getString("globalScriptConfig"))) {
diffMap.put("globalScriptConfigRaw1", bloBsNew.getString("globalScriptConfig"));
diffMap.put("globalScriptConfigRaw2", bloBsOld.getString("globalScriptConfig"));
}
// 对比全局前置脚本(单个请求)
if (!StringUtils.equals(bloBsNew.getString("preProcessor"), bloBsOld.getString("preProcessor"))) {
diffMap.put("preProcessorRaw1", bloBsNew.getString("preProcessor"));
diffMap.put("preProcessorRaw2", bloBsOld.getString("preProcessor"));
}
// 对比全局前置脚本(所有请求)
if (!StringUtils.equals(bloBsNew.getString("preStepProcessor"), bloBsOld.getString("preStepProcessor"))) {
diffMap.put("preStepProcessorRaw1", bloBsNew.getString("preStepProcessor"));
diffMap.put("preStepProcessorRaw2", bloBsOld.getString("preStepProcessor"));
}
// 对比全局后置脚本(单个请求)
if (!StringUtils.equals(bloBsNew.getString("postProcessor"), bloBsOld.getString("postProcessor"))) {
diffMap.put("postProcessorRaw1", bloBsNew.getString("postProcessor"));
diffMap.put("postProcessorRaw2", bloBsOld.getString("postProcessor"));
}
// 对比全局后置脚本(所有请求)
if (!StringUtils.equals(bloBsNew.getString("postStepProcessor"), bloBsOld.getString("postStepProcessor"))) {
diffMap.put("postStepProcessorRaw1", bloBsNew.getString("postStepProcessor"));
diffMap.put("postStepProcessorRaw2", bloBsOld.getString("postStepProcessor"));
}
if (diffMap.size() > 1) {
return JSON.toJSONString(diffMap);
}
} catch (Exception e) {
LogUtil.error(e);
}
return null;
}
}

View File

@ -186,8 +186,17 @@ public class ReflexObjectUtil {
String oldValue = column.getOriginalValue().toString();
column.setDiffValue(ApiDefinitionDiffUtil.diffResponse(newValue, oldValue));
}
} else {
String newValue = Objects.toString(column.getNewValue(), "");
}
// 环境全局前后置脚本深度对比
else if(StringUtils.equals(module, "PROJECT_ENVIRONMENT_SETTING")){
if (originalColumns.get(i).getColumnName().equals("config")) {
String newValue = newColumns.get(i).getOriginalValue().toString();
String oldValue = column.getOriginalValue().toString();
column.setDiffValue(ApiTestEnvironmentDiffUtil.diff(newValue, oldValue));
}
}
else {
String newValue = column.getNewValue().toString();
if (StringUtils.isNotEmpty(newValue)) {
column.setNewValue(newValue.replaceAll("\\n", " "));
}

View File

@ -30,6 +30,11 @@
:is-read-only="isReadOnly"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.all_pre_script')" name="prescript">
<div style="padding-bottom: 20px;">
<el-link style="float: right;" type="primary" @click="openHis">
{{ $t('operating_log.change_history') }}
</el-link>
</div>
<environment-global-script
v-if="isRefresh && environment.config.globalScriptConfig && environment.config.preProcessor && environment.config.preStepProcessor"
:filter-request.sync="environment.config.globalScriptConfig.filterRequestPreScript"
@ -42,6 +47,11 @@
@updateGlobalScript="updateGlobalScript"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.all_post_script')" name="postscript">
<div style="padding-bottom: 20px;">
<el-link style="float: right;" type="primary" @click="openHis">
{{ $t('operating_log.change_history') }}
</el-link>
</div>
<environment-global-script
v-if="isRefresh && environment.config.globalScriptConfig && environment.config.postProcessor && environment.config.postStepProcessor"
:filter-request.sync="environment.config.globalScriptConfig.filterRequestPostScript"
@ -76,12 +86,13 @@
<global-assertions :is-read-only="isReadOnly" :assertions="environment.config.assertions" :is-show-json-path-suggest="false"/>
</el-tab-pane>
</el-tabs>
<div class="environment-footer">
<ms-dialog-footer
@cancel="cancel"
@confirm="save()"/>
</div>
<!-- <div class="environment-footer">-->
<!-- <ms-dialog-footer-->
<!-- @cancel="cancel"-->
<!-- @confirm="save()"/>-->
<!-- </div>-->
</el-form>
<ms-change-history ref="changeHistory"/>
</el-main>
</template>
@ -103,6 +114,8 @@ import Jsr233ProcessorContent from "@/business/components/api/automation/scenari
import {createComponent} from "@/business/components/api/definition/components/jmeter/components";
import EnvironmentGlobalScript from "@/business/components/api/test/components/environment/EnvironmentGlobalScript";
import GlobalAssertions from "@/business/components/api/definition/components/assertion/GlobalAssertions";
import MsChangeHistory from "../../../../history/ChangeHistory";
import MsDialogHeader from "../../../../common/components/MsDialogHeader";
export default {
name: "EnvironmentEdit",
@ -115,7 +128,8 @@ export default {
MsEnvironmentHttpConfig,
MsEnvironmentSSLConfig,
EnvironmentGlobalScript,
MsDatabaseConfig, MsApiHostTable, MsDialogFooter, MsApiKeyValue, MsApiScenarioVariables
MsDatabaseConfig, MsApiHostTable, MsDialogFooter, MsApiKeyValue, MsApiScenarioVariables, MsChangeHistory,
MsDialogHeader
},
props: {
environment: new Environment(),
@ -269,6 +283,9 @@ export default {
}
});
},
openHis() {
this.$refs.changeHistory.open(this.environment.id, ["项目-环境设置", "項目-環境設置", "Project environment setting"]);
},
validate() {
let isValidate = false;
this.$refs['environment'].validate((valid) => {

View File

@ -49,16 +49,18 @@
<ms-history-detail ref="historyDetail"/>
<ms-tags-history-detail ref="tagsHistoryDetail"/>
<ms-api-history-detail ref="apiHistoryDetail"/>
<ms-environment-history-detail ref="environmentHistoryDetail"/>
</el-dialog>
</template>
<script>
import MsHistoryDetail from "./HistoryDetail";
import MsTagsHistoryDetail from "./tags/TagsHistoryDetail";
import MsApiHistoryDetail from "./api/ApiHistoryDetail";
import MsEnvironmentHistoryDetail from "./api/EnvironmentHistoryDetail";
export default {
name: "MsChangeHistory",
components: {MsHistoryDetail, MsTagsHistoryDetail, MsApiHistoryDetail},
components: {MsHistoryDetail, MsTagsHistoryDetail, MsApiHistoryDetail, MsEnvironmentHistoryDetail},
props: {
title: String,
},
@ -67,7 +69,8 @@ export default {
infoVisible: false,
loading: false,
details: [],
linkDatas: ["prerequisite", "steps", "remark", "request", "response", "scenarioDefinition", "tags", "loadConfiguration", "advancedConfiguration"],
linkDatas: ["prerequisite", "steps", "remark", "request", "config",
"response", "scenarioDefinition", "tags", "loadConfiguration", "advancedConfiguration"],
}
},
methods: {
@ -79,6 +82,23 @@ export default {
let data = response.data;
this.loading = false;
if (data) {
//
if(modules.length > 0 && modules[0] === '项目-环境设置'){
// id
let ids = [];
for(let i=0; i<data.length; i++){
if(data[i].details.columns.findIndex(d => (d.diffValue === null || d.diffValue === '' || d.diffValue === undefined)) !== -1){
ids.push(data[i].id);
continue;
}
}
if(ids.length > 0){
ids.forEach(row => {
const index = data.findIndex(d => d.id === row);
data.splice(index, 1);
});
}
}
this.details = data;
}
})
@ -96,7 +116,11 @@ export default {
} else if ((value.columnName === "request" || value.columnName === "response") &&
(row.operModule === "接口定义" || row.operModule === "接口定義" || row.operModule === "Api definition" || row.operModule === "API_DEFINITION")) {
this.$refs.apiHistoryDetail.open(value);
} else {
}
else if(row.operModule === "项目-环境设置" || row.operModule === "項目-環境設置" || row.operModule === "PROJECT_ENVIRONMENT_SETTING"){
this.$refs.environmentHistoryDetail.open(value);
}
else {
this.$refs.historyDetail.open(value);
}
},

View File

@ -0,0 +1,107 @@
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<!-- 全局前后置脚本 -->
<div style="border:1px #DCDFE6 solid;" v-if="!loading">
<el-tabs v-model="activeName" class="request-tabs">
<!--全局前置脚本-->
<el-tab-pane :label="$t('api_test.definition.request.all_pre_script')" name="allPreScript" v-if="request.script
&& (request.script.preProcessorRaw1 || request.script.preProcessorRaw2 || request.script.preStepProcessorRaw1 || request.script.preStepProcessorRaw2)">
<div v-if="request.script.preProcessorRaw1 || request.script.preProcessorRaw2">
<el-radio-group v-model="preProcessor" size="mini">
<el-radio-button :label="$t('api_test.script.execute_before_step')" />
</el-radio-group>
<div v-html="getDiff(request.script.preProcessorRaw2, request.script.preProcessorRaw1)"></div>
</div>
<div v-if="request.script.preStepProcessorRaw1 || request.script.preStepProcessorRaw2">
<el-radio-group v-model="preStepProcessor" size="mini">
<el-radio-button :label="$t('api_test.script.execute_before_all_steps')" />
</el-radio-group>
<div v-html="getDiff(request.script.preStepProcessorRaw2, request.script.preStepProcessorRaw1)"></div>
</div>
</el-tab-pane>
<!--全局后置脚本-->
<el-tab-pane :label="$t('api_test.definition.request.all_post_script')" name="allPostScript" v-if="request.script
&& (request.script.postProcessorRaw1 || request.script.postProcessorRaw2 || request.script.postStepProcessorRaw1 || request.script.postStepProcessorRaw2)">
<div v-if="request.script.postProcessorRaw1 || request.script.postProcessorRaw2">
<el-radio-group v-model="postProcessor" size="mini">
<el-radio-button :label="$t('api_test.script.execute_post_step')"/>
</el-radio-group>
<div v-html="getDiff(request.script.postProcessorRaw2, request.script.postProcessorRaw1)"></div>
</div>
<div v-if="request.script.postStepProcessorRaw1 || request.script.postStepProcessorRaw2">
<el-radio-group v-model="postStepProcessor" size="mini">
<el-radio-button :label="$t('api_test.script.execute_post_all_steps')"/>
</el-radio-group>
<div v-html="getDiff(request.script.postStepProcessorRaw2, request.script.postStepProcessorRaw1)"></div>
</div>
</el-tab-pane>
<!--通用全局脚本配置-->
<el-tab-pane :label="$t('api_test.script.global_script_config')" name="globalScriptConfig" v-if="request.script
&& (request.script.globalScriptConfigRaw1 || request.script.globalScriptConfigRaw2)">
<template v-slot:default="scope">
<div v-html="getDiff(request.script.globalScriptConfigRaw2, request.script.globalScriptConfigRaw1)"></div>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import MsJsonCodeEdit from "./json-view/ComparedEditor";
const jsondiffpatch = require('jsondiffpatch');
const formattersHtml = jsondiffpatch.formatters.html;
export default {
name: "EnvironmentEditParams",
components: {MsJsonCodeEdit},
props: {
method: String,
request: {},
type: String,
},
created() {
this.active();
},
data() {
return {
activeName: "",
preProcessor: "preProcessor",
postProcessor: "preProcessor",
preStepProcessor: "preStepProcessor",
postStepProcessor: "preStepProcessor",
loading: false,
}
},
methods: {
active() {
if (this.request.script && (this.request.script.preProcessorRaw1 || this.request.script.preProcessorRaw2
|| this.request.script.preStepProcessorRaw1 || this.request.script.preStepProcessorRaw2)) {
this.activeName = "allPreScript";
}
else if (this.request.script
&& (this.request.script.postProcessorRaw1 || this.request.script.postProcessorRaw2
|| this.request.script.postStepProcessorRaw1 || this.request.script.postStepProcessorRaw2)) {
this.activeName = "allPostScript";
}
else if (this.request.script && (this.request.script.globalScriptConfigRaw1 || this.request.script.globalScriptConfigRaw2)) {
this.activeName = "globalScriptConfig";
}
},
getDiff(v1, v2) {
let delta = jsondiffpatch.diff(v1 , v2);
return formattersHtml.format(delta, v1);
},
}
}
</script>
<style scoped>
@import "~jsondiffpatch/dist/formatters-styles/html.css";
@import "~jsondiffpatch/dist/formatters-styles/annotated.css";
</style>

View File

@ -0,0 +1,84 @@
<template>
<el-dialog :close-on-click-modal="false" :title="$t('operating_log.info')" :visible.sync="infoVisible" width="900px" :destroy-on-close="true"
@close="handleClose" append-to-body>
<div style="height: 700px;overflow: auto">
<div v-if="detail.createUser">
<p class="tip">{{ this.$t('report.user_name') }} {{ detail.createUser }}</p>
</div>
<div>
<p class="tip">{{ this.$t('operating_log.time') }} {{ detail.operTime | timestampFormatDate }}</p>
</div>
<div style="overflow: auto">
<p class="tip">{{ this.$t('report.test_log_details') }} </p>
<ms-environment-edit-params :request="detail" v-if="detail.columnName === 'config'"/>
</div>
</div>
</el-dialog>
</template>
<script>
import MsEnvironmentEditParams from "./EnvironmentEditParams";
export default {
name: "EnvironmentHistoryDetail",
components: {MsEnvironmentEditParams},
props: {
title: String,
},
data() {
return {
infoVisible: false,
detail: {script: {}, type: ""},
}
},
methods: {
handleClose() {
this.infoVisible = false;
},
open(value) {
this.infoVisible = true;
this.detail = value;
let diffValue = value.diffValue;
if (diffValue) {
if (value !== null && value.diffValue !== 'null' && value.diffValue !== '' && value.diffValue !== undefined) {
if (Object.prototype.toString.call(value.diffValue).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object'
&& Object.prototype.toString.call(value.diffValue).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'array') {
diffValue = JSON.parse(value.diffValue);
}
}
if (diffValue.type === 'preAndPostScript') {
this.formatScript(diffValue);
}
this.detail.type = diffValue.type;
}
},
formatScript(diffValue) {
this.detail.script = {};
if (diffValue.globalScriptConfigRaw1 || diffValue.globalScriptConfigRaw2) {
this.detail.script.globalScriptConfigRaw1 = diffValue.globalScriptConfigRaw1;
this.detail.script.globalScriptConfigRaw2 = diffValue.globalScriptConfigRaw2;
}
if (diffValue.preProcessorRaw1 || diffValue.preProcessorRaw2) {
this.detail.script.preProcessorRaw1 = diffValue.preProcessorRaw1;
this.detail.script.preProcessorRaw2 = diffValue.preProcessorRaw2;
}
if (diffValue.preStepProcessorRaw1 || diffValue.preStepProcessorRaw2) {
this.detail.script.preStepProcessorRaw1 = diffValue.preStepProcessorRaw1;
this.detail.script.preStepProcessorRaw2 = diffValue.preStepProcessorRaw2;
}
if (diffValue.postProcessorRaw1 || diffValue.postProcessorRaw2) {
this.detail.script.postProcessorRaw1 = diffValue.postProcessorRaw1;
this.detail.script.postProcessorRaw2 = diffValue.postProcessorRaw2;
}
if (diffValue.postStepProcessorRaw1 || diffValue.postStepProcessorRaw2) {
this.detail.script.postStepProcessorRaw1 = diffValue.postStepProcessorRaw1;
this.detail.script.postStepProcessorRaw2 = diffValue.postStepProcessorRaw2;
}
},
}
}
</script>
<style scoped>
</style>

View File

@ -63,7 +63,12 @@
<!-- 创建编辑复制环境时的对话框 -->
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" :title="dialogTitle" top="50px" width="66%">
<el-form label-width="80px" :rules="rules">
<ms-dialog-header
style="margin-bottom: 10px; float: right;"
:btn-size="'medium'"
@cancel="close"
@confirm="save()"/>
<el-form label-width="80px" :rules="rules" style="display: flow-root">
<el-form-item class="project-item" prop="currentProjectId" :label="$t('project.select')">
<el-select @change="handleProjectChange" v-model="currentProjectId" filterable clearable>
<el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
@ -138,6 +143,7 @@ import EnvironmentImport from "@/business/components/project/menu/EnvironmentImp
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import {_handleSelect, _handleSelectAll, getSelectDataCounts, setUnSelectIds} from "@/common/js/tableUtils";
import EnvGroupCascader from "@/business/components/settings/workspace/environment/EnvGroupCascader";
import MsDialogHeader from "../../../common/components/MsDialogHeader";
export default {
name: "EnvironmentList",
@ -154,7 +160,8 @@ export default {
MsTableOperator,
MsTableButton,
MsTableHeader,
ShowMoreBtn
ShowMoreBtn,
MsDialogHeader
},
data() {
return {
@ -308,7 +315,9 @@ export default {
this.currentEnvironment = temEnv;
this.dialogVisible = true;
},
save(){
this.$refs.environmentEdit.save();
},
copyEnv(environment) {
this.currentProjectId = environment.projectId; //
this.dialogTitle = this.$t('api_test.environment.copy_environment');

View File

@ -1849,6 +1849,7 @@ export default {
before_the_pre_script_step: "Before pre-script in step",
after_the_post_script_step: "After the script is placed in the step",
before_the_post_script_step: "Post-in-step before script",
global_script_config: "Global script config",
}
},
api_report: {

View File

@ -1854,6 +1854,7 @@ export default {
before_the_pre_script_step: "步骤内前置脚本前",
after_the_post_script_step: "步骤内后置脚本后",
before_the_post_script_step: "步骤内后置脚本前",
global_script_config: "全局脚本配置",
}
},
api_report: {

View File

@ -1854,6 +1854,7 @@ export default {
before_the_pre_script_step: "步驟內前置腳本前",
after_the_post_script_step: "步驟內後置腳本後",
before_the_post_script_step: "步驟內後置腳本前",
global_script_config: "全局腳本配置",
}
},
api_report: {