Jenkins Pipeline 扩展使用外部共享库(Shared Libraries)

官方文档 - Extending with Shared Libraries
CloudBees - getting-started-with-shared-libraries-in-jenkins
CloudBees - github - pipeline-library
CloudBees - github - global-library-课程范例
How To Use Shared Libraries In A Jenkins Pipeline?

一、Shared Libraries 简介

1、Directory structure

Shared Library repository 的结构

(root)
+- src                     # Groovy source files
|   +- org
|       +- foo
|           +- Bar.groovy  # for org.foo.Bar class
+- vars
|   +- foo.groovy          # for global 'foo' variable
|   +- foo.txt             # help for 'foo' variable
+- resources               # resource files (external libraries only)
|   +- org
|       +- foo
|           +- bar.json    # static helper data for org.foo.Bar
  • src 目录类似标准的Java源目录。在执行Pipeline的时候会被添加到classpath
  • vars 目录存放脚本文件,这些文件在Pipelines中作为变量。文件的名称就是Pipeline中变量的名称。比如存在文件vars/log.groovy,文件下存在函数 def info(message)…,那么在Pipeline以 log.info "hello world"的方式访问。
  • resources 目录允许扩展库使用 libraryResource step 加载非Groovy文件。目前内部库不支持此功能。参考Loading resources

2、Global Shared Libraries

  • 推荐方式
  • 通过 Manage Jenkins » System » Global Pipeline Libraries 进行配置,然后在pipeline调用。详情参见下文 使用 libraries

3、Folder-level Shared Libraries

https://stackoverflow.com/questions/37800195/how-do-you-load-a-groovy-file-and-execute-it

或许有其他使用方法,如下范例是文件级别,并非目录级别的共享库。

范例

  • 创建测试groovy文件 /opt/jenkins_library_test/Tools.groovy
public class Demo {
    String message;
     
    Demo(String message) {
        this.message = message;
    }

    public void print(def script) {
        script.sh "echo " + message
    }
}

Demo createDemo(String message) {
    new Demo(message)
}

return this
  • 编辑pipeline script
    声明式 pipeline 如下
pipeline {
    agent any

    stages {
        stage('Hello') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Demo stage') {
            steps {
                script {
                    Object lib = load '/opt/jenkins_library_test/Tools.groovy'
                    Object demo = lib.createDemo('a demo')
                    demo.print(this)
                }
            }
        }
    }
  }

脚本式pipeline 如下

node {
    stage('Hello') {
        echo 'Hello World'
    }
    stage('Demo stage') {
        script {
            Object lib = load '/opt/jenkins_library_test/Tools.groovy'
            Object demo = lib.createDemo('a demo')
            demo.print(this)
        }
    }
}
  • 执行结果如下


    image.png

4、Automatic Shared Libraries

其他插件有更多动态定义库的方法。如 Pipeline: GitHub Groovy Libraries 插件,允许无需配置即可使用不可信任的库,比如github.com/someorg/somerepo。指定库会以匿名 checkout 的方式 从 master 分支加载。

二、使用 libraries

1、常规调用

Jenkinsfile 使用 @Library 标识符,加 library 的名字,来进行调用。示例如下:

@Library('my-shared-library') _
/* Using a version specifier, such as branch, tag, etc */
@Library('my-shared-library@1.0') _
/* Accessing multiple libraries with one statement */
@Library(['my-shared-library', 'otherlib@abc1234']) _
@Library('somelib')
import com.mycorp.pipeline.somelib.UsefulClass

当引用 class librarysrc/目录)时,@注释需要在 import语句上面
annotation 帮助文档

对于只定义了全局变量 Global Variables (vars/) 的 Shared Libraries,或只需要全局变量的 Jenkinsfile@Library('my-shared-library') _ 的注释格式有助于保持代码简洁。本质上,是注释 _,而非不必要的 import

不建议 import 全局变量/函数,即便是实例,这也会强迫编译器将字段和方法解释为 static ,这种情况下 Groovy compiler 会报错。

Libraries 在脚本执行前的编译过程被解析、加载。这就允许 Groovy compiler 在静态类型检查时理解所使用符号的含义,并允许它们在脚本中的类型声明中使用,例如:

这允许Groovy编译器理解静态类型检查中使用的符号的含义,并允许它们在脚本中的类型声明中使用,例如:

@Library('somelib')
import com.mycorp.pipeline.somelib.Helper

int useSomeLib(Helper helper) {
    helper.prepare()
    return helper.count()
}

echo useSomeLib(new Helper('some text'))

Global Variables 在 runtime 中被解析。

2、动态加载 Loading libraries dynamically

自插件 Pipeline: Shared Groovy Libraries 2.7 版本后,有一种动态加载library的方法(library step )。

官方描述不严谨。Pipeline: Shared Groovy Libraries 已退役,代替以 Pipeline: Groovy Libraries
参见说明文档:https://plugins.jenkins.io/workflow-cps-global-lib/

library 'my-shared-library'

然后,脚本就可以访问该 library 中的任何全局变量了。

访问 src/ 目录下的 class 也可以,略麻烦。@Library 在编译前已经设定好了 classpath,到library step的时候脚本已经编译完毕了。因此,不能importstatic类型引用。

但是,您可以动态地使用 library classes(不进行类型检查),通过 library step 返回值中的完全限定名称来访问。静态方法可以通过类似Java的语法调用:

library('my-shared-library').com.mycorp.pipeline.Utils.someStaticMethod()

当使用 new 的静态方法时,也是可以访问静态字段,并调用构造函数的:

def useSomeLib(helper) { // dynamic: cannot declare as Helper
    helper.prepare()
    return helper.count()
}

def lib = library('my-shared-library').com.mycorp.pipeline // preselect the package

echo useSomeLib(lib.Helper.new(lib.Constants.SOME_TEXT))

3、版本设定 Library versions

@Library('my-shared-library') _
@Library('my-shared-library@master') _
library 'my-shared-library@master'
library "my-shared-library@$BRANCH_NAME"

# 根据传递的参数设定版本
properties([parameters([string(name: 'LIB_VERSION', defaultValue: 'master')])])
library "my-shared-library@${params.LIB_VERSION}"

4、获取库的方法 Retrieval Method

  • 使用 Modern SCM ,仅当老版本不支持Shared Libraries的新特性时使用 Legacy SCM

Jenkins -- 系统管理 -- 系统配置 -- Global Pipeline Libraries

Sharable libraries available to any Pipeline jobs running on this system. These libraries will be trusted, meaning they run without “sandbox” restrictions and may use @Grab.

范例:
Name: cloudbee-sample-library
项目仓库: https://github.com/darinpope/github-api-global-lib

如果library step指定了library名称,Jenkins将查找该名称的预配置库。
也可以指定动态检索方法,无需在Jenkins中预先配置。
如下范例:

library identifier: 'custom-lib@master', retriever: modernSCM(
  [$class: 'GitSCMSource',
   remote: 'git@git.mycorp.com:my-jenkins-utils.git',
   credentialsId: 'my-private-key'])

该方式必须指定版本
更多关于SCM的语法,参考 Pipeline Syntax

5、范例

配置 Global Share Libraries 如下:

Name: cloudbee-sample-library
项目仓库: https://github.com/darinpope/github-api-global-lib

pipeline script

library 'cloudbee-sample-library'
node {
    stage('test') {
        helloWorld(name:"Darin", dayOfWeek:"Tuesday")
    }
}
image.png

修改如下

library 'cloudbee-sample-library@main'

这边的分支是 main , 不是 master。继续执行,如图。


image.png

三、编写 libraries

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容