使用GitHub Actions创建release并发布npm包

863 阅读4分钟

Enterprise-LightMode-4.webp

逛开源项目时发现它们的版本维护十分规整,好奇是如何做打包和发布的,便简单研究了GitHub Actions的使用,并用demo的形式记录整个过程,以加深印象,也供其他有同样需求的开发者参考。

一、一个假设的需求

写一个工具库,然后通过迭代之后发布新版本,要在GitHub上生成新的release并提供下载包,同时发布到npmjs上。

二、Demo演示

下面从零开始演示创建工具库并实现版本自动发布,以下是演示步骤:

  1. 创建远程仓库
  2. 开发工具库并推送到远程仓库
  3. 生成个人GitHub personal access token
  4. 生成个人npm access token
  5. 将上述tokens关联到仓库
  6. 创建GitHub Actions workflow实现自动发布

演示环境:

  • macOS 14.6
  • Nodejs 20
  • pnpm 8

演示目标:TypeScript实现的工具库,在推送tag时自动发布release和npm版本

演示侧重GitHub Actions使用环节,非重要内容简单带过

演示仓库:github.com/tonyerx/pac…

创建远程仓库

在自己的GitHub帐号下新建一个远程仓库用于管理工具库代码,如下:

image.png

初始化工具库

创建目录并初始化npm:

mkdir package-demo
cd ./package-demo
pnpm init

安装typescript包:

pnpm add typescript -D

创建tsconfig.json文件(这里随便写了点配置,如果需要定制编译请查看文档调整):

{
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./lib",
    "sourceMap": true,
    "declaration": true,
    "target": "ESNext",
    "module": "ESNext",
  },
  "include": ["./src/**/*"]
}

修改package.json,添加构建命令并修改指定入口:

{
  "main": "./lib.js"
}
{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "tsc"
  },
}

接着开始写工具函数,创建src/index.ts(随便写了一个,主要为了有内容可以打包):

export const plus = (...args: number[]) => args.reduce((a, b) => a + b);

尝试本地构建,运行pnpm build发现lib目录生成以下文件即代表打包没问题了:

image.png

接着初始化git:

git init

创建.gitignore文件:

/node_modules/
/lib/

设置远程仓库地址:

git remote add origin https://github.com/tonyerx/package-demo.git

运行以下命令提交代码:

git add .
git commit -m 'feat: initialize project'

将默认分支重置为main并推送到远程仓库:

git branch -M main
git push origin main -u

至此一个简陋的工具库搭建好了:

image.png

生成个人GitHub personal access token

这一步是让actions有权限操作代码

  1. 点击 右上角头像 - Settings - Developer Settings - Personal access tokens - Tokens(classic) - Generate new token 创建新的token:

image.png

image.png

image.png

  1. 接着填写token的作用、过期时间以及可操作的范围,如图:

image.png

  1. 点击generate按钮之后会生成token,记得复制下来后面要用,之后就再不可见了

生成个人npm access token

这一步是让action有权限发布npm包到npmjs

  1. 点击 右上角头像 - Access Tokens - Generate New Token

image.png

  1. 填写token名字及权限,注意选择publish权限:

image.png

  1. 这里注意一样要复制下来后面用,关掉页面之后就拿不到了

将上述tokens关联到仓库

回到远程仓库,点击 Settings - Secrets and variables - Actions - Ne repository secret 创建两个token:

  • GHP_TOKEN对应GitHub personal access token
  • NPM_TOKEN对应npm access token

image.png

创建GitHub Actions workflow实现自动发布

回到远程仓库,点击 Actions,可以看到当前仓库没有任何workflow:

image.png

可以使用GitHub Actions模板创建或者手动创建workflow yml文件。我们想实现两个功能,所以自己写一个。 回到代码目录,创建.github/workflows/main.yml,配置如下:

name: Publish And Release
on:
  push:
    tags:
      - 'v*'

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Setup Node and Build
        uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: https://registry.npmjs.org/
          cache: 'pnpm'

      - run: pnpm install

      - run: pnpm build

      - name: Publish to npmjs
        run: pnpm publish --access public --no-git-checks
        env:
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

      - run: tar -zcvf release.tgz ./lib/

      - name: Release
        uses: softprops/action-gh-release@v2
        with:
          token: ${{ secrets.GHP_TOKEN }}
          name: ${{ github.ref }}
          files: ./release.tgz
          draft: false
        

我们稍后解析配置项的作用。先将workflow推到远程仓库:

git add .
git commit -m 'chore: add release workflow'
git push

打个版本,并尝试打个tag推到远程看看能不能触发workflow运行:

pnpm version minor
git push
git push origin v1.1.0

检查远程仓库的Actions运行状态:

image.png

检查远程仓库的release:

image.png

检查npmjs包发布状态:

image.png

至此流程配置完成。

三、Workflow解析

GitHub Actions分成三层级:Workflow > Job > Step

即一个仓库可以有多条workflow,每个workflow可以有多个job,每个job里可以有若干个step

配置workflow名字

# workflow的名称,见下图
name: Publish And Release

image.png

配置运行条件

# 当push v*的时候会运行这个action,如:在本地执行git push origin v1.1.0,会运行这个workflow
on:
  push:
    tags:
      - 'v*'

配置Job名字和运行的操作系统

jobs:
  # job的名称,见下图
  build-and-publish:
    # job运行的操作系统,一般选择最新的ubuntu即可
    runs-on: ubuntu-latest

image.png

配置Step名称

steps:
  # step的名称,见下图
  - name: Checkout
    uses: actions/checkout@v4

image.png

可以看到,配置了step的名称会对应任务窗口中的单个step,方便查看执行情况,对我们排查workflow故障非常友好。 注意:一个step最多只能有一个run,可以不命名,默认以执行的命令作为名字。

关于step use:

steps:
  # step的名称,见下图
  - name: Checkout
    uses: actions/checkout@v4

其实uses的值是第三方action的仓库地址缩写,省略了github.com前缀,完整是github.com/actions/che…。 可以查看所有官方收录的action

全部配置解析

name: Publish And Release
on:
  push:
    tags:
      - 'v*'

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    steps:
      # Step1: 检出源码
      - name: Checkout
        # 使用的第三方action名称,其实是仓库地址的缩写,省略了github.com/前缀,完整是https://github.com/actions/checkout/tree/v4/
        uses: actions/checkout@v4
      
      # Step2: 安装pnpm环境
      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          # 这里可以设置pnpm的版本,但前提是不要用pnpm配置文件或package.packageManager指定版本,否则会报错
          # https://github.com/pnpm/action-setup/tree/master?tab=readme-ov-file#install-only-pnpm-without-packagemanager
          # 我在package指定了,所以不在此处指定
          # version: 8
          run_install: false

      # Step3: 安装Nodejs环境并打包
      - name: Setup nodejs and build package
        uses: actions/setup-node@v4
        with:
          node-version: 20
          # 设置要发布到哪个npm镜像仓库,这里指向npmjs
          registry-url: https://registry.npmjs.org/
          cache: 'pnpm'

      # Step4:安装依赖
      - run: pnpm install

      # Step5:打包
      - run: pnpm build

      # Step6:发布到npmjs
      - name: Publish to npmjs
        # 这里用了带scope的包名防止和其他公共包冲突,因此需要加上--access public
        # 因为当前检出的是tag的代码,没有分支,因此会报错,需要加上--no-git-checks,见https://github.com/pnpm/pnpm/issues/5894
        run: pnpm publish --access public --no-git-checks
        env:
          # 这里环境变量写配置在仓库secret的npm access token的名字
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

      # Step7:将lib目录压缩成一个文件,用于release附件
      - run: tar -zcvf release.tgz ./lib/

      # Step8: 发布release
      - name: Release
        uses: softprops/action-gh-release@v2
        with:
          # 这里环境变量写配置在仓库secret的GitHub Personal access token的名字
          token: ${{ secrets.GHP_TOKEN }}
          name: ${{ github.ref }}
          files: ./release.tgz
          draft: false

四、插件推荐

我使用的是VSCode,这里强烈推荐安装GitHub官方的这个插件:GitHub Actions,它有以下好处:

  • 在编辑器中可以自动检查,避免低级的语法错误,减少调试时间
  • 提示可用的key
  • 第三方action说明、链接