Jenkins实现持续集成中的那些坑

小伙伴在《这些年我们一起搞过的持续集成~Jenkins+Perland Shell script》中详细介绍了优化后的job流,接下来总结一下在构建这一套job中遇到的Shell  Script和Jenkins的问题。

1.      比较两个文件后有特殊字符< 会导致Jenkins job failure;

图片1

解决方法:过滤特殊字符<同时利用diff–b去除最后的错位行,更多diff使用请参考diff--help;

-------------1)

[annzan@vm10226address]$ diff current.txt base.txt

1,2d0

<annzan

<wadexu

52c50

<davima

---

>davima

-----------2)

[annzan@vm10226address]$ diff -b current.txt base.txt

1,2d0

<annzan

<wadexu

-------------3)

[annzan@vm10226address]$ diff -b current.txt base.txt | grep "<"|sed 's/^<//g'

annzan

wadexu

 

2.      awk按分隔符分段输出,例如 echo $PROJECT_LIST|awk –F “,”‘{print $1}’ 。 将PROJECT_LIST遍历输出,需要参数化输出段数,$$id肯定是不行的;

解决方法: echo $PROJECT_LIST|awk  -v id=$id  -F”,” ‘{print$id}’

这边之前也试过cut这个命令去分隔字符串, echo $PROJECT_LIST|cut  -f $id  -d “,” 但是这里有个问题,当PROJECT_LIST中没有,这个分隔符的时候,不论id是几结果都是本身。所以cut命令无法实现我们想要遍历所有project的初衷,除非强制PROJECT_LIST一定要有一个分隔符。

 

3.      用curl命令调用下一个job大大提高了我们job流程的灵活机动性,同时用data json将参数值也一起传递到下一个job,实现我们整个流程的参数化。

curl -X POST --user "jadmin:71103407"-s http://vm10686.global.test.net:8080/view/Template/job/Template_Service_Commit_Auto_Build/build --data json='{"parameter":[{"name":"PROJECT_NAME","value":"'$projectName'"},{"name":"PIPELINE_NUM","value":"'$BUILD_NUMBER'"}]}' 

注意: value后面双引号里面直接加值,如果是参数的话,需要在参数名外面加单引号。

 

4.       这里着重讲一下我们遇到的天坑,单引号,双引号再顺便提一下反引号和反斜杠。[转自互联网]

 1. 单引号( '' ) 
# grep Susan phonebook 
Susan Goldberg 403-212-4921 
Susan Topple 212-234-2343 
如果我们想查找的是SusanGoldberg,不能直接使用grep Susan Goldberg phonebook命令,grep会把Goldbergphonebook当作需要搜索的文件 
# grep 'Susan Gold' phonebook 
Susan Goldberg 403-212-4921 
shell碰到第一个单引号时,它忽略掉其后直到右引号的所有特殊字符 

2. 双引号( " " ) 
双引号作用与单引号类似,区别在于它没有那么严格。单引号告诉shell忽略所有特殊字符,而双引号只要求忽略大多数,具体说,括在双引号中的四种特殊字符不被忽略:$,\,`,!,即双引号会解释字符串的特别意思,而单引号直接使用字符串.如果使用双引号将字符串赋给变量并反馈它,实际上与直接反馈变量并无差别。如果要查询包含空格的字符串,经常会用到双引号。 
# x=* 
# echo $x 
hello.sh menus.sh misc.sh phonebook tshift.sh 
# echo '$x' 
$x 
# echo "$x" 

这个例子可以看出无引号、单引号和双引号之间的区别。在最后一种情况中,双引号告诉shell在引号内照样进行变量名替换,所以shell$x替换为*,因为双引号中不做文件名替换,所以就把*作为要显示的值传递给echo对于第一种情况需要进一步说明,shell在给变量赋值时不进行文件名替换(这从第三种情况中也能看出来),各步骤发生的精确次序如下: shell扫描命令行,把x的值设为星号* 
shell再次扫描命令行,碰到星号*,把它替换成当前目录下的文件清单; 
shell启动执行echo命令,把文件清单作为参数传递给echo. 
这个赋值的先后次序非常重要:shell先作变量替换,然后作文件名替换,最后把这行处理为参数 

3. 反引号(``) 
命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置。shell中有两种方法作命令替换:把shell命令用反引号或者$(...)结构括起来,其中,$(...)格式受到POSIX标准支持,也利于嵌套。 
# echo The date and time is `date` 
The date and time is 6 15 06:10:35CST 2005 
# echo Your current working directory is $(pwd) 
Your current working directory is/ home/annzan/test

4. 反斜杠backslash-escaped( \ ) 
反斜杠一般用作转义字符,或称逃脱字符,linux如果echo要让转义字符发生作用,就要使用-e选项,且转义字符要使用双引号 
echo -e "\n" 
反斜杠的另一种作用,就是当反斜杠用于一行的最后一个字符时,shell把行尾的反斜杠作为续行,这种结构在分几行输入长命令时经常使用

 

5.      由单双引号引发的血案还有很多,比如下面遇到的中括号,if后面加中括号,注意加空格,可是结果却总是不对:


整了半天发现还是双引号的问题,字符串比较需要把$test放在双引号里,或者在外面再加一个中括号:

 


6.      grep和egrep的使用区别

1)     grep  [option]  pattern  filename 注意: pattern如果是表达式或者超过两个单词的, 需要用引号引用. 可以是单引号也可双引号, 区别是单引号无法引用变量而双引号可以.

2)     egrep= grep -E 可以使用基本的正则表达外, 还可以用扩展表达式. 注意区别.
扩展表达式:
+ 匹配一个或者多个先前的字符, 至少一个先前字符.
? 匹配0个或者多个先前字符.
a|b|c 匹配a或b或c
() 字符组, 如: love(able|ers) 匹配loveable或lovers.
(..)(..)\1\2 模板匹配. \1代表前面第一个模板, \2代第二个括弧里面的模板.
x{m,n} =x\{m,n\} x的字符数量在m到n个之间.

具体使用请参考grep –help;  egrep -- help


7.      当参数名是参数时,取值用eval。 例如configfile中每个定义两个project的GIT_PROJECT_NAME,用projectname作为前缀:

PROA_GIT_PROJECT_NAME=git_proa

PROB_GIT_PROJECT_NAME=git_prob

当用project name作为参数时,$($PROJECT_NAME_GIT_PROJECT_NAME)是没有这种写法的,正确取值如下: GIT_PROJECT_NAME=${PROJECT_NAME}"_GIT_PROJECT_NAME"

GIT_PROJECT_NAME=$(eval echo\${$GIT_PROJECT_NAME})

 

8.      大侠用perl语言写了打包安装等核心功能,需要执行这些脚本前,需要把脚本路径加到path里,要不然有核心代码也执行不了:

1)     把路径添到PATH路径里面

       cd ${SCRIPTS_HOME}

       chmod 755 *

       export PATH=$PATH:`pwd`

2)      直接修改.bashrc文件

 [annzan@vm10876 ~]$ vim .bashrc

文件被打开如下 
# .bashrc 
# Source global definitions 
if [ -f /etc/bashrc ]; then 
. /etc/bashrc 
fi 
# User specific aliases and functions 
export PATH=/home/annzan/bin:$PATH 
-----增加自己的Path,在已有:$PATH的之前 保存并退出 
[annzan@vm10876 ~]$ . .bashrc 
.相当于source让修改生效 
[annzan@vm10876 bin]$ echo $PATH 
/home/annzan/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin

 

9.      上面讲到.bashrc文件,就顺便记录一下.bashrc和.bash_profile文件的区别:

/etc/profile: 此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行。并从/etc/profile.d目录的配置文件中搜集shell的设置;
/etc/bashrc: 为每一个运行bashshell的用户执行此文件.当bashshell被打开时,该文件被读取;
~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件;
~/.bashrc:该文件包含专用于你的bashshell的bash信息,当登录时以及每次打开新的shell时,该文件被读取;
~/.bash_logout:当每次退出系统(退出bashshell)时,执行该文件;
另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是"父子"关系。
 
~/.bash_profile 是交互式、login方式进入bash 运行的
~/.bashrc 是交互式non-login 方式进入bash 运行的
通常二者设置大致相同,所以通常前者会调用后者。

设置生效:可以重启生效,也可以使用命令:source

 

10.  小数之间的比较用bc, 不是整数比较,不可以简单的用大于小于来比较;

if [ $(echo "$code_coverage_integer< $SONAR_MIN_COVERAGE" | bc) ]   or

if (( $(echo "$code_coverage_integer< $SONAR_MIN_COVERAGE" | bc) ))

注意 : 对于数据比较有以下两种格式:

 

以下是文件,字符串和算术比较运算符:

 

11.  换行问题;

1)     字符串换行:

mail_body="Hi,${PROJECT_NAME}"" project member"$'\n'"Alerts"

2)     echo写入文件换行:

         echo -e "exportCONFIG_TIME=${CURRENT_TIME}\n

                        exportPROJECT_LIST=${PROJECT_LIST}\n

                        exportSHARED_FOLDER=~/jenkins/common\n" > config.txt

 

12.  通过git commit hash来判断代码有没有更新,取当前commit hash与base hash对比,有不一样,打包安装,并把当前的commithash放入base文件;同理,取出当前所有的author list,与base list对比,取出代码修改的所有作者。

               git log --max-count=1--pretty=format:"%H" > ${CURRENT_MD5_FILE}  

               gitlog --pretty=format:"Author: %an" > ${CURRENT_AUTHOR_LIST}

   Refer to git log paras: https://www.kernel.org/pub/software/scm/git/docs/git-log.html   

 

13.  从pom.xml 文件中取一指定节点的值:


例如<name>testService</name>,取testService值: 

1)sed -n'/name/{s/.*<name>\(.*\)<\/name>.*/\1/p;q;}' pom.xml

2)catpom.xml|sed -n '/name/p'|awk -F "[<>]" '{print $3}'

如果取的值是一个数字,例如<num>12</ num >,我们可以通过取数字得到;

 cat pom.xml | sed -n '/ num /p' | sed -r's/([^0-9]*([0-9]*)){1}.*/\2/'      

 但是当num显示的值为1,000时,就只能取到1 而 不是1,000。所以 还是上面两种方法比较奏效。

 

14.  JSON对象取值,示例如下:

JSON 对象:

 response='{"name"="annzan","value"="test"}'

用如下方法取值:

function jsonValue(){

KEY=$1

VALUE=$2

awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${VALUE}p

}

如果要取到name里的值annzan,调用jsonValue方法并输入相应的Key值:

 

15.  在linux系统中,可以使用mount命令挂载光盘镜像文件、移动硬盘、U盘以及Windows网络共享和UNIX NFS网络共享等,这里主要介绍一下Linux系统中NFS文件共享;

1) 首先要看一下需要被挂载盘的文件地址:  df  /mnt/ifs10001

2)在需要挂载的系统中创建相应文件夹:mkdir /mnt/ifs10001

3)实现挂载共享文件:mount -t nfs isiloncwy0001.transfer.test.net:/ifs/data/transfer/clients /mnt/ifs10001 

具体可以参考http://www.jb51.net/os/RedHat/1109.html

 

16.  Jenkins自身设定的按时启动job,时间是有延迟的,比如我设置为下午4点,可是却发现没有动静,后来发现每天都是4点15运行job。而且这个设置的时间是jenkins服务器的时间不是本机时间。设置格式如下:

例如设置每周一到周五,3点钟执行job。设置定时任务:  H 3 * *  1-5 

    

17.  Jenkins中执行job前大都需要先export 环境变量,我们可以不需要手动写shell 脚本,可以在Jenkins Nodeconfig页面设置Node属性,如下图:

 

 

18.  除了在Node端设置环境变量,我们也可以在Jenkins系统设置进行全局设置,例如MAVEN_OPTS或者账号密码, $ENV{USERNAME}即为调用账号;

 

19.  因为我们现在用Git管理代码库,所以在Jenkins中要checkout代码,需要先设置git账号,把key配置在Jenkins的ManageCredentials中,如下图:

 

 

 

展开阅读全文

没有更多推荐了,返回首页