【Android】靜態(tài)代碼檢查-2.本地Hooks檢查

一.Hooks檢查大致流程

  1. 編寫CheckStyle文件: 檢查JavaCode的規(guī)范文件
  2. 編寫Gradle:執(zhí)行checkstyle task方法并調(diào)用checkstyle.xml對修改過的java文件進(jìn)行檢查
  3. 編寫pre-commit腳本文件:在app目錄下執(zhí)行g(shù)radlew命令中的checkstyle task
  4. 編寫commit-msg腳本文件:對代碼提交所輸入的日志進(jìn)行規(guī)范檢查
  5. 編寫hooks腳本文件:自動在.git下生成pre-commit&commit-msg

二.Hooks檢查代碼

1. CheckStyle.xml文件:

如下所示一個比較完整的demo,檢查的規(guī)范比較多,可以根據(jù)公司or項目組情況自定義規(guī)范。
注意幾點(diǎn):
a.配置文件中不能有重復(fù)的規(guī)則,否則創(chuàng)建或者導(dǎo)入時可能會導(dǎo)致失敗。
b.配置文件中每一個<module> </module> 代表一個檢測的功能點(diǎn)。
c.配置文件中的< property > </property > 可以配置一些參數(shù),其中name="severity"參數(shù)表示該代碼規(guī)范報錯的嚴(yán)重程度,如果嚴(yán)重程度設(shè)置為error,則提交會不通過。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE module PUBLIC
    "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
    "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<module name="Checker">
    <property name="charset" value="UTF-8" />
    <property name="severity" value="warning" />

    <!-- 檢查文件是否以一個空行結(jié)束 -->
    <module name="NewlineAtEndOfFile" />

    <!-- 文件長度不超過1500行 -->
    <module name="FileLength">
        <property name="max" value="1500" />
    </module>

    <!-- 每個java文件一個語法樹 -->
    <module name="TreeWalker">
        <!-- import檢查-->
        <!-- 避免使用* -->
        <module name="AvoidStarImport">
            <property name="excludes" value="java.io,java.net,java.lang.Math" />
            <!-- 實(shí)例;import java.util.*;.-->
            <property name="allowClassImports" value="false" />
            <!-- 實(shí)例 ;import static org.junit.Assert.*;-->
            <property name="allowStaticMemberImports" value="true" />
        </module>
        <!-- 檢查是否從非法的包中導(dǎo)入了類 -->
        <module name="IllegalImport" />
        <!-- 檢查是否導(dǎo)入了多余的包 -->
        <module name="RedundantImport" />
        <!-- 沒用的import檢查,比如:1.沒有被用到2.重復(fù)的3.import java.lang的4.import 與該類在同一個package的 -->
        <module name="UnusedImports" />


        <!-- 注釋檢查 -->
        <!-- 檢查方法和構(gòu)造函數(shù)的javadoc -->
        <module name="JavadocType">
            <property name="allowUnknownTags" value="true" />
            <message key="javadoc.missing" value="Class Comments: Lack of Javadoc annotations." />
        </module>
        <module name="JavadocMethod">
            <property name="tokens" value="METHOD_DEF" />
            <!--允許get set 方法沒有注釋-->
            <property name="allowMissingPropertyJavadoc" value="true" />
            <message key="javadoc.missing" value="Method Comments: Lack of Javadoc annotations." />
        </module>

        <!-- 命名檢查 -->
        <!-- 局部的final變量,包括catch中的參數(shù)的檢查 -->
        <module name="LocalFinalVariableName" />
        <!-- 局部的非final型的變量,包括catch中的參數(shù)的檢查 -->
        <module name="LocalVariableName" />
        <!-- 包名的檢查(只允許小寫字母),默認(rèn)^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->
        <module name="PackageName">
            <!--<property name="severity" value="error" />-->
            <!--<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" />-->
            <!--<message key="name.invalidPattern"-->
            <!--value="Class comment package names are allowed only in lowercase letters." />-->
        </module>
        <!-- 僅僅是static型的變量(不包括static final型)的檢查 -->
        <module name="StaticVariableName" />
        <!-- Class或Interface名檢查,默認(rèn)^[A-Z][a-zA-Z0-9]*$-->
        <module name="TypeName">
            <property name="severity" value="warning" />
            <message key="name.invalidPattern"
                value="Class comment package names are allowed only in lowercase letters." />
        </module>
        <!-- 非static型變量的檢查 -->
        <module name="MemberName" />
        <!-- 方法名的檢查 -->
        <module name="MethodName" />
        <!-- 方法的參數(shù)名 -->
        <module name="ParameterName " />
        <!-- 常量名的檢查(只允許大寫),默認(rèn)^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->
        <module name="ConstantName" />

        <!-- 定義檢查 -->
        <!-- 檢查數(shù)組類型定義的樣式 -->
        <module name="ArrayTypeStyle" />
        <!-- 檢查long型定義是否有大寫的“L” -->
        <module name="UpperEll" />

        <!-- 長度檢查 -->
        <!-- 每行不超過120個字符 -->
        <module name="LineLength">
            <property name="max" value="120" />
        </module>
        <!-- 方法不超過50行 -->
        <module name="MethodLength">
            <property name="tokens" value="METHOD_DEF" />
            <property name="max" value="50" />
        </module>
        <!-- 方法的參數(shù)個數(shù)不超過5個。 并且不對構(gòu)造方法進(jìn)行檢查-->
        <module name="ParameterNumber">
            <property name="max" value="5" />
            <property name="ignoreOverriddenMethods" value="true" />
            <property name="tokens" value="METHOD_DEF" />
            <property name="severity" value="error"/>
        </module>

        <!-- 空格檢查-->
        <!-- 方法名后跟左圓括號"(" -->
        <module name="MethodParamPad" />
        <!-- 在類型轉(zhuǎn)換時,不允許左圓括號右邊有空格,也不允許與右圓括號左邊有空格 -->
        <module name="TypecastParenPad" />
        <!-- 檢查在某個特定關(guān)鍵字之后應(yīng)保留空格 -->
        <module name="NoWhitespaceAfter" />
        <!-- 檢查在某個特定關(guān)鍵字之前應(yīng)保留空格 -->
        <module name="NoWhitespaceBefore" />
        <!-- 操作符換行策略檢查 -->
        <module name="OperatorWrap" />
        <!-- 圓括號空白 -->
        <module name="ParenPad" />
        <!-- 檢查分隔符是否在空白之后 -->
        <module name="WhitespaceAfter" />
        <!-- 檢查分隔符周圍是否有空白 -->
        <module name="WhitespaceAround" />

        <!-- 修飾符檢查 -->
        <!-- 檢查修飾符的順序是否遵照java語言規(guī)范,默認(rèn)public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
        <module name="ModifierOrder" />
        <!-- 檢查接口和annotation中是否有多余修飾符,如接口方法不必使用public -->
        <module name="RedundantModifier" />

        <!-- 代碼塊檢查 -->
        <!-- 檢查是否有嵌套代碼塊 -->
        <module name="AvoidNestedBlocks" />
        <!-- 檢查是否有空代碼塊 -->
        <module name="EmptyBlock" />
        <!-- 檢查左大括號位置 -->
        <module name="LeftCurly" />
        <!-- 檢查代碼塊是否缺失{} -->
        <module name="NeedBraces" />
        <!-- 檢查右大括號位置 -->
        <module name="RightCurly" />

        <!-- 代碼檢查 -->
        <!-- 檢查空的代碼段 -->
        <module name="EmptyStatement" />
        <!-- 檢查在重寫了equals方法后是否重寫了hashCode方法 -->
        <module name="EqualsHashCode" />
        <!-- 檢查局部變量或參數(shù)是否隱藏了類中的變量 -->
        <module name="HiddenField">
            <property name="tokens" value="VARIABLE_DEF" />
        </module>
        <!-- 檢查是否使用工廠方法實(shí)例化 -->
        <module name="IllegalInstantiation" />
        <!-- 檢查子表達(dá)式中是否有賦值操作 -->
        <module name="InnerAssignment" />
        <!-- 檢查是否有"魔術(shù)"數(shù)字 -->
        <module name="MagicNumber">
            <property name="ignoreNumbers" value="0, 1" />
            <property name="ignoreAnnotation" value="true" />
        </module>
        <!-- 檢查switch語句是否有default -->
        <module name="MissingSwitchDefault" />
        <!-- 檢查是否有過度復(fù)雜的布爾表達(dá)式 -->
        <module name="SimplifyBooleanExpression" />
        <!-- 檢查是否有過于復(fù)雜的布爾返回代碼段 -->
        <module name="SimplifyBooleanReturn" />

        <!-- 類設(shè)計檢查 -->
        <!-- 檢查類是否為擴(kuò)展設(shè)計l -->
        <!-- 檢查只有private構(gòu)造函數(shù)的類是否聲明為final -->
        <module name="FinalClass" />
        <!-- 檢查工具類是否有putblic的構(gòu)造器 -->
        <module name="HideUtilityClassConstructor" />
        <!-- 檢查接口是否僅定義類型 -->
        <module name="InterfaceIsType" />
        <!-- 檢查類成員的可見度 檢查類成員的可見性。只有static final 成員是public的
        除非在本檢查的protectedAllowed和packagedAllowed屬性中進(jìn)行了設(shè)置-->
        <module name="VisibilityModifier">
            <property name="packageAllowed" value="true" />
            <property name="protectedAllowed" value="true" />
        </module>

        <!-- 語法 -->
        <!-- String的比較不能用!= 和 == -->
        <module name="StringLiteralEquality" />
        <!-- 限制for循環(huán)最多嵌套2層 -->
        <module name="NestedForDepth">
            <property name="max" value="2" />
        </module>
        <!-- if最多嵌套3層 -->
        <module name="NestedIfDepth">
            <property name="max" value="3" />
        </module>
        <!-- 檢查未被注釋的main方法,排除以Appllication結(jié)尾命名的類 -->
        <module name="UncommentedMain">
            <property name="excludedClasses" value=".*Application$" />
        </module>
        <!-- 禁止使用System.out.println -->
        <module name="Regexp">
            <property name="format" value="System\.out\.println" />
            <property name="illegalPattern" value="true" />
        </module>
        <!-- return個數(shù) 3個-->
        <module name="ReturnCount">
            <property name="max" value="3" />
        </module>
        <!--try catch 異常處理數(shù)量 3-->
        <module name="NestedTryDepth ">
            <property name="max" value="3" />
        </module>
        <!-- clone方法必須調(diào)用了super.clone() -->
        <module name="SuperClone" />
        <!-- finalize 必須調(diào)用了super.finalize() -->
        <module name="SuperFinalize" />

    </module>
</module>

2. Gradle文件:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }

    apply plugin: 'checkstyle'

    checkstyle {
        toolVersion '6.13'
        ignoreFailures false
        showViolations true
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

// 腳本pre-commit 調(diào)用 checkstyle task 檢查代碼(修改提交的代碼)
task checkstyle(type: Checkstyle) {
    source 'app/src/main/java'
    exclude '**/gen/**'
    exclude '**/R.java'
    exclude '**/BuildConfig.java'

    if (project.hasProperty('checkCommit') && project.property("checkCommit")) {
        List<String> fileS = filterCommitter(getChangeFiles())
        def includeList = new ArrayList<String>()
        for (String split : fileS) {
            String[] splits = split.split("/")
            String fileName = splits[splits.length - 1]
            includeList.add("**/" + fileName)
        }
        if (includeList.size() == 0) {
            exclude '**/*.java'
        } else {
            println("includeList==" + includeList)
            include includeList
        }
    } else {
        include '**/*.java'
    }
    configFile rootProject.file('hook/checkstyle.xml')
    classpath = files()
}

//根據(jù)git status 獲取 修改的文件
def getChangeFiles() {
    try {
        String changeInfo = 'git status -s'.execute(null, project.rootDir).text.trim()
        return changeInfo == null ? "" : changeInfo
    } catch (Exception e) {
        return ""
    }
}

//只對java代碼
def filterCommitter(String info) {
    ArrayList<String> filterList = new ArrayList<String>()
    String[] lines = info.split("\\n")
    for (String line : lines) {
        if (line.contains(".java")) {
            String[] split = line.trim().split(" ")
            for (String str : split) {
                if (str.contains(".java")) {
                    filterList.add(str)
                }
            }
        }
    }
    return filterList
}

3. pre-commit腳本代碼:

#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".

if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

#開始 代碼檢查攔截
TAG="pre-commit log----------------->"

#打印success日志函數(shù)
printS(){
   echo -e "\033[0;32m $* \033[0m"
}

#打印fail日志函數(shù)
printE(){
   echo -e "\033[0;31m $* \033[0m"
}

#獲取腳本的根目錄
SCRIPT_DIR=$(dirname "$0")
#echo "SCRIPT_DIR=$SCRIPT_DIR"
SCRIPT_ABS_PATH=`cd "$SCRIPT_DIR"; pwd`
#echo "SCRIPT_ABS_PATH=$SCRIPT_ABS_PATH"
#在app項目目錄下執(zhí)行 gradlew 命令執(zhí)行 checkstyle task
$SCRIPT_ABS_PATH/../../gradlew  -P checkCommit="true" checkstyle
if [ $? -eq 0   ]; then
# checkstyle檢查成功
    info=$TAG"checkstyle OK"
    printS $info
else
#checkstyle檢查失敗
    info=$TAG"checkstyle fail"
    printE $info
    exit 1
fi
#結(jié)束

# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)

# Redirect output to stderr.
exec 1>&2

# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
    # Note that the use of brackets around a tr range is ok here, (it's
    # even required, for portability to Solaris 10's /usr/bin/tr), since
    # the square bracket bytes happen to fall in the designated range.
    test $(git diff --cached --name-only --diff-filter=A -z $against |
      LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
    cat <<\EOF
Error: Attempt to add a non-ASCII file name.

This can cause problems if you want to work with people on other platforms.

To be portable it is advisable to rename the file.

If you know what you are doing you can disable this check using:

  git config hooks.allownonascii true
EOF
    exit 1
fi

# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

4. commit-msg腳本代碼:

#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message.  The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit.  The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".

# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

# This example catches duplicate Signed-off-by lines.

#開始 日志攔截
TAG="commit-msg log----------------->"

#打印success日志函數(shù)
printS(){
    info=$TAG$*
    echo -e "\033[0;32m $info \033[0m"
}

#打印fail日志函數(shù)
printE(){
   info=$TAG$*
   echo -e "\033[0;31m $info \033[0m"
}

fileName=$1
#message 獲取提交日志
message=$(<$fileName)
if [ -z $message ]
#message 為空
  then
  printE "submit message info is null"
  exit 1
fi


#例子,對下面的字符串模板解析
#[update|add|change|fix]xxx
printS $message
#日志最大長度
maxLen=30
#日志最小長度
minLen=4
sI=-1
eI=-1
#提交日志模板樣式
logFormat="log format--->\"[update|add|change|fix]xxxxxxxx\""

#判斷[]起始結(jié)束位置
sI=$(awk -v a="$message" -v b="[" 'BEGIN{print index(a,b)}')
eI=$(awk -v a="$message" -v b="]" 'BEGIN{print index(a,b)}')
#sI=`expr index "$message" [`
#eI=`expr index "$message" ]`
len=${#message}
eeI=`expr $eI-2`

#printS "sI=$sI,eI=$eI"

#判斷[]開始
if [[ $sI -eq 1 && $eeI -ge $sI ]]
 then
    action=${message:$sI:$eeI}
    log=${message:$eI}
    logLen=${#log}
    #printS "action=$action,log=$log,logLen=$logLen"
    #提交action判斷
    if [[ $action = "update" || $action = "add" || $action = "change" || $action = "fix" ]]
        then
        subLog=${log:0:1}
        #printS "log=$log,subLog=$subLog"
        #提交的本次記錄內(nèi)容
        if [ -z $log ]
            then
            printE "log is empty"
            exit 1
        elif [ $logLen -lt $minLen ]
            #提交的本次記錄內(nèi)容太少
            then
            printE "log is min $minLen"
            exit 1
        elif [ -z $subLog ]
            #提交的本次記錄內(nèi)容與】之間有空格,[update] XXXX
            then
            printE $logFormat
            exit 1
        elif [ $logLen -gt $maxLen ]
            #提交的本次記錄內(nèi)容太多
            then
            printE "log is max $maxLen"
            exit 1
        else
            printS "check log success"
        fi
    else
        printE $logFormat
        exit 1
    fi
 else
    printE $logFormat
    exit 1
fi
#結(jié)束

5. hooks腳本代碼:

#!/bin/bash
#開始
# 復(fù)制 pre-commit commit-msg腳本到/.git/hooks/目錄下
# r d
action='r'
#獲取輸入命令的第一個參數(shù)
cmd=$1
if [ $cmd ]
 then
  action=$1
fi
echo "action=$action"
# 獲取hook下的commit-msg和pre-commit
precommitName="pre-commit"
commitName="commit-msg"
#獲取當(dāng)前目錄
sourcePath=$(pwd)
sourcePrecommit=$sourcePath"/"$precommitName
sourceCommitmsg=$sourcePath"/"$commitName
echo "sourcePrecommit=$sourcePrecommit"
echo "sourceCommitmsg=$sourceCommitmsg"
cd ..
rootPath=$(pwd)
echo "rootPath=$rootPath"
gitDir=$rootPath"/.git"
echo "gitDir=$gitDir"
hooksDir=$gitDir"/hooks"
echo "hooksDir=$hooksDir"
pre_hooks=$hooksDir"/"$precommitName
commit_hooks=$hooksDir"/"$commitName

# 創(chuàng)建一個.git目錄
if [ -d $gitDir ]
then
 echo "$gitDir exsit"
 if [ -d $hooksDir ]
  then
   echo "$hooksDir exsit"
  else
   echo "$hooksDir not exsit"
   # mkdir 創(chuàng)建一個新目錄
   mkdir $hooksDir
   echo "$hooksDir mkdir ok"
 fi
else
 echo "$gitDir not exsit"
 git init
 echo "git init ok"
fi
#復(fù)制 pre_commit 文件
if [ -e $pre_hooks ]
then
 echo "$pre_hooks exsit"
 if [ $action = "d" ]
 then
    rm -r $pre_hooks
    echo "$pre_hooks remove ok"
 else
    cp $sourcePrecommit $hooksDir
    chmod 777 $pre_hooks
    echo "$pre_hooks replace ok"
 fi
else
 echo "$pre_hooks not exsit"
 cp $sourcePrecommit $hooksDir
 chmod 777 $pre_hooks
 echo "$pre_hooks copy ok"
fi

#復(fù)制 commit-msg 文件  -e 判斷文件是否存在
if [ -e $commit_hooks ]
then
  echo "$commit_hooks exsit"
  if [ $action = "d" ]
  then
    # rm -r 遞歸刪除
    rm -r $commit_hooks
    echo "$commit_hooks remove ok"
  else
    # cp復(fù)制
    cp $sourceCommitmsg $hooksDir
    chmod 777 $commit_hooks
    echo "$commit_hooks replace ok"
  fi
else
 echo "$commit_hooks not exsit"
 cp $sourceCommitmsg $hooksDir
 chmod 777 $commit_hooks
 echo "$commit_hooks copy ok"
fi
#結(jié)束

三.如何集成到項目以及演示(以下演示都是基于Android studio以及Mac系統(tǒng))

1.Hook下5個配置文件在Project下的位置如圖:

1 配置文件位置

2.運(yùn)行hooks.sh,把pre-commit & commit-msg配置到 .git下。

第一步.找到Project下 .git中的hooks查看里面內(nèi)容(如果沒有初始化git,可以在命令行輸入git init, 也可以不初始化,hooks.sh腳本中配置了初始化git)。
2.1 腳本執(zhí)行前hooks下的內(nèi)容

第二步.在Android studio中的Terminal運(yùn)行命令cd hook,進(jìn)入hook文件。
2.2 進(jìn)入hook文件

第三步.輸入chmod 777 hooks.sh,給hooks.sh腳本增加可執(zhí)行權(quán)限。
2.3 給腳本添加可執(zhí)行權(quán)限

第四步.輸入./hooks.sh。這時候我們再打開 .git下的hooks會發(fā)現(xiàn)pre-commit & commit-msg已經(jīng)copy到該目錄下
2.4 執(zhí)行hooks.sh腳本
2.5 腳本執(zhí)行后hooks下的內(nèi)容

第五步.輸入cd ..,退出hook文件夾
2.6 退出hook文件夾

3.編寫一份Test代碼,然后輸入 git add. + git commit -m test提交(提交失敗)

package hulk.com;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void test(String s1, String s2, String s3, String s4, String s5, String s6) {

    }
}
3.1 提交失敗1

4.修改error級別錯誤代碼后,然后輸入 git add. + git commit -m test提交(提交失敗)

3.2 提交失敗2

5.輸入 git add. + git commit -m [update]test提交

3.3 提交成功

四.除了用shell腳本語言配置Hooks外,是否還能用其他腳本語言進(jìn)行配置?

內(nèi)置的腳本大多都是shell和PERL語言,但是我們可以使用任何腳本語言包括當(dāng)前市場上最火熱的Python語言,只要它們最后能編譯到可執(zhí)行文件當(dāng)中即可。每次腳本中的#!/bin/sh定義了你的文件將被如何解釋。比如,使用其他語言時你只需要將path改為你的解釋器的路徑。

五.Hooks檢查的優(yōu)勢之處與不足之處在哪

相對與代碼的自測,Hooks檢查可謂是進(jìn)了一大步,它是強(qiáng)制,一次配置終身檢查,它是自動的,即我們每次提交代碼時它都會自動攔截,它不但可以對你提交的內(nèi)容進(jìn)行檢查,還可以對你提交的日志進(jìn)行規(guī)范,使我們的每一次提交變得規(guī)范與嚴(yán)謹(jǐn)。但是它還是有不足之處,第一,它只能對當(dāng)前提交的代碼進(jìn)行檢查,我們無法追溯歷史代碼;第二,如果開發(fā)人員不對Hooks進(jìn)行配置或者對配置好的Hooks進(jìn)行修改,那么可以達(dá)到逃避檢查的目的。針對以上兩點(diǎn),我們就需要引入Jenkins打包時對代碼進(jìn)行進(jìn)一步掃描。


最后附上項目github地址:

hooks檢查.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容