日期: 2022 年 5 月 16 日

通过工具来规范代码提交与发布日志

背景

1.因为我们的现场版本发布是比较频繁的,关于本次发布为了解决什么问题,修复了什么BUG。这个全靠项目经理自觉,并不是每次发布都有写,也不一定每次都能写的全,我想有一个能兜底的机制。

2.这个时候我想起了github发布版本时有一个“auto-generate release notes”功能,它通过 git logs 命令,将两次版本变化之间的git message信息导出成markdown格式的文档,如果我们的gitea有这样一个工具,那就太棒了.

3.在gitea官网和github上进行了查阅,发现gitea目前不打算抄这个功能,未来也不会做,而我们的git服务端用的是gitea,于是我想通过drone CI流水线来实现这个功能

4.通过查阅,我发现nodejs有一个很火的工具https://github.com/conventional-changelog/standard-version 能够完成这件事,只要我们开发人员提交的 git message是符合https://www.conventionalcommits.org/https://semver.org/规范的即可

5.根据这个规范,找到vscode里有一个插件”Conventional Commits”工具是非常契合的

6.结局是我们的开发人员,只需要在vscode上安装好这个”Conventional Commits”工具,并且根据工具提示来提交代码,后续就可以自动生成changelog了,从而达到标准化“代码提交”和“发布日志”的目的

效果图

下面这个Changelog由发布之后的流水线自动生成

开发人员做什么

在vscode里下载该插件,插件扩展ID vivaxy.vscode-conventional-commits

提交代码的时候,按照工具提示一路选择即可

运维人员做什么

根据https://github.com/conventional-changelog/standard-version库来编写一个简单的流水线工具

这里我用的代码是python,流水线运行环境是DroneCI,git服务端是gitea

废话不多说,下面直接上代码,可以通过 docker build命令

docker build -t drone-changelog-plugin:1.0.1 .

去制作drone的流水线镜像

main.py

import os
import shutil

import requests


def search_tag_info(git_url,token, repo):
    '''
    搜索git上的tag信息
    :param git_url: git 的地址
    :param token: git 的access token
    :param repo: git 待查询的git仓库信息
    :return: tag信息集合
    '''
    url = "https://"+git_url+"/api/v1/repos/" + repo + "/releases"
    headers = {'accept': 'application/json',
               'Authorization': 'token ' + token,
               'Content-Type': 'application/json'
               }
    response = requests.get(url, headers=headers)
    tag_list = response.json()
    return tag_list


def modify_tag_body(git_url,token, repo, tag_id, body):
    '''
    修改git仓库的tag里的内容
    :param git_url: git 的地址
    :param token: git 的access token
    :param repo: git 待查询的git仓库信息
    :param tag_id: git tag的id信息
    :param body: 需要修改的内容,一般是changelog.md文件
    :return:
    '''
    url = "https://"+git_url+"/api/v1/repos/" + repo + "/releases/" + str(tag_id)
    headers = {'accept': 'application/json',
               'Authorization': 'token ' + token,
               'Content-Type': 'application/json'
               }
    body = {
        "body": body
    }
    response = requests.patch(url, json=body, headers=headers)


if __name__ == '__main__':
    print(os.environ)
    tag = os.environ["DRONE_TAG"]
    branch = os.environ["DRONE_REPO_BRANCH"]
    username = os.environ["DRONE_NETRC_USERNAME"]
    password = os.environ["DRONE_NETRC_PASSWORD"]
    git_repo = os.environ["DRONE_REPO"]
    git_token = os.environ["PLUGIN_TOKEN"]
    src_file = "/lzw/.versionrc"
    dst_foleder = os.environ["DRONE_WORKSPACE"]
    git_url= os.environ["PLUGIN_GIT_SERVER"]
    shutil.copy(src_file, dst_foleder)

    # 获取当前仓库里所有的tag信息
    tag_info_list = search_tag_info(git_url,git_token, git_repo)
    # 获取最新的一个tag
    now_tag = tag_info_list[0]
    # 获取所有的tag信息,这个地方是因为standard-version的特性,
    # 要获取所有的tag信息,再删掉当前的tag信息,
    # 再使用standard-version 重新生成一个tag信息
    os.system("git remote set-url origin https://'" + username + "':'" + password + "'@"+git_url+"/" + git_repo)
    os.system("git fetch --all")
    os.system("git tag -d " + tag)
    cmd = 'standard-version --tag-prefix "" --release-as ' + tag
    print(cmd)
    os.system(cmd)
    # standard-version命令会产生一个CHANGELOG.md文件
    with open('CHANGELOG.md', encoding='utf-8') as f:
        line = f.read()
    print("tag len is:" + str(len(tag_info_list)))
    # 判断一下目前有几个tag,分割保留最新的git tag 变更信息
    if len(tag_info_list) > 1:
        pre = tag_info_list[1]
        list = line.split(" " + pre['tag_name'] + " ")
        # print(list[0])
        now_content = list[0]
    else:
        now_content = line
    # 把CHANGELOG.md中本次变更的传到git的tag信息里
    modify_tag_body(git_url,git_token, git_repo, now_tag['id'], now_content)

Dockerfile

FROM python:3.9-buster
LABEL maintainer="357244849@qq.com"

RUN set -eux \
    && sed -i "s@http://ftp.debian.org@https://repo.huaweicloud.com@g" /etc/apt/sources.list \
    && sed -i "s@http://security.debian.org@https://repo.huaweicloud.com@g" /etc/apt/sources.list \
    && apt-get update \
    && apt-get install -y nodejs npm
ENV NODE_PATH="/usr/lib/node_modules"
ENV LANG=C.UTF-8 PYTHONUNBUFFERED=1
RUN npm i -g standard-version
WORKDIR /lzw
ADD . /lzw
RUN pip install -r /lzw/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
CMD ["python3","/lzw/main.py"]

requirements.txt

requests

.versionrc

{
  "types": [
    {"type": "feat","section": "Features"},
    {"type": "fix","section": "Bug Fixes"},
    {"type": "docs","section": "Documentation" },
    {"type": "style","section": "Styling" },
    {"type": "refactor","section": "Refactors" },
    {"type": "perf","section": "Performance" },
    {"type": "test","section": "Tests" },
    {"type": "build","section": "Build System" },
    {"type": "ci","section": "CI" },
    {"type": "chore","section": "Chore","hidden":true },
    {"type": "revert","section": "Reverts" }
  ]
}

如何嵌入到DroneCI流水线呢

在drone.yml文件里嵌入如下yml即可

---
kind: pipeline
type: kubernetes
name: tag
steps:
  - name: generator change log
    image: drone-changelog-plugin:1.0.1
    settings:
      token: XXXXXX
      git_url: XXXXXX
trigger:
  event:
    - tag

苏ICP备18047533号-1