日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
開源端到端流水線實踐-需求與代碼管理

業(yè)務(wù)的簡稱為demo,微服務(wù)架構(gòu)。N多個微服務(wù)。服務(wù)命名:業(yè)務(wù)簡稱-應(yīng)用名稱-類型(demo-hello-service)。特性分支開發(fā),版本分支發(fā)布。每個需求(任務(wù)/故事)對應(yīng)一個特性分支。每個發(fā)布(release)對應(yīng)一個版本分支。

1.需求與代碼管理
Jira作為需求和缺陷管理,采用Scrum開發(fā)方法,jira中的項目名稱與業(yè)務(wù)簡稱一致(demo)。Gitlab作為版本控制系統(tǒng),每個Group對應(yīng)一個業(yè)務(wù),每個微服務(wù)對應(yīng)一個代碼庫。

需求與代碼關(guān)聯(lián):在jira中創(chuàng)建一個任務(wù)/故事,關(guān)聯(lián)模塊后自動在該模塊創(chuàng)建一個以ISSUE(任務(wù)/故事)ID的特性分支。此時的模塊等同于每個微服務(wù)的項目(代碼庫)名稱。以下面圖中為例:我們在demo項目中創(chuàng)建了一個模塊demo-hello-service,其實對應(yīng)的就是Gitlab代碼庫中demo組的demo-hello-service服務(wù)。

特性分支:創(chuàng)建好每個模塊后,就可以實現(xiàn)需求與代碼關(guān)聯(lián)。例如:我們在Jira項目demo中創(chuàng)建一個問題,類型為故事(不受限制可為其他),重點是需要將改故事關(guān)聯(lián)到模塊(只有關(guān)聯(lián)到模塊,我們才能通過接口得知哪個問題關(guān)聯(lián)的哪個代碼庫)。

版本分支:當(dāng)特性分支開發(fā)完成以及測試驗證完成后,基于主干分支創(chuàng)建一個版本分支,然后將所有的特性分支合并到版本分支。此時可以通過Jira中創(chuàng)建一個發(fā)布版本,然后問題關(guān)聯(lián)發(fā)布版本(此動作表示該特性分支已經(jīng)通過驗證,可以合并)。自動完成版本分支的創(chuàng)建和特性分支到版本分支的合并請求。

2. 配置過程
需求與代碼庫關(guān)聯(lián),主要用到的工具鏈為: Jira + GitLab + Jenkins。Jira負(fù)責(zé)創(chuàng)建需求,配置webhook。Jenkins負(fù)責(zé)接收J(rèn)ira webhook請求,然后通過接口實現(xiàn)GitLab項目分支創(chuàng)建。

特性分支自動化:當(dāng)我們在jira上面創(chuàng)建了問題,此時會通過Jira的webhook觸發(fā)對應(yīng)的Jenkins作業(yè),該Jenkins作業(yè)通過解析Jira webhook傳遞的數(shù)據(jù),找到問題名稱和模塊名稱。調(diào)用GitlabAPI 項目查詢接口,根據(jù)模塊名稱找到代碼庫。調(diào)用GitLabAPI 分支創(chuàng)建接口,根據(jù)問題名稱基于主干分支創(chuàng)建一個特性分支。任務(wù)結(jié)束。

版本分支自動化:Jira創(chuàng)建發(fā)布版本,Issue關(guān)聯(lián)版本。自動在gitlab代碼庫基于master創(chuàng)建版本分支,并開啟特性分支到版本分支的合并請求。

2.1 準(zhǔn)備工作
在Jenkins, 創(chuàng)建一個Pipeline 作業(yè)并配置GenericTrigger 觸發(fā)器,接收J(rèn)iraWebhook數(shù)據(jù)。projectKey 參數(shù)表示Jira項目名稱,webHookData 參數(shù)為Jira webhook的所有數(shù)據(jù)。token 是觸發(fā)器的觸發(fā)token,這里默認(rèn)采用的作業(yè)名稱(作業(yè)名稱要唯一)。

 
 
 
 
  1. triggers {
  2.         GenericTrigger( causeString: 'Trigger By Jira Server -->>>>> Generic Cause', 
  3.                         genericRequestVariables: [[key: 'projectKey', regexpFilter: '']], 
  4.                         genericVariables: [[defaultValue: '', key: 'webHookData', regexpFilter: '', value: '$']], 
  5.                         printContributedVariables: true, 
  6.                         printPostContent: true, 
  7.                         regexpFilterExpression: '', 
  8.                         regexpFilterText: '', 
  9.                         silentResponse: true, 
  10.                         token: "${JOB_NAME}"
  11.         )

在Jira項目中配置Webhook,勾選觸發(fā)事件填寫觸發(fā)URL。http://jenkins.idevops.site/generic-webhook-trigger/invoke?token=demo-jira-service&projectKey=${project.key} (這個地址是jenkins Generictrigger生成的,這里不做過多的介紹)

Jira webhook數(shù)據(jù)參考, 這些參數(shù)可以在Jenkinsfile中通過readJSON格式化,然后獲取值。

 
 
 
 
  1. response = readJSON text: """${webHookData}"""
  2. println(response)
  3. //獲取webhook的事件類型
  4. env.eventType = response["webhookEvent"]
 
 
 
 
  1. {
  2.     "timestamp":1603087582648,
  3.     "webhookEvent":"jira:issue_created",
  4.     "issue_event_type_name":"issue_created",
  5.     "user":Object{...},
  6.     "issue":{
  7.         "id":"10500",
  8.         "self":"http://192.168.1.200:8050/rest/api/2/issue/10500",
  9.         "key":"DEMO-2",
  10.         "fields":{
  11.             "issuetype":{
  12.                 "self":"http://192.168.1.200:8050/rest/api/2/issuetype/10001",
  13.                 "id":"10001",
  14.                 "description":"",
  15.                 "iconUrl":"http://192.168.1.200:8050/images/icons/issuetypes/story.svg",
  16.                 "name":"故事",
  17.                 "subtask":false
  18.             },
  19.             "components":[
  20.                 {
  21.                     "self":"http://192.168.1.200:8050/rest/api/2/component/10200",
  22.                     "id":"10200",
  23.                     "name":"demo-hello-service",
  24.                     "description":"demo-hello-service應(yīng)用"
  25.                 }
  26.             ],
  27.             "timespent":null,
  28.             "timeoriginalestimate":null,
  29.             "description":null,
  30.             ...
  31.             ...
  32.             ...

2.2 封裝GitLab接口
Gitlab接口文檔

共享庫:src/org/devops/gitlab.groovy

 
 
 
 
  1. package org.devops
  2. //封裝HTTP請求
  3. def HttpReq(reqType,reqUrl,reqBody){
  4.     def gitServer = "http://gitlab.idevops.site/api/v4"
  5.     withCredentials([string(credentialsId: 'gitlab-token', variable: 'gitlabToken')]) {
  6.       result = httpRequest customHeaders: [[maskValue: true, name: 'PRIVATE-TOKEN', value: "${gitlabToken}"]], 
  7.                 httpMode: reqType, 
  8.                 contentType: "APPLICATION_JSON",
  9.                 consoleLogResponseBody: true,
  10.                 ignoreSslErrors: true, 
  11.                 requestBody: reqBody,
  12.                 url: "${gitServer}/${reqUrl}"
  13.                 //quiet: true
  14.     }
  15.     return result
  16. }
  17. //更新文件內(nèi)容
  18. def UpdateRepoFile(projectId,filePath,fileContent){
  19.     apiUrl = "projects/${projectId}/repository/files/${filePath}"
  20.     reqBody = """{"branch": "master","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}"""
  21.     response = HttpReq('PUT',apiUrl,reqBody)
  22.     println(response)
  23. }
  24. //獲取文件內(nèi)容
  25. def GetRepoFile(projectId,filePath){
  26.     apiUrl = "projects/${projectId}/repository/files/${filePath}/raw?ref=master"
  27.     response = HttpReq('GET',apiUrl,'')
  28.     return response.content
  29. }
  30. //創(chuàng)建倉庫文件
  31. def CreateRepoFile(projectId,filePath,fileContent){
  32.     apiUrl = "projects/${projectId}/repository/files/${filePath}"
  33.     reqBody = """{"branch": "master","encoding":"base64", "content": "${fileContent}", "commit_message": "create a new file"}"""
  34.     response = HttpReq('POST',apiUrl,reqBody)
  35.     println(response)
  36. }
  37. //更改提交狀態(tài)
  38. def ChangeCommitStatus(projectId,commitSha,status){
  39.     commitApi = "projects/${projectId}/statuses/${commitSha}?state=${status}"
  40.     response = HttpReq('POST',commitApi,'')
  41.     println(response)
  42.     return response
  43. }
  44. //獲取項目ID
  45. def GetProjectID(repoName='',projectName){
  46.     projectApi = "projects?search=${projectName}"
  47.     response = HttpReq('GET',projectApi,'')
  48.     def result = readJSON text: """${response.content}"""
  49.     
  50.     for (repo in result){
  51.        // println(repo['path_with_namespace'])
  52.         if (repo['path'] == "${projectName}"){
  53.             
  54.             repoId = repo['id']
  55.             println(repoId)
  56.         }
  57.     }
  58.     return repoId
  59. }
  60. //刪除分支
  61. def DeleteBranch(projectId,branchName){
  62.     apiUrl = "/projects/${projectId}/repository/branches/${branchName}"
  63.     response = HttpReq("DELETE",apiUrl,'').content
  64.     println(response)
  65. }
  66. //創(chuàng)建分支
  67. def CreateBranch(projectId,refBranch,newBranch){
  68.     try {
  69.         branchApi = "projects/${projectId}/repository/branches?branch=${newBranch}&ref=${refBranch}"
  70.         response = HttpReq("POST",branchApi,'').content
  71.         branchInfo = readJSON text: """${response}"""
  72.     } catch(e){
  73.         println(e)
  74.     }  //println(branchInfo)
  75. }
  76. //創(chuàng)建合并請求
  77. def CreateMr(projectId,sourceBranch,targetBranch,title,assigneeUser=""){
  78.     try {
  79.         def mrUrl = "projects/${projectId}/merge_requests"
  80.         def reqBody = """{"source_branch":"${sourceBranch}", "target_branch": "${targetBranch}","title":"${title}","assignee_id":"${assigneeUser}"}"""
  81.         response = HttpReq("POST",mrUrl,reqBody).content
  82.         return response
  83.     } catch(e){
  84.         println(e)
  85.     }
  86. }
  87. //搜索分支
  88. def SearchProjectBranches(projectId,searchKey){
  89.     def branchUrl =  "projects/${projectId}/repository/branches?search=${searchKey}"
  90.     response = HttpReq("GET",branchUrl,'').content
  91.     def branchInfo = readJSON text: """${response}"""
  92.     
  93.     def branches = [:]
  94.     branches[projectId] = []
  95.     if(branchInfo.size() ==0){
  96.         return branches
  97.     } else {
  98.         for (branch in branchInfo){
  99.             //println(branch)
  100.             branches[projectId] += ["branchName":branch["name"],
  101.                                     "commitMes":branch["commit"]["message"],
  102.                                     "commitId":branch["commit"]["id"],
  103.                                     "merged": branch["merged"],
  104.                                     "createTime": branch["commit"]["created_at"]]
  105.         }
  106.         return branches
  107.     }
  108. }
  109. //允許合并
  110. def AcceptMr(projectId,mergeId){
  111.     def apiUrl = "projects/${projectId}/merge_requests/${mergeId}/merge"
  112.     HttpReq('PUT',apiUrl,'')
  113. }

2.3 共享庫配置

演示效果:上傳了兩個小視頻,可以掃描進入視頻號查看。


文章題目:開源端到端流水線實踐-需求與代碼管理
文章URL:http://www.5511xx.com/article/dhogcsp.html