逛开源项目时发现它们的版本维护十分规整,好奇是如何做打包和发布的,便简单研究了GitHub Actions的使用,并用demo的形式记录整个过程,以加深印象,也供其他有同样需求的开发者参考。
一、一个假设的需求
写一个工具库,然后通过迭代之后发布新版本,要在GitHub上生成新的release并提供下载包,同时发布到npmjs上。
二、Demo演示
下面从零开始演示创建工具库并实现版本自动发布,以下是演示步骤:
- 创建远程仓库
- 开发工具库并推送到远程仓库
- 生成个人GitHub personal access token
- 生成个人npm access token
- 将上述tokens关联到仓库
- 创建GitHub Actions workflow实现自动发布
演示环境:
- macOS 14.6
- Nodejs 20
- pnpm 8
演示目标:TypeScript实现的工具库,在推送tag时自动发布release和npm版本
演示侧重GitHub Actions使用环节,非重要内容简单带过
创建远程仓库
在自己的GitHub帐号下新建一个远程仓库用于管理工具库代码,如下:
初始化工具库
创建目录并初始化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目录生成以下文件即代表打包没问题了:
接着初始化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
至此一个简陋的工具库搭建好了:
生成个人GitHub personal access token
这一步是让actions有权限操作代码
- 点击 右上角头像 - Settings - Developer Settings - Personal access tokens - Tokens(classic) - Generate new token 创建新的token:
- 接着填写token的作用、过期时间以及可操作的范围,如图:
- 点击generate按钮之后会生成token,记得复制下来后面要用,之后就再不可见了
生成个人npm access token
这一步是让action有权限发布npm包到npmjs
- 点击 右上角头像 - Access Tokens - Generate New Token:
- 填写token名字及权限,注意选择publish权限:
- 这里注意一样要复制下来后面用,关掉页面之后就拿不到了
将上述tokens关联到仓库
回到远程仓库,点击 Settings - Secrets and variables - Actions - Ne repository secret 创建两个token:
- GHP_TOKEN对应GitHub personal access token
- NPM_TOKEN对应npm access token
创建GitHub Actions workflow实现自动发布
回到远程仓库,点击 Actions,可以看到当前仓库没有任何workflow:
可以使用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运行状态:
检查远程仓库的release:
检查npmjs包发布状态:
至此流程配置完成。
三、Workflow解析
GitHub Actions分成三层级:Workflow > Job > Step
即一个仓库可以有多条workflow,每个workflow可以有多个job,每个job里可以有若干个step
配置workflow名字
# workflow的名称,见下图
name: Publish And Release
配置运行条件
# 当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
配置Step名称
steps:
# step的名称,见下图
- name: Checkout
uses: actions/checkout@v4
可以看到,配置了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说明、链接