自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

vivo 互聯(lián)網(wǎng)自研代碼評審 VCR 落地實(shí)踐

開發(fā)
本文介紹了vivo工程效能團(tuán)隊(duì)基于 Gitlab、Gerrit等開源工具搭建的VCR平臺,代碼評審idea插件開發(fā)及開發(fā)過程中遇到的挑戰(zhàn)、困難,并分享了相應(yīng)的應(yīng)對策略和優(yōu)化方案。

代碼評審是軟件質(zhì)量保證一種活動(dòng),由一個(gè)或者多個(gè)人對一個(gè)程序的部分或者全部源代碼進(jìn)閱讀理解。一般來說分為作者和評審者兩種角色,作者方提供代碼邏輯的介紹和代碼,評審者則對提供的代碼基于設(shè)計(jì),功能性和非功能性等方面認(rèn)知進(jìn)行閱讀并提出問題。常見的評審組織形式是有同行評審(Peer Review)和小組檢查 (Team Inspection)兩種方式。

在代碼評審中,評審的目的在通過代碼的評審發(fā)現(xiàn)潛在的問題,同時(shí)分享和表達(dá)是代碼評審的重要收獲,我們知道人相同在不同的文化下生產(chǎn)力是不同的,代碼評審是一個(gè)工具,工具受文化的影響的同時(shí)也影響著文化,最終朝著我們希望的責(zé)任共擔(dān)、持續(xù)改進(jìn)的方向發(fā)展。

一、代碼評審演進(jìn)


圖片

隨著互聯(lián)網(wǎng)的發(fā)展,開發(fā)人員也越來越重視代碼評審帶來的代碼的代碼質(zhì)量提高以及代碼評審間接帶來的分享及人員備份效果,已經(jīng)不滿足于只是簡單的發(fā)現(xiàn)當(dāng)前問題解決問題記錄問題,需要滿足從評審基本跟進(jìn)、評論管理、評審報(bào)告以及評審方式多樣化、評審與研發(fā)流程相結(jié)合等需求。

① 代碼評審檢查表:手工定義要檢查項(xiàng),檢查完進(jìn)行打卡標(biāo)記結(jié)果。

② 插件快速評審導(dǎo)入導(dǎo)出:快速在插件上進(jìn)行評論,并將評論結(jié)果導(dǎo)出給被評審人,被評審人導(dǎo)入評審結(jié)果查看,評審表不可復(fù)用,一旦代碼變更則無法準(zhǔn)確定位、也無法再次跟蹤評審修改結(jié)果。

③ 在線代碼評審:在線插件或網(wǎng)頁評審,提供提交前提交后評審,可多人評審策略管控、代碼評審與需求/缺陷關(guān)聯(lián)管理。

④ 自動(dòng)化代碼評審:結(jié)合現(xiàn)有的Sonar掃描、安全掃描進(jìn)行對提交的代碼進(jìn)行自動(dòng)化檢查,使代碼在人工評審之前已經(jīng)經(jīng)歷一輪自動(dòng)評審,代碼評審?fù)ㄟ^之后可自動(dòng)觸發(fā)構(gòu)建、部署等。

⑤ 智能化代碼評審:根據(jù)AI大模型,可對提交代碼進(jìn)行綜合評價(jià)(編碼標(biāo)準(zhǔn)、可用性、可讀性、可維護(hù)性、安全性、高性能、異??刂啤⒃O(shè)計(jì)原則、可擴(kuò)展性、代碼復(fù)雜度等等)并給出相關(guān)測試建議等,未來大模型對代碼評審還有更大的空間。

二、代碼評審解決的需求和痛點(diǎn)是什么?

vivo當(dāng)前已經(jīng)有EasyCR評審工具,那為什么我們還需要繼續(xù)開發(fā)調(diào)研代碼評審工具呢?

我們先看看下面通過內(nèi)部調(diào)研獲取的信息,看看用戶希望的代碼評審工具需求和痛點(diǎn)是什么?


圖片

針對當(dāng)前vivo代碼評審工具我們繼續(xù)升級補(bǔ)充場景:

  1. 增加評審方式:對原自由評審方式(主要是提交后進(jìn)行代碼評審)增加評審控制方式(提交代碼至倉庫前進(jìn)行代碼評審、合并時(shí)提交代碼評審)。
  2. 支持網(wǎng)頁/插件:增加網(wǎng)頁端評審功能,滿足不同角色進(jìn)行評審及用戶體驗(yàn)上的優(yōu)化,增強(qiáng)插件版評審功能。
  3. 支持研發(fā)流程控制:上線過程中可作為人工卡點(diǎn)一項(xiàng)檢查項(xiàng)(可通過代碼是否評審、代碼評分、代碼問題解決情況等進(jìn)行判斷),通過線上管理,提高上線質(zhì)量。
  4. 支持自動(dòng)化檢查:代碼提交前,提交后可進(jìn)行代碼自動(dòng)化檢查,對代碼進(jìn)行自動(dòng)評審。
  5. 增加用戶定制化需求:如評審權(quán)限、評審?fù)ㄖ绞?、評審策略多人評審管理、評審報(bào)告訂閱等。

當(dāng)前市場上有很多優(yōu)秀的代碼評審工具,但是很少有評審工具能滿足所有的場景,角色不同,需要的能力不同,同一個(gè)角色不同團(tuán)隊(duì)使用的方式不同,我們需要一款解決用戶痛癢爽的代碼評審工具。

三、vivo代碼評審系統(tǒng)架構(gòu)

圖片


四、vivo代碼評審工具使用流程

在代碼評審中,CR可以是一次Commit,也可以是一次MergeCommit,那么針對一次CR我們可以隨時(shí)對已經(jīng)提交的commit進(jìn)行評審,也可以在CRpush至代碼庫之前攔截,同時(shí)也可以在一次合并之前進(jìn)行代碼評審。

代碼評審模式:

1. 提交前評審(Pre-push Code Review)

2. 提交后評審(Post-push Code Review)

    ① 合并評審

    ② 自由評審


圖片


提交前評審:VCR基于VCR在提交push至Gitlab代碼倉庫之前,對代碼進(jìn)行攔截,并進(jìn)行評審,支持一次評審請求作為一次評審,可對一次一次評審請求查看所有變更記錄并進(jìn)行評審追蹤。利用開源工具Gerrit,將評審請求推送至Gerrit中,評審?fù)ㄟ^后,將代碼從Gerrit同步至Gitlab倉庫

提交后評審

①合并評審:VCR基于Gitlab 在一次MR的基礎(chǔ)上進(jìn)行代碼評審。

②自由評審:針對用戶當(dāng)前代碼庫當(dāng)前分支信息或歷史commit進(jìn)行評審。

五、vivo代碼評審工具實(shí)施

5.1 確認(rèn)技術(shù)架構(gòu)

提交倉庫前進(jìn)行代碼評審,我們使用當(dāng)前成熟的代碼評審Gerrit,實(shí)施過程中最大的問題是用戶如何低成本切換及簡單評審的問題,對于當(dāng)前Gerrit評審工具遇到的問題如何解決呢?

1) 我們知道Gerrit評審工具需要提供給用戶Gerrit代碼庫地址,并進(jìn)行下載使用,當(dāng)前用戶使用的代碼庫習(xí)慣不能更改,也是不愿意修改的,那么我們?nèi)绾谓鉀Q呢?

給插件加持,提供用戶黑盒切換至評審代碼庫,或執(zhí)行一鍵下載代碼庫功能,底層使用Gerrit與代碼托管庫同步機(jī)制解決代碼一致性問題,用戶在使用代碼庫時(shí)同原使用方式一致。

圖片

2) Git代碼提交,CR為最小單位,CR可作為一次評審,但還有很多用戶使用的習(xí)慣是一次push作為一次評審,如何解決用戶一次push為一次評審呢?

a)需要對代碼關(guān)系鏈需要進(jìn)行整理,識別出一次push作為一次評審記錄,用戶多次追加提交記錄至評審請求,需要重新識別出關(guān)系鏈作為原push請求的評審記錄,Git原生對代碼變更的情況比較多,我們對一些場景進(jìn)行分析再特殊處理,不窮舉。

圖片

b)可對最小粒度CR的評審,也同時(shí)提供一次push請求內(nèi)容進(jìn)行評審,更方便快捷。

用戶不管是提交前評審、合并時(shí)評審,都可能會產(chǎn)生一次push,多次commit,用戶需要對最小粒度CR評審,也需要對最新變更所有內(nèi)容進(jìn)行評審。

5.2 插件改造實(shí)施

根據(jù)我們對用戶的調(diào)研過程中,用戶對代碼評審插件網(wǎng)頁同時(shí)兼容的要求比較高,針對idea插件我們?nèi)绾胃脑齑a評審,這里我們著重對Gerrit插件改造展開說明。

步驟1:了解插件框架、配置、打包、運(yùn)行

1)插件框架整體介紹

圖片


(圖片來源于網(wǎng)絡(luò))

  • 開發(fā)方式:在官網(wǎng)的描述中,創(chuàng)建IDEA插件工程的方式有兩種分別是使用DevKit(IntelliJ Platform Plugin 模版創(chuàng)建)和Gradle構(gòu)建方式,這兩種方式在構(gòu)建項(xiàng)目和打包發(fā)布上有所區(qū)別,同時(shí)官方提供了將Devkit遷移至Gradle的方式。
    參考:https://plugins.jetbrains.com/docs/intellij/developing-plugins.html
  • 框架入口:一個(gè) IDEA 插件開發(fā)完,要考慮把它嵌入到哪,比如是從 IDEA 窗體的 Edit、Tools 等進(jìn)入配置還是把窗體嵌入到左、右工具條還是IDEA窗體下的對話框。
  • UI:思考的是窗體需要用到什么語言開發(fā),沒錯(cuò),用的就是 Swing、Awt 的技術(shù)能力。
  • API:在 IDEA 插件開發(fā)中,一般都是圍繞工程進(jìn)行的,那么基本要從通過 IDEA 插件 JDK 開發(fā)能力中獲取到工程信息、類信息、文件信息等。
  • 外部功能:這一個(gè)是用于把插件能力與外部系統(tǒng)結(jié)合,比如你是需要把拿到的接口上傳到服務(wù)器,還是從遠(yuǎn)程下載文件等等。

 2)Gradle創(chuàng)建

新版通過 New-> Project->IDE Plugin進(jìn)行創(chuàng)建,舊版通過New Project->Gradle->IntelliJ Platform Plugin進(jìn)行創(chuàng)建。

項(xiàng)目結(jié)構(gòu)如下:

圖片

3)配置介紹

plugin.xml

<!DOCTYPE idea-plugin PUBLIC "Plugin/DTD" "http://xxxx">
<idea-plugin>
  <!-- 插件唯一id,不能和其他插件項(xiàng)目重復(fù),所以推薦使用包名+插件名com.xxx.xxx的格式
       插件不同版本之間不能更改,若沒有指定,則與name相同 -->
    <id> com.your.company.unique.plugin.id </id>
<!-- 插件名稱,別人在官方插件庫搜索你的插件時(shí)使用的名稱 -->
    <name> Plugin display name here </name>
<!-- 插件版本,格式:BRANCH.BUILD.FIX (MAJOR.MINOR.FIX) -->vs
    <version>1.0.0</version>
<!-- 供應(yīng)商主頁和email(不能使用默認(rèn)值,必須修改成自己的)-->
   <vendor email="support@yourcompany.com" url="https://www.yourcompany.com">YourCompany</vendor>


  <!-- 插件的描述 (不能使用默認(rèn)值,必須修改成自己的。并且需要大于40個(gè)字符)-->
  <description><![CDATA[
  Enter short description for your plugin here.<br>
  <em>most HTML tags may be used</em>
]]></description> 
    <!-- 插件版本變更信息,使用<![CDATA[  ]]> 來支持HTML格式;
       將展示在 settings | Plugins 對話框和插件倉庫的Web頁面 -->
    <change-notes><![CDATA[
      <p>
          <li>1.0.0</li>
          <ul>
            <li>
             1.新增xxx功能 <br/>
             2.優(yōu)化xxx功能 <br/>
            </li>
          </ul>
      </p>
     ]]>
    </change-notes>


    <!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
   <!-- 插件兼容構(gòu)建的IDE版本, until-build可以不寫,默認(rèn)到最新版 -->
   <idea-version since-build="203.4818.26" until-build="211"/>




    <!-- please see http://confluence.jetbrains.net/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
         on how to target different products -->
  <!-- 插件依賴,可以依賴模塊或插件 -->
    <depends>com.intellij.modules.lang</depends>
    <depends>Git4Idea</depends>
    <depends optional="true" config-file="plugin-maven.xml">org.jetbrains.idea.maven</depends>


<!—idea第一次打開, 實(shí)際上就是訂閱了應(yīng)用程序打開的事件-->
    <application-components>
        <component>
            <implementation-class>xxxxx</implementation-class>
        </component>
    </application-components>
<!—打開項(xiàng)目 -->
    <project-components>
        <component>
            <implementation-class>
                xxxxx
            </implementation-class>
        </component>
    </project-components>
<!-- 插件定義的擴(kuò)展點(diǎn),以供其他插件擴(kuò)展該插件,類似Java的抽象類的功能 
     如何在https://plugins.jetbrains.com/docs/intellij/plugin-extensions.html -->
   <extensionPoints>
   </extensionPoints>




<!-- 聲明該插件對IDEA core或其他插件的擴(kuò)展,Ns是NameSpace的縮寫 -->
    <extensions defaultExtensionNs="com.intellij">
        <toolWindow id="代碼評審" icon="/icons/xx_13x13.png" anchor="bottom" factoryClass="xxx" />
    </extensions>
    <!-- 編寫插件動(dòng)作 https://plugins.jetbrains.com/docs/intellij/plugin-actions.html-->
    <actions>
     <action id="com.xx.xx.AddCommentAction"
        class="com.xx.xx.actions.AddCommentAction"
        text="添加評論"
        description="為選中的代碼添加評論意見"
        icon="AllIcons.Actions.StartDebugger"> 
    <!—編輯器右鍵彈出菜單--!>
    <add-to-group group-id="EditorPopupMenu" anchor="first"/>
    <!--快捷方式--!>
    <keyboard-shortcut first-keystroke="alt X" keymap="$default"/> </action>
    </action>
    </actions>
</idea-plugin>

4)插件運(yùn)行調(diào)試打包安裝

Gradle構(gòu)建方式進(jìn)行調(diào)試打包安裝

運(yùn)行/調(diào)試:runIde 可以選擇Debug模式或者是Run模式

圖片

打包

圖片

安裝:可以將打的包發(fā)布市場(本地idea配置插件倉庫),從Marketplace搜索插件或者是直接從Settings->plugins->Install->Install Plugin from Disk安裝

圖片

步驟2:研究Gerrit插件源碼,搞清楚整理開發(fā)流程和模塊

圖片

步驟3:基于Gerrit插件規(guī)劃VCR插件模塊,增加clone、branch、mergeRequest、VCR模塊,并對各組件增強(qiáng)

圖片

步驟4:定制原有流程模塊push,自動(dòng)化關(guān)聯(lián)工作項(xiàng)

圖片


圖片

在使用Git依賴插件之前,先了解一下插件的擴(kuò)展以及擴(kuò)展點(diǎn)(Extensions、Extension Points)。

Intellij 平臺提供了允許一個(gè)插件與其他插件或者 IDE 交互的 extensions 以及 extension points 的概念。

  • Extension Points:如果你想要你的插件可以被其他插件使用,那么你必須在你的插件內(nèi)聲明一個(gè)或多個(gè)擴(kuò)展點(diǎn)(extension points)。每個(gè)擴(kuò)展點(diǎn)定義了允許訪問這個(gè)點(diǎn)的類或者接口。
  • Extensions:如果你想要你的插件擴(kuò)展其他插件或者 Intellij 平臺,你必須聲明一個(gè)或多個(gè) extensions。

可以在 plugin.xml 中的和塊中定義 extensions 以及 extension points。

圖片


plugin.xml

<!--依賴插件包--!>
<depends>Git4Idea</depends>
<!—idea第一次打開, 實(shí)際上就是訂閱了應(yīng)用程序打開的事件-->
<application-components>
<component>
<implementation-class>com.demo.intellij.plugin.vcr.push.VcrPushExtension$Proxy</implementation-class>
</component>
</application-components>

上述我們看到依賴的Git4Idea 包,如果我們想修改原生的的Git,先看下push依賴包中如何實(shí)現(xiàn)的。

Git4Idea(plugin.xml)

<extensions defaultExtensionNs="com.intellij">


<pushSupport implementation="git4idea.push.GitPushSupport"/>
...
</extensions>

intellij-dvcs.jar(plugin.xml)

<extensionPoints>
  <extensionPoint name="pushSupport"
                  interface="com.intellij.dvcs.push.PushSupport"
                  area="IDEA_PROJECT"
                  dynamic="true"/>
....
</extensionPoints>

從上述可看到,Git4Idea 的GitPushSupport擴(kuò)展實(shí)現(xiàn)push的功能點(diǎn),接下來我們主要對GitPushSupport進(jìn)行javassist字節(jié)碼修改以達(dá)到擴(kuò)展git push組件能力。

擴(kuò)展使用GitPushSupport之前,需要將需要的類進(jìn)行裝載至GitPlugin中,然后再對GitPushSupport進(jìn)行字節(jié)碼改造,至此對git Push原生插件頁進(jìn)行改造。


圖片

步驟5:使用樹狀列表模式,展示一次push請求VCR提交內(nèi)容及多個(gè)CR情況

主要是實(shí)現(xiàn)JTreeTable,對VCR與CR進(jìn)行管理。

一次評審請求VCR包含所有CR的提交變更記錄,可針對該變更記錄進(jìn)行代碼評審,單個(gè)CR也可以進(jìn)行評審。


圖片


步驟6:展示變更文件視圖及定制評論展示模塊,精準(zhǔn)定位代碼

代碼評審主要根據(jù)編輯器獲取代碼行及位置,評論可精準(zhǔn)定位到代碼行。

圖片

1)changeBrowser變更視圖展示VCR變更文件信息

圖片

2)雙擊文件,diff視圖展示inline和side-by-side兩種代碼差異

聲明擴(kuò)展,針對擴(kuò)展類進(jìn)行定制化改造。

plugin.xml

<diff.DiffTool implementatinotallow="com.demo.intellij.plugin.vcr.ui.diff.VcrCommentsDiffTool$Proxy"/>


圖片

3)添加代碼塊評論,定位代碼塊

AddCommentAction.java

public class AddCommentAction extends AnAction implements DumbAware {


public AddCommentAction(String label,
                        Icon icon,
                        CommentsDiffTool commentsDiffTool,                 
                        Editor editor, 
                        List<CommentInfo> fileComments
                        ....
                        ) {
    super(label, null, icon);
}
private CommentInput createComment() {
//獲取用戶選擇代碼位置位置


//行的情況下,默認(rèn)是開頭和行結(jié)束  得到光標(biāo)的位置caretModel.getOffset();
/*取到插字光標(biāo)模式對象 CaretModel caretModel = editor.getCaretModel();
得到光標(biāo)的位置int caretOffset = caretModel.getOffset();
//得到一行開始和結(jié)束的地方
int lineNum = document.getLineNumber(caretOffset);
int lineStartOffset = document.getLineStartOffset(lineNum);
int lineEndOffset = document.getLineEndOffset(lineNum);
獲取一行內(nèi)容String lineContent = document.getText(new TextRange(lineStartOffset, lineEndOffset));
*/
Document document = editor.getDocument();
int lineNum  = document.getLineNumber(editor.getCaretModel().getOffset()) ;
int lineStartOffset = document.getLineStartOffset(lineNum);
int lineEndOffset = document.getLineEndOffset(lineNum);
String lineContent = document.getText(new TextRange(lineStartOffset, lineEndOffset));
.....
}
}

所有評論展示列表如何精準(zhǔn)定位代碼

SafeHtmlHistoryComments.java

public class SafeHtmlHistoryComments extends JPanel {
    private Iterable<CommentInfo> fileComments;
    private List<CommentInfo> commentInfos = new ArrayList<>();
    private CommentInfo currentCommentInfo;
    private SelectedComment selectedComment;
    private SelectedComment operatorSelectedComment;
    private Editor editor;
    public SafeHtmlHistoryComments(Editor editor,Iterable<CommentInfo> fileComments, Comment selectedComment) {
        super(new BorderLayout());
        ....
      HistoryCommentListPanel historyCommentListPanel = new HistoryCommentListPanel(fileComments);
       
        //雙擊table某行觸發(fā)代碼定位
        historyCommentListPanel.addTableMouseDoubleHit(new Consumer<CommentInfo>() {
            @Override
            public void consume(CommentInfo commentInfo) { 
                codeTextHit(editor,commentInfo);
            }
        });
    }


    /**
     * 定位代碼
     * @param editor
     * @param commentInfo
     */
    private static void codeTextHit(Editor editor, CommentInfo commentInfo) {
        SelectionModel selectionModel = editor.getSelectionModel();
        // 優(yōu)化:如果文件修改過了,則不進(jìn)行選中操作,換為提示
        if (null != commentInfo.startIndex && null != commentInfo.endIndex && commentInfo.startIndex != 0 && commentInfo.endIndex != 0) {
            editor.getCaretModel().moveToOffset(commentInfo.endIndex);
            selectionModel.setSelection(commentInfo.startIndex, commentInfo.endIndex);
        } else if (null != commentInfo.line && commentInfo.line != 0) {
            int lineNum = commentInfo.line - 1;
            editor.getCaretModel().moveToOffset(lineNum);
            CharSequence charsSequence = editor.getMarkupModel().getDocument().getCharsSequence();
            if(null!=commentInfo.range) {
                RangeUtils.Offset offset = RangeUtils.rangeToTextOffset(charsSequence, commentInfo.range);
                selectionModel.setSelection(offset.start, offset.end);
            }else{
                Document document = editor.getDocument();
                int lineStartOffset = document.getLineStartOffset(lineNum);
                int lineEndOffset = document.getLineEndOffset(lineNum);
                selectionModel.setSelection(lineStartOffset, lineEndOffset);
            }
        }
        editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
    }
....
}

六、未來展望

6.1 自動(dòng)化代碼評審

  1. 代碼提交評審或代碼合并之前,先自動(dòng)化檢查(Sonar/安全掃描)快速發(fā)現(xiàn)并糾正潛在問題,檢查成功后提交評審。
  2. 代碼評審?fù)ㄟ^之后,結(jié)合流水線,自定義部署構(gòu)建策略,實(shí)現(xiàn)快速迭代。
  3. 自動(dòng)匯聚測試報(bào)告,根據(jù)評審問題類型進(jìn)行分類,不斷改進(jìn)Sonar檢查規(guī)則,從而形成良性循環(huán)。

6.2智能化代碼評審

  1. 提交代碼評審之后,通過AI大模型對代碼進(jìn)行綜合評價(jià),并給出建議。
  2. 通過智能代碼評審,產(chǎn)生評審報(bào)告,并進(jìn)行智能化分析。
責(zé)任編輯:龐桂玉 來源: vivo互聯(lián)網(wǎng)技術(shù)
相關(guān)推薦

2022-12-08 13:40:58

vivo互聯(lián)網(wǎng)

2013-06-13 10:21:25

云計(jì)算

2022-04-21 08:09:18

Spark字段血緣Spark SQL

2023-02-09 08:08:01

vivoJenkins服務(wù)器

2015-07-01 13:53:06

致遠(yuǎn)協(xié)同

2023-06-29 11:06:46

vivoID服務(wù)器

2015-08-11 13:52:27

戴爾云計(jì)算anycloud

2016-09-12 17:57:48

云端 互聯(lián)網(wǎng)

2015-06-24 15:35:54

2012-06-07 15:49:25

2019-11-13 10:45:43

互聯(lián)網(wǎng)安全運(yùn)維

2017-10-27 14:52:31

互聯(lián)網(wǎng)高可用架構(gòu)高可用

2012-07-08 20:59:35

移動(dòng)互聯(lián)網(wǎng)創(chuàng)業(yè)

2022-09-14 23:14:10

vivoPulsar大數(shù)據(jù)

2024-05-30 14:18:04

2022-12-15 11:26:44

云原生

2022-06-01 09:04:58

Kafka運(yùn)維副本遷移

2010-08-26 15:15:45

2014-01-15 14:35:35

云計(jì)算

2015-05-28 16:11:07

互聯(lián)網(wǎng)+
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號