从零开发自己的工具库(三)配置 Github Actions CI 自动发布 NPM

上一篇我们讲了如何使用 ESLint、Prettier、Husky 等工具约束代码开发、提交规范。

本文和大家分享如何利用 Github Actions 部署一套 CI/CD,推送代码后自动发布 NPM。

成品可以参考 utils ,欢迎 star 🤞❤️

在部署 CI/CD 之前,我们还有一个小尾巴,就是完善 README ,一份好的 REAMME 不光能让人看懂内容,更要让人油然而生一种赏心悦目的美感。知名的开源项目,README 通常写得都非常好,而且还有很多的 badge,比如 Ant Design

为 README 添加 badge (徽章)

之前没怎么注意过这个东西,点开 README 看了看,发现是一些图片链接。这些链接都是由 shields 网站一键生成的,里面琳琅满目各种徽章应有尽有。具体的格式可以参考 《如何在github的README中增加Badge标识》,写得很详细。这里,我们以许可证 License 为例,示范一下如何使用:

  1. 侧边栏找到需要的徽章;
  2. 右边输入仓库信息(用户名、组织名、仓库名等信息);
  3. Execute 一键生成。

值得一提的是,测试覆盖率(coverage)需要一些前置准备,稍微有些麻烦:

  1. 进入 coveralls 官网,进行 Github 授权;
  2. 授权后点击左侧侧边栏的 ADD REPOS ,将需要生成 badge 徽章的库设置为 on;
  3. 在 CI 中执行测试脚本并生成测试覆盖率的文件然后上传到 coveralls 就可以了。

Github Actions

GitHub Actions 是一种持续集成和持续交付 (CI/CD) 平台,可用于自动执行生成、测试和部署管道。

生成 NPM_TOKEN

发布 NPM 包之前,我们需要做一些前置工作,在 NPM 中生成 NPM_TOKEN,用它打通 GitHub 和 NPM。

首先,进入 NPM 首页,登录后点击头像,选择 Access Tokens,点击 Generate New Token,选择 Classic Token 就可以了。

接着,给 token 起个名字,并选择 publish 权限。

生成 token 后记得保存,关闭页面后就再也看不到了。

生成 Github Repositor secrets

回到 Github 仓库中来,首先点击 Settings,然后选择 Secrets and variables 下的 Actions,再点击 New repository secret,取名 NPM_ACCESS_TOKEN,并将先前生成的 NPM_TOKEN 填入,最后 add secret

请注意这里取的名字,要与 Workflows 脚本中的一致,后面就可以在 CI 中通过 secrets.NPM_ACCESS_TOKEN 获取到。

构建 Workflows 流水线

Workflows 是一个可配置的自动化流程,一条 Workflows 可运行一个或多个 Job 。

Workflows 由签入到存储库的 YAML 文件定义,并在存储库中的事件触发时运行,也可以手动触发,或按定义的时间表触发。

Workflows 定义在存储库的 .github/workflows 目录中,存储库可以有多个 Workflows,每个 Workflows 都可以执行不同的任务集。

1. 创建脚本

点击 Tab 栏上的 Actions ,我们要发布到 NPM,所以选择其中的 Punlish Node.js Package

此时,会自动新建一个 npm-publish.yml 脚本,修改脚本后,点击右上角 Commit changes 保存并提交,在项目中就会生成对应的脚本文件。

当然,你也可以直接在本地新建 .github/workflows/npm-publish.yml 文件,修改完后再上传。

2. 创建 build job

这里,有一个名叫 Node.js CI 的 Workflows,我们给它添加第一个任务,取名 build,用来打包构建项目。具体内容如下:

yml 复制代码
jobs:
  # 创建了一个名叫 'build' 的 job
  build:
    # 指定了操作系统为 'ubuntu-latest'
    runs-on: ubuntu-latest

    # 设置变量
    strategy:
      matrix:
        node-version: [18.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    # steps 代表一系列任务作为作业的一部分而被执行
    steps:
      # 检查仓库以便作业能正常访问
      - uses: actions/checkout@v3

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm install
      # 测试,并生成测试覆盖率文件
      - run: npm run coveralls
      # 打包
      - run: npm run build
      # 查看打包后的目录文件
      - run: ls -a

      # 上报
      - name: 上报 Coveralls
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

3. 创建 publish-npm job

接着,我们创建第二个任务,取名 publish-npm,用它来进行 NPM 发包。具体内容如下:

yml 复制代码
  # 创建 publish-npm 任务
  publish-npm:
    # 在 ubuntu 最新版本的虚拟机执行
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [ 18.x ]

    steps:
      # 检查并切换到 main 分支
      - name: 检查 main 分支
        # 使用 actions/checkout 插件
        uses: actions/checkout@v3

      # 初始化缓存
      - name: 初始化缓存
        uses: actions/cache@v3
        id: cache-dependencies
        with:
          path: node_modules
          key: ${{runner.OS}}-${{hashFiles('**/package-lock.json')}}

      # 安装 node
      - name: 安装 Node.js
        # 使用 actions/setup-node 插件
        uses: actions/setup-node@v3
        with:
          # node版本
          node-version: ${{ matrix.node-version }}
      - run: npm install
      - run: npm run build

      # 读取当前版本号
      - name: 读取当前版本号
        id: version
        uses: notiz-dev/github-action-json-property@release
        with:
          # 读取版本号
          path: './package.json'
          prop_path: 'version'

      - run: echo ${{steps.version.outputs.prop}}

      - name: 创建 Release
        uses: softprops/action-gh-release@v1
        with:
          files: ./lib/index.umd.js
          name: v${{steps.version.outputs.prop}}
          tag_name: v${{steps.version.outputs.prop}}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: 发布 NPM 包
        # 执行发布代码
        run: |
          npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
          npm publish
        env:
          # 配置 npm access token 环境变量
          NPM_TOKEN: ${{secrets.NPM_ACCESS_TOKEN}}

      - name: 刷新缓存
        run: |
          curl https://purge.jsdelivr.net/npm/iemotion-pic@latest/lib/name.json

现在,我们的 Workflows 结构应该长这样:

main 分支有新的推送时,就会触发 Actions 自动执行 Workflows 中的两个 Job。

FAQ

1. GitHub release failed with status: 403

md 复制代码
Run softprops/action-gh-release@v1
👩‍🏭 Creating new GitHub release for tag v1.0.0...
⚠️ GitHub release failed with status: 403
undefined
retrying... (2 retries remaining)
👩‍🏭 Creating new GitHub release for tag v1.1.0...
⚠️ GitHub release failed with status: 403
undefined
retrying... (1 retries remaining)
👩‍🏭 Creating new GitHub release for tag v1.0.0...
⚠️ GitHub release failed with status: 403
undefined
retrying... (0 retries remaining)
❌ Too many retries. Aborting...
Error: Too many retries.

这是因为当前的 GITHUB_TOKEN 没有该仓库创建 release 的权限,在 Wrokflows 中添加 contents 属性,并赋予其 write 操作权限:

yml 复制代码
permissions:
    contents: write

GITHUB_TOKEN 还有其他权限,如果想修改默认权限,可以查阅 👉 Assigning permissions to jobs

2. 402 Payment Required - You must sign up for private packages

md 复制代码
npm ERR! code E402
npm ERR! 402 Payment Required - PUT https://registry.npmjs.org/@zerozhang%2futils - You must sign up for private packages
...
Error: Process completed with exit code 1.

这是因为当前包的私有属性配置不当所致。对于一般的包,我们在 package.json 中添加 private: false 即可,但是如果是范围包(即包的名称以 @org-name/ 开头) ,仅仅配置 private 还不够,还需要搭配 publishConfig 来使用:

json 复制代码
{
  "private": false,
  "publishConfig": {
    "access": "public",
    "registry": "https://registry.npmjs.org/"
  }
}

3. You cannot publish over the previously published versions: 1.0.0.

md 复制代码
npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT <https://registry.npmjs.org/@zerozhang%2futils> - You cannot publish over the previously published versions: 1.0.0.
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy, or
npm ERR! 403 on a server you do not have access to.

Error: Process completed with exit code 1.

这是因为当前包的版本没有更新所致。如果要进行迭代,那么必须提升包的版本号,不允许在原来的版本号上继续迭代。

所以,main 分支在合并完代码后,不要急着推送,而是先使用 npm version 进行升级。此时,package.jsonpackage-lock.json 中的 version 会进行相应的提升。再进行迭代发布就没有问题了。

  • npm version patch 1.0.0--> 1.0.1
  • npm version minor 1.0.0--> 1.1.0
  • npm version major 1.0.0--> 2.0.0

顺便提一嘴,如果是迭代发布,请做好更新日志的说明,在项目根目录中创建 CHANGELOGO.md 文档,记录好本次迭代的更新内容,这是一个规范开源项目的基本操作。

总结

  1. 如何使用 shields 给 README 添加 badge 徽章;
  2. 如果使用 Github Actions 构建 Workflows 自动执行 NPM 发布;
  3. Bugfix 处理与答疑。

往期文章

《从零开发自己的工具库(一)配置 TS + Rollup + Jest》

《从零开发自己的工具库(二)配置 ESLint + Perttier + Husky + Commitlint》

参考资料

使用Typescript和Rollup从零开发一个工具库, 并使用Github Actions进行CI操作

shields

如何在github的README中增加Badge标识

项目徽章的添加和设置

GitHub Actions 文档

记录通过GitHub Action来自动化发布npm包

GitHub release failed with status: 403

Assigning permissions to jobs

Code: 402 You must sign up for private packages

相关推荐
lxcw2 小时前
npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED
前端·npm·node.js
布丁椰奶冻2 小时前
解决使用nvm管理node版本时提示npm下载失败的问题
前端·npm·node.js
影子落人间3 小时前
已解决npm ERR! request to https://registry.npm.taobao.org/@vant%2farea-data failed
前端·npm·node.js
又写了一天BUG6 小时前
npm install安装缓慢及npm更换源
前端·npm·node.js
森叶7 小时前
Electron-vue asar 局部打包优化处理方案——绕开每次npm run build 超级慢的打包问题
vue.js·electron·npm
GoppViper9 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
贩卖纯净水.17 小时前
白月光git
git·github
chen序员1 天前
如何切换淘宝最新镜像源(npm)【2024版】
npm
FakeOccupational1 天前
nodejs 007:错误npm error Error: EPERM: operation not permitted, symlink
前端·npm·node.js
亦舒.1 天前
JSDelivr & NPM CDN 国内加速节点
前端·npm·node.js