一、Groovy简明教程

1.1 Groovy简明教程

无论是声明式还是脚本式Pipeline 都依赖了 Groovy 脚本,所以如果要很好的掌握 Pipeline 脚本的用法,我们非常有必要去了解下 Groovy 语言。

1.2 什么是Groovy

Groovy 是跑在 JVM 中的另外一种语言,我们可以用 GroovyJava 平台上进行编程,使用方式基本与使用 Java 代码的方式相同,所以如果你熟悉 Java 代码的话基本上不用花很多精力就可以掌握 Groovy 了,它的语法与 Java 语言的语法很相似,而且完成同样的功能基本上所需要的 Groovy 代码量会比 Java 的代码量少。

官方网站:https://groovy.apache.org

1.3 环境搭建

要安装 Groovy 环境非常简单,前往官网网站下载对应的平台安装包一键安装即可:https://groovy.apache.org/download.html,我这里使用的是 Mac,当然也可以使用比较方便的 Homebrew 工具来进行一键安装:

$ brew install groovy

可以使用下面的命令查看 groovy 是否安装成功:

$ groovy -v
Groovy Version: 3.0.4 JVM: 13.0.2 Vendor: Oracle Corporation OS: Mac OS X

1.4 基本语法

1.4.1 运行方法

使用编辑器(vscode)新建一个 Groovy 文件 hello.groovy,文件内容如下:

class Example {
   static void main(String[] args) {
        // 使用 println 打印信息到 stdout
        /*除了上面的注释方法外这里没也是注释信息哦*/
        println 'Hello World'
        println "Hello World";
   }
}

如果你对 Java 代码较熟悉的话,可以看到上面的 Groovy 是非常类似的。

然后可以使用 groovy 命令运行上面的程序:

$ groovy 1hello.groovy
Hello World
Hello World
  • 从输出结果可以看出了 Groovy 里面支持单引号双引号两种方式,
  • 注释支持///**/两种方式,
  • 而且不以分号“;”结尾也可以,
  • 但是我们还是推荐都带上分号保持代码的一致性

1.4.2 标识符

标识符被用来定义变量,函数或其他用户定义的变量。标识符以字母、美元或下划线开头,不能以数字开头

以下是有效标识符的一些例子 :

def employeename 
def student1 
def student_name

其中,def是在 Groovy 中用来定义标识符的关键字。

如下代码:2datatype.groovy

class Example{
    static void main(String[] agrs){
        String x ="Happy";
        println(x);

        def _Holiday = "Mother's Day";
        println(_Holiday);
        println(x + " "+_Holiday);
    }
}

运行结果如下:

$ groovy 1hello.groovy
Happy
Mother's Day
Happy Mother's Day

1.4.3 数据类型

上述例子中我们定义了一个字符串 x 和一个标识符 _Name。当然除了字符串之外,Groovy 也支持有符号整数、浮点数、字符等:

class Example {
    static void main(String[] args) {
        String str = "Hello";  // 字符串
        int x = 5;  // 整数
        long y = 100L;  // 长整型
        float a = 10.56f;  // 32位浮点数 
        double b = 10.5e40;  // 64位浮点数
        char c = 'A';  // 字符
        Boolean l = true;  // 布尔值可以是true或falseprintln(str);
        println(x);
        println(y);
        println(a);
        println(b);
        println(c);
        println(l);
    }
}

运行结果如下:

$ groovy 2datatype.groovy
Hello
5
100
10.56
1.05E41
A
true
  • String => 字符串
  • int => 整数
  • long => 长整型
  • float => 32位浮点数
  • double => 64位浮点数
  • char => 字符
  • Boolean => 布尔值,可以是true或false。

1.4.4 打印变量

上面用 def 关键字来定义变量,当然也可以用一个确定的数据类型来声明一个变量,我们可以用下面的几种方式来打印变量:

class Example {
    static void main(String[] args) {
        // 初始化两个变量
        int x = 5; 
        int X = 6; 

        // 打印变量值
        println("x = " + x + " and X = " + X);  
        println("x = ${x} and X = ${X}");
        println('x = ${x} and X = ${X}');
    }
}

运行结果如下:

$ groovy 3Variable.groovy
x = 5 and X = 6
x = 5 and X = 6
x = ${x} and X = ${X}

从这里我们可以看出 Groovy单引号的字符串里面是不支持插值的,这点非常重要,很多同学在使用 Pipeline 脚本的时候经常会混淆。

除此之外,还支持三引号:

class Example {
    static void main(String[] args) {
        // 初始化两个变量
        int x = 5; 
        int X = 6; 

println """
x = ${x}
X = ${X}
"""

println '''
x = ${x}
X = ${X}
'''
    }
}

运行结果如下:

$ groovy 3Variable.groovy
x = 5
X = 6

x = ${x}
X = ${X}

可以看出 Groovy 里面三引号支持双引号和单引号两种方式,但是单引号同样不支持插值,要记住。

1.4.5 函数

Groovy 中的函数是使用返回类型或使用 def 关键字定义的,函数可以接收任意数量的参数,定义参数时,不必显式定义类型

可以添加修饰符,如 publicprivateprotected,默认情况下,如果未提供可见性修饰符,则该方法为 public,如下所示:

class Example {
   static def PrintHello() {
      println("This is a print hello function in groovy");
   } 

   static int sum(int a, int b, int c = 10) {
      int d = a+b+c;
      return d;
   }  

   static void main(String[] args) {
      PrintHello();
      println(sum(5, 50));
   } 
}
  • static def PrintHello(){}
  • static int sum(int a, int b, int c = 10) {}
  • static void main(String[] args) {}

运行结果如下:

$ groovy 4func.groovy
This is a print hello function in groovy
65

1.4.6 条件语句

在我们日常工作中条件判断语句是必不可少的,即使在 Jenkins Pipeline 脚本中也会经常遇到,Groovy 里面的条件语句和其他语言基本一致,使用 if/else 判断:

class Example { 
   static void main(String[] args) { 
      // 初始化变量值
      int a = 2

      // 条件判断
      if (a < 100) { 
         // 如果a<100打印下面这句话
         println("The value is less than 100"); 
      } else { 
         // 如果a>=100打印下面这句话
         println("The value is greater than 100"); 
      } 
   } 
}

运行结果如下:

$ groovy 5cond.groovy
The value is less than 100

1.4.7 循环语句

除了条件判断语句之外,循环语句也是非常重要的,Groovy 中可以使用三种方式来进行循环:whilefor语句for-in语句,如下:

class Example {
   static void main(String[] args) {
      int count = 0;
      println("while循环语句:");
      while(count<5) {
         println(count);
         count++;
      }

      println("for循环语句:");
      for(int i=0;i<5;i++) {
         println(i);
      }

      println("for-in循环语句:");
      int[] array = [0,1,2,3]; 
      for(int i in array) { 
         println(i); 
      } 

      println("for-in循环范围:");
      for(int i in 1..5) {
         println(i);
      }
   }
}

运行结果如下:

$ groovy 6loop.groovy
while循环语句:
0
1
2
3
4
for循环语句:
0
1
2
3
4
for-in循环语句:
0
1
2
3
for-in循环范围:
1
2
3
4
5

上面是常用的三种循环方式,其中一个比较特殊的地方是我们可以用..来定义一个数据范围,比如1:5表示1到5的数组

另外我们还可以使用for-in来循环 Map,Map(字典)是我们在编写程序的过程中会镜像使用到的数据结构,大部分的编程语言都是使用{}来定义 Map,而在 Groovy 中有点不一样的地方,是使用[]来定义的 Map,如下所示:

class Example {
   static void main(String[] args) {
       // 定义一个Map
      def ageMap = ["Ken" : 21, "John" : 25, "Sally" : 22];

      for(am in ageMap) {
         println(am);
      }
   }
}

运行结果如下:

$ groovy 7map.groovy
Ken=21
John=25
Sally=22

除了上面这些最基本的特性外,Groovy 还支持很多其他的特性,比如异常处理、面向对象设计、正则表达式、泛型、闭包等等,由于我们这里只是为了让大家对 Jenkins Pipeline 的脚本有一个基本的认识,更深层次的用法很少会涉及到.

二、Groovy基础

2.1 字符串与列表

2.1.1 Groovy - 简介

  • Groovy是一种功能强大,可选类型和动态语言,支持Java平台
  • 旨在提高开发人员的生产力得益于简洁,熟悉且简单易学的语法
  • 可以与任何Java程序顺利集成,并立即为您的应用程序提供强大的功能, 包括脚本编写功能,特定领域语言编写,运行时和编译时元编程以及函数式编程

Alt Image Text

2.1.2 Install Groovy

https://groovy-lang.org/install.html

You should now have Groovy installed properly. You can test this by typing the following in a command shell:

groovysh
$ groovysh
Groovy Shell (3.0.4, JVM: 13.0.2)
Type ':help' or ':h' for help.
--------------------------------------------------------------------------------------------------------------------------------------------------------
groovy:000> println("hello world");
hello world
===> null

Which should create an interactive groovy shell where you can type Groovy statements.

groovyConsole

Alt Image Text

To run a specific Groovy script type:

groovy SomeScript

2.1.3 Groovy数据类型

  • 字符串表示:单引号、双引号、三引号
  • 常用方法:
    • contains()工是否包含特定内容返回true false
    • size() length()字符串数量大小长度
    • toString() 转换成string类型 indexOf()
    • 元素的索引 endsWith() 是否指定字符结尾
    • minus() plus() 去掉、增加字符串
    • reverse() 反向排序
    • substring(1,2)字符串的指定索引开始的子字符串
    • toUpperCase() toLowerCase()字符串大小写转换
    • split()字符串分割默认空格分割返回列表
groovy:000> "devsecurityops".contains("ops")
===> true
groovy:000> "devsecurityops".contains("users")
===> false
groovy:000> "devsecurityops".endsWith("ops")
===> true
groovy:000> "devsecurityops".endsWith("abc")
===> false
groovy:000> "devsecurityops".length()
===> 14
groovy:000> "devsecurityops".size()
===> 14
groovy:000> "dev"+"ops"
===> devops
groovy:000> "devops" - "dev"
===> ops
groovy:000> "devops".toUpperCase()
===> DEVOPS
groovy:000> "DEVOPS".toLowerCase()
===> devops
 "dev1,dev2,dev3"
===> dev1,dev2,dev3

groovy:000>  "host1,host2,host3".split(',')
===> [host1, host2, host3]

groovy:000> hosts = "host1,host2,host3".split(',')
===> [host1, host2, host3]

groovy:000> for( i in hosts){
groovy:001>   println(i)
groovy:002> }
host1
host2
host3
===> null

groovy:000> result = [1,2,3,4].add(5)
===> true

2.1.4 Groovy数据类型一list

  • 列表符号:[]
  • 常用方法
    • + - + -= 元素增加减少
    • add() << 添加元素
    • isEmpty()判断是否为空
    • intersect([2,3]) disjoint([1]) 取交集、判断是否有交集
    • flatten() 合并嵌套的列表
    • unique()去重
    • reverse() sort()反转升序
    • count() 元素个数
    • join() 将元素按照参数链接
    • sum() min() max() 求和最小值最大值
    • contains() 包含特定元素
    • remove(2) removeAll()
    • each{}遍历
groovy:000> []
===> []
groovy:000> [1,2,3,4] + 4
===> [1, 2, 3, 4, 4]
groovy:000> [1,2,3,4] + 46
===> [1, 2, 3, 4, 46]
groovy:000> [1,2,3,4] << 14
===> [1, 2, 3, 4, 14]
groovy:000> result = [1,2,3,4].add(5)
===> true
groovy:000> print(result)
true===> null
groovy:000> [2,3,4,5,6,6,6].unique()
===> [2, 3, 4, 5, 6]
groovy:000> [2,3,4,5,6,6,6].join("-")
===> 2-3-4-5-6-6-6
groovy:000> [2,3,4,5,6,6,6].each{
groovy:001> println it}
2
3
4
5
6
6
6
===> [2, 3, 4, 5, 6, 6, 6]

2.2 字典条件语句与循环

本节介绍 Groovy 基础语法中的字典条件语句循环语句。

2.2.1 Groovy数据类型一Map

  • 表示: [:]
  • 常用方法:
    • size() map 大小
    • ['key'].key get() 获取value
    • isEmpty () 是否为空 containKey () 是否包含key
    • containValue ()是否包含指定的value
    • keySet () 生成key的列表
    • each{}遍历map
    • remove( 'a')删除元素(k-v)
groovy:000> [:]
===> [:]
groovy:000> [1:2]
===> [1:2]
groovy:000> [1:2][1]
===> 2

groovy:000> [1:2,3:4,5:6].keySet()
===> [1, 3, 5]
groovy:000> [1:2,3:4,5:6].values()
===> [2, 4, 6]

groovy:000> [1:2,3:4,5:6]+[7:8]
===> [1:2, 3:4, 5:6, 7:8]

groovy:000> [1:2,3:4,5:6]-[1:2]
===> [3:4, 5:6]

2.2.2 Groovy条件语句一if

if(表达式){ 
    //xxxx 
    } else if(表达式2) {
    //xxxxx 
    } else { 
    // 
    } 
groovy:000> buildType = "maven"
===> maven
groovy:000> if (buildType == "maven"){
groovy:001>   println("This is a maven project");
groovy:002> } else if(buildType == "gradle"){
groovy:003>   println("project type error");
groovy:004> }
This is a maven project
===> null

2.2.3 Groovy条件语句一switch

switch(" ${buildType}")
{ 
    case: "maven":
    //xxxx 
    break;
    case "ant": 
    //xxxx 
    break; 
    default:
    //xxxx 
}
buildType = "maven";
switch("${buildType}"){ 
case 'maven': 
    println("This is a maven project !"); 
    break;
    ;;
    case 'gradle': 
    println("This is a gradle projects !"); 
    break;
    ;; 
    default: 
    println("Project Type Error");
    ;;
}
$ groovy switch.groovy 
This is a maven project !
groovy:000> langs = ["java","python","ruby"]
===> [java, python, ruby]

$ groovy for.groovy 
lang is java
lang is python
lang is ruby

2.3 函数使用

2.3.1 def定义函数语法

 def PrintMes(Value){ 
    printin(Value) 
    //xxxx 
    return value 
 } 
def PrintMes(info){ 
    println (info) 
    return info 
} 

response = PrintMes("DevOps") 
println(response) 

2.3.2 Groovy正则表达式

@NonCPS 
String getBranch(String branchName){ 
    def matcher = (branchName =~ "RELEASE-[0-9]{4}") 
    if (matcher.find()) { 
        newBranchName = matcher[0] 
        } else { 
        newBranchName = branchName 
        ) 
    newBranchName 
} 

newBranchName = getBranch(branchName) 
println("New branch Name" ----> ${newBranchName}") 

2.4 常用的Pipeline DSL方法

2.4.1 常用DSL- readJSON- JSON数据格式化

def response = readJSON text: "${scanResult}" 
println(scanResult) 

//原生方法

import groovy.json.* 

@NonCPS 

def GetJson(text) {
    def prettyJson = JsonOutput.prettyPrint(text) 
    new JsonSlurperClassic().parseText(prettyJson) 
}

2.4.2 常用DSL-withCredentials

withCredentias([string(credentialsId: "xxxxx", variable: "sonarToken")])
{ 
    printin(sonarToken) 
} 

2.4.3 常用DSL一checkout

//Git 
checkout([$class: 'GitSCM', branches:  [[name: "branchName"]],          
            doGenerateSubmoduleConfigurations: false, 
            extensions: [], submoduleCfg: [], 
            userRemoteConfigs: [[credentialsId: "${credentialsId}", 
            url: "${srcUrl}"]]])

//Svn 
checkout([$class: 'SubversionSCM', additionalCredentials: [], 
            filterChangelog: false, ignoreDirPropChanges: false, 
            locations: [[credentialsId: "${credentialsId}", 
            depthOption: 'infinity', ignoreExternalsOption: true, 
            remote: "${svnUrl}"]], workspaceUpdater: [$class: 'CheckoutUpdater']] 
) 

2.4.4 常用DSL一publishHTML

publishHTML([allowMissing: false, 
    alwaysLinkToLastBuild: false, 
    keepAll: true, 
    reportDir: './report/', 
    reportFiles: "a.html, b.html", 
    reportName: 'InterfaceTestReport', 
    reportTitles: 'HTML'
])

2.4.5 常用DSL一input

def result = input message: '选择xxxxx, 
                ok: '提交',
                parameters: [extendedChoice( 
                        description: 'xxxxx', 
                        descriptionPropertyValue:'', 
                        multiSelectDelimiter: ',', 
                        name: 'failePositiveCases', 
                        quoteValue: false, 
                        saveJSONParameterToFile: false, 
                        type: 'PT_CHECKBOX', 
                        value: "1,2,3", 
                        visibleltemCount: 99)] 
println(result) 

2.4.6 常用DSL-BuildUser

wrap([$class: 'BuildUser']) {
    echo "full name is $BUILD_USER" 
    echo "user id is $BUILD_USER_ID" 
    echo "user email is $BUILD_USER_EMAIL"  
}

2.4.7 常用DSL一httpRequest

ApiUrl = "http://xxxxxx/api/project_branches/list?project=${projectName}" 
Result = httpRequest authentication: 'xxxxxxxxx', 
    quiet: true, 
    contentType: 'APPLICATION_JSON' , 
    url: "${ApiUrl}" 

2.4.8 常用DSL一email

Alt Image Text