最近都好忙,需求太多了,幹不完,加上最近做息時間的調整,都沒時間寫博客了,趁着這兩天稍微有點時間,想擼一發; java
其實在寫的博客有好幾篇,但都是陸陸續續的,原本想繼續寫以前的,忽然想起半個月前,同窗提出,能不能在開發提tag時自動打包?python
以前發佈過一篇項目流程規範,目前的項目都在遵照這個規範,而研發每次有改動過代碼的時候,都會提測,而提測就至關於提tag,這個tag
的概念不說了,就是基於當前產品分支從新拉的分支,tag的格式以下圖; git
而測試拿到這個tag後,就須要去到jenkins打包,要輸入一堆參數,而後等待打包結果; github
有時候,研發勤奮點,一天提屢次tag,測試就須要屢次去打包,測試同窗以爲太麻煩了,所以就提出一個想法,能不能在開發提tag時自動打包?shell
能,必須能,沒有作不到的事情; json
作事以前,要先想一想要作什麼?api
想了下,大體就這3步,那就來一塊兒作吧;安全
爲了測試,jb就用了本身的阿里雲服務器從頭開始搭建一遍,具體搭建過程不說明,以前寫的一篇文章有說起到,直接對照操做就好;bash
安裝jenkins服務器
步驟 | 說明 |
---|---|
安裝Java | sudo yum install java |
安裝jenkins | yum install jenkins |
啓動jenkins | service jenkins start |
安裝插件 | 完 |
修改jenkins端口 jenkins默認端口是8080,可能會跟別的軟件衝突,所以建議修改下端口;
進入jenkins配置文件
vi /etc/sysconfig/jenkins
複製代碼
打開後,找到JENKINS_USER
跟JENKINS_PORT
這兩項進行修改便可;
修改爲root跟具體端口保存退出便可;
這時候,直接輸入主機IP+剛設置的端口就好啦;
阿里雲開放端口權限 上面訪問ip+端口,有可能打不開連接,由於阿里雲對端口作了限制,所以須要開放端口;
登陸阿里雲,首頁右上找到控制檯;
找到雲服務器ECS
點擊實例,找到該實例的安裝組配置
點擊規則說明,新增便可;
若是是按照上面的文檔來,安裝完插件,建立完用戶後,就應該進入到首頁,會顯示以下內容,至此,jenkins環境搭建就完啦~!
對了,jenkins的目錄在這裏:
/var/lib/jenkins
複製代碼
公司的代碼倉庫是用gitlab,因某種緣由,就開放公網啦,那jb就在gitlab新建一個jbtest項目;
若是有小夥伴說,沒有gitlab怎麼辦?不要緊,能夠用github代替,至於github相關的配置,能夠查看該文章:git介紹及GitHub配置教程
既然肯定是要用jenkins+gitlab,那就先在jenkins上安裝下gitlab插件吧;
點擊jenkins首頁,有個系統管理按鈕;
點擊後右側會顯示內容,下滑,點擊插件管理;
進入到插件管理界面,就看到updates等4個欄目,那點擊Available
,右側輸入gitlab
,而後找到GitLab
跟GitLab Hook
,勾選,點擊底部的install便可;
test項目有了,gitlab的插件也安裝了,那咱們就在jenkins新建一個job吧,輸入了項目名稱,就進入到設置項;
這裏的丟棄舊的構建,可選,可是習慣選擇7天,,最大保留300個; 緣由是,jenkins每次構建都會生成一個歷史構建記錄及對應的產物,若是公司有100個產品,天天自動打包10次,一天就有1000個產物,服務器磁盤空間是個問題,所以設置個7天,設置個最大數,定時刪除便可;
上面的丟棄舊構建不是要點,繼續;
繼續下滑,會發現Source Code Management
,中文是源碼管理,而咱們的代碼是存放到gitlab的,所以就選擇git了,點擊後以下圖展開;
這裏有小夥伴可能有疑問,既然是放gitlab,爲啥不是選擇gitlab,而是選擇git?
這裏就花點時間說明下git、github、gitlab;
git是一款免費的、開源的分佈式版本管理控制系統(工具);
gitHub是一個面向開源及私有軟件項目的託管平臺,
只支持git做爲惟一的版本庫格式進行託管;
gitlab,是一款基於Git的項目管理軟件,擁有GitHub擁有的一切,但它還具有讓團隊對它們的repositories進行控制的功能;
複製代碼
但願通過這麼一說,能讓你稍微清楚下;
點擊git,把項目的地址copy到這裏;
沒權限是確定的,那咱們就點擊add
建立帳戶唄,選擇jenkins;
輸入gitlab/github的帳號密碼,可是輸入完後發現仍是報錯;
彆着急,那去服務器上看看,git安裝了嗎?
沒安裝,那就安裝羅;
yum install git
複製代碼
等待安裝完,再輸入git --version
跟where is git
來看版本及安裝位置;
安裝完後,就順便試試能不能clone項目吧;
不出所料,果真不行,由於還要配置密鑰啊;
$ ssh-keygen -t rsa -C "your_email@youremail.com"
//注意,雙引號裏面是你的郵箱。填你註冊github的郵箱就好了。按enter執行。
複製代碼
一路回車就行,密碼通常不用設置~
上圖紅框裏的就是地址,cd過去;
有id_rsa
和id_rsa.pub
兩個文件,這兩個就是SSH Key的祕鑰對, id_rsa
是私鑰,不能泄露, id_rsa.pub
是公鑰,能夠公開;
配置ssh 在git bash 執行 cat id_rsa.pub
,把輸出的內容copy出來,而後打開gitlab/github網站,點擊右上角本身的圖標,點擊Setting->ssh key
頁面,點擊add ssh key
~
這裏還有一個特殊的問題: 因開放公網的緣由,每次git clone
的下載代碼的時候是鏈接的https://
而不是git@git (ssh)
的形式,致使每次pull/push等遠程操做的時候,都須要輸入帳號密碼,很是麻煩;
解決辦法:
在項目根目錄輸入:
git config --global credential.helper store
git pull/git push(第一次要再輸入一次,之後就不用)
複製代碼
會在用戶目錄下生成文件.git-credential記錄用戶名密碼的信息;
那回到jenkins,打開測試job的設置,再看是否正常;
發現已經好了,沒問題,固然也會有小夥伴依然有問題,那就須要這樣作;
打開後,滑動到git欄,若是有問題的話,可能會看到錯誤提示:
There's no such executable git in PATH: /sbin, /usr/sbin, /bin, /usr/bin.
複製代碼
在出錯的地方填入:
"whereis git"的地址 + "/bin/git"
(如上面"whereis git"的地址爲"/usr/bin/git",則應該填入 "/usr/bin/git/bin/git") 並保存
複製代碼
而後再回到job的源碼管理中添加git地址,就會好了;
既然能夠鏈接到gitlab了,那咱們就直接下滑到build,選擇add build step,由於是服務器,因此直接選擇執行shell
,若是是Windows系統,也能夠選擇執行Windows批處理命令
;
因jb的項目裏面有個test.py
文件,那項目clone下來確定是想執行這個文件啦,所以內容就是輸入python test.py
,而後點擊保存;
回到job的首頁,點擊當即構建;
因test.py
的做用是向釘釘發一條消息,所以成功的話,釘釘就會收到一條信息;
到這裏,說明jenkins是對接到gitlab是通的了;
看看標題,目的是:提tag自動打包
那先看看,tag是怎麼生成的? 具體看git命令行第11章,這裏有說明;
這裏就不bb了,直接貼:
git tag -a '3.4.0/1811111212' -m 'jbtest tag'
git push --tags
複製代碼
-a
指定標籤名字便可;-m
選項則指定了對應的標籤說明;git push --tags
就是一次推送全部本地新增的標籤;而後再輸入git tag
查看當前tag信息;
既然知道tag是怎麼生成的,那就看看有沒有辦法知道tag被建立了?
第一時間固然是想到鉤子-hook啦;
來看下官方解釋:
鉤子(hooks)是一些在"$GIT-DIR/hooks"目錄的腳本, 在被特定的事件(certain points)觸發後被調用。
當"git init"命令被調用後, 一些很是有用的示例鉤子文件(hooks)被拷到新倉庫的hooks目錄中; 可是在默認狀況下這些鉤子(hooks)是不生效的。 把這些鉤子文件(hooks)的".sample"文件名後綴去掉就可使它們生效了。
複製代碼
簡單地來講有點相似回調,就是特定事情完成後回調執行事件。
那這鉤子,在jenkins
跟gitlab
上怎麼搞?gitlab
支持嗎?
打開gitlab
對應的項目,點擊settings
-Integrations(集成)
打開後,就是hook的內容啦,簡單瞄下,發現有個選項叫Tag push events
,看了下描述,好像蠻符合咱們的要求,界面顯示,須要輸入URL
跟Secret Token
,這兩玩意怎麼來?
打開jenkins,打開對應的job,點擊設置,查找Build when a change is pushed to GitLab
,gitlab上的URL就是該處的連接,以下圖紅框,複製過去便可;
同時點擊右下的Advanced(高級)
按鈕;
而後點擊右下的Generate按鈕;
而後會生成一串Secret token,複製到gitlab那;
那咱們再試試,直接在服務器打個tag且push看釘釘會不會收到信息?
嘖嘖嘖,沒問題啊,搞定啦,另外看了下hook,支持的內容蠻多的,tag push
、push event
、merge requests
等;
上面說的條條是道,但實際現實是殘忍的,打開實際的項目,會發現本身沒有setting
權限:
遇到這種狀況,不是說不能處理,只能看門檻變高了,有2個方法:
嘗試跟對應的負責人溝通,看可否給一個帶master權限的帳號;
若是有足夠的數據讓老大承認這個功能,就會給一個帶master權限的帳號,就能夠隨心所欲啦;
但若是給的理由不讓人信服或者老大以爲沒卵用,但依然要作這個功能,那隻能換種方式了,但至少要求依然有倉庫的可讀權限
; 換個角度,連倉庫權限都沒有,就別想作了。。
大體的思路就是,利用定時功能,不斷檢測該項目的tag,當發現原tag不是最新tag時,就認爲有最新tag,此時再通知jenkins處理;
若是是這樣,那jenkins上的選項會有點不一樣,構建的時候就要選擇腳本調用,指定TOKEN_NAME,而後能夠經過鏈接JENKINS_URL/job/JOBNAME/build?token=TOKEN_NAME
來啓動build
;
對了,作這個功能,還有兩種形式:
第一種方式的好處時,省事,可是通常不容許,由於產品項目通常存放跟該產品相關的內容,而這個腳本典型是通用的,後面若是多個產品想複用就麻煩了
第二種方式的就是獨立項目,可複用,把檢測項目跟產品項目放到同一臺jenkins機器上,這樣它們都在jenkins/workspace
目錄下,經過傳參的方式切換不一樣目錄便可;
而jb採用的是第二種方式;
這個腳本的目的是什麼? 就是定時檢測tag是否是最新的,若是不是,則執行相應操做;
那難度就在於,怎麼判斷tag是否是最新的? Google下,有例子:
git describe --tags `git rev-list --tags --max-count=1`
複製代碼
嘗試下,好像沒問題,那就暫且相信吧;
好奇問下,這命令究竟是啥意思?
其實這是兩條git命令;
git describe --tags
git rev-list --tags --max-count=1
複製代碼
git describe --tags 顯示當前離當前提交最近的tag,實際發現,帶不帶參數都同樣?
不加任何參數的狀況下,git describe 只會列出帶有註釋的tag;
實際,該命令是能夠帶3個參數的,tags
、always
、dirty
,這通常用的比較少,不展開說明;
git rev-list --tags --max-count=1
git-rev-list :按反向時間順序列出提交對象 意思就是把倒序方式展現最新提交內容;
max-count=1,也很好理解,只獲取1個,若是寫2,則獲取2個;
那命令實際就變成了這樣:
git describe 9c7246b2026cec052af6a3b6297995e494c7b398
複製代碼
最終輸出的就是tag,有種奇淫怪招的感受;
固然,不會用git的話,也有另一種方式達到獲取最終一個tag的效果:
#獲取tag信息,轉list
content = os.popen("git tag" ).read().split("\n")
for i in content:
if ( i != ''):
tag_list.append(i)
print(tag_list[-1])
複製代碼
就是輸入git tag
,獲取全部tag信息,再從新存在一個list,只拿最後一個,也能夠再作下判斷,只保存最後一條,方式不少,相似,但這種效果很差是,假如一個項目通過多輪迭代,有幾千條tag,就須要時間了,所以仍是推薦第一種;
爲了模擬真實場景,就在跟目錄下新建一個腳本,跟項目同一根目錄;
腳本的內容以下:
# _*_ coding:utf-8 _*_
import re
import os
import sys
import json
import time
import requests
from apscheduler.schedulers.blocking import BlockingScheduler
tag = ""
scheduler = BlockingScheduler()
base_dir = os.getcwd()
def postDingDing(content):
dingdingurl = ["https://oapi.dingtalk.com/robot/send?access_token=你的釘釘token"]
headers = {'Content-Type': 'application/json'}
String_textMsg = {
"msgtype": "markdown",
"markdown": {
"title" : "有新tag啦",
"text": "新tag: "+content
}
}
requests.packages.urllib3.disable_warnings()
String_textMsg = json.dumps(String_textMsg)
for i in dingdingurl:
requests.post(i, data=String_textMsg, headers=headers, verify=False)
def getProjectsName():
if len(sys.argv) > 1:
return sys.argv[1]
else:
print("沒有傳項目參數,請從新輸入,例子:python check_gittag.py jbtest")
def check_tag(dir):
os.chdir(base_dir+"/"+dir)
# 原型:git describe --tags 'git rev-list --tags --max-count=1'
id = os.popen("git rev-list --tags --max-count=1").read()
content = os.popen("git describe --tags "+ id).read()
return content
def start_task():
global tag
projects_name = getProjectsName()
last_tag = check_tag(projects_name)
if (tag != last_tag):
print("有新tag啦: "+last_tag)
postDingDing(last_tag)
tag = last_tag
# else:
# print("沒有新tag,繼續輪訓")
def get_time():
""" 獲取當前時間 """
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
if __name__ == "__main__":
print(get_time() + " 魔法儀式已啓動!")
scheduler.add_job(start_task, "interval", seconds=6, id="check_tag")
scheduler.start()
複製代碼
由於是用來測試,所以jb是作了通知釘釘的功能,執行上面的代碼,會發現有一個問題:push了新tag,沒有通知!!!
後來想了下,哦,是沒有,由於本地的代碼仍是舊的,好比研發本地push到倉庫,可是檢測腳本是在服務器A,那確定是不會知道有代碼更新啦;
解決方案,立刻想到,那push後就通知啊,結果想起,沒鉤子權限。。
那沒問題,在上面的腳本加多一個更新命令就好啦;
#更新遠程代碼到本地倉庫
git fetch origin
複製代碼
流程通了,那怎麼對接到jenkins?
看回jenkins,按照要求試試,輸入如下命令:
curl -i jenkins_url/job/job_name/build?token=yourtoken
複製代碼
結果出現403.。。
兩種解決方案:
jb選擇的是第二種方案,勾選後,再次運行上面的命令,沒問題,而且能夠收到啦~
其實故事到上面就完啦,可是呢,雖然知道hook怎麼用,但仍是想了解更多,所以就有了這篇啦;
Git Hooks就是在Git執行特定事件(如commit、push、receive等)後觸發運行的腳本。
按照Git Hooks腳本所在的位置能夠分爲兩類:
基本上,用上鉤子都是定製化的腳本程序,在實際工做中,基本鉤子是萬能的,如:
$project_name/.git/hooks
複製代碼
.git/hooks/
文件夾下。當你init一個倉庫的時候,下邊會有一些鉤子的例子,以
.sample
結尾。
固然也能夠在這個目錄下自由定製hooks的功能,當觸發一些git行爲的時候,就會自動觸發執行的hooks功能;
本地鉤子:
名稱 | 功能 |
---|---|
pre-commit | 當執行commit 動做時先執行此hook ,能夠用此hook 作一些檢查,好比代碼風格檢查,或者先跑測試; |
prepare-commit-msg | 當commit時須要輸入message 前會觸發此hook ,能夠用此hook 來定製本身的default message 信息; |
commit-msg | 當用戶輸入commit 的message 後被觸發,能夠用此hook 校驗message 的信息,好比是否符合規定,有沒有cr等; |
post-commit | 在整個提交過程完成以後會被調用,能夠用於發送new commit 通知; |
post-checkout | 由git checkout 命令調用,能夠用於爲本身的項目設置合適的工做區,好比自動生成文檔、移動一些大型二進制文件等,也能夠用於檢查版本庫的有效性; |
pre-rebase | 由git rebase 命令調用,能夠用來拒絕全部的已經push的commits進行rebase操做; |
post-merge | 由git merge 調用,在merge 成功後執行,能夠用於merge後的消息通知; |
post-receive | 在成功推送後被調用,適合用於發送通知; |
pre-receive | 由git push 調用,向倉庫推送代碼時會被執行; |
update | 在pre-receive 以後被調用,分別被每一個推送上來的引用分別調用; |
pre-push | 當push時,remote refs被更新,可是在全部的objects傳輸前被觸發; |
服務端鉤子:
名稱 | 功能 |
---|---|
pre-receive | 當收到push動做以前會被執行; |
update | 收到push動做以前被執行,可是有可能被執行屢次,每一個branch一次; |
post-receive | 當push動做已經完成的時候會被觸發,能夠用此hook來push notification等,好比發郵件,通知持續構建服務器等; |
若是想自定義鉤子怎麼辦? 好比如今新增一個jb
鉤子,用於發送common
通知的;
#!/usr/bin/env python
import smtplib
from email.mime.text import MIMEText
from subprocess import check_output
# 得到新提交的git log --stat輸出
log = check_output(['git', 'log', '-1', '--stat', 'HEAD'])
# 建立一個純文本的郵件內容
msg = MIMEText("Look, I'm actually doing some work:\n\n%s" % log)
msg['Subject'] = 'Git post-commit hook notification'
msg['From'] = 'mary@example.com'
msg['To'] = 'boss@example.com'
# 發送信息
SMTP_SERVER = 'smtp.example.com'
SMTP_PORT = 587
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
session.login(msg['From'], 'secretPassword')
session.sendmail(msg['From'], msg['To'], msg.as_string())
session.quit()
複製代碼
固然,記得給權限給你鉤子,chmod
;
好啦,本章就到此接觸啦,基礎內容有點,可是很少,都是環境配置,本章主要講述如下內容:
大體是這樣,還有些細節,差很少就的啦;
好啦,若是有什麼疑問,歡迎一塊兒溝通;
最後,謝謝你們~