<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          開源端到端流水線實(shí)踐-需求與代碼管理

          共 7422字,需瀏覽 15分鐘

           ·

          2020-11-12 16:21

          業(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中的項(xiàng)目名稱與業(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ù)的項(xiàng)目(代碼庫)名稱。以下面圖中為例:我們在demo項(xiàng)目中創(chuàng)建了一個模塊demo-hello-service,其實(shí)對應(yīng)的就是Gitlab代碼庫中demo組的demo-hello-service服務(wù)。


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

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


          2. 配置過程

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

          特性分支自動化:當(dāng)我們在jira上面創(chuàng)建了問題,此時會通過Jira的webhook觸發(fā)對應(yīng)的Jenkins作業(yè),該Jenkins作業(yè)通過解析Jira webhook傳遞的數(shù)據(jù),找到問題名稱和模塊名稱。調(diào)用GitlabAPI 項(xiàng)目查詢接口,根據(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項(xiàng)目名稱,webHookData 參數(shù)為Jira ?webhook的所有數(shù)據(jù)。token 是觸發(fā)器的觸發(fā)token,這里默認(rèn)采用的作業(yè)名稱(作業(yè)名稱要唯一)。

          triggers?{
          ????????GenericTrigger(?causeString:?'Trigger?By?Jira?Server?-->>>>>?Generic?Cause',?
          ????????????????????????genericRequestVariables:?[[key:?'projectKey',?regexpFilter:?'']],?
          ????????????????????????genericVariables:?[[defaultValue:?'',?key:?'webHookData',?regexpFilter:?'',?value:?'$']],?
          ????????????????????????printContributedVariables:?true,?
          ????????????????????????printPostContent:?true,?
          ????????????????????????regexpFilterExpression:?'',?
          ????????????????????????regexpFilterText:?'',?
          ????????????????????????silentResponse:?true,?
          ????????????????????????token:?"${JOB_NAME}"
          ????????)
          ????}

          在Jira項(xiàng)目中配置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格式化,然后獲取值。

          response?=?readJSON?text:?"""${webHookData}"""
          println(response)

          //獲取webhook的事件類型
          env.eventType?=?response["webhookEvent"]
          {
          ????"timestamp":1603087582648,
          ????"webhookEvent":"jira:issue_created",
          ????"issue_event_type_name":"issue_created",
          ????"user":Object{...},
          ????"issue":{
          ????????"id":"10500",
          ????????"self":"http://192.168.1.200:8050/rest/api/2/issue/10500",
          ????????"key":"DEMO-2",
          ????????"fields":{
          ????????????"issuetype":{
          ????????????????"self":"http://192.168.1.200:8050/rest/api/2/issuetype/10001",
          ????????????????"id":"10001",
          ????????????????"description":"",
          ????????????????"iconUrl":"http://192.168.1.200:8050/images/icons/issuetypes/story.svg",
          ????????????????"name":"故事",
          ????????????????"subtask":false
          ????????????},
          ????????????"components":[
          ????????????????{
          ????????????????????"self":"http://192.168.1.200:8050/rest/api/2/component/10200",
          ????????????????????"id":"10200",
          ????????????????????"name":"demo-hello-service",
          ????????????????????"description":"demo-hello-service應(yīng)用"
          ????????????????}
          ????????????],
          ????????????"timespent":null,
          ????????????"timeoriginalestimate":null,
          ????????????"description":null,
          ????????????...
          ????????????...
          ????????????...

          2.2 封裝GitLab接口

          Gitlab接口文檔:https://docs.gitlab.com/ce/api/README.html

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

          package?org.devops

          //封裝HTTP請求
          def?HttpReq(reqType,reqUrl,reqBody){
          ????def?gitServer?=?"http://gitlab.idevops.site/api/v4"
          ????withCredentials([string(credentialsId:?'gitlab-token',?variable:?'gitlabToken')])?{
          ??????result?=?httpRequest?customHeaders:?[[maskValue:?true,?name:?'PRIVATE-TOKEN',?value:?"${gitlabToken}"]],?
          ????????????????httpMode:?reqType,?
          ????????????????contentType:?"APPLICATION_JSON",
          ????????????????consoleLogResponseBody:?true,
          ????????????????ignoreSslErrors:?true,?
          ????????????????requestBody:?reqBody,
          ????????????????url:?"${gitServer}/${reqUrl}"
          ????????????????//quiet:?true
          ????}
          ????return?result
          }


          //更新文件內(nèi)容
          def?UpdateRepoFile(projectId,filePath,fileContent){
          ????apiUrl?=?"projects/${projectId}/repository/files/${filePath}"
          ????reqBody?=?"""{"branch":?"master","encoding":"base64",?"content":?"${fileContent}",?"commit_message":?"update?a?new?file"}"""
          ????response?=?HttpReq('PUT',apiUrl,reqBody)
          ????println(response)

          }

          //獲取文件內(nèi)容
          def?GetRepoFile(projectId,filePath){
          ????apiUrl?=?"projects/${projectId}/repository/files/${filePath}/raw?ref=master"
          ????response?=?HttpReq('GET',apiUrl,'')
          ????return?response.content
          }

          //創(chuàng)建倉庫文件
          def?CreateRepoFile(projectId,filePath,fileContent){
          ????apiUrl?=?"projects/${projectId}/repository/files/${filePath}"
          ????reqBody?=?"""{"branch":?"master","encoding":"base64",?"content":?"${fileContent}",?"commit_message":?"create?a?new?file"}"""
          ????response?=?HttpReq('POST',apiUrl,reqBody)
          ????println(response)
          }


          //更改提交狀態(tài)
          def?ChangeCommitStatus(projectId,commitSha,status){
          ????commitApi?=?"projects/${projectId}/statuses/${commitSha}?state=${status}"
          ????response?=?HttpReq('POST',commitApi,'')
          ????println(response)
          ????return?response
          }

          //獲取項(xiàng)目ID
          def?GetProjectID(repoName='',projectName){
          ????projectApi?=?"projects?search=${projectName}"
          ????response?=?HttpReq('GET',projectApi,'')
          ????def?result?=?readJSON?text:?"""${response.content}"""
          ????
          ????for?(repo?in?result){
          ???????//?println(repo['path_with_namespace'])
          ????????if?(repo['path']?==?"${projectName}"){
          ????????????
          ????????????repoId?=?repo['id']
          ????????????println(repoId)
          ????????}
          ????}
          ????return?repoId
          }

          //刪除分支
          def?DeleteBranch(projectId,branchName){
          ????apiUrl?=?"/projects/${projectId}/repository/branches/${branchName}"
          ????response?=?HttpReq("DELETE",apiUrl,'').content
          ????println(response)
          }

          //創(chuàng)建分支
          def?CreateBranch(projectId,refBranch,newBranch){
          ????try?{
          ????????branchApi?=?"projects/${projectId}/repository/branches?branch=${newBranch}&ref=${refBranch}"
          ????????response?=?HttpReq("POST",branchApi,'').content
          ????????branchInfo?=?readJSON?text:?"""${response}"""
          ????}?catch(e){
          ????????println(e)
          ????}??//println(branchInfo)
          }

          //創(chuàng)建合并請求
          def?CreateMr(projectId,sourceBranch,targetBranch,title,assigneeUser=""){
          ????try?{
          ????????def?mrUrl?=?"projects/${projectId}/merge_requests"
          ????????def?reqBody?=?"""{"source_branch":"${sourceBranch}",?"target_branch":?"${targetBranch}","title":"${title}","assignee_id":"${assigneeUser}"}"""
          ????????response?=?HttpReq("POST",mrUrl,reqBody).content
          ????????return?response
          ????}?catch(e){
          ????????println(e)
          ????}
          }

          //搜索分支
          def?SearchProjectBranches(projectId,searchKey){
          ????def?branchUrl?=??"projects/${projectId}/repository/branches?search=${searchKey}"
          ????response?=?HttpReq("GET",branchUrl,'').content
          ????def?branchInfo?=?readJSON?text:?"""${response}"""
          ????
          ????def?branches?=?[:]
          ????branches[projectId]?=?[]
          ????if(branchInfo.size()?==0){
          ????????return?branches
          ????}?else?{
          ????????for?(branch?in?branchInfo){
          ????????????//println(branch)
          ????????????branches[projectId]?+=?["branchName":branch["name"],
          ????????????????????????????????????"commitMes":branch["commit"]["message"],
          ????????????????????????????????????"commitId":branch["commit"]["id"],
          ????????????????????????????????????"merged":?branch["merged"],
          ????????????????????????????????????"createTime":?branch["commit"]["created_at"]]
          ????????}
          ????????return?branches
          ????}
          }

          //允許合并
          def?AcceptMr(projectId,mergeId){
          ????def?apiUrl?=?"projects/${projectId}/merge_requests/${mergeId}/merge"
          ????HttpReq('PUT',apiUrl,'')
          }

          2.3 共享庫配置





          ?點(diǎn)擊屏末?|??|?即刻學(xué)習(xí)

          瀏覽 56
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  伦理无码| 国产在线无码视频 | 蜜乳一区二区三区有限公司 | 天天操,天天干,天天日 | 国产一级免费观看视频 |