From 7b061f28678c436daef68d7ae702b547dbcc38c8 Mon Sep 17 00:00:00 2001 From: Yuanruitao <1075097840@qq.com> Date: Mon, 28 Nov 2022 11:42:55 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat=EF=BC=9A=E5=8D=87=E7=BA=A7Atom=20Sdk,?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9EKubernetes=E6=8E=A5=E5=85=A5=20#23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/core/build.gradle | 2 +- .../src/main/kotlin/com/tencent/devops/docker/DockerRun.kt | 3 ++- .../core/src/main/kotlin/com/tencent/devops/docker/scm/Scm.kt | 2 +- .../main/kotlin/com/tencent/devops/docker/tools/LogUtils.kt | 4 ++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backend/core/build.gradle b/src/backend/core/build.gradle index 2e90092..2d6ff3c 100644 --- a/src/backend/core/build.gradle +++ b/src/backend/core/build.gradle @@ -19,7 +19,7 @@ buildscript { jacksonVersion = "2.9.2" jacksonDatabindVersion = "2.13.4.2" compressVersion = "1.15" - javaPluginSdkVersion = "1.1.5" + javaPluginSdkVersion = "1.1.7" kotlinVersion = "1.5.30" } } diff --git a/src/backend/core/src/main/kotlin/com/tencent/devops/docker/DockerRun.kt b/src/backend/core/src/main/kotlin/com/tencent/devops/docker/DockerRun.kt index c432f58..c0d9213 100644 --- a/src/backend/core/src/main/kotlin/com/tencent/devops/docker/DockerRun.kt +++ b/src/backend/core/src/main/kotlin/com/tencent/devops/docker/DockerRun.kt @@ -43,7 +43,8 @@ object DockerRun { projectId = commandParam.landunParam.devopsProjectId, pipelineId = commandParam.landunParam.devopsPipelineId, buildId = commandParam.landunParam.buildId, - param = param + param = param, + taskId = null ).data!! var extraOptions = dockerRunResponse.extraOptions diff --git a/src/backend/core/src/main/kotlin/com/tencent/devops/docker/scm/Scm.kt b/src/backend/core/src/main/kotlin/com/tencent/devops/docker/scm/Scm.kt index aa1f4f3..2d3c5bd 100644 --- a/src/backend/core/src/main/kotlin/com/tencent/devops/docker/scm/Scm.kt +++ b/src/backend/core/src/main/kotlin/com/tencent/devops/docker/scm/Scm.kt @@ -36,7 +36,7 @@ abstract class Scm( try { DockerRun.runImage(imageParam, commandParam, toolName) } catch (e: Throwable) { - LogUtils.printLog("Scm operate exception, message: ${e.message}") + LogUtils.printErrorLog("Scm operate exception, message: ${e.message}", e) scmOpFail(inputFile) throw CodeccTaskExecException(errorMsg = e.message ?: "", toolName = toolName) } diff --git a/src/backend/core/src/main/kotlin/com/tencent/devops/docker/tools/LogUtils.kt b/src/backend/core/src/main/kotlin/com/tencent/devops/docker/tools/LogUtils.kt index 13dd8c1..a5021d8 100644 --- a/src/backend/core/src/main/kotlin/com/tencent/devops/docker/tools/LogUtils.kt +++ b/src/backend/core/src/main/kotlin/com/tencent/devops/docker/tools/LogUtils.kt @@ -47,6 +47,10 @@ object LogUtils { logger.errorInTag("[${getToolName()}]" + msg?.toString(), getToolName()) } + fun printErrorLog(msg: Any?, e : Throwable) { + logger.error("[${getToolName()}]" + msg?.toString(), e) + } + fun printStr(msg: Any?) { print(msg) } From 2e4c75d2ad915ad22d0cba27a814bba07ec104c9 Mon Sep 17 00:00:00 2001 From: RJ <eazence@163.com> Date: Mon, 16 Jan 2023 18:00:50 +0800 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=20#26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/Atom.vue | 12 +++-- src/frontend/src/components/Async.vue | 2 +- .../src/components/AuthorTransfer.vue | 6 +-- src/frontend/src/components/Basic.vue | 8 +-- .../src/components/CodeccAccordion.vue | 2 +- src/frontend/src/components/ItemEdit.vue | 2 +- src/frontend/src/components/RuleSetDialog.vue | 36 ++++++------- src/frontend/src/components/RuleSetSelect.vue | 2 +- src/frontend/src/components/Shield.vue | 12 ++--- src/frontend/src/components/TaskSelect.vue | 2 +- src/frontend/src/i18n/index.js | 46 ++++++++++++++++ src/frontend/src/i18n/lang/cn.json | 4 ++ src/frontend/src/i18n/lang/en.json | 52 +++++++++++++++++++ src/frontend/src/i18n/lang/messages.js | 6 +++ src/frontend/src/main.js | 2 + 15 files changed, 154 insertions(+), 40 deletions(-) create mode 100644 src/frontend/src/i18n/index.js create mode 100644 src/frontend/src/i18n/lang/cn.json create mode 100644 src/frontend/src/i18n/lang/en.json create mode 100644 src/frontend/src/i18n/lang/messages.js diff --git a/src/frontend/src/Atom.vue b/src/frontend/src/Atom.vue index 10be583..d7b7da9 100644 --- a/src/frontend/src/Atom.vue +++ b/src/frontend/src/Atom.vue @@ -38,7 +38,7 @@ <component :is="panel.name" :atom-props-model="atomModel" :atom-props-value="atomValue" :atom-props-container-info="containerInfo"></component> </bk-tab-panel> <template slot="setting"> - <a :href="linkUrl" target="_blank" class="codecc-link">前往CodeCC</a> + <a :href="linkUrl" target="_blank" class="codecc-link">{{ $t('前往CodeCC') }}</a> </template> </bk-tab> </div> @@ -52,6 +52,7 @@ import Scan from '@/components/Scan' import Shield from '@/components/Shield' import Async from '@/components/Async' + import { toggleLang } from './i18n' export default { name: 'atom', @@ -65,9 +66,9 @@ data () { return { panels: [ - { name: 'basic', label: '基础设置' }, - { name: 'scan', label: '扫描配置' }, - { name: 'shield', label: '路径屏蔽' } + { name: 'basic', label: this.$t('基础设置') }, + { name: 'scan', label: this.$t('扫描配置') }, + { name: 'shield', label: this.$t('路径屏蔽') } ], active: 'basic', tabRedTips: {} @@ -115,6 +116,9 @@ if (name === 'scan') { window.localStorage.setItem('mr-20200702', '1') } + }, + handleToggleLang() { + toggleLang() } } } diff --git a/src/frontend/src/components/Async.vue b/src/frontend/src/components/Async.vue index 3751fd7..f5cba04 100644 --- a/src/frontend/src/components/Async.vue +++ b/src/frontend/src/components/Async.vue @@ -1,6 +1,6 @@ <template> <div class="task-content" :style="{height: extraHeight + 'px'}"> - <div class="atom-txt"><i class="bk-icon icon-exclamation-circle-shape"></i>如流水线配置了质量红线请谨慎使用异步功能,可能会由于结果异步输出导致红线拦截</div> + <div class="atom-txt"><i class="bk-icon icon-exclamation-circle-shape"></i>{{$t('如流水线配置了质量红线请谨慎使用异步功能,可能会由于结果异步输出导致红线拦截')}}</div> <template v-for="(obj, key) in asyncModel"> <form-field class="head-level" diff --git a/src/frontend/src/components/AuthorTransfer.vue b/src/frontend/src/components/AuthorTransfer.vue index 779065a..933bed3 100644 --- a/src/frontend/src/components/AuthorTransfer.vue +++ b/src/frontend/src/components/AuthorTransfer.vue @@ -10,7 +10,7 @@ :handle-change="(name, value) => handleParamChange(name, value, index)" v-validate.initial="`required`" name="sourceAuthor" - placeholder="原处理人" + :placeholder="$t('原处理人')" :value="param.sourceAuthor" /> </form-field> <form-field :is-error="errors.has(`param-${index}.targetAuthor`)" :error-msg="errors.first(`param-${index}.targetAuthor`)"> @@ -20,7 +20,7 @@ :handle-change="(name, value) => handleParamChange(name, value, index)" v-validate.initial="`required`" name="targetAuthor" - placeholder="目标处理人" + :placeholder="$t('目标处理人')" :value="param.targetAuthor" /> </form-field> <i @click.stop.prevent="editParam(index, false)" class="bk-icon icon-minus hover-click" v-if="!disabled" /> @@ -28,7 +28,7 @@ </template> <a class="text-link hover-click" v-if="!disabled" @click.stop.prevent="editParam(paramList.length, true)"> <i class="bk-icon icon-plus-circle" /> - <span>添加处理人转换</span> + <span>{{$t('添加处理人转换')}}</span> </a> </ul> </div> diff --git a/src/frontend/src/components/Basic.vue b/src/frontend/src/components/Basic.vue index cc4321d..e6b7b0a 100644 --- a/src/frontend/src/components/Basic.vue +++ b/src/frontend/src/components/Basic.vue @@ -2,8 +2,8 @@ <section class="bk-form"> <template> <div class="atom-txt" v-if="envSupport"> - <span>Linux私有构建机/Mac/Win10需安装docker,Win7仅支持Coverity。 - <a target="_blank" :href="dockerHref">具体请见>></a> + <span>{{$t('Linux私有构建机/Mac/Win10需安装docker,Win7仅支持Coverity。')}} + <a target="_blank" :href="dockerHref">{{ $t('具体请见') }}>></a> </span> </div> <template v-for="(obj, key) in basicTabModel"> @@ -82,7 +82,7 @@ groupList: [ { id: 'script', - label: '编译脚本', + label: this.$t('编译脚本'), rely: ['COVERITY', 'KLOCWORK', 'PINPOINT', 'CODEQL', 'CLANG', 'CLANGWARNING', 'SPOTBUGS'], item: ['scriptType', 'script'] } @@ -141,7 +141,7 @@ return curTool && curTool.name || tool }) } - return toolsCn.length ? `涉及工具:${toolsCn.join('、')}` : '' + return toolsCn.length ? `${this.$t('涉及工具')}:${toolsCn.join('、')}` : '' }, envSupport () { return ['MACOS', 'WINDOWS'].includes(this.containerInfo.baseOS) || (this.containerInfo.dispatchType && this.containerInfo.dispatchType.buildType.indexOf('THIRD_PARTY') !== -1) diff --git a/src/frontend/src/components/CodeccAccordion.vue b/src/frontend/src/components/CodeccAccordion.vue index 1ae6ce5..2f61f35 100644 --- a/src/frontend/src/components/CodeccAccordion.vue +++ b/src/frontend/src/components/CodeccAccordion.vue @@ -14,7 +14,7 @@ </span> <span v-if="desc" class="desc" v-bk-tooltips.top="desc">{{ desc }}</span> <span class="fold-open"> - {{ isShow ? '收起' : '展开' }} + {{ isShow ? $t('收起') : $t('展开') }} <i class="bk-icon icon-angle-down" style="display:inline-block"> </i> </span> diff --git a/src/frontend/src/components/ItemEdit.vue b/src/frontend/src/components/ItemEdit.vue index dc73c76..91f5038 100644 --- a/src/frontend/src/components/ItemEdit.vue +++ b/src/frontend/src/components/ItemEdit.vue @@ -21,7 +21,7 @@ </template> <a class="text-link hover-click" v-if="!disabled" @click.stop.prevent="editParam(paramList.length, true)"> <i class="bk-icon icon-plus-circle" /> - <span>{{ addBtnText }}</span> + <span>{{$t(addBtnText)}}</span> </a> </ul> </div> diff --git a/src/frontend/src/components/RuleSetDialog.vue b/src/frontend/src/components/RuleSetDialog.vue index 74a057a..8365e0c 100644 --- a/src/frontend/src/components/RuleSetDialog.vue +++ b/src/frontend/src/components/RuleSetDialog.vue @@ -7,9 +7,9 @@ :show-footer="false"> <div class="main-content" v-bkloading="{ isLoading: loading, opacity: 0.3 }"> <div class="info-header"> - <span>选择规则集<i class="bk-icon icon-refresh checkerset-fresh" :class="fetchingList ? 'spin-icon' : ''" @click="refresh" /></span> + <span>{{$t('选择规则集')}}<i class="bk-icon icon-refresh checkerset-fresh" :class="fetchingList ? 'spin-icon' : ''" @click="refresh" /></span> <div class="handle-option"> - <bk-select class="search-select" v-model="language" multiple style="width: 120px;" placeholder="请选择语言"> + <bk-select class="search-select" v-model="language" multiple style="width: 120px;" :placeholder="$t('请选择语言')"> <bk-option v-for="option in codeLangs" :key="option.displayName" :id="option.displayName" @@ -18,7 +18,7 @@ </bk-select> <bk-input class="search-input" - :placeholder="'快速搜索'" + :placeholder="$t('快速搜索')" :clearable="true" :right-icon="'bk-icon icon-search'" v-model="keyWord" @@ -27,13 +27,13 @@ </bk-input> <bk-popconfirm always v-if="showTipsConfirm" - confirm-text="我知道了" + :confirm-text="$t('我知道了')" cancel-text="" :delay="500" :confirm-button-is-text="false" @confirm="handleTipsConfirm"> <div slot="content"> - <div>在此处关闭规则集弹框</div> + <div>{{$t('在此处关闭规则集弹框')}}</div> </div> <i class="bk-icon icon-close" @click="closeDialog" /> </bk-popconfirm> @@ -59,13 +59,13 @@ <span class="name" :title="checkerSet.checkerSetName">{{checkerSet.checkerSetName}}</span> <span v-if="['DEFAULT', 'RECOMMEND'].includes(checkerSet.checkerSetSource)" :class="['use-mark', { 'preferred': checkerSet.checkerSetSource === 'DEFAULT', 'recommend': checkerSet.checkerSetSource === 'RECOMMEND' }]" - >{{checkerSet.checkerSetSource === 'DEFAULT' ? '精选' : '推荐'}}</span> + >{{checkerSet.checkerSetSource === 'DEFAULT' ? $t('精选') : $t('推荐')}}</span> <span class="language" :title="getCodeLang(checkerSet.codeLang)">{{getCodeLang(checkerSet.codeLang)}}</span> </p> - <p class="checkerset-desc" :title="checkerSet.description">{{checkerSet.description || '暂无描述'}}</p> + <p class="checkerset-desc" :title="checkerSet.description">{{checkerSet.description || $t('暂无描述')}}</p> <p class="other-msg"> - <span>由 {{ checkerSet.creator }} 发布</span> - <span>共 {{checkerSet.checkerCount || 0}} 条规则</span> + <span>{{$t('由x发布',{ name: checkerSet.creator })}}</span> + <span>{{$t('共x条规则', { sum: checkerSet.checkerCount || 0 })}}</span> </p> </div> <div class="info-operate" @@ -85,12 +85,12 @@ <div v-if="!checkerSetList.length"> <div class="codecc-table-empty-text"> <img src="../images/empty.png" class="empty-img"> - <div>暂无数据</div> + <div>{{$t('暂无数据')}}</div> </div> </div> </bk-tab-panel> <template slot="setting"> - <a :href="linkUrl" target="_blank" class="codecc-link">创建规则集</a> + <a :href="linkUrl" target="_blank" class="codecc-link">{{$t('创建规则集')}}</a> </template> </bk-tab> </div> @@ -170,7 +170,7 @@ }, classifyCodeList () { if (this.categoryList.length) { - return [{ cnName: '所有', enName: 'all' }, ...this.categoryList, { cnName: '研发商店', enName: 'store' }] + return [{ cnName: this.$t('所有'), enName: 'all' }, ...this.categoryList, { cnName: this.$t('研发商店'), enName: 'store' }] } return [] } @@ -261,9 +261,9 @@ getSelectText (checkerSet, index) { let txt = '' if (this.classifyCode === 'store' && !checkerSet.projectInstalled) { - txt = '安装' + txt = this.$t('安装') } else { - txt = this.checkIsSelected(checkerSet.checkerSetId) ? this.currentHoverItem === index ? '取消选中' : '已选中' : '选择' + txt = this.checkIsSelected(checkerSet.checkerSetId) ? this.currentHoverItem === index ? this.$t('取消选中') : this.$t('已选中') : this.$t('选择') } return txt }, @@ -340,21 +340,21 @@ this.loading = true this.$store.dispatch('install', params).then(res => { if (res.code === '0') { - this.$bkMessage({ theme: 'success', message: '安装成功' }) + this.$bkMessage({ theme: 'success', message: this.$t('安装成功') }) this.refresh() } }).catch(e => { this.$bkMessage({ - message: '安装失败', + message: this.$t('安装失败'), theme: 'error' }) }) }, getToolTips (hasMultiLang, notCurLang) { if (hasMultiLang) { - return '该规则集不适用于当前插件' + return this.$t('该规则集不适用于当前插件') } else if (notCurLang) { - return '该规则集不适用于当前插件已选择的语言' + return this.$t('该规则集不适用于当前插件已选择的语言') } return { disabled: true } }, diff --git a/src/frontend/src/components/RuleSetSelect.vue b/src/frontend/src/components/RuleSetSelect.vue index 0627519..a9b4fd8 100644 --- a/src/frontend/src/components/RuleSetSelect.vue +++ b/src/frontend/src/components/RuleSetSelect.vue @@ -2,7 +2,7 @@ <div class="rule-set-selector"> <div class="rule-set-input" @click="openSelect"> <p class="rule-set-value" :title="getValueShow(renderList)">{{ getValueShow(renderList) }}</p> - <span class="placeholder" v-if="!renderList.length">请选择</span> + <span class="placeholder" v-if="!renderList.length">{{$t('请选择')}}</span> <span class="bk-select-clear bk-icon icon-close-circle-shape" @click.stop="handleClear"></span> </div> <rule-set-dialog diff --git a/src/frontend/src/components/Shield.vue b/src/frontend/src/components/Shield.vue index 32ee987..9feb42e 100644 --- a/src/frontend/src/components/Shield.vue +++ b/src/frontend/src/components/Shield.vue @@ -38,24 +38,24 @@ return { groupList: [ { - label: '路径白名单', + label: this.$t('路径白名单'), item: ['path'], - desc: `以绝对路径/data/landun/workspace/CodeCCTest/cpp/为例: + desc: this.$t(`以绝对路径/data/landun/workspace/CodeCCTest/cpp/为例: 扫描相对路径可输入/CodeCCTest/cpp/,只输入/cpp/不会生效 扫描某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc 扫描工作空间中某个文件夹如P2PLive,可以输入.*/P2PLive/.* 只扫描某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c 若一行中输入多个路径或路径匹配式可用英文逗号分隔 -支持流水线变量` +支持流水线变量`) }, { - label: '路径黑名单', + label: this.$t('路径黑名单'), item: ['customPath'], - desc: `屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc + desc: this.$t(`屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc 屏蔽所有分支中某个文件夹如P2PLive,可以输入.*/P2PLive/.* 屏蔽某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c 若一行中输入多个路径匹配式可用英文逗号分隔 -支持流水线变量` +支持流水线变量`) } ] } diff --git a/src/frontend/src/components/TaskSelect.vue b/src/frontend/src/components/TaskSelect.vue index b0d9137..04a3556 100644 --- a/src/frontend/src/components/TaskSelect.vue +++ b/src/frontend/src/components/TaskSelect.vue @@ -26,7 +26,7 @@ <div class="bk-select-extension"> <a class="bk-selector-create-item" @click="handleNewTask"> <i class="bk-icon icon-plus-circle" /> - 新增任务 + {{$t('新增任务')}} </a> </div> </div> diff --git a/src/frontend/src/i18n/index.js b/src/frontend/src/i18n/index.js new file mode 100644 index 0000000..4d30398 --- /dev/null +++ b/src/frontend/src/i18n/index.js @@ -0,0 +1,46 @@ +import Vue from 'vue'; +import VueI18n from 'vue-i18n'; +import Cookies from 'js-cookie'; +import langMessages from './lang/messages'; +import { locale, lang } from 'bk-magic-vue'; + +Vue.use(VueI18n); + +const languageMaps = { + zh_cn: 'zh-CN', + 'zh-cn': 'zh-CN', + zh: 'zh-CN', +}; + +const messages = { + 'zh-CN': Object.assign(lang.zhCN, langMessages['zh-CN']), + en: Object.assign(lang.enUS, langMessages.en), +}; + +let curLocale = Cookies.get('blueking_language') || 'zh-CN'; +curLocale = Object.prototype.hasOwnProperty.call(languageMaps, curLocale) ? languageMaps[curLocale] : curLocale; + +// console.log(locale, messages) + +const i18n = new VueI18n({ + locale: curLocale, + fallbackLocale: 'zh-CN', + messages, + silentTranslationWarn: true, // 取消本地化失败时输出的警告 + missing(locale, path) { + const parsedPath = i18n._path.parsePath(path) // eslint-disable-line + return parsedPath[parsedPath.length - 1]; + }, +}); + +locale.i18n((key, value) => i18n.t(key, value)); + +export const toggleLang = () => { + i18n.locale = i18n.locale === 'zh-CN' ? 'en' : 'zh-CN'; + + Cookies.set('blueking_language', i18n.locale); +}; + +export const language = i18n.locale; + +export default i18n; diff --git a/src/frontend/src/i18n/lang/cn.json b/src/frontend/src/i18n/lang/cn.json new file mode 100644 index 0000000..1e156d0 --- /dev/null +++ b/src/frontend/src/i18n/lang/cn.json @@ -0,0 +1,4 @@ +{ + "共x条规则": "共{sum}条规则", + "由x发布": "由{name}发布" +} diff --git a/src/frontend/src/i18n/lang/en.json b/src/frontend/src/i18n/lang/en.json new file mode 100644 index 0000000..a998115 --- /dev/null +++ b/src/frontend/src/i18n/lang/en.json @@ -0,0 +1,52 @@ +{ + "前往CodeCC": "Go to CodeCC", + "基础设置": "Basic", + "扫描配置": "Scan", + "路径屏蔽": "Filter", + "一": "Mon", + "二": "Tues", + "三": "Wed", + "四": "Thur", + "五": "Fri", + "六": "Sat", + "日": "Sun", + "收起": "Fold", + "展开": "Unfold", + "路径白名单": "Whitelist path", + "路径黑名单": "Blacklist path", + "Linux私有构建机/Mac/Win10需安装docker,Win7仅支持Coverity。": "Linux private build machine/Mac/Win10 needs to install docker, and Win7 only supports Coverity.", + "具体请见": "For details, please see", + "在此处关闭规则集弹框": "Close the rule set pop-up here", + "该规则集不适用于当前插件": "The rule set is not applicable to the current plugin", + "该规则集不适用于当前插件已选择的语言": "The rule set is not applicable to the language selected by the current plugin", + "我知道了": "I got it!", + "快速搜索": "Quick search", + "暂无描述": "No description", + "暂无数据": "Empty", + "创建规则集": "New rule set", + "由x发布": "Published by {name}", + "共x条规则": "{sum} rules in total", + "编译脚本": "Compile script", + "涉及工具": "Tools involved", + "所有": "All", + "安装": "Install", + "安装成功": "Install succeeded", + "安装失败": "Install failed", + "取消选中": "Uncheck", + "已选中": "Selected", + "选择": "Select", + "请选择": "Please select", + "研发商店": "R&D store", + "精选": "Picked", + "推荐": "Recommend", + "新增任务": "New task", + "新增路径": "New path", + "原处理人": "original handler", + "目标处理人": "Target handler", + "添加处理人转换": "Configure handler conversion", + "选择规则集": "Please select rule set", + "请选择语言": "Please select languages", + "如流水线配置了质量红线请谨慎使用异步功能,可能会由于结果异步输出导致红线拦截": "If the pipeline is configured with a quality red line, please use the asynchronous function carefully. The red line may be blocked due to the asynchronous output of the result", + "以绝对路径/data/landun/workspace/CodeCCTest/cpp/为例:\n扫描相对路径可输入/CodeCCTest/cpp/,只输入/cpp/不会生效\n扫描某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n扫描工作空间中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n只扫描某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径或路径匹配式可用英文逗号分隔\n支持流水线变量": "Take the absolute path /data/landun/workspace/CodeCCTest/cpp/\nas an example: The scan relative path can be entered /CodeCCTest/cpp/\nBut only /cpp/ will not take effect. Scan a certain type of file,\nSuch as *.pb.cc generated by protobuffer, and you can enter .*/.*\\.Pb\\.cc\nScan a folder in the workspace, such as P2PLive, you can enter. */P2PLive/*\nOnly scan a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple paths are entered in a line or path matching can be separated by\nEnglish commas, and pipeline variables are supported", + "屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n屏蔽所有分支中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n屏蔽某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径匹配式可用英文逗号分隔\n支持流水线变量": "Exclude a certain type of file, such as *.pb.cc generated by protobuffer,\nand you can enter .*/.*\\.pb\\.cc\nMask a folder in all branches, such as P2PLive, you can enter .*/P2PLive/*\nExclude a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple path matching types are entered in a line, they can be separated\nby English commas, and pipeline variables are supported" +} diff --git a/src/frontend/src/i18n/lang/messages.js b/src/frontend/src/i18n/lang/messages.js new file mode 100644 index 0000000..faf83a2 --- /dev/null +++ b/src/frontend/src/i18n/lang/messages.js @@ -0,0 +1,6 @@ +import en from './en.json' +import cn from './cn.json' +export default { + en, + 'zh-CN': cn, +} diff --git a/src/frontend/src/main.js b/src/frontend/src/main.js index ea01187..95da479 100644 --- a/src/frontend/src/main.js +++ b/src/frontend/src/main.js @@ -12,6 +12,7 @@ import request from '@/utils/request' import validDictionary from './utils/validDictionary' import ExtendsCustomRules from './utils/customRules' import store from './store/index' +import i18n from './i18n'; // 全量引入 bk-magic-vue 样式 require('bk-magic-vue/dist/bk-magic-vue.min.css') @@ -35,6 +36,7 @@ ExtendsCustomRules(VeeValidate.Validator.extend) global.atomVue = new Vue({ el: '#pipeline-atom', + i18n, components: { PublicAtom, LocalAtom From 54f9dfb16395d707c50c21b393db0b082d9a576e Mon Sep 17 00:00:00 2001 From: RJ <eazence@163.com> Date: Mon, 16 Jan 2023 18:08:28 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=20#26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/data/task.json | 462 +++++++++++++++++--------------- 1 file changed, 240 insertions(+), 222 deletions(-) diff --git a/src/frontend/src/data/task.json b/src/frontend/src/data/task.json index 4fd8bc1..2453b62 100644 --- a/src/frontend/src/data/task.json +++ b/src/frontend/src/data/task.json @@ -1,228 +1,246 @@ { - "input": { - "languages": { - "rule": {}, - "type": "atom-checkbox-list", - "required": true, - "label": "工程语言", - "list": [], - "default": [], - "desc": "不同代码语言,可选择相匹配的工具", - "tabName": "basic" - }, - "tools": { - "rule": {}, - "required": true, - "hidden": true, - "type": "atom-checkbox-list", - "label": "代码检查工具", - "list": [], - "default": [], - "tabName": "basic" - }, - "asyncTask": { - "rule": {}, - "type": "enum-input", - "label": "执行方式", - "list": [ - { - "value": false, - "label": "同步" - }, - { - "value": true, - "label": "异步" - } - ], - "default": false, - "desc": "", - "tabName": "main", - "inline": true - }, - "asyncTaskId": { - "rule": { - "asyncTaskRequired": true - }, - "type": "task-select", - "label": "任务", - "required": true, - "tabName": "async", - "inline": true, - "list": {}, - "default": "", - "rely": {}, - "desc": "可选择CodeCC服务中自建任务,也可以直接输入任务ID。ID可从CodeCC链接中获取到,例如/codecc/myproj/task/25324/中的数字。支持流水线变量。" - }, - "goPath": { - "rule": {}, - "type": "vuex-input", - "label": "GOPATH", - "default": "", - "required": false, - "desc": "可帮助工具查找依赖库代码路径,更好地扫描告警", - "placeholder": "${WORKSPACE}下相对路径,多路径请用英文逗号分割,支持使用流水线变量", - "tabName": "basic", - "inline": true, - "rely": { - "operation": "AND", - "expression": [ - { - "key": "tools", - "value": "GOML" - } - ] - } - }, - "pyVersion": { - "rule": {}, - "type": "enum-input", - "label": "Python版本", - "required": true, - "list": [ - { - "label": "Python2", - "value": "py2" - }, - { - "label": "Python3", - "value": "py3" - } - ], - "default": "py3", - "tabName": "basic", - "inline": true, - "rely": { - "operation": "AND", - "expression": [ - { - "key": "tools", - "value": "PYLINT" - } - ] - } - }, - "scriptType": { - "rule": {}, - "type": "enum-input", - "label": "脚本类型", - "required": true, - "hidden": false, - "list": [ - { - "id": "sh", - "value": "SHELL", - "label": "Shell" - } - ], - "default": "SHELL", - "tabName": "basic", - "lang": "sh", - "inline": true - }, - "script": { - "rule": { - "scriptRequired": true - }, - "label": "脚本内容", - "hidden": false, - "default": "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh", - "required": true, - "type": "atom-ace-editor", - "desc": "相应工具将使用该脚本编译代码,以便追踪编译过程,发现代码缺陷", - "tabName": "basic" - }, - "languageRuleSetMap": { - "hidden": true, - "default": {} - }, - "C_CPP_RULE": { - "rule": { - "ruleSetRequired": true - }, - "type": "rule-set-select", - "label": "C/C++", - "required": true, - "tabName": "basic", - "inline": true, - "list": {}, - "default": [], - "rely": { - "operation": "AND", - "expression": [ - { - "key": "languages", - "value": "C_CPP" - } - ] - } - }, - "toolScanType": { - "rule": {}, - "type": "radio-group", - "label": "扫描方式", - "required": true, - "list": [ - { - "label": "增量扫描(推荐)", - "value": "1" - }, - { - "label": "MR/PR扫描", - "value": "2" - }, - { - "label": "全量扫描", - "value": "0" - } - ], - "default": "1", - "desc": "增量扫描:扫描本次构建与上次构建的差异代码。首次为全量扫描。\nMR/PR扫描:扫描MR/PR的源分支与目标分支的差异代码。源分支代码需拉取到工作空间。\n全量扫描:扫描全部代码。Klocwork、Pinpoint、Gometalinter、重复率仅支持该扫描方式。" - }, - "mrCommentEnable": { - "label": "", - "default": true, - "type": "atom-checkbox", - "text": "将扫描出的问题同步到工蜂代码查看页面" - }, - "newDefectJudgeFromDate": { - "default": "", - "label": "新告警判定", - "desc": "所选日期之后产生的告警为新告警" - }, - "transferAuthorList": { - "default": [], - "type": "author-transfer", - "label": "处理人转换", - "desc": "各工具原处理人的告警都将自动转给新处理人" - }, - "path": { - "default": [], - "type": "item-edit" - }, - "customPath": { - "default": [], - "type": "item-edit" - }, - "openScanPrj": { - "label": "", - "default": false, - "placeholder": "", - "type": "atom-checkbox", - "text": "是否是开源扫描项目", - "desc": "选中则走开源扫描流程", - "required": false, - "disabled": false, - "hidden": true + "atomCode": "CodeCCCheckAtom", + "execution": { + "packagePath": "CodeCCCheckAtom.jar", + "language": "java", + "minimumVersion": "1.8", + "deFmands": [], + "target": "$bk_java_path -Dfile.encoding=utf8 -jar CodeCCCheckAtom.jar" + }, + "input": { + "languages": { + "rule": {}, + "type": "atom-checkbox-list", + "required": true, + "label": "Programming Language", + "list": [], + "default": [], + "desc": "tools will match different programming language", + "tabName": "basic" + }, + "tools": { + "rule": {}, + "required": true, + "hidden": true, + "type": "atom-checkbox-list", + "label": "Code Review Tool", + "list": [], + "default": [], + "tabName": "basic" + }, + "asyncTask": { + "rule": {}, + "type": "enum-input", + "label": "Sync Method", + "list": [ + { + "value": false, + "label": "Synchronize" + }, + { + "value": true, + "label": "Asynchronous" } + ], + "default": false, + "desc": "", + "tabName": "main", + "inline": true }, - "output": { - "BK_CI_CODECC_TASK_ID": { - "type": "string", - "description": "CodeCC的任务id" - }, - "BK_CI_CODECC_TASK_STATUS": { - "type": "string", - "description": "CodeCC任务是否运行成功,成功则未true,不然取不到" + "asyncTaskId": { + "rule": { + "asyncTaskRequired": true + }, + "type": "task-select", + "label": "Task", + "required": true, + "tabName": "async", + "inline": true, + "list": {}, + "default": "", + "rely": {}, + "desc": "You can choose to create a task yourself in the CodeCC service, or you can directly enter the task ID. The task ID can be obtained from the CodeCC link (in /codecc/myproj/task/25324/, 25324 is the task ID). Support pipeline variables." + }, + "goPath": { + "rule": {}, + "type": "vuex-input", + "label": "GOPATH", + "default": "", + "required": false, + "desc": "Help find the code path of the dependent library to get a more useful result", + "placeholder": "Relative paths under {WORKSPACE}, please use comma to separate multiple paths, support pipeline variables", + "tabName": "basic", + "inline": true, + "rely": { + "operation": "AND", + "expression": [ + { + "key": "tools", + "value": "GOML" + } + ] + } + }, + "pyVersion": { + "rule": {}, + "type": "enum-input", + "label": "Python Version", + "required": true, + "list": [ + { + "label": "Python2", + "value": "py2" + }, + { + "label": "Python3", + "value": "py3" + } + ], + "default": "py3", + "tabName": "basic", + "inline": true, + "rely": { + "operation": "AND", + "expression": [ + { + "key": "tools", + "value": "PYLINT" + } + ] + } + }, + "scriptType": { + "rule": {}, + "type": "enum-input", + "label": "Script Type", + "required": true, + "hidden": false, + "list": [ + { + "id": "sh", + "value": "SHELL", + "label": "Shell" + } + ], + "default": "SHELL", + "tabName": "basic", + "lang": "sh", + "inline": true + }, + "script": { + "rule": { + "scriptRequired": true + }, + "label": "Script", + "hidden": false, + "default": "#Coverity/Klocwork will compile your code by calling the compilation script to identify defects\n# Please use build tools such as maven/cmake to write a compilation script build.sh\n# Make sure build.sh can compile the code\n# cd path/to/build.sh\n# sh build.sh", + "required": true, + "type": "atom-ace-editor", + "desc": "The corresponding tool will use this script to compile the code in order to track the compilation process and find code defects", + "tabName": "basic" + }, + "languageRuleSetMap": { + "hidden": true, + "default": {} + }, + "C_CPP_RULE": { + "rule": { + "ruleSetRequired": true + }, + "type": "rule-set-select", + "label": "C/C++", + "required": true, + "tabName": "basic", + "inline": true, + "list": {}, + "default": [], + "rely": { + "operation": "AND", + "expression": [ + { + "key": "languages", + "value": "C_CPP" + } + ] + } + }, + "multiPipelineMark": { + "rule": {}, + "label": "label", + "placeholder": "Optional. Only numbers, letters, and underscores are supported.", + "type": "vuex-input", + "default": "", + "tabName": "basic", + "desc": "If the pipeline has multiple code analysis plugins, a label can be used to distinguish them.", + "inline": true + }, + "toolScanType": { + "rule": {}, + "type": "radio-group", + "label": "Scan Method", + "required": true, + "list": [ + { + "label": "Incremental Scan(recommended)", + "value": "1" + }, + { + "label": "MR/PR Scan", + "value": "2" + }, + { + "label": "Full Scan", + "value": "0" } + ], + "default": "1", + "desc": "Incremental scan: Scan the difference code between current build and previous build. Full scan will be used in the first time.\nMR/PR Scan: Scan the difference code between the source branch and the target branch of MR/PR. The source branch code needs to be pulled to the workspace\nFull Scan: Scan all codes. Klocwork, Pinpoint, Gometalinter, and repetition rate only support this scanning method." + }, + "mrCommentEnable": { + "label": "", + "default": true, + "type": "atom-checkbox", + "text": "Sync the defect info to Tencent internal Git viewing page" + }, + "newDefectJudgeFromDate": { + "default": "", + "label": "New Alerts Threshold", + "desc": "Alerts sent after the selected date are New Alerts" + }, + "transferAuthorList": { + "default": [], + "type": "author-transfer", + "label": "change owner", + "desc": "Alerts will sent to the new owner when the tools's ownership changed " + }, + "path": { + "default": [], + "type": "item-edit" + }, + "customPath": { + "default": [], + "type": "item-edit" + }, + "openScanPrj": { + "label": "", + "default": false, + "placeholder": "", + "type": "atom-checkbox", + "text": "use open sourced tool to scan project", + "desc": "Use open sourced scanning tool when selected", + "required": false, + "disabled": false, + "hidden": true + } + }, + "output": { + "BK_CI_CODECC_TASK_ID": { + "type": "string", + "description": "CodeCC task id" + }, + "BK_CI_CODECC_TASK_STATUS": { + "type": "string", + "description": "Whether the CodeCC task runs successfully" } + } } \ No newline at end of file From 4ff072f2769a8b9022187b01a9d22a1a58449b95 Mon Sep 17 00:00:00 2001 From: RJ <eazence@163.com> Date: Tue, 17 Jan 2023 10:18:37 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=20#26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/package.json | 4 +++- src/frontend/src/components/Basic.vue | 14 +++++++------- src/frontend/src/i18n/lang/en.json | 6 +++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/frontend/package.json b/src/frontend/package.json index ea117cc..660f92d 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -8,11 +8,13 @@ "public": "rimraf dist && webpack --mode production" }, "dependencies": { + "axios": "^0.21.1", "bk-magic-vue": "^2.2.4", "bkci-atom-components": "^1.0.0", - "axios": "^0.21.1", + "js-cookie": "^3.0.1", "vee-validate": "^2.0.3", "vue": "^2.6.10", + "vue-i18n": "^8.10.0", "vue-router": "^2.8.1", "vuex": "^2.4.0" }, diff --git a/src/frontend/src/components/Basic.vue b/src/frontend/src/components/Basic.vue index e6b7b0a..bf30949 100644 --- a/src/frontend/src/components/Basic.vue +++ b/src/frontend/src/components/Basic.vue @@ -3,7 +3,7 @@ <template> <div class="atom-txt" v-if="envSupport"> <span>{{$t('Linux私有构建机/Mac/Win10需安装docker,Win7仅支持Coverity。')}} - <a target="_blank" :href="dockerHref">{{ $t('具体请见') }}>></a> + <a target="_blank" :href="dockerHref">{{$t('具体请见')}}>></a> </span> </div> <template v-for="(obj, key) in basicTabModel"> @@ -158,9 +158,9 @@ "value": "BAT", "label": "bat" }] - this.atomModel.script.default = "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat" - if (this.atomValue.script === "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh") { - this.atomValue.script = "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat" + this.atomModel.script.default = this.$t("# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat") + if (this.atomValue.script === this.$t("# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh")) { + this.atomValue.script = this.$t("# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat") } } } @@ -201,7 +201,7 @@ return lang }) - this.groupList.unshift({ id: 'ruleSet', label: '规则集', item:ruleModelNameList }) + this.groupList.unshift({ id: 'ruleSet', label: this.$t('规则集'), item:ruleModelNameList }) }) this.$store.dispatch('getToolList').then(res => { this.atomModel.tools.list = res.map(item => { @@ -234,9 +234,9 @@ const res = await this.$store.dispatch('listPageable', params) this.list = res } catch (err) { - console.log(err, '获取规则集失败') + console.log(err, this.$t('获取规则集失败')) this.$bkMessage({ - message: '获取规则集失败', + message: this.$t('获取规则集失败'), theme: 'error' }) } finally { diff --git a/src/frontend/src/i18n/lang/en.json b/src/frontend/src/i18n/lang/en.json index a998115..938d1ed 100644 --- a/src/frontend/src/i18n/lang/en.json +++ b/src/frontend/src/i18n/lang/en.json @@ -26,6 +26,8 @@ "创建规则集": "New rule set", "由x发布": "Published by {name}", "共x条规则": "{sum} rules in total", + "规则集": "Rule set", + "获取规则集失败": "Failed to get rule set", "编译脚本": "Compile script", "涉及工具": "Tools involved", "所有": "All", @@ -48,5 +50,7 @@ "请选择语言": "Please select languages", "如流水线配置了质量红线请谨慎使用异步功能,可能会由于结果异步输出导致红线拦截": "If the pipeline is configured with a quality red line, please use the asynchronous function carefully. The red line may be blocked due to the asynchronous output of the result", "以绝对路径/data/landun/workspace/CodeCCTest/cpp/为例:\n扫描相对路径可输入/CodeCCTest/cpp/,只输入/cpp/不会生效\n扫描某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n扫描工作空间中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n只扫描某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径或路径匹配式可用英文逗号分隔\n支持流水线变量": "Take the absolute path /data/landun/workspace/CodeCCTest/cpp/\nas an example: The scan relative path can be entered /CodeCCTest/cpp/\nBut only /cpp/ will not take effect. Scan a certain type of file,\nSuch as *.pb.cc generated by protobuffer, and you can enter .*/.*\\.Pb\\.cc\nScan a folder in the workspace, such as P2PLive, you can enter. */P2PLive/*\nOnly scan a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple paths are entered in a line or path matching can be separated by\nEnglish commas, and pipeline variables are supported", - "屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n屏蔽所有分支中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n屏蔽某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径匹配式可用英文逗号分隔\n支持流水线变量": "Exclude a certain type of file, such as *.pb.cc generated by protobuffer,\nand you can enter .*/.*\\.pb\\.cc\nMask a folder in all branches, such as P2PLive, you can enter .*/P2PLive/*\nExclude a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple path matching types are entered in a line, they can be separated\nby English commas, and pipeline variables are supported" + "屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n屏蔽所有分支中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n屏蔽某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径匹配式可用英文逗号分隔\n支持流水线变量": "Exclude a certain type of file, such as *.pb.cc generated by protobuffer,\nand you can enter .*/.*\\.pb\\.cc\nMask a folder in all branches, such as P2PLive, you can enter .*/P2PLive/*\nExclude a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple path matching types are entered in a line, they can be separated\nby English commas, and pipeline variables are supported", + "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat": "#Coverage/Klocwork will compile your code by calling the compilation script to track the deep-seated defects\n#Please use a dependent build tool such as maven/make to write a build script build.bat\n#Ensure that build.bat can compile code\n# cd path/to/build.bat\n# call build.bat", + "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh": "#Coverage/Klocwork will compile your code by calling the compilation script to track the deep-seated defects.\n# Please write a compilation script build.sh using a dependent build tool such as maven/make\n# Ensure that build.sh can compile the code\n# cd path/to/build.sh\n# sh build.sh" } From 37aad048a12aca702c94d2588a17f04256537c14 Mon Sep 17 00:00:00 2001 From: RJ <eazence@163.com> Date: Tue, 17 Jan 2023 14:57:32 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=20#26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/components/TaskSelect.vue | 4 +- src/frontend/src/i18n/lang/cn.json | 7 +- src/frontend/src/i18n/lang/en.json | 123 ++++++++++++--------- src/frontend/src/utils/customRules.js | 4 +- src/frontend/src/utils/validDictionary.js | 32 +++--- 5 files changed, 96 insertions(+), 74 deletions(-) diff --git a/src/frontend/src/components/TaskSelect.vue b/src/frontend/src/components/TaskSelect.vue index 04a3556..285da7c 100644 --- a/src/frontend/src/components/TaskSelect.vue +++ b/src/frontend/src/components/TaskSelect.vue @@ -9,8 +9,8 @@ </bk-input> <div class="bk-options-wrapper" v-show="optionsVisible"> <ul class="bk-options"> - <li class="bk-select-empty" v-if="optionsLoading">正在加载中...</li> - <li class="bk-select-empty" v-else-if="!filterTaskList || !filterTaskList.length">无匹配数据</li> + <li class="bk-select-empty" v-if="optionsLoading">{{$t('正在加载中')}}...</li> + <li class="bk-select-empty" v-else-if="!filterTaskList || !filterTaskList.length">{{$t('无匹配数据')}}</li> <li class="bk-option custom-option" v-show="!optionsLoading && filterTaskList && filterTaskList.length" diff --git a/src/frontend/src/i18n/lang/cn.json b/src/frontend/src/i18n/lang/cn.json index 1e156d0..d2f0842 100644 --- a/src/frontend/src/i18n/lang/cn.json +++ b/src/frontend/src/i18n/lang/cn.json @@ -1,4 +1,9 @@ { "共x条规则": "共{sum}条规则", - "由x发布": "由{name}发布" + "由x发布": "由{name}发布", + "字段不符合(x)正则表达式规则": "字段不符合({regex})正则表达式规则", + "字段长度不能超过x个字符": "字段长度不能超过{num}个字符", + "字段长度不能少于x个字符": "字段长度不能少于{num}个字符", + "最大不能超过x": "最大不能超过{num}", + "最小不能少于x": "最小不能少于{num}" } diff --git a/src/frontend/src/i18n/lang/en.json b/src/frontend/src/i18n/lang/en.json index 938d1ed..c5b14db 100644 --- a/src/frontend/src/i18n/lang/en.json +++ b/src/frontend/src/i18n/lang/en.json @@ -1,56 +1,71 @@ { - "前往CodeCC": "Go to CodeCC", - "基础设置": "Basic", - "扫描配置": "Scan", - "路径屏蔽": "Filter", - "一": "Mon", - "二": "Tues", - "三": "Wed", - "四": "Thur", - "五": "Fri", - "六": "Sat", - "日": "Sun", - "收起": "Fold", - "展开": "Unfold", - "路径白名单": "Whitelist path", - "路径黑名单": "Blacklist path", - "Linux私有构建机/Mac/Win10需安装docker,Win7仅支持Coverity。": "Linux private build machine/Mac/Win10 needs to install docker, and Win7 only supports Coverity.", - "具体请见": "For details, please see", - "在此处关闭规则集弹框": "Close the rule set pop-up here", - "该规则集不适用于当前插件": "The rule set is not applicable to the current plugin", - "该规则集不适用于当前插件已选择的语言": "The rule set is not applicable to the language selected by the current plugin", - "我知道了": "I got it!", - "快速搜索": "Quick search", - "暂无描述": "No description", - "暂无数据": "Empty", - "创建规则集": "New rule set", - "由x发布": "Published by {name}", - "共x条规则": "{sum} rules in total", - "规则集": "Rule set", - "获取规则集失败": "Failed to get rule set", - "编译脚本": "Compile script", - "涉及工具": "Tools involved", - "所有": "All", - "安装": "Install", - "安装成功": "Install succeeded", - "安装失败": "Install failed", - "取消选中": "Uncheck", - "已选中": "Selected", - "选择": "Select", - "请选择": "Please select", - "研发商店": "R&D store", - "精选": "Picked", - "推荐": "Recommend", - "新增任务": "New task", - "新增路径": "New path", - "原处理人": "original handler", - "目标处理人": "Target handler", - "添加处理人转换": "Configure handler conversion", - "选择规则集": "Please select rule set", - "请选择语言": "Please select languages", - "如流水线配置了质量红线请谨慎使用异步功能,可能会由于结果异步输出导致红线拦截": "If the pipeline is configured with a quality red line, please use the asynchronous function carefully. The red line may be blocked due to the asynchronous output of the result", - "以绝对路径/data/landun/workspace/CodeCCTest/cpp/为例:\n扫描相对路径可输入/CodeCCTest/cpp/,只输入/cpp/不会生效\n扫描某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n扫描工作空间中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n只扫描某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径或路径匹配式可用英文逗号分隔\n支持流水线变量": "Take the absolute path /data/landun/workspace/CodeCCTest/cpp/\nas an example: The scan relative path can be entered /CodeCCTest/cpp/\nBut only /cpp/ will not take effect. Scan a certain type of file,\nSuch as *.pb.cc generated by protobuffer, and you can enter .*/.*\\.Pb\\.cc\nScan a folder in the workspace, such as P2PLive, you can enter. */P2PLive/*\nOnly scan a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple paths are entered in a line or path matching can be separated by\nEnglish commas, and pipeline variables are supported", - "屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n屏蔽所有分支中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n屏蔽某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径匹配式可用英文逗号分隔\n支持流水线变量": "Exclude a certain type of file, such as *.pb.cc generated by protobuffer,\nand you can enter .*/.*\\.pb\\.cc\nMask a folder in all branches, such as P2PLive, you can enter .*/P2PLive/*\nExclude a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple path matching types are entered in a line, they can be separated\nby English commas, and pipeline variables are supported", - "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat": "#Coverage/Klocwork will compile your code by calling the compilation script to track the deep-seated defects\n#Please use a dependent build tool such as maven/make to write a build script build.bat\n#Ensure that build.bat can compile code\n# cd path/to/build.bat\n# call build.bat", - "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh": "#Coverage/Klocwork will compile your code by calling the compilation script to track the deep-seated defects.\n# Please write a compilation script build.sh using a dependent build tool such as maven/make\n# Ensure that build.sh can compile the code\n# cd path/to/build.sh\n# sh build.sh" + "前往CodeCC": "Go to CodeCC", + "基础设置": "Basic", + "扫描配置": "Scan", + "路径屏蔽": "Filter", + "一": "Mon", + "二": "Tues", + "三": "Wed", + "四": "Thur", + "五": "Fri", + "六": "Sat", + "日": "Sun", + "收起": "Fold", + "展开": "Unfold", + "路径白名单": "Whitelist path", + "路径黑名单": "Blacklist path", + "Linux私有构建机/Mac/Win10需安装docker,Win7仅支持Coverity。": "Linux private build machine/Mac/Win10 needs to install docker, and Win7 only supports Coverity.", + "具体请见": "For details, please see", + "在此处关闭规则集弹框": "Close the rule set pop-up here", + "该规则集不适用于当前插件": "The rule set is not applicable to the current plugin", + "该规则集不适用于当前插件已选择的语言": "The rule set is not applicable to the language selected by the current plugin", + "我知道了": "I got it!", + "快速搜索": "Quick search", + "暂无描述": "No description", + "暂无数据": "Empty", + "创建规则集": "New rule set", + "由x发布": "Published by {name}", + "共x条规则": "{sum} rules in total", + "规则集": "Rule set", + "获取规则集失败": "Failed to get rule set", + "编译脚本": "Compile script", + "涉及工具": "Tools involved", + "所有": "All", + "安装": "Install", + "安装成功": "Install succeeded", + "安装失败": "Install failed", + "取消选中": "Uncheck", + "已选中": "Selected", + "选择": "Select", + "请选择": "Please select", + "研发商店": "R&D store", + "精选": "Picked", + "推荐": "Recommend", + "正在加载中": "Loading", + "无匹配数据": "No matching data", + "新增任务": "New task", + "新增路径": "New path", + "原处理人": "Original handler", + "目标处理人": "Target handler", + "添加处理人转换": "Configure handler conversion", + "选择规则集": "Please select rule set", + "请选择语言": "Please select languages", + "字段只能包含字母": "Field can only contain letters", + "字段不能为空": " Field cannot be empty", + "字段不能重复": "Field cannot be duplicate", + "字段不能包含英文逗号": "Field cannot contain English comma", + "字段只能包含数字,字母和下划线": "Field can only contain numbers, letters and underscores", + "只能以字母和下划线开头,同时只包含字母,数字以及下划线": "It can only start with letters and underscores, and only contain letters, numbers and underscores", + "字段只能包含数字": "Field can only contain numbers", + "字段不符合(x)正则表达式规则": "The field does not conform to the ({regex}) regular expression rule", + "字段长度不能超过x个字符": "Field length cannot exceed {num} characters", + "字段长度不能少于x个字符": "Field length cannot be less than {num} characters", + "最大不能超过x": "Maximum cannot exceed {num}", + "最小不能少于x": "Minimum cannot be less than {num}", + "规则集字段不能为空": "Rule set field cannot be empty", + "如流水线配置了质量红线请谨慎使用异步功能,可能会由于结果异步输出导致红线拦截": "If the pipeline is configured with a quality red line, please use the asynchronous function carefully. The red line may be blocked due to the asynchronous output of the result", + "以绝对路径/data/landun/workspace/CodeCCTest/cpp/为例:\n扫描相对路径可输入/CodeCCTest/cpp/,只输入/cpp/不会生效\n扫描某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n扫描工作空间中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n只扫描某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径或路径匹配式可用英文逗号分隔\n支持流水线变量": "Take the absolute path /data/landun/workspace/CodeCCTest/cpp/\nas an example: The scan relative path can be entered /CodeCCTest/cpp/\nBut only /cpp/ will not take effect. Scan a certain type of file,\nSuch as *.pb.cc generated by protobuffer, and you can enter .*/.*\\.Pb\\.cc\nScan a folder in the workspace, such as P2PLive, you can enter. */P2PLive/*\nOnly scan a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple paths are entered in a line or path matching can be separated by\nEnglish commas, and pipeline variables are supported", + "屏蔽某类文件如protobuffer生成的*.pb.cc,可以输入.*/.*\\.pb\\.cc\n屏蔽所有分支中某个文件夹如P2PLive,可以输入.*/P2PLive/.* \n屏蔽某个文件夹下某类文件如P2PLive下*.c,可以输入.*/P2PLive/.*\\.c\n若一行中输入多个路径匹配式可用英文逗号分隔\n支持流水线变量": "Exclude a certain type of file, such as *.pb.cc generated by protobuffer,\nand you can enter .*/.*\\.pb\\.cc\nMask a folder in all branches, such as P2PLive, you can enter .*/P2PLive/*\nExclude a certain type of file under a folder, such as *.c under P2PLive,\nyou can enter .*/P2PLive/.*\\.c\nIf multiple path matching types are entered in a line, they can be separated\nby English commas, and pipeline variables are supported", + "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat": "#Coverage/Klocwork will compile your code by calling the compilation script to track the deep-seated defects\n#Please use a dependent build tool such as maven/make to write a build script build.bat\n#Ensure that build.bat can compile code\n# cd path/to/build.bat\n# call build.bat", + "# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh": "#Coverage/Klocwork will compile your code by calling the compilation script to track the deep-seated defects.\n# Please write a compilation script build.sh using a dependent build tool such as maven/make\n# Ensure that build.sh can compile the code\n# cd path/to/build.sh\n# sh build.sh" } diff --git a/src/frontend/src/utils/customRules.js b/src/frontend/src/utils/customRules.js index 2e86527..0bf4251 100644 --- a/src/frontend/src/utils/customRules.js +++ b/src/frontend/src/utils/customRules.js @@ -47,8 +47,8 @@ const customeRules = { }, scriptRequired: { validate: function (value, args) { - const defValue1 = '# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh' - const defValue2 = '# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat' + const defValue1 = this.$t('# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.sh\n# 确保build.sh能够编译代码\n# cd path/to/build.sh\n# sh build.sh') + const defValue2 = this.$t('# Coverity/Klocwork将通过调用编译脚本来编译您的代码,以追踪深层次的缺陷\n# 请使用依赖的构建工具如maven/cmake等写一个编译脚本build.bat\n# 确保build.bat能够编译代码\n# cd path/to/build.bat\n# call build.bat') return value !== defValue1 && value !== defValue2 } } diff --git a/src/frontend/src/utils/validDictionary.js b/src/frontend/src/utils/validDictionary.js index 2b2a41b..272e9b9 100644 --- a/src/frontend/src/utils/validDictionary.js +++ b/src/frontend/src/utils/validDictionary.js @@ -1,31 +1,33 @@ +import i18n from "../i18n" + const dictionary = { cn: { messages: { - alpha: field => '字段只能包含字母', - required: field => '字段不能为空', - unique: field => '字段不能重复', - excludeComma: field => '字段不能包含英文逗号', - string: field => '字段只能包含数字,字母和下划线', - varRule: field => `只能以字母和下划线开头,同时只包含字母,数字以及下划线`, - numeric: field => '字段只能包含数字', + alpha: field => i18n.t('字段只能包含字母'), + required: field => i18n.t('字段不能为空'), + unique: field => i18n.t('字段不能重复'), + excludeComma: field => i18n.t('字段不能包含英文逗号'), + string: field => i18n.t('字段只能包含数字,字母和下划线'), + varRule: field => i18n.t(`只能以字母和下划线开头,同时只包含字母,数字以及下划线`), + numeric: field => i18n.t('字段只能包含数字'), regex: (field, regex) => { - return `字段不符合(${regex})正则表达式规则` + return i18n.t('字段不符合(x)正则表达式规则', { regex: regex }) }, max: (field, args) => { - return `字段长度不能超过${args}个字符` + return i18n.t('字段长度不能超过x个字符', { num: args }) }, min: (field, args) => { - return `字段长度不能少于${args}个字符` + return i18n.t('字段长度不能少于x个字符', { num: args }) }, max_value: (field, args) => { - return `最大不能超过${args}` + return i18n.t('最大不能超过x', { num: args }) }, min_value: (field, args) => { - return `最小不能少于${args}` + return i18n.t('最小不能少于x', { num: args }) }, - ruleSetRequired: field => '规则集字段不能为空', - scriptRequired: field => '字段不能为空', - asyncTaskRequired: field => '字段不能为空' + ruleSetRequired: field => i18n.t('规则集字段不能为空'), + scriptRequired: field => i18n.t('字段不能为空'), + asyncTaskRequired: field => i18n.t('字段不能为空') // customPath: field => '路径请以 .* 开头' } } From a9d2949c0cb222381df13427da51adce7ea79c7c Mon Sep 17 00:00:00 2001 From: Yuanruitao <1075097840@qq.com> Date: Tue, 14 Feb 2023 11:30:49 +0800 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=E5=8C=96=E7=9B=B4=E6=8E=A5=E5=AE=89=E8=A3=85=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=20#29?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/desc.md | 0 doc/desc_en.md | 0 images/logo.png | Bin 0 -> 24274 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/desc.md create mode 100644 doc/desc_en.md create mode 100644 images/logo.png diff --git a/doc/desc.md b/doc/desc.md new file mode 100644 index 0000000..e69de29 diff --git a/doc/desc_en.md b/doc/desc_en.md new file mode 100644 index 0000000..e69de29 diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..90f2dedb5beff73610f05c5c48926647887088ad GIT binary patch literal 24274 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 FV1f>hz@7jA literal 0 HcmV?d00001 From 7b39ea2b447bd99a53b9ba49019095aeefcac0a5 Mon Sep 17 00:00:00 2001 From: carrywang05 <464918711@qq.com> Date: Tue, 14 Feb 2023 12:14:22 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0CodeCC=E4=B8=AD=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E4=BB=8B=E7=BB=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +++ doc/aboutCodeCC.md | 62 +++++++++++++++++++++++++++++++++++++++++++ doc/aboutCodeCC_en.md | 62 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 .gitignore create mode 100644 doc/aboutCodeCC.md create mode 100644 doc/aboutCodeCC_en.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec33037 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.codecc +.idea +.vscode \ No newline at end of file diff --git a/doc/aboutCodeCC.md b/doc/aboutCodeCC.md new file mode 100644 index 0000000..9e026f6 --- /dev/null +++ b/doc/aboutCodeCC.md @@ -0,0 +1,62 @@ +# 插件功能 + +支持Linux、MacOS、Windows系统下执行所有CodeCC代码检查工具,包括代码缺陷(bkcheck等)、安全漏洞(敏感信息、高危组件等)、代码规范(CppLint、CheckStyle等)、圈复杂度、重复率等。 + +# 适用场景 + +## Linux: +公共构建机(已预装Docker) +私有构建机(需安装Docker) +私有构建集群(需安装Docker) + +## MacOS: +私有构建机(需安装Docker) +私有构建集群(需安装Docker) + +## Windows(win10及以上): +私有构建机(需安装Docker) +私有构建集群(需安装Docker) + +# 使用限制和受限解决方案 +私有构建机需要安装Docker + + +# CodeCC特色功能 +CodeCC是腾讯领先的代码分析平台,提供专业的代码检查解决方案及服务,为产品质量保驾护航。 + +- 目前已集成十余款含商用、开源、自研的代码检查工具,覆盖代码缺陷、安全漏洞、编码规范、圈复杂度、代码重复率五大维度; + +- 支持规则开发框架和工具开发框架,可自主将开发的规则或工具集成到CodeCC平台; + +- 自研bkcheck缺陷检查工具,可以支持游戏C++后台、Unreal客户端、Unity客户端的缺陷检查; + +- 与蓝盾流水线进行了深度整合,通过质量红线服务,可以在流水线中使用CodeCC的检查结果来控制代码库MR/PR、转测、部署等流程,从而使得每一阶段的流水线产出都符合质量标准。 + +# CodeCC能发现什么代码问题 + +## 发现代码缺陷 + +代表工具:ClangWarning、Clang +代表规则:API使用、内存非法访问、程序卡死、资源泄露、空指针、性能低效…… + +## 发现安全漏洞 + +代表工具:敏感信息、高危组件 +代表规则:密码/密钥等信息泄露、加密风险、XSS、CSRF、注入攻击…… + +## 代码规范,检查一些逻辑错误 + +代表工具:CppLint、CheckStyle、ESLint、StyleCop、Gometalinter、detekt、PHPCS、PyLint等 +代表规则:注释、空代码块、异常处理、命名、格式化、风格…… + +## 控制复杂度 +代表工具:圈复杂度 +代表规则:函数圈复杂度>=20 + +## 检测重复率 +代表工具:重复率 +代表规则:文件代码重复率>=5% + +## 统计代码行数 +代表工具:代码统计 +代表规则:统计代码中各类语言代码行、注释行、空白行的情况 \ No newline at end of file diff --git a/doc/aboutCodeCC_en.md b/doc/aboutCodeCC_en.md new file mode 100644 index 0000000..f24574e --- /dev/null +++ b/doc/aboutCodeCC_en.md @@ -0,0 +1,62 @@ +# Plugin function + +Support all CodeCC code inspection tools under Linux, MacOS, and Windows systems, including code defects (bkcheck, etc.), security vulnerabilities (sensitive information, high-risk components, etc.), code specifications (CppLint, CheckStyle, etc.), cyclomatic complexity, repetition rate, etc. . + +# Applicable scene + +## Linux: +Public build machine (with Docker pre-installed) +Private build machine (docker needs to be installed) +Build a cluster privately (Docker needs to be installed) + +## MacOS: +Private build machine (docker needs to be installed) +Build a cluster privately (Docker needs to be installed) + +## Windows (win10 and above): +Private build machine (docker needs to be installed) +Build a cluster privately (Docker needs to be installed) + +# Use restricted and restricted solutions +Private build machines need to install Docker + + +# CodeCC Features +CodeCC is Tencent's leading code analysis platform, providing professional code inspection solutions and services to protect product quality. + +- At present, more than ten code inspection tools including commercial, open source, and self-developed have been integrated, covering five dimensions of code defects, security vulnerabilities, coding standards, cyclomatic complexity, and code repetition rate; + +- Support rule development framework and tool development framework, and can independently integrate the developed rules or tools into the CodeCC platform; + +- Self-developed bkcheck defect inspection tool, which can support defect inspection of game C++ background, Unreal client, and Unity client; + +- Deeply integrated with the Blue Shield pipeline, through the quality red line service, you can use the inspection results of CodeCC in the pipeline to control the code base MR/PR, transfer test, deployment and other processes, so that the output of each stage of the pipeline can meet the Quality Standard. + +# CodeCC can find what code problems + +## Find code bugs + +Representative tools: ClangWarning, Clang +Representative rules: API usage, illegal memory access, program freezes, resource leaks, null pointers, inefficient performance... + +## Security vulnerabilities found + +Representative tools: sensitive information, high-risk components +Representative rules: information leakage such as passwords/keys, encryption risks, XSS, CSRF, injection attacks... + +## Code specification, check some logic errors + +Representative tools: CppLint, CheckStyle, ESLint, StyleCop, Gometalinter, detekt, PHPCS, PyLint, etc. +Representative rules: comments, empty code blocks, exception handling, naming, formatting, style... + +## Control complexity +Representative Tool: Cyclomatic Complexity +Representative rules: function cyclomatic complexity>=20 + +## Detect repetition rate +Rep Tool: Repetition Rate +Representative rule: file code repetition rate>=5% + +## Count the number of lines of code +Representative Tool: Code Statistics +Representative rules: Statistical code lines, comment lines, and blank lines of various languages in the code. \ No newline at end of file