Gitlab,Jira和Confluence的Python集成可自动执行发布版本

最近,在一个站台上,一位同事提出了一个合理的建议:自动化发布版本,并以与Python编写的Jira进行交互的现成的实践为基础。

我们的部署过程如下:当积累了足够数量的经过测试的任务时,它们会在受任务影响的每个项目中释放候选候选(RC),然后将这些任务作为RC的一部分进行测试。此后,将RC倒入登台服务器,在该服务器上靠近战斗环境的地方仍要对其进行测试,并进行完全回归。然后,在采取必要的部署操作后,将新发行版注入主服务器。

直到最近,整个组装过程还是由一名开发人员手动完成的。在我看来,这花费了一个小时,两个或更多个时间,这并不是一个非常有趣的职业。现在,当几乎所有事情都准备就绪时,影响不到5个项目的20个任务的发布将花费不到一分钟的时间。当然,仍然存在冲突解决,运行遗漏的测试等更多内容,但是即使考虑到这一点,开发人员和测试人员的时间也节省了很多,他们不得不等到有人率先释放自己并创建RC的时间。

总的来说,我着手完成这项任务,结果发现它非常有趣且令人着迷。如果没有令人兴奋的项目,还需要什么才能使工作愉快?

我研究了遗留问题:事实证明,它直接使用Jira API,对我来说,它不是最佳的。例如,获取发布任务的列表如下:从Jira下载所有现有发布,然后将每个发布的名称与我们的发布名称进行比较,直到找到所需的发布:

def get_release_info(config):

   try:

       release_input = sys.argv[1]

   except IndexError:

       raise Exception('Enter release name')

   releases_json = requests.get(url=RELEASES_LIST_URL, auth=(login, jira_password).json()

   for release in releases_json:

       if release['name'] == release_input:

                ...


通常,与API的直接交互导致代码的可读性不高。而且我不想发明自行车。我对Github的首次搜索使我进入了JIRA Python库,这是一个相当简单而强大的库。我最初计划使用也在Github上找到的GitPython库创建Marge请求。但是对该问题的进一步研究立即产生了一种想法,即发现与git不相关的东西,而是立即与Gitlab相关的东西。结果,我选择了最著名的解决方案:Python GitLab。

我首先获得了处于发布状态的任务列表。我决定不对先前的解决方案进行重大更改,而是通过立即请求所需发行版任务的API使其更加有效:

fix_issues = jira.search_issues(f'fixVersion={release_input}')

fix_id = jira.issue(fix_issues.iterable[0]).fields.fixVersions[0].id

尽管最有可能在引擎盖下发生相同的事情,但是事实证明,它更美观,更优化,但可读性仍然不高。此外,从接收到的任务中,有必要收集链接以合并请求。我决定将找到的合并请求存储在namedtuple中,它们非常适合:

Merge_request = namedtuple('Merge_request', ['url', 'iid', 'project', 'issue'])

还使用Jira API接收了合并请求:

projects = set()

links_json = requests.get(url=REMOTE_LINK.format(issue_number),

                            auth=login,jira_password).json()

for link in links_json:

   url_parts = link['object']['url'].split('/')

   project = f'{url_parts[4]}'

   iid = url_parts[6]

   projects.add(project)   

之后,我决定可以在哪里使用找到的库然后,也许,我将重构这些片段。

接下来,您需要检查一下,突然正确的RC分支已经存在,如果已经尝试构建,则必须删除它们并创建新的分支。我已经使用Python GitLab库做到了这一点:

gl = gitlab.Gitlab('https://gitlab...ru/', private_token=GITLAB_PRIVATE_TOKEN)

pr = gl.projects.get(project)

try:

   rc = pr.branches.get(f'{RC_name}')

   rc.delete()

   pr.branches.create({'branch': f'{RC_name}', 'ref': 'master'})

except gitlab.GitlabError:

   pr.branches.create({'branch': f'{RC_name}', 'ref': 'master'})

之后,您可以开始在Jira组装任务中填写表格。表中的信息包含在以下列中:编号,任务,优先级,来自RC中任务的合并请求,合并请求的状态(是否在Gitlab中通过了测试,是否存在冲突,是否注入)。

在这一步,我遇到了一个令人不愉快的Gitlab缺陷:如果以前将更改推送到合并请求的目标分支,则Gitlab API在请求合并请求的状态时会给出有关冲突的答案。从原则上讲,这可以理解:如果没有东西可倒,那将是行不通的,但是为什么要说这个地方存在冲突呢? Gitlab论坛已经问了人们好几年了,但是还没有答案。

就我而言,这会导致错误的冲突状态,并手动检查合并请求。我还没有想出什么。

创建合并请求时的逻辑如下:如果未通过测试,或者存在冲突,则创建合并请求,但是合并请求不会流入RC,相应的状态将放入表中。

为了检查测试的执行情况,我们寻找合适的管道清单。Gitlab根据需要按日期降序发出它们。我们采取第一个-这将是所需要的:

pipelines = project.pipelines.list(ref=f'{issue}')

if pipelines:

   pipelines = pipelines[0]

   if pipelines.attributes['status'] != 'success':

       status = '(x)   !, '

然后自己创建合并请求如果不是第一次尝试构建,我们会检查是否有开放的。在没有必需的合并请求的情况下,创建以下命令:

mr = project.mergerequests.list(

 state='opened',

source_branch=source_branch,         target_branch=target_branch)

if mr:

   mr = mr[0]

else:

   mr = project.mergerequests.create(

{'source_branch': source_branch,

           'target_branch': target_branch,

           'title': f"{(MR.issue).replace('-', '_')} -> {RC_name}",

           'target_project_id': PROJECTS_NAMES[MR.project],})

status = mr.attributes['merge_status']

url = mr.attributes['web_url']

return status, url, mr

MR.issue.replace('-','_')-更改任务的名称,以摆脱Gitlaba对Jira中任务无用的评论。

接下来,我们查看接收到的合并请求的状态:如果没有冲突,我们将其倒入RC中。如果存在冲突,请记下适当的状态,然后进行手动验证。

此外,通过类推,我们为所有项目创建了从RC到暂存以及从暂存到主的合并请求。在检查完RC分支的整个发行版之后,将倾倒它们。

在Jira任务模板中添加了两个字段:用于预发布前和发布后操作。对于所有涉及的任务,该算法收集此类动作的列表并输入组装任务,以免遗忘任何东西。

最后,Jira的输出是创建组装任务

existing_issue = jira.search_issues(

f'project=PROJ AND summary ~ " {release_name}"')

if existing_issue:

   existing_issue = existing_issue[0]

   existing_issue.update(fields={

       'description': message,

       'customfield_xxx': message_before_deploy,

       'customfield_yyy': message_post_deploy,})

else:

   issue_dict = {

       "fixVersions": [{"name": release_name,}],

       'project': {'key': 'PROJ'},

       'summary': f" {release_name}",

       'description': message,

       'issuetype': {'name': 'RC'},  #      

       'customfield_xxx': message_before_deploy,

       'customfield_yyy': message_post_deploy,}

   new_issue = jira.create_issue(fields=issue_dict)

进一步的想法如下:使用来自Jira的Web挂钩在Gitlab上运行脚本。例如,您可以制作一个Webhook来创建组装任务(为其创建特殊类型的任务),或创建标题中带有“ Assembly”一词的任务。然后,该钩子上的Gitlab将运行bash脚本以启动整个过程,或者使用Python生成Docker映像并在其上运行脚本。尽管第二种选择已经太复杂了。是的,并且需要Jira和Gitlab的技术人员。通常,还没有最终决定。

创建RC分支后,您还可以在必要的分支上部署测试平台并运行回归测试。詹金斯可以解决这个问题。但这也是目前的计划。

所有这些都是为了加快测试人员的工作,并使开发人员摆脱常规工作。但是,这里的经济意义也很具体:以一名普通开发人员(处于真空状态),假设其工资为15万卢布,每天工作8个小时。两年来,我们大约发布了700个版本-这大约是每天发布的版本。我认为,开发人员花了更多,更少的时间,但平均而言,至少花了一个小时来构建发行版。也就是说,该过程的自动化每月可为公司节省至少150,000 / 8 = 18,750卢布。

在此过程中,我为自己制作了一个单独的脚本,显示了即将发布的版本的统计信息:多少任务,受影响的项目等。由于如果我在Gitlab的任何项目中都没有开发人员身份,那么在创建合并请求时将拒绝访问。此外,还可以方便地提前了解部署操作或捕获错误地落入此版本的任务。使用SMTP和电子邮件模块解决了发行通知的分发问题。

我对这个问题的解决方案感到满意:学习新知识并将其付诸实践总是很有趣的。如果这种经历对某人有用,那就太好了。

All Articles