使用GitHub Actions通过CI提高代码质量

Blog
Author:
Omer MishaniaOmer Mishania
Published On:
8月 4, 2022
Estimated reading time:
1 minutes

不论是开发、暂存还是生产环境,无时无刻都有代码不间断地被推送到 Git 上。 我们总是想要确保我们投入大量时间设计和编写的代码是具备可读性与安全性的,并且没有漏洞,能够平稳地运行。

使用自动化可以节省时间、工作量以及成本,同时减少人为错误,使您能够专注于主要目标。自动化代码质量测试过程,并将该过程添加到 CI 工作流中,因为每项任务都是一致执行且自动触发的,因此即使存在大量任务有待完成,也能确保高质量的结果。

在本文中,我们所讨论的主题将围绕代码质量展开,并探讨编写高质量代码的含义,需要给予关注的原因,以及如何使用 CI 工具来对其进行改进。

提高代码质量意义何在?

讨论代码质量时,我们通常假设我们正在审查的代码已经通过了功能测试,并且没有致命的或重大的缺陷(也就是说,代码按预期工作)。但其可能存在潜在的漏洞,或者受到其他低质量属性的影响。

代码质量是软件设计和编写水平,以及是否遵循设计约束、最佳实践和编码惯例的衡量标准。这关系到程序员是否可以写出易读、易维护以及重复使用的代码。提高您的代码质量有助于确保您的软件能够可靠、安全地运行,并且确保对其提供帮助并非难事。我们已经在之前的博文中讨论了如何提高 C++ 代码质量此文不专门针对 C++(但当然也可能与 C++ 有关),而是更侧重于 CI 管道技术,从而提高代码质量。

其理念在于使用 CI 工作流来检查代码质量(安全漏洞、可读性和编码惯例等)。如果代码不符合您的组织标准,您可以触发警报,或者在某些情况下甚至可以阻止它被推送到特定的环境中。

什么是 Github Actions

GitHub Actions 是一个 CI/CD 平台,能够使应用程序的构建、测试和部署管道自动化,并且允许您在特定事件发生时运行一个动作或一组动作。例如,您可以测试应用程序代码,如果成功通过所有测试,即可构建容器镜像,并将其推送到容器注册表。

GitHub 提供现成的 Linux、Windows 和 macOS 虚拟机来运行您的工作流,但如果需要订制的虚拟机,且其硬件能完全满足您的需求,您可以在数据中心或云基础设施中托管自己的自托管运行器。

过去,我们已经在一些博文中使用并讨论了 GitHub Actions:

而本文将使用 GitHub Actions 来追求更高的代码质量。

如何提高代码质量

有多种方法可以用来提高代码质量,但在本文中,我们将深入探讨三种方法,并会解释如何通过 CI 工作流来执行每种方法。我们将重点关注以下几个方面:

我们已经就各方面创建了 Git 存储库,并且加以实施,如果您在环境中设置事物遇到困难,便可依靠于此 Git 存储库。

代码覆盖率

自动化的代码测试使您能够自信地对现有代码进行变更、重构和添加功能,并且了解它会正常地运行。

代码覆盖率衡量测试期间所执行代码的百分比。代码覆盖率是一个非常重要的衡量指标,可以让您了解实际测试了多少代码库。

您可能认为您所编写的测试涵盖了所有相关场景,但情况往往并非如此。测试每一行的代码都非常困难——即使您有 100% 的覆盖率,由于实际流基于不同流的组合,在逻辑上也不能涵盖系统的所有方面和可能性。即便如此,达到较高的代码覆盖率通常可以很好地衡量测试是否彻底。通过使用代码覆盖率工具,您可以更容易地发现未经测试的区域,增强团队对测试的信心,并提高代码质量。

有几种代码覆盖工具可以与您现有的 CI 管道集成。CodeCov 就是其中之一,能很好地与 GitHub Actions (通过 GitHub Actions 市场上的应用程序)集成在一起。它还会生成一份报告,详细说明每个测试所涵盖的代码的百分比,哪些测试未能通过,以及哪些分支未被测试。

我们的 Git 存储库中,有一个用 Python 编写的计算器应用程序和一个包含应用程序测试的测试目录。

您可以采取以下步骤在 GitHub Actions 工作流中轻松设置 CodeCov:

  1. 使用您的 GitHub 账户从此处登录 CodeCov。
  2. 复制将要显示的 CODECOV_TOKEN 值,并将其添加到存储库秘密中。
  3. 将此代码添加到您的工作流之中:
jobs:
  codcov:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          # Make sure the actual branch is checked out when running on pull requests
          ref: ${{ github.head_ref }}

      - name: Setup Python
        uses: actions/setup-python@master
        with:
          python-version: 3.7
      - name: Generate coverage report
        run: |
          pip install pytest
          pip install pytest-cov
          pytest --cov=./api
      - name: Check code coverage
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

您可以在此处看到结果。要了解更多详细信息,请点击存储库名称。

以下是我们详细的结果示例:

现在,在确定代码具备合理的测试覆盖率之后,那么应该讨论一下安全问题了。

安全漏洞

代码漏洞是指可能导致安全漏洞和对系统用户造成潜在伤害的错误和不适当或未应用的做法。漏洞可以是任何小错误,如缺位错误,也可以是允许攻击者执行任意代码并接管运行易受攻击应用程序的服务器的重大错误。重要的是要确保代码和数据足够安全,以防止恶意攻击者利用代码漏洞,从而访问敏感数据。

要处理应用程序的安全问题,您需赶在恶意攻击者之前找到漏洞。有许多技术有助于发现这些漏洞。使用静态分析安全工具可以大大增加暴露问题的机会,甚至无需执行代码。

有许多工具可以用来保护您的代码,但较为引人注目的还是 SonarQube,一种用于静态代码分析的开源工具。它有一个专门的 Github Action 应用程序,允许开发人员在其 Docker 环境中运行 SonarQube,作为其 CI 工作流的一部分。它会检测一些其他方面的安全漏洞,对各方面的各存储库进行评级,并估计解决此问题的所需时长。

我们采用了一个简单的 Python 应用程序,用不同的货币返回比特币的值。该应用程序使用“requests” Python 模块访问包含比特币价值的 API。为了检查工具的完整性,我们在 HTTPS GET 请求中添加了“verify=False”,以禁用证书验证并模拟安全威胁(“requests”文档中关于将 verify flag 设置为 False 的更多信息请参见此处)。由于不会验证 SSL 证书,那将 verify flag 设置为 False 明显是一种安全威胁(GET 请求将接受服务器提供的任何 TLS 证书,并将忽略主机名不匹配和/或过期的证书)。我们想看看 SonarQube 是否能够取得明显进展。

以下是原代码在 SonarQube 中显示的结果示例:

这是向 HTTPS GET 请求添加 “verify=False” 后的结果:

通过对新发现的漏洞进行钻研:

如你所见,SonarQube 是个不错的选择。

如何将 SonarQube 添加到工作流中?

您需要:

要对代码进行分析,首先需要在 SonarQube 上设置您的项目。设置完毕后,您将得到两个变量——一个 是SONAR_TOKEN,另一个是 SONAR_HOST_URL ,以及它们的值,在之后会用到。此外,必须可以从 GitHub 访问您的 SonarQube 实例,并且您需要一个访问令牌来运行分析。

  1. 在您的环境中设置 SonarQube。
  2. 创建一个新的手动项目,为其选择一个名称,并选择 GitHub Actions 选项,然后按照屏幕教程中显示的指示操作。
  3. 点击此按钮创建“SONAR_TOKE”:
  4. 复制“SONAR_TOKE”和“SONAR_HOST_URL”变量的值,将这两个值添加到您的存储库秘密中,变量名称相同。
  5.  选择最能描述您的构建的选项,并在存储库中创建一个 sonar-project.properties 文件,将教程中提到的代码(来自步骤 2)粘贴到该文件中。例如:
  6. 将以下代码添加到您的工作流之中:
jobs:
  sonarqube:
       runs-on: ubuntu-latest

       steps:
       - name: Checkout
       uses: actions/checkout@v2
       with:
      # Make sure the actual branch is checked out when running on pull requests
      ref: ${{ github.head_ref }}

       - name: SonarQube Scan
       uses: sonarsource/sonarqube-scan-action@master
       env:
      # The variables and values you added to the project's environment variables
      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
      SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

行了,那么测试正常运行,代码也受到保护,但是代码样式怎么样呢?

样式

代码样式是一套人类可读的惯例,以便于理解和使用代码。常见的样式规则示例是制表符与空格,反之亦然。代码符合常规标准时,人类更容易读取和理解。

我们可以随心所欲地写代码。为什么使用像这样的格式很重要?只要代码能运行而且我们能搞清楚其作用,那是否会有人真的在意我们的代码看起来如何呢?

答案是肯定的。要想立刻弄清楚别人的代码如何运行并不容易。开发人员所面临的最大问题之一就是试图确定现有代码是否能完成它们的任务。代码样式可以帮助我们消除一些猜测——如果必须遵守某些规则或惯例,我们可以就这些规则达成共识,并始终予以遵循。这样一来,任何快速查看我们的代码的人都对其作用有所了解。

我们选择使用 Prettier 来改进代码样式。它可以与 Github Actions 工作流集成,以便在进行更改和提交时自动格式化代码。Prettier 将帮助你对 JavaScript、HTML、CSS、YAML 和 MarkDown 文件进行格式化,但是还有更多可用的社区插件。该插件免费且开源,因而任何人都可以查看其运作方式,或者如果不喜欢所提供的代码格式的话,也可以对其进行更改。

我们的 Git 储存库中,我们使用了简单的前端应用程序文件 (HTML、JavaScript 和 CSS)。通过使用 Prettier,重新格式化代码以符合某种标准。

该工具直接编辑您的文件,并在您的存储库中对其进行重新格式化,因而没有专门的平台来运行。您可以在此处看到在我的储存库中对代码所做的修改。

您可以简单地使用 Prettier GitHub action 应用程序在项目 CI 工作流中更改代码样式。要将其付诸行动,您需做两件事:

  1. 确保工作流已在存储库的设置中(“actions”部分)具有读写权限。
  2. 将此添加到您的工作流中:
jobs:
  prettier:
       runs-on: ubuntu-latest

       steps:
       - name: Checkout
       uses: actions/checkout@v2
       with:
      # Make sure the actual branch is checked out when running on pull requests
      ref: ${{ github.head_ref }}

       - name: Prettify code
       uses: creyD/prettier_action@v4.2

这样即可!运行此作业后,您的代码将更具可读性,且更为美观。

结论

通过防止将坏代码推入源存储库,CI 工作流有助于编写质量更高的代码。如此便可防止出错,并简化开发过程。在本文中,我们介绍了提高代码质量的三个方面,但您可使用的还有更多,比如检测应该用作秘密的密码和令牌,或者使用 linting 检查代码,以便发现诸如未使用的变量、不可访问的代码、不必要的代码、使用一般例外等样式错误。

工作流有其自身的挑战,需要进行开发,并将流程落实到位。配置工具与建立像样的工作流并非易事,但如果您完成得不错,您就会发现您的代码质量很快就得到了提高。

那么问题是:您准备好提高代码质量了吗?