二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Nexus系列文章

  • Jenkins系列文章

    • Jenkins入门系列笔记汇总整理
    • 前言与介绍
    • Jenkins初始部署与简单配置
    • Jenkins各配置选项介绍
    • Jenkins中一个项目的构建
    • Jenkins配置项目构建的钉钉通知
    • Jenkins忘记管理员密码怎么办
    • Jenkins与gitlab的交互探微
    • Jenkins根目录详解
    • Jenkins插件之显示构建时间
    • Jenkins插件之批量修改配置
    • Jenkins配置简单构建邮件推送
    • Jenkins复杂邮件推送配置详解
    • Jenkins配置复杂构建邮件推送
    • Jenkins构建安卓项目之前的一些唠叨
    • Jenkins构建安卓项目配置
    • Jenkins与Gitlab分支的交互
    • Jenkins构建nodejs项目
    • 使用docker部署Jenkins及初始配置
    • 配置gitlab提交代码Jenkins自动构建
    • Jenkins回滚方案探微
    • Jenkins角色控制(小黄锁)探微
    • Jenkins构建的应用配置问题解决探微
    • Jenkins构建中tag的应用
    • Jenkins插件之Ansicolor(神器)
    • 最基础核心的Jenkins功能部署一个java应用
    • Jenkins+sonar构建代码扫描
    • Jenkins+docker+gitlab将应用部署到docker
    • Jenkins参数化构建犀利插件Active-Choices-Plugin
    • 记一次将代码中参数外显到构建历史中的操作
    • Jenkins升级与迁移的经验分享
    • pipeline笔记之从一个简单的项目构建开始
    • Jenkinsfile声明式语法详解
    • 自动构建的原始配置以及pipeline中的用法
    • 多分支构建的实践与思考
    • 使用Jenkinsfile类前端项目的部署与回滚
    • 如何在Jenkinsfile中定义一个全局的时间戳变量
    • Jenkins中自由风格回滚方案的最佳实践
    • Jenkins中pipeline风格回滚方案的最佳实践
    • pipeline结合ansible剧本进行批量的部署与回滚配置
    • 最近配置安卓iOS打包本地化流程中一些值得记录的内容
    • pipeline中如何在environment环节声明一个含有通配符的变量
    • git-Parameter插件在pipeline共享库中的实践详解
    • jenkins作为ci检测代码是否合并的实践
    • 将Jenkins共享库的Jenkinsfile放到ci静态检测的实践
      • 1,前言
      • 2,调研
      • 3,准备
      • 4,验证
      • 5,实践
    • Jenkins的pipeline实践之GitSCM参数配置项详解
    • Jenkins中pipeline对接CMDB接口获取主机列表的发布实践
    • Jenkins有任务无法kill提示即将关闭
    • Jenkins基于Share Library共享库的最佳实践探索
    • Jenkins结合MySql Database插件的平台化实践思路
    • Jenkins-Groovy中三元表达式的用法
    • Jenkins-Groovy中Switch的高阶用法
    • Jenkins-pipeline之利用activity choice插件对接查询MySQL数据实现动态参数化的功能
    • CentOS通过yum快速安装Jenkins
    • Jenkins-pipeline语法之错误处理详解(文末有干货)
    • Jenkins常用插件汇总以及简单介绍
    • Jenkins所遇报错汇总及解决
    • Jenkins管理维护运维规范
  • ELK笔记

  • Kubernetes笔记

  • LLM专题

  • 系列专题
  • Jenkins系列文章
二丫讲梵
2021-08-28
目录

将Jenkins共享库的Jenkinsfile放到ci静态检测的实践

文章发布较早,内容可能过时,阅读注意甄别。

# 1,前言

我们所有的构建都已经托管在 Jenkins 上,Jenkins 所有的 Job 都采用的 pipeline 形式,pipeline 所有的引导文件都已经托管在 gitlab 统一调用共享库,共享库也都托管在 gitlab 像普通项目那样走开发-review 的流程进行上线。

but,有一个问题是,共享库这种提纲挈领的,以一持万的,纲举目张的存在,到如今都还没有走严格意义上的开发流程。事实上前几天已经吃过这种亏了,一个贡献库文件被上百个发布 job 引用非常常见,而因为运维同学稍稍粗心,少了个后关闭的大括号,push 到共享库之后就下班走人了,结果影响了不少项目的构建。而这种比较低级的错误,本来可以通过前置工作进行一些检测的。

# 2,调研

今天就来做一下共享库内主要发布逻辑脚本的语法静态检测,看了一下,网上有不少的相关资料,整理如下:

  • Jenkins 官方文档–管道开发工具 (opens new window)
  • stack overflow
    • Jenkins: How do I lint Jenkins pipelines from the command line? (opens new window)
  • jflint (opens new window)
    • 一个开源的检测工具,使用相当简便,本文使用这个。
  • npm-groovy-lint (opens new window)
    • 同样是一个检测工具,看起来功能更强大,有点复杂。

# 3,准备

有了如上介绍以及文档基础之后,我们选择 jflint 这个工具来进行检测,结合 jenkins 作为 ci 检测代码是否合并的实践 (opens new window)此文章配置流水线 ci,将共享库托管起来。

由于如上工具没有直接给到容器化的版本,所以我这里构建一个容器,读者可以直接拿去使用:

  • 官方:eryajf/jflint
  • 国内:registry.cn-hangzhou.aliyuncs.com/eryajf/jflint

简单查看:

$ docker run -it  eryajf/jflint  jflint -h
Usage: jflint [options] Jenkinsfile

Options:
  -v, --version                output the version number
  -j, --jenkins-url <url>      Jenkins URL
  -u, --username <username>    Username for Jenkins
  -p, --password <password>    Password or API Token for Jenkins
  --csrf-disabled              Specify if CSRF prevention is disabled on Jenkins
  -c, --config <path>          Path to config json file
  --ssl-verification-disabled  Disable SSL verification
  -h, --help                   output usage information
1
2
3
4
5
6
7
8
9
10
11
12

其中在构建镜像时,声明了两个 ENV,以便于调用:

ENV USER=admin
ENV PASS=admin
1
2

# 4,验证

此时准备一个非常简单的流水线作为测试使用:

cat >> test.jenkins << 'EOF'
pipeline {
    agent any
    environment {
        // 输出结果为 20200330142150_4
        _version = sh(script: "echo `date '+%Y%m%d%H%M%S'`" + "_${env.BUILD_ID}", returnStdout: true).trim()
    }
    stages {
        stage ("test") {
            steps {
                echo "${_version}"
            }
        }
    }
}
EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

然后运行如下命令进行检测:

$ docker run -itd --name jflint eryajf/jflint # 如果你的用户名密码并不是上边两个,可以通过-e进行覆盖
$ docker cp test.jenkins jflint:/opt
$ docker exec -it jflint jflint -u $USER -p $PASS -j https://ci.test.com /opt/test.jenkins
Jenkinsfile successfully validated.
1
2
3
4

此时将如上流水线进行简单调整:

cat >> test.jenkins << 'EOF'
pipeline {
    agent any
    environment {
        // 输出结果为 20200330142150_4
        _version = sh(script: "echo `date '+%Y%m%d%H%M%S'`" + "_${env.BUILD_ID}", returnStdout: true).trim()
    }
    stages {
        stage ("test") {
            steps {
                echo "${_version}"
            }
        }
    }
EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注意删除了最后一行的括号。

然后再次运行检测:

$ docker exec -it jflint jflint -u $USER -p $PASS -j https://ci.test.com /opt/test.jenkins
Errors encountered validating Jenkinsfile:
WorkflowScript: 14: expecting '}', found '' @ line 14, column 1.
1
2
3

可以看到不仅报错了,还提示了我们错误的行数,可以说非常清晰了。

11

# 5,实践

有了如上准备以及实验之后,我们就可以直接添加如下流水线,作为静态 ci 的配置信息:

pipeline {
    agent any
    environment {
        // 服务名称
        SERVICE_NAME="${JOB_BASE_NAME}"
        MODE="DEPLOY"
        REASON="无"
        REMOTE_HOST="占位"
        _VERSION="测试验证"
        ROBOT_KEY="6a781aaf-0cda-41ab-9bd2-ed81ee7fc7"
        // 主项目地址
        GIT_URL = "https://gitlab.test.com/jenkins/shared-library.git"
    }
    parameters {
        string(name: 'BRANCH', defaultValue: 'master', description: '请输入将要构建的代码分支')
    }
    options {
        timestamps() // 输出构建日志打印时间信息
        timeout(time: 10, unit: 'MINUTES') // 设置构建超时时间
        buildDiscarder(logRotator(numToKeepStr: '15')) // 设置历史构建保留次数
        gitLabConnection('gitlab-token') // 操作gitlab的token
    }
    triggers{
        gitlab(
            triggerOnPush: false,
            triggerOnMergeRequest: true,
            branchFilterType: 'All',
            secretToken: "${env.GIT_TOKEN}"
        ) // 预留Gitlab提交自动构建
    }
    stages {
        stage('置为pending') {
            steps {
                script {
                    try {
                        updateGitlabCommitStatus name: 'build', state: 'pending'
                    }catch(exc) {
                        env.REASON = "置为pending出错"
                        throw(exc)
                    }
                }
            }
        }
        stage('拉取代码') {
            steps {
                script {
                    try {
                        env.CAUSE = currentBuild.getBuildCauses()[0].(userId)
                        if ("${CAUSE}" == 'null') {
                            env.BRANCH = sh(script: 'echo ${gitlabBranch}',  returnStdout: true).trim()
                        }
                        checkout(
                            [$class: 'GitSCM', doGenerateSubmoduleConfigurations: false, submoduleCfg: [], extensions: [[$class: 'CloneOption', depth: 1, noTags: false, reference: '', shallow: true]],
                            branches: [[name: "$BRANCH"]],userRemoteConfigs: [[url: "${env.GIT_URL}", credentialsId: "cicd-pass"]]]
                        )
                        // 定义全局变量
                        env.COMMIT_ID   = sh(script: 'git log --pretty=format:%h',  returnStdout: true).trim() // 提交ID
                        env.COMMIT_USER = sh(script: 'git log --pretty=format:%an', returnStdout: true).trim() // 提交者
                        env.COMMIT_TIME = sh(script: 'git log --pretty=format:%ai', returnStdout: true).trim() // 提交时间
                        env.COMMIT_INFO = sh(script: 'git log --pretty=format:%s',  returnStdout: true).trim() // 提交信息
                    }catch(exc) {
                        env.REASON = "拉取代码出错"
                        throw(exc)
                    }
                }
            }
        }
        stage('检测项目') {
            steps {
                script {
                    try {
                        docker.image('eryajf/jflint').inside("-e USER=admin -e PASS=admin12345") {
                            sh '''
                                for i in `ls vars`;do
                                    jflint -u $USER -p $PASS -j https://ci.test.com vars/$i
                                done
                            '''
                        }
                        sh "printenv"
                    }catch(exc) {
                        env.REASON = "检测项目出错"
                        throw(exc)
                    }
                }
            }
        }
    }
    post {
        always {
            script{
                wrap([$class: 'BuildUser']){
                    buildName "#${BUILD_ID}-${BRANCH}-${BUILD_USER}" // 更改构建名称
                    currentBuild.description = "提交者: ${COMMIT_USER}" // 添加说明信息
                    currentBuild.description += "\n构建主机: ${REMOTE_HOST}" // 添加说明信息
                    currentBuild.description += "\n提交ID: ${COMMIT_ID}" // 添加说明信息
                    currentBuild.description += "\n提交时间: ${COMMIT_TIME}" // 添加说明信息
                    currentBuild.description += "\n提交内容: ${COMMIT_INFO}" // 添加说明信息
                }
                sh "printenv"
            }
            cleanWs()
        }
        success {
            updateGitlabCommitStatus(name: 'build', state: 'success')
            addGitLabMRComment comment: "🤖Jenkins ci check success🥳, see the log: ${BUILD_URL}console"
        }
        failure {
            updateGitlabCommitStatus(name: 'build', state: 'failed')
            addGitLabMRComment comment: "🤖Jenkins ci check failed🤯, see the log: ${BUILD_URL}console"
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

注意,基于容器运行的时候,可以通过后边的参数来指定自己的用户名信息,当然也可以使用 token 的方式。

这样我们就可以把共享库的维护,走类似常规项目开发的流程,通过 check 普通分支,走 merge 的方式,并且有静态自动检测语法,成功之后方可合并到主干分支,以期将影响降到最低。

微信 支付宝
#Jenkins
上次更新: 2025/03/06, 21:25:58
jenkins作为ci检测代码是否合并的实践
Jenkins的pipeline实践之GitSCM参数配置项详解

← jenkins作为ci检测代码是否合并的实践 Jenkins的pipeline实践之GitSCM参数配置项详解→

最近更新
01
睡着的人不关灯
06-12
02
学习周刊-总第215期-2025年第24周
06-12
03
学习周刊-总第214期-2025年第23周
06-05
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式