React 应用架构实战 0x8:配置 CI/CD 进行测试和部署

2023-05-17 21:04:06 浏览数 (2)

在本节中,我们将学习什么是 CI/CD 。然后,我们将学习 GitHub Actions 是什么以及 GitHub Actions 流水线的主要部分是什么。然后,我们将学习如何创建一个 CI/CD 流水线,将自动验证并将应用程序部署到 Vercel。

# 什么是 CI/CD

持续集成/持续部署(CI/CD)是一种自动化地向应用程序用户提供应用程序变更的方法。CI/CD 通常应包括以下几个部分:

  • 持续集成是验证代码已经构建、测试并合并到仓库的自动化过程
  • 持续交付是将更改交付到仓库的过程
  • 持续部署是将更改发布到生产服务器,使更改可供用户使用的过程

现在,让我们考虑如何为应用程序实现 CI/CD 。我们已经拥有了所有必需的部分——只需要将它们组合起来。整个流程将如下所示:

  • 运行应用程序的所有代码检查(单元测试和集成测试、linting、类型检查、格式检查等)
  • 构建应用程序并运行端到端测试
  • 如果两个过程都成功完成,我们可以部署我们的应用程序

这个过程将确保我们的应用程序始终处于最佳状态,并且更改可以频繁且轻松地发布到生产环境。当在较大的团队中工作时,每天都会引入许多更改,因此这尤其有用。

为了运行 CI/CD 流水线,我们需要适当的基础设施。由于我们将仓库放在 GitHub 上,因此我们可以使用 GitHub Actions 来处理 CI/CD。

# 使用 GitHub Actions

GitHub Actions 是一种 CI/CD 工具,它允许我们自动化、构建、测试和部署流水线。我们可以创建在仓库中的特定事件上运行的 workflow

# Workflow

workflow 是一个可以运行一个或多个任务(job)的过程。我们可以在 .github/workflows 文件夹中以 YAML 格式定义它们。workflow 会在触发指定事件(Event)时运行,我们还可以直接从 GitHub 手动重新运行 workflow。一个仓库可以有任意多个 workflow。

# Event

一个事件被触发时,将会引起 workflow 运行。GitHub 的活动可以触发事件,例如将代码推送到仓库或创建一个 pull 请求。此外,它们也可以定时启动或通过 HTTP POST 请求启动。

# Job

一个 job 定义了一系列在 workflow 中会执行的步骤。一个步骤可以是一个 action 或者可以被执行的脚本。一个 workflow 可以有多个 job,它们可以并行执行,或者在依赖的 job 执行完成后再开始执行。

# Action

Action 是在 GitHub Actions 上运行的应用程序,用于执行重复任务。我们可以使用已经构建好的 Action,它们可以在 https://github.com/marketplace?type=actions (opens new window) 上找到,或者我们可以自己创建。在我们的流程中,我们将使用一些预定义的 Actions。

# Runner

runner 是用于运行 workflow 的服务,它可以托管在 GitHub 上,但也可以自行托管。

现在我们已经熟悉了 GitHub Actions 的基础知识,可以开始创建我们的应用程序工作流程。

让我们创建 .github/workflows/main.yml 文件和初始代码:

代码语言:javascript复制
name: CI/CD
on:
  - push
jobs:
# add jobs here

在上面的代码中,我们提供了工作流的名称,如果我们省略它,名称将被设置为工作流文件的名称。在这里,我们定义了 push 事件,这会使每当代码更改被推送到仓库时,工作流就会运行。

对于我们定义的每个 job,我们将提供以下内容:

代码语言:javascript复制
name: Name of the job
runs-on: ubuntu-latest

这些属性将适用于所有 job:

  • name:设置运行作业的名称
  • runs-on:设置将运行作业的运行程序

# 配置测试流水线

我们的测试流水线将包含两个 job,应该完成以下操作:

  • 运行所有代码检查,如 linting,类型检查,单元测试和集成测试等
  • 构建应用程序并运行端到端测试
# 代码检查
代码语言:javascript复制
name: CI/CD
on:
  - push
jobs:
  code-checks:
    name: Code Checks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16
      - run: mv .env.example .env
      - run: npm install
      - run: npm run test
      - run: npm run lint

# E2E 测试
代码语言:javascript复制
name: CI/CD
on:
  - push
jobs:
  # ...
  e2e:
    name: E2E Tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: mv .env.example .env
      - uses: cypress-io/github-action@v4
        with:
          build: npm run build
          start: npm run start

# 部署到 Vercel

Vercel 是一个平台,它与 GitHub 具有出色的集成性。这意味着每当我们推送更改到仓库时,应用程序的新版本将自动部署到 Vercel 上。但是,我们希望在部署步骤之前验证我们的应用程序是否按预期工作,以便我们可以从 CI/CD 流程中执行此任务。

要做到这一点,我们需要在 Vercel 中禁用 GitHub 集成。这可以通过创建包含以下内容的 vercel.json 文件来完成:

代码语言:javascript复制
{
  "github": {
    "silent": true
  }
}

现在,我们可以在 workflow 中添加部署步骤:

代码语言:javascript复制
name: CI/CD
on:
  - push
jobs:
  deploy:
    name: Deploy To Vercel
    runs-on: ubuntu-latest
    needs: [code-checks, e2e]
    if: github.repository_owner == 'cellinlab'
    permissions:
      contents: read
      deployments: write
    steps:
      - name: start deployment
        uses: bobheadxi/deployments@v1
        id: deployment
        with:
          step: start
          token: ${{ secrets.GITHUB_TOKEN }}
          env: ${{ fromJSON('["Production", "Preview"]')[github.ref != 'refs/heads/main'] }}
      - uses: actions/checkout@v3
      - run: mv .env.example .env
      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-args: ${{ fromJSON('["--prod", ""]')[github.ref != 'refs/heads/main'] }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID}}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID}}
          scope: ${{ secrets.VERCEL_ORG_ID}}
          working-directory: ./
      - name: update deployment status
        uses: bobheadxi/deployments@v1
        if: always()
        with:
          step: finish
          token: ${{ secrets.GITHUB_TOKEN }}
          status: ${{ job.status }}
          env: ${{ steps.deployment.outputs.env }}
          deployment_id: ${{ steps.deployment.outputs.deployment_id }}

0 人点赞