1. 程式人生 > >Jenkins高階篇之Pipeline實踐篇-9-Selenium和Jenkins持續整合-日誌檔案歸檔和外掛rebuild介紹--完結篇

Jenkins高階篇之Pipeline實踐篇-9-Selenium和Jenkins持續整合-日誌檔案歸檔和外掛rebuild介紹--完結篇

寫到這裡,我記得我前面提出的兩個需求,引數化構建和報告和日誌顯示就差一個日誌檔案顯示了。本篇就先來介紹如何在jenkins上提供日誌檔案下載,第二個介紹一下rebuild外掛。如果一個jenkins job有十個以上的引數化構建,那麼下一次構建,選擇rebuild選單是最方便,rebuild選單會記住上一次構建的輸入值,支援修改後再提交構建。

1.日誌檔案歸檔

早期jenkins中,檔案歸檔使用的命令是archive,然後這個方法就棄用了,改成了archiveArtifacts,這裡我兩個方法都測試了下。這裡我先貼出關鍵程式碼,完整程式碼我後面給出,大部分程式碼都是和前面一篇相同。

 post{
        always{
            script{
                node(win_node){
                    //delete report file
                    println "Start to delete old html report file."
                    bat("del /s /q C:\\JenkinsNode\\workspace\\selenium-pipeline-demo\\test-output\\*.html")
                    //list the log files on jenkins ui
                    archive 'log/*.log'
                }
            }
        }
    }

看最後一行程式碼,archive是方法名稱,後面表示在根目錄下的log資料夾下所有以.log結尾的檔案進行歸檔操作,在jenkns當前構建頁面可以看到這些歸檔檔案。

我測試了下,發現有下面這個提示錯誤,構建失敗。

The archive step is deprecated, please use archiveArtifacts instead.

然後,只能嘗試archiveArtifacts了。

post{
        always{
            script{
                node(win_node){
                    //delete report file
                    println "Start to delete old html report file."
                    bat("del /s /q C:\\JenkinsNode\\workspace\\selenium-pipeline-demo\\test-output\\*.html")
                    //list the log files on jenkins ui
                    //archive 'log/*.log'
                    archiveArtifacts artifacts: 'log/*.log'
                }
            }
        }
    }

測試效果如下。

 

如果你想看日誌內容,直接點選紅框內的檔案就可以。當然,我們框架內log資料夾下有三個日誌檔案,這裡還缺一個html檔案。

你可以歸檔的時候寫成以下這樣。

post{
        always{
            script{
                node(win_node){
                    //delete report file
                    println "Start to delete old html report file."
                    bat("del /s /q C:\\JenkinsNode\\workspace\\selenium-pipeline-demo\\test-output\\*.html")
                    //list the log files on jenkins ui
                    archiveArtifacts artifacts: 'log/*.*'
                }
            }
        }
    }

我們知道,按照上面這麼寫,就是把log資料夾下所有檔案都歸檔,效果如下

這裡三個檔案都出來,但是不要擔心.gitkeep這個檔案,這個我原來程式碼倉庫中,需要保留一個空的log資料夾,在git中為了能push一個空的資料夾,需要在這個資料夾下寫一個.gitkeep檔案,並且在這個檔案寫幾行內容,內容如下。

# Ignore everything in this directory 
* 
# Except this file !.gitkeep 

同理,在我github這個程式碼倉庫中,有log,screenshots,test-output三個資料夾都使用了這個檔案。以上兩種方法,一個是精確到log檔案型別,一個是模糊的一個資料夾下所有檔案都歸檔。結合你自己專案實際情況,自己選擇取捨。

2.這裡介紹一個rebuild外掛

在pipeline的開發和測試過程中,有一個rebuild外掛,這裡介紹下。rebuild安裝完會變成一個選單,點選之後,會自動記錄前面的構建時填寫的引數。這樣其實是很方便,特別是一個專案有十多個引數是需要每次構建都選擇或者填寫的,而且預設值不一定是你要的,這樣如果沒有rebuild功能,你每次點選引數化構建,都需要填寫多次引數變數的值,這樣就很麻煩。

所以,你得去安裝一個rebuild的外掛,外掛名稱就叫rebuild,搜尋並安裝,很簡單,下面是一個效果圖。

這裡注意下rebuild和replay的區別,在實際工作中,兩者往往是經常使用,前一個構建使用了replay是為了debug,改程式碼,下一個構建為了再次驗證,點選rebuild就可以。

上面的圖表示,下一次構建,也就是第83次構建是在82的記錄下觸發的,這個時候按鈕是Rebuild,而不是引數化構建頁面的build的按鈕。

3.新增事後刪除日誌功能

和前面報告一樣,每次構建,都會產生日誌檔案和報告檔案,那麼我們這裡也新增事後清空日誌資料夾的功能。當然,也會把.gitkeep檔案一塊刪除,但是由於刪除的是本地拉取完之後的檔案,不會影響到github上的檔案,所以這個就不要擔心。

這裡,我把兩個groovy檔案的程式碼都貼出來。

檔案:selenium-jenkins.groovy

import hudson.model.*;

pipeline{

    agent any
    parameters {
        string(name: 'BROWSER_TYPE', defaultValue: 'chrome', description: 'Type a browser type, should be chrome/firefox')
        string(name: 'TEST_SERVER_URL', defaultValue: '', description: 'Type the test server url')
        string(name: 'NODE', defaultValue: 'win-anthony-demo', description: 'Please choose a windows node to execute this job.')
    }
    
	stages{
	    stage("Initialization"){
	        steps{
	            script{
	                browser_type = BROWSER_TYPE?.trim()
	                test_url = TEST_SERVER_URL?.trim()
	                win_node = NODE?.trim()
	            }
	        }
	    }

	    stage("Git Checkout"){
	        steps{
	            script{
	                node(win_node) {
	                     checkout([$class: 'GitSCM', branches: [[name: '*/master']],
						    userRemoteConfigs: [[credentialsId: '6f4fa66c-eb02-46dc-a4b3-3a232be5ef6e', 
							url: 'https://github.com/QAAutomationLearn/JavaAutomationFramework.git']]])
	                }
	            }
	        }
	    }
	    
        stage("Set key value"){
	        steps{
	            script{
	                node(win_node){
	                    selenium_test = load env.WORKSPACE + "\\pipeline\\selenium.groovy"
	                    config_file = env.WORKSPACE + "\\Configs\\config.properties"
	                    try{
	                        selenium_test.setKeyValue("browser", browser_type, config_file)
	                        file_content = readFile config_file
                            println file_content
	                    }catch (Exception e) {
	                        error("Error met:" + e)
	                    }
	                }
	            }
	        }
	    }
	    
	    stage("Run Selenium Test"){
	        steps{
	            script{
	                node(win_node){
	                    run_bat = env.WORKSPACE + "\\run.bat"
	                    bat (run_bat)
	                }
	            }
	        }
	    }
	    stage("Publish Selenium HTML Report"){
	        steps{
	            script{
	                node(win_node){
	                   html_file_name = selenium_test.get_html_report_filename("test-output")
	                   publishHTML (target: [
                        	allowMissing: false,
                        	alwaysLinkToLastBuild: false,
                        	keepAll: true,
                        	reportDir: 'test-output',
                        	reportFiles: html_file_name,
                        	reportName: "Selenium Test Report"
                    	])
	                }
	            }
	        }
	    }
	}

    post{
        always{
            script{
                node(win_node){
                    //delete report file
                    println "Start to delete old html report file."
                    bat("del /s /q C:\\JenkinsNode\\workspace\\selenium-pipeline-demo\\test-output\\*.html")
                    //archive the log files on jenkins ui
                    archive 'log/*.*'
                    println "Start to delete old log files."
                    bat("del /s /q C:\\JenkinsNode\\workspace\\selenium-pipeline-demo\\log\\*.*")
                }
            }
        }
    }

}

檔案:selenium.groovy

import hudson.model.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

def setKeyValue(key, value, file_path) {
    // read file, get string object
    file_content_old = readFile file_path
    println file_content_old
    lines = file_content_old.tokenize("\n")
    new_lines = []
    lines.each { line ->
        if(line.trim().startsWith(key)) {
            line = key + "=" + value
            new_lines.add(line)
        }else {
            new_lines.add(line)
        }
    }
    // write into file
    file_content_new = ""
    new_lines.each{line ->
        file_content_new += line + "\n"
    }

    writeFile file: file_path, text: file_content_new, encoding: "UTF-8"
}

def get_html_report_filename(report_store_path) {
    get_html_file_command = "cd ${report_store_path}&dir /b /s *.html"
    out = bat(script:get_html_file_command,returnStdout: true).trim()
    out = out.tokenize("\n")[1] // get the second line string
    println out
    html_report_filename = out.split("test-output")[1].replace("\\", "")
    println html_report_filename
    return html_report_filename
}

return this;

完整程式碼在github上

https://github.com/QAAutomationLearn/JavaAutomationFramework.git

總結:

       到了這裡,我算把jenkins+pipeline+selenium持續整合的方案全部介紹完了,希望對於那些想學習pipeline的朋友有一些幫助。我不得不吐槽下,我的Jenkins環境太慢了,由於jenkins master機器在美國洛杉磯,我本地個人膝上型電腦作為一臺windows slave機器連線,每次跑Jenkins job,拉取程式碼到windows上都很慢,而且連線很不穩定,寫這個系列文章花了很多測試時間,總之,比我預想的要慢很多。從我現在的pipeline使用經驗和技術水平來講,我覺得我完成了pipeline從入門到實戰運用,這篇系列教程,我個人感覺寫得還不錯,至少比java+selenium系列和python+selenium系列要寫得好,只是,在國內,不管開發還是測試還是運維,使用pipeline的人還是很少數,希望這個隊伍會越來越壯大。將來的軟體都會在雲端,所以雲端軟體的自動化和基礎設施的自動化測試會越來越多,工作機會相信也會一樣越多。學會pipeline去用程式碼的方式完成不同專案的CI和CD的開發測試工作,這個要求會在招聘需求裡越來越突出。