在gitlab通過webhook觸發Jenkins的job中用script獲取當前分支

webhook給jenkins發了什麼

gitlab觸發jenkins的job是通過webhook完成的,也就是一次http請求,請求體在jenkins的job的ConsoleOutput中可以看到。長這樣子(網頁上的json是一坨,這裏format了一下):

GenericWebhookEnvironmentContributor
 Received:

{
    "object_kind": "push",
    "before": "0000000000000000000000000000000000000000",
    "after": "1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
    "ref": "refs/heads/xxx-dev",
    "checkout_sha": "1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
    "message": null,
    "user_id": 142,
    "user_name": "xxx",
    "user_email": "[email protected]",
    "project_id": 531,
    "repository": {
        "name": "test",
        "url": "ssh://[email protected].*.*:*/test.git",
        "description": "test",
        "homepage": "http://172.16.*.*:*/test",
        "git_http_url": "http://172.16.*.*:*/test.git",
        "git_ssh_url": "ssh://[email protected].*.*:*/test.git",
        "visibility_level": 10
    },
    "commits": [
        {
            "id": "1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
            "message": "test\n",
            "timestamp": "2020-03-17T21:34:10+08:00",
            "url": "http://172.16.*.*:*/test/commit/1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
            "author": {
                "name": "xxx",
                "email": "[email protected]"
            }
        }
    ],
    "total_commits_count": 1
}

找對分支名了嗎

在單元測試之類的觸發中,通常需要跑pipeline的分支是不可預知的,這就需要在jenkins腳本中進行動態獲取。我們可以注意到上面有一個字段ref的值爲refs/heads/xxx-dev,看上就是他了,但實際上這是不能用的,我們先試一下。

在jenkinsJob的Post content parameters中配置了ref後,就可以獲取到ref的值:

node(label) {
    println ref
}

這裏println是groovy的語法,jenkins的PiplineScript基本上就是groovy。

然後我們來試一下直接用ref當分支:

node(label) {
    stage('test') {
        dir('/home/jenkins/agent/workspace/test') {
            git branch: ref, credentialsId: 'xxxx', url: 'http://172.16.*.*:*/test.git'
        }
    }
}

然後會看到這樣的報錯:

using GIT_ASKPASS to set credentials 
 > git fetch --tags --force --progress -- http://172.16.*.*:*/test.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git rev-parse refs/remotes/origin/refs/heads/xxx-dev^{commit} # timeout=10
 > git rev-parse refs/remotes/origin/origin/refs/heads/xxx-dev^{commit} # timeout=10
 > git rev-parse origin/refs/heads/xxx-dev^{commit} # timeout=10

...

ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.

第一種方法調整分支

我們有兩個辦法讓jenkins拿到準確分支,先說第一種,checkout的方式:

node(label) {
    stage('test') {
        dir('/home/jenkins/agent/workspace/test') {
            git branch: 'develop', credentialsId: 'xxxx', url: 'http://172.16.*.*:*/test.git'
            sh '''
            git checkout ${ref##*/}
            '''
        }
    }
}

在script裏調用sh來實現checkout,這裏${ref##*/}就是xxx-dev,如果寫${ref#*/}就是heads/xxx-dev,如果寫${ref}就是refs/heads/xxx-dev

但是有些情況下,checkout會報錯:

+ git checkout xxx-dev
error: The following untracked working tree files would be overwritten by checkout:
vendor/github.com/PuerkitoBio/purell/.gitignore
vendor/github.com/PuerkitoBio/purell/.travis.yml
...

這時我們就該考慮能不能讓jenkins上來就在指定分支上工作呢,其實是可以的,我們來看第二種方法。

第二種方法調整分支

第二種方法就是藉助groovy代碼對ref變量做手腳,簡單思路就是用split函數將字符串分割,然後取後面的部分。

ref.split("refs/heads/")

這裏有點奇怪的是,他的返回值首先是個引用類型,如果直接println ref.split("refs/heads/")會看到[Ljava.lang.String;@618657aa,所以不能直接ref.split("refs/heads/")[0]

def arr = ref.split("refs/heads/") as List

第二點比較奇怪的是,在其他語言比如C#、Java、go中,這種情況返回的數組只包含一個元素,而這裏返回的卻是兩個元素:

def arr = ref.split("refs/heads/") as List
println arr

// [, xxx-dev]

所以我們需要取arr[1]來拿到分支名,這樣一來我們就可以將上面的腳本改寫:

node(label) {
    stage('test') {
        dir('/home/jenkins/agent/workspace/test') {
            def arr = ref.split("refs/heads/") as List
            def currentBranch = arr[1]
            git branch: currentBranch, credentialsId: 'xxxx', url: 'http://172.16.*.*:*/test.git'
        }
    }
}

感謝

參考文章:我在這裏看到了split;在這裏看到了as LinkedList。感謝以上作者的文章!如果你有更巧妙的方法,歡迎留言告訴我!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章