如何使用Python脚本实现Git操作,实现增量代码覆盖率统计

开发工具 潘老师 2小时前 6 ℃ (0)

软件测试的代码覆盖率是衡量测试是否达标的重要标准之一。前段时间,我用fastapi框架重新编写了覆盖率统计服务。这个服务的核心操作,就是先获取全量代码覆盖率,再通过diff操作来统计增量代码覆盖率。而要进行diff操作,就不可避免地要和Git打交道。那么,如何在Python中操作Git呢?今天就来给大家分享一下。

一、认识GitPython库

在Python环境里操作Git,有个超好用的工具——GitPython库。它提供了一系列方法,让我们能轻松访问和操作Git仓库。有了它,原本复杂的Git操作在Python里变得简单许多。

安装GitPython库

安装GitPython很简单,使用pip包管理器就行,在命令行输入下面的命令:

pip install gitpython

这样就把GitPython库安装到我们的开发环境中啦。

二、GitPython库的基础操作

克隆仓库

在使用GitPython操作Git仓库前,得先把远程仓库克隆到本地。下面是示例代码:

from git import Repo

remote_url = 'https://github.com/username/repository.git'
local_path = '/path/to/local/repository'

Repo.clone_from(remote_url, local_path)

在这段代码里,我们先设定好远程仓库的URL和本地存储路径。然后调用Repo.clone_from()方法,它就会把远程仓库克隆到我们指定的本地路径下。

不过,如果本地仓库已经存在,就不用再克隆了。可以像下面这样加个判断:

remote_url = 'https://github.com/username/repository.git'
local_path = '/path/to/local/repository'
if os.path.exists(local_path):
    repo = Repo(local_path)
else:
    repo = Repo.clone_from(remote_url, local_path)

这段代码先检查本地路径是否存在仓库,如果存在,直接实例化;不存在的话,再进行克隆操作。

获取分支信息

克隆好仓库后,有时我们需要获取仓库里的分支信息。代码如下:

from git import Repo

repo_path = '/path/to/your/git/repository'

repo = Repo(repo_path)
branches = repo.heads

for branch in branches:
    print(f"Branch: {branch.name}, Commit ID: {branch.commit}")

这里通过repo.heads获取所有分支,然后遍历这些分支,打印出每个分支的名称和对应的commit ID ,这样就能清楚地知道仓库里都有哪些分支以及它们的提交记录了。

提交更改

在开发过程中,提交代码更改是常有的事。用GitPython提交更改的代码如下:

from git import Repo

repo_path = '/path/to/your/git/repository'

repo = Repo(repo_path)
repo.index.add(['file1.py', 'file2.py'])
repo.index.commit("Commit message")

这段代码先指定仓库路径并实例化仓库对象,然后用repo.index.add()方法把需要提交的文件添加到暂存区,最后用repo.index.commit()方法提交更改,并附上提交信息。虽然在代码覆盖率统计中没用到这个功能,但了解一下还是很有必要的。

查看状态

想知道仓库当前的状态,比如哪些文件被修改了、哪些还没被暂存等,可以用下面的代码:

from git import Repo

repo_path = '/path/to/your/git/repository'

repo = Repo(repo_path)

repo_status = repo.git.status()
print(repo_status)

这段代码通过repo.git.status()获取仓库状态,和在命令行里使用git status命令的效果是一样的,执行后就能看到仓库的详细状态信息了。

切换分支和合并代码

在开发中,切换分支和合并代码也是常见操作。用GitPython实现的代码如下:

from git import Repo

repo_path = '/path/to/your/git/repository'
repo = Repo(repo_path)

repo.git.checkout('develop')

repo.git.merge('feature-branch')

这里先使用repo.git.checkout('develop')切换到develop分支,然后用repo.git.merge('feature-branch')feature-branch分支合并到当前分支。

获取远程仓库的最新变更

为了保证本地代码和远程仓库同步,我们需要获取远程仓库的最新变更,代码如下:

from git import Repo

repo_path = '/path/to/your/git/repository'

repo = Repo(repo_path)
repo.fetch()

执行repo.fetch()后,会从远程仓库获取最新的提交记录、分支和文件,但这些变更不会自动合并到本地代码。也就是说,执行完git fetch后,还需要手动进行合并或者基于远程分支重新开发。

diff操作

在统计增量代码覆盖率时,diff操作非常关键。下面的代码展示了如何使用GitPython进行diff操作:

from git import Repo

repo_path = '/path/to/your/git/repository'

repo = Repo(repo_path)
repo.git.diff(base_branch, current_branch)

git.diff()方法用来比较base_branchcurrent_branch这两个分支之间的差异,通过它就能知道两个分支的代码有哪些不同。

三、实战案例:统计增量覆盖率的核心代码

下面这段代码是我在统计增量覆盖率时的核心部分:

def get_diff(self, current_branch: str, base_branch: str = "origin/master"):
    """获取版本之间代码差异"""
    diff = self.repo.git.diff(base_branch, current_branch).split("\n")

    ret = {}
    file_name = ""
    diff_lines = []
    current_line = 0
    for line in diff:
        if line.startswith("diff --git"):
            if file_name != "":
                ret[file_name] = diff_lines
            file_name = re.findall("b/(\S+)$", line)[0]
            diff_lines = []
            current_line = 0

        elif re.match("@@ -\d+,\d+ +(\d+),\d+ @@", line):
            match = re.match("@@ -\d+,\d+ +(\d+),\d+ @@", line)
            current_line = int(match.group(1)) - 1

        elif line.startswith("-"):
            continue
        elif line.startswith("+") and not line.startswith("+++"):
            current_line += 1
            diff_lines.append(current_line)
        else:
            current_line += 1
    ret[file_name] = diff_lines
    return ret

这个get_diff方法接收current_branchbase_branch两个参数,current_branch表示当前分支,base_branch表示基准分支,默认是origin/master

方法内部先调用self.repo.git.diff(base_branch, current_branch)获取两个分支之间的代码差异,并按行拆分成列表。然后用一个字典ret来存储差异信息,键是文件名,值是差异的行号列表。

在遍历差异行时,会根据行的内容进行不同处理:

  • 遇到以diff --git开头的行,说明开始处理新文件的差异,这时就提取文件名。
  • 匹配到以@@ -\d+,\d+ +(\d+),\d+ @@格式的行,提取新版本代码的起始行号。
  • -开头的行,表示该行在基准分支中有但当前分支中没有,直接忽略。
  • +开头且不以+++开头的行,代表当前分支新增的行,记录行号并添加到差异行列表。
  • 其他情况,行号递增。
    最后把最后一个文件的差异行信息添加到字典并返回,这样就能得到两个版本之间详细的代码差异信息了。

GitPython真的给Python操作Git带来了极大的便利,让我顺利实现了增量代码覆盖率的统计工作。这里展示的只是我在工作中用到的部分GitPython方法,它还有很多其他实用的功能,大家可以去官方文档(gitpython.readthedocs.io/en/stable/)深入了解。希望今天的分享能帮助到大家哦!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/tool/18318.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】