乐趣区

关于ci-cd:GrowingIO-Design-组件库搭建之-CICD

前言

在《GrowingIO SaaS 产品 CI/CD 实际》一文中,介绍了继续集成(Continuous Intergration,简称 CI)、继续交付(Continuous Delivery,简称 CD)和继续部署(Continuous Deployment,简称 CD)三个概念,以及在 GrowingIO SaaS 产品中的实际。
文中还强调一个典型的 CI/CD 流程建设至多须要具备以下性能的工具:

  • 代码存储库,即须要版本控制软件来保障代码的可维护性,同时作为构建过程的素材库
  • 继续集成服务器,用于主动执行构建,测试,部署等工作
  • 集中的制品治理仓库,用于寄存构建的成绩物,用于部署
  • 主动部署工具,用于将构建到的程序主动的部署到指标服务器
    对于 GrowingIO Design,应用的工具是:
  • 代码存储库:GitHub
  • 继续集成服务器:GitHub Actions
  • 集中的制品治理仓库:npm
  • 主动部署工具:Vercel

继续集成

代码查看(Lint codes)

在《GrowingIO Design 组件库搭建之开发工具》一文中,介绍了组件库应用 stylelint 和 ESLint 作为代码标准工具。
为了方便使用,在 package.json 文件中减少一下两个脚本(后文简称脚本化):

{ 
  "scripts": { 
    "eslint": "eslint src --ext .ts,.tsx", 
    "stylelint": "stylelint'src/**/*.{css,less}'--syntax less", 
  }, 
} 

而后用 GitHub Actions 来执行这两个命令:

jobs: 
  lint: 
    name: Lint codes 
    needs: install 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout repository 
        uses: actions/checkout@v2 
        with: 
          ref: ${{github.event.pull_request.head.sha}} 
      - name: Setup Node.js 
        uses: actions/setup-node@v2.4.1 
        with: 
          node-version: 14 
      - name: Restore Node.js modules 
        uses: actions/cache@v2.1.6 
        with: 
          path: node_modules 
          key: ${{runner.os}}-${{hashFiles('yarn.lock') }} 
      - name: StyleLint 
        run: yarn stylelint 
      - name: ESLint 
        run: yarn eslint 

单元测试(Unit test)

《GrowingIO Design 组件库搭建之单元测试》中提到单元测试工具次要应用 Jest,在 CI 流程中除了保障单元测试通过,还要统计测试笼罩状况(通过 –coverage 参数来实现)。
命令脚本化:

{ 
  "scripts": {"test": "jest",}, 
} 

GitHub Actions 中的 job:

jobs: 
  unit_test: 
    name: Unit test 
    needs: install 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout repository 
        uses: actions/checkout@v2 
        with: 
          ref: ${{github.event.pull_request.head.sha}} 
      - name: Setup Node.js 
        uses: actions/setup-node@v2.4.1 
        with: 
          node-version: 14 
      - name: Restore Node.js modules 
        uses: actions/cache@v2.1.6 
        with: 
          path: node_modules 
          key: ${{runner.os}}-${{hashFiles('yarn.lock') }} 
      - name: Cache test report 
        id: cache-test-report 
        uses: actions/cache@v2.1.6 
        with: 
          path: coverage/lcov.info 
          key: test-report-${{github.event.pull_request.head.sha}} 
      - name: Test 
        if: steps.cache-test-report.outputs.cache-hit != 'true' 
        run: yarn test --coverage 

打包(Build package)

组件库打包应用 father-build 工具,次要看重它的三个个性:

  • 基于 rollup 和 babel 的组件打包性能
  • 反对 TypeScript
  • 反对 cjs、esm 和 umd 三种格局的打包

三种格局打包对应的目录为:

打包命令脚本化:

{ 
  "scripts": {"build": "father-build",}, 
} 
GitHub Actions 中的 job:jobs: 
  build: 
    name: Build package 
    needs: install 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout repository 
        uses: actions/checkout@v2 
        with: 
          ref: ${{github.event.pull_request.head.sha}} 
      - name: Setup Node.js 
        uses: actions/setup-node@v2.4.1 
        with: 
          node-version: 14 
      - name: Restore Node.js modules 
        uses: actions/cache@v2.1.6 
        with: 
          path: node_modules 
          key: ${{runner.os}}-${{hashFiles('yarn.lock') }} 
      - name: Cache package 
        id: cache-package 
        uses: actions/cache@v2.1.6 
        with: 
          path: | 
            dist 
            es 
            lib 
          key: package-${{github.event.pull_request.head.sha}} 
      - name: Build 
        if: steps.cache-package.outputs.cache-hit != 'true' 
        run: yarn build 

代码品质(Sonar scan)

应用 Sonar 来检测代码品质,并且用来展现单元测试报告。
GitHub Actions 中的 job:

jobs: 
  sonar: 
    name: Sonar scan 
    needs: unit_test 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout repository 
        uses: actions/checkout@v2 
        with: 
          fetch-depth: 0 
          ref: ${{github.event.pull_request.head.sha}} 
      - name: Restore test report 
        uses: actions/cache@v2.1.6 
        with: 
          path: coverage/lcov.info 
          key: test-report-${{github.event.pull_request.head.sha}} 
      - name: Upload reports to SonarCloud 
        uses: sonarsource/sonarcloud-github-action@master 
        env: 
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 
          SONAR_TOKEN: ${{secrets.SONAR_TOKEN}} 

这个 job 会把代码扫描后果和笼罩测试报告上传到 sonar cloud,并把后果反馈在 PR 上:

继续交付

有了继续集成流程后,继续交付流程就比较简单了。因为对于 GrowingIO Design 来说,交付产物是 npm 包,对应的命令就是:

$ yarn build 
$ yarn publish

GitHub Actions 的 job:

jobs: 
  publish-package: 
    if: ${{startsWith(github.event.head_commit.message, 'docs(release)') }} 
    name: Publish package 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout 
        uses: actions/checkout@v2 
      - name: Setup Node.js 
        uses: actions/setup-node@v2.4.1 
        with: 
          node-version: 14 
          registry-url: 'https://registry.npmjs.org' 
      - name: Cache Node.js modules 
        id: cache-node-modules 
        uses: actions/cache@v2.1.6 
        with: 
          path: node_modules 
          key: ${{runner.os}}-${{hashFiles('yarn.lock') }} 
      - name: Install 
        if: steps.cache-node-modules.outputs.cache-hit != 'true' 
        run: yarn install 
      - name: Build 
        run: yarn build 
      - name: Publish package 
        run: yarn publish --non-interactive --access public 
        env: 
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 
      - name: Get package version 
        id: get-package-version 
        run: echo "::set-output name=version::$(yarn -s get-version)" 
      - name: Publish GitHub release 
        uses: actions/create-release@v1 
        env: 
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 
        with: 
          tag_name: v${{steps.get-package-version.outputs.version}} 
          release_name: v${{steps.get-package-version.outputs.version}} 
          body_path: VERSION.md 
          draft: false 
          prerelease: false 

额定说一下,在公布包之后,咱们还想把以后版本的 changelog 公布到 GitHub 的 release 中,咱们约定先提交一个用于发版的 Pull Request,例如:

当这个 Pull Request 被合并后,就会触发继续交付流程,这也是有以下判断条件的起因:
if: ${{startsWith(github.event.head_commit.message, ‘docs(release)’) }}
当 job 执行完后,会在 GitHub 上创立对应的 release:

其余流程

依赖包更新

这里应用 GitHub Dependabot 主动保护仓库的依赖项。Dependabot 确定依赖项是否有新版本,它通过查看依赖的语义版本 (semver) 来决定是否应更新该版本。当 Dependabot 发现过期的依赖项时,它会发动 Pull Request 以将清单更新到依赖项的最新版本。查看测试是否通过,查看 Pull Request 摘要中蕴含的更改日志和发行阐明,而后合并它。

dependabot 的配置:

version: 2 
updates: 
  - package-ecosystem: 'npm' 
    directory: '/' 
    schedule: 
      interval: 'weekly' 
    ignore: 
      - dependency-name: '*' 
        update-types: ['version-update:semver-patch'] 
      - dependency-name: '@storybook/*' 
 
  - package-ecosystem: 'github-actions' 
    directory: '/' 
    schedule: 
      interval: 'monthly' 

部署预览网站

在《GrowingIO Design 组件库搭建之组件开发》文章中提到组件文档应用 Storybook 来生成网站,为了实现每个 Pull Request 能独自部署生成预览网站,调研了一些产品,最终筛选出三个 Netlify、Vercel 和 Surge,以下是这个三个产品的个性比照:

对于 Netlify,每个 Pull Request 提交频率会比拟频繁,300 分钟的额度会很快被用完,所以 Netlify 也不适宜在此应用。

对于 Surge,一开始想通过 GitHub Actions 把网站部署到 Surge,然而遇到一个问题,Surge 网站的 token 只能寄存在仓库的 secrets 中,GitHub 禁止从 fork 仓库提交的 Pull Request 拜访 secrets,GitHub 上的原话是:
Secrets are not passed to workflows that are triggered by a pull request from a fork.

咱们只能另辟蹊径,应用 Azure DevOps,它是通过环境变量来存储 token,然而不会像 GitHub 对 fork 仓库的 Pull Request 有限度。参考 Netlify 的实现,把部署的 URL 通过评论的模式增加到 Pull Request 上。

对于 Vercel,对 GitHub 上的组织账号是免费,然而对于开源我的项目能够申请 Open Source 的 License,咱们用 GrowingIO Design 申请了 License 后,最终应用 Vercel 来托管预览网站。

总结

通过 CI/CD 流程把组件库搭建的前序工作都串联起来了,基础设施已搭建实现,接下来次要工作就是丰盛组件了。

GrowingIO Design 组件库搭建系列文章只是告一段落,但并不是完结。接下来还会一些简单组件实现的文章,或者相干工具库的实现。随着时间推移和技术迭代,将来甚至可能会推到现有基础设施,从新构建。敬请期待!

参考文献

  1. *GrowingIO SaaS 产品 CI/CD 实际 (一):https://mp.weixin.qq.com/s/4F…
  2. GrowingIO Design 组件库搭建之开发工具:https://mp.weixin.qq.com/s/rd…
  3. GrowingIO Design 组件库搭建之单元测:https://mp.weixin.qq.com/s/BP…
  4. GrowingIO Design 组件库搭建之组件开发:https://mp.weixin.qq.com/s/Ey…
  5. GitHub Actions:https://docs.github.com/en/ac…
  6. Depandabot:https://docs.github.com/cn/gi…
  7. 语义版本:https://semver.org/ *

退出移动版