开源端到端流水线实践-需求与代码管理

开发 前端
业务的简称为demo,微服务架构。N多个微服务。服务命名:业务简称-应用名称-类型(demo-hello-service)。特性分支开发,版本分支发布。每个需求(任务/故事)对应一个特性分支。每个发布(release)对应一个版本分支。

 [[348244]]

业务的简称为demo,微服务架构。N多个微服务。服务命名:业务简称-应用名称-类型(demo-hello-service)。特性分支开发,版本分支发布。每个需求(任务/故事)对应一个特性分支。每个发布(release)对应一个版本分支。

1.需求与代码管理
Jira作为需求和缺陷管理,采用Scrum开发方法,jira中的项目名称与业务简称一致(demo)。Gitlab作为版本控制系统,每个Group对应一个业务,每个微服务对应一个代码库。

需求与代码关联:在jira中创建一个任务/故事,关联模块后自动在该模块创建一个以ISSUE(任务/故事)ID的特性分支。此时的模块等同于每个微服务的项目(代码库)名称。以下面图中为例:我们在demo项目中创建了一个模块demo-hello-service,其实对应的就是Gitlab代码库中demo组的demo-hello-service服务。

特性分支:创建好每个模块后,就可以实现需求与代码关联。例如:我们在Jira项目demo中创建一个问题,类型为故事(不受限制可为其他),重点是需要将改故事关联到模块(只有关联到模块,我们才能通过接口得知哪个问题关联的哪个代码库)。

版本分支:当特性分支开发完成以及测试验证完成后,基于主干分支创建一个版本分支,然后将所有的特性分支合并到版本分支。此时可以通过Jira中创建一个发布版本,然后问题关联发布版本(此动作表示该特性分支已经通过验证,可以合并)。自动完成版本分支的创建和特性分支到版本分支的合并请求。

2. 配置过程
需求与代码库关联,主要用到的工具链为: Jira + GitLab + Jenkins。Jira负责创建需求,配置webhook。Jenkins负责接收Jira webhook请求,然后通过接口实现GitLab项目分支创建。

特性分支自动化:当我们在jira上面创建了问题,此时会通过Jira的webhook触发对应的Jenkins作业,该Jenkins作业通过解析Jira webhook传递的数据,找到问题名称和模块名称。调用GitlabAPI 项目查询接口,根据模块名称找到代码库。调用GitLabAPI 分支创建接口,根据问题名称基于主干分支创建一个特性分支。任务结束。

版本分支自动化:Jira创建发布版本,Issue关联版本。自动在gitlab代码库基于master创建版本分支,并开启特性分支到版本分支的合并请求。

2.1 准备工作
在Jenkins, 创建一个Pipeline 作业并配置GenericTrigger 触发器,接收JiraWebhook数据。projectKey 参数表示Jira项目名称,webHookData 参数为Jira webhook的所有数据。token 是触发器的触发token,这里默认采用的作业名称(作业名称要唯一)。

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}" 
        ) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

在Jira项目中配置Webhook,勾选触发事件填写触发URL。http://jenkins.idevops.site/generic-webhook-trigger/invoke?token=demo-jira-service&projectKey=${project.key} (这个地址是jenkins Generictrigger生成的,这里不做过多的介绍)

Jira webhook数据参考, 这些参数可以在Jenkinsfile中通过readJSON格式化,然后获取值。

response = readJSON text: """${webHookData}""" 
println(response) 
 
//获取webhook的事件类型 
env.eventType = response["webhookEvent"
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

    "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应用" 
                } 
            ], 
            "timespent":null
            "timeoriginalestimate":null
            "description":null
            ... 
            ... 
            ... 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

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: truename'PRIVATE-TOKEN', value: "${gitlabToken}"]],  
                httpMode: reqType,  
                contentType: "APPLICATION_JSON"
                consoleLogResponseBody: true
                ignoreSslErrors: true,  
                requestBody: reqBody, 
                url: "${gitServer}/${reqUrl}" 
                //quiet: true 
    } 
    return result 

 
 
//更新文件内容 
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) 
 

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

 
//创建仓库文件 
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) 

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

 
//获取项目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) 

 
//创建分支 
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) 

 
//创建合并请求 
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,''

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.

2.3 共享库配置

演示效果:上传了两个小视频,可以扫描进入视频号查看。

 

 

责任编辑:姜华 来源: DevOps云学堂
相关推荐

2021-04-29 08:55:54

GitLabDevOps项目

2017-03-02 14:12:13

流水线代码Clojure

2022-07-18 06:05:28

Gitlab流水线

2024-01-07 12:47:35

Golang流水线设计模式

2023-12-11 18:35:37

测试流水线自动化

2021-04-13 06:15:37

开源部署流水线Jenkins

2021-12-24 08:02:48

GitLabCI模板库流水线优化

2019-11-07 09:00:39

Jenkins流水线开源

2017-02-28 16:00:45

DevOpsMarkdownreST

2023-05-10 15:08:00

Pipeline设计模式

2023-05-26 08:31:09

2017-02-28 15:40:30

Docker流水线Azure

2013-06-06 09:31:52

2021-11-08 07:41:16

Go流水线编程

2021-06-26 14:22:34

Tekton流水线Kubernetes

2022-01-26 08:12:42

Jenkins开源流水线

2023-08-18 10:24:52

GitLabCI 流水线

2025-02-20 08:00:00

2019-11-07 10:02:33

开源开源工具DevOps

2021-10-12 08:47:01

Nexus存储库管理器DevOps
点赞
收藏

51CTO技术栈公众号