使用Github Action自动化发布npm包

GitHub Actions 提供了一种强大的自动化构建和发布流程的方式,通过组合github action的方式形成了workflow,来实现CI/CD。我们完全可以将 npm 包的发布流程集成到 GitHub workflow中,做到自动化发包,这可以可以提高效率并减少人为错误。以下是如何使用 GitHub Actions 实现自动化发布的详细指南。

0. 原理解释

github actions是一个github推出的CI/CD工具,可以模拟平台(比如linux等)自动化执行一些操作。
npm可以通过token实现免登陆发布包,并且Github Secrets能很好的保护token不被泄露(后面会说简单说一下为什么),这样就避免了在登陆信息在CI/CD时泄露

这是我编写的权限验证的一个包,支持vue,react以及函数式调用,同时使用github workflow实现的自动npm化发包。欢迎大家参考,同时提出优化意见:
validate-permission/.github/workflows at main · 2ue/validate-permission · GitHub

1. 准备工作

在开始之前,请确保:

  • 你有一个 GitHub 账户,并且已经创建了一个仓库。
  • 你的项目中包含一个 package.json 文件。
  • 你有一个 npm 账户,并且已经获取了 npm token。
  • 你即将发布的包的包名没有被占用。

获取Access Token

首先登陆npm官网,然后点击Access Tokens:

image.png

然后进入access Tokens生成页面:

image.png

两者任选一个点击进入,两者都可以作为token在github actions中使用,只是Classic Token设置更简单,Granular Access Token设置更多,控制更精细化

点击Classic Token后:一定勾选publish,后面才能正常从github actions推送

image.png

点击:Granular Access Token,红框勾选的三个必填:

  • Token name:不必多说,token名字,起一个你喜欢的
  • Expiration:有效期,默认三十天,可以改得更长,过期后需要重新生成
  • Permissions:权限,即生成的token能做什么样的操作,同样需要选择 read && write,不然github actions执行是无法推送
  • 其余的选项可以根据需要适当勾选

填写完成后,滑到底部点击Generate token按钮

image.png

2. 如何免登陆发布npm包

创建.npmrc文件

前面你已经生成了一个npm的具有publish或者write权限的access token。
那么你只需在项目根目录下创建 .npmrc 文件,写入以下内容这个文件将包含 npm registry 的授权信息。但要注意,因为access token具有你的npm账户读写权利,所有不应该将.npmrc文件提交到远程仓库,需要将该文件加入到.gitignore中

1
//registry.npmjs.org/:_authToken=你刚刚申请的token

或者直接在项目根目录命令行执行,将会自动生成:

1
echo "//registry.npmjs.org/:_authToken=你刚刚申请的token" > .npmrc

然后,将 .npmrc 文件添加到你的版本控制系统中。

发布

将你准备发布的文件,编译好。假设你已经准备好了,那么就愉快的执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
npm logout
npm publish

# 将会输出下面类似字样,就是成功了
# ...
# npm notice package size: 12.6 kB
# npm notice unpacked size: 84.1 kB
# npm notice shasum: d282cbe9374611e6d10d6fb30215f61bb6c95c89
# npm notice integrity: sha512-N4iu+YUebBPCP[...]21dOqKE6G43iQ==
# npm notice total files: 18
# npm notice
# npm notice Publishing to [https://registry.npmjs.org/](https://registry.npmjs.org/) with tag latest and default access
# ...

或者登陆npm官网,查看刚刚发布的包

发布失败

如果你没有成功,出现如下报错:

1
npm ERR! need auth You need to authorize this machine using `npm adduser` [https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow](https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow)

有三个可能原因:

  • .npmrc配置问题:确保你的.npmrc文件路径,命名和内容正确
  • .npmrc:确保你的access token正确,或者具有publish或write权限
  • 本地没有使用npm官方源:由于某些不可描述原因,你将本地npm的源设置为其他源,没有设置为https://registry.npmjs.org,比如腾讯源,阿里云云等,此时需要切换过来才能正确

至此使用npm access token发布npm包的流程已经跑通了。

相信大家已经发现了,上面这种方式有一个问题:.npmrc只能放到本地,意味着每次换一个电脑写代码都要重新去复制access token,生成.npmrc,那有没有一种方式可以比较安全的管理它呢,答案肯定是有的:答案就在Github。
我们不但可以利用GitHub Secrets管理npm的access token,而且还可利用github actions能力实现自动化workflow,来自动化发包到npm。

3. 配置 GitHub Secrets

在 GitHub 仓库中添加 npm token:

  1. 进入 GitHub 仓库的 “Settings” > “Secrets”。
  2. 点击 “New repository secret”。
  3. 输入 NPM_TOKEN 作为名称,并粘贴你的 npm token 作为值。
  4. 保存秘密。
    image.png

请注意,这里我们可以选择Secrets和Variables,他们都在我们编写的workflow中被读取到,其实都是变量,但是两者有区别:

变量类型 存储方式 界面是否可见 修改内容 修改变量名 workflow是否可见
Secrets 加密 不可见 只能更新且更新时不能看到之前内容 无法修改 以***显示
Variables 明文 明文且可见 可自由更改且可以看到之前内容 可以修改 明文可见
从上面的比较可以看出为什么github Secrets能够有效的保护npm access token,当然万事不是绝对,如果非要追求百分百安全,那就使用最原始的方式吧,毕竟放在你本地的文件也可能因为中木马泄露出去。

4. 编写 GitHub Actions Workflow

至此我们就可以利用github actions来编写一个workflow。让我们捋一下思路:

  • 什么时候执行:在代码推送到某分支,或者打tag的时候,这里我们选择当代码推送时
  • 执行流程
    • 拉取代码
    • 设置时区:如果需要
    • 设置node环境
    • 安装pnpm,yarn等工具:如果需要
    • 安装代码依赖,并打包
    • 写入token到.npmrc
    • 执行npm 发布
      当然如果所有的操作都需要我们自己去实现,就比较复杂,好在有第三方action可以快速的让我们实现这些能力:
  • run:可以执行脚本命令,让我们可以执行类似npm i这样的命令
  • actions/checkout@v4:实现代码拉取
  • actions/setup-node@v4:实现node环境,可以指定node版本

那么我们就用这些能力创建一个workflow吧

在项目根目录下创建 .github/workflows/npm-publish.yml 文件,并添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# workflow名字
name: Publish to npm

# 触发条件:当 main 分支有 push 事件时触发
on:
push:
branches:
- main

jobs:
publish:
# 在 Ubuntu 最新版本上运行作业
runs-on: ubuntu-latest
steps:
# 使用 actions/checkout 检出当前代码
- name: Checkout code
uses: actions/checkout@v4

# 设置 Node.js 环境
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20.11.1

# 安装项目依赖,并编译
- name: Install dependencies
run: |
npm i
npm run build

# 添加access token到.npmrc
- name: Add Npm Token
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ./.npmrc
ls -al
cat ./.npmrc

# 发布到 npm registry
- name: Publish to npm
run: npm publish
env:
# 读取github的secrets变量,这里的NPM_TOKEN是前面设置的变量名
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

此 workflow 会在推送到 main 分支时触发。

image.png

5. 推送更改到 GitHub

将你的更改推送到 GitHub 仓库:

1
2
3
git add .
git commit -m "Set up automated npm publishing with GitHub Actions"
git push

6. 测试 Workflow

一旦你推送了更改,GitHub Actions workflow 将会运行。你可以在 GitHub 仓库的 “Actions” 选项卡中查看 workflow 的状态。

7. 发布新版本

当你准备发布新版本时,更新 package.json 中的版本号,然后提交并推送这些更改到 main 分支。GitHub Actions 将自动处理剩余的发布流程。

8.优化

这个workflow脚本还有很多优化的空间,比如:

优化触发时机

如果我们推送代码就执行发包操作,在有些情况下可能不符合我们要求,所有我们可以更改触发条件:
正常情况我们想的是创建了一个v1.0.0这样的tag分支才触发,并且是修改了关键源码才触发

  • 设置当推送了tag分支并且需要tag符合某种格式才触发流水
1
2
3
4
5
name: Npm publish
on:
push:
tags:
- "v*" # 这段的意思是仅在出现名为 v 字符开头的tag时,触发此任务,如v1.2.1
  • 设置修改了某些文件才执行发包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- uses: dorny/paths-filter@v3
- #必须设定ID,用于后面读取这一步的结果
id: changes
with:
filters: |
update:
- 'main/**'
- 'types/**'
- 'utils/**'
- README.md
- package.json
- rollup.config.js
- tsconfig.json
- .babelrc
- .github/workflows/publish.yml
- name: Install pnpm
- # 这里是当【changes】输出了update为true才执行执行编译等工作
if: steps.changes.outputs.update == 'true'
run: |
npm install -g pnpm

dorny/paths-filter@v3github actions市场的一个包,可以用来检查哪些文件有变动,如果有变动则输出一个变量update,为true时表示有变动,可以用steps.changes.outputs.update来读取这个变量

自动化生成版本号

每次改动需要发布npm包时,都需要修改package.json的版本号,无疑有点麻烦,那我们可以使用npm version 命令来做到自动化版本修改:

  • <update_type> 是语义化版本类型之一,如 majorminor 或 patch
  • 例如,运行 npm version patch 将会更新版本号为当前版本号的下一个补丁版本

甚至你可以通过github workflow的内置变量拿到tag名字,根据tag特征做到修改哪一个版本号

自动化生成tag和release

如果你的commit比较规范,比如使用了@changesets/cli等,那么可以利用github actions市场的三方包来自动化为你的发布生成changelog,tag,release等信息,比如semantic-release-action等

当然根据个人需求不同,可能还可以做更多的优化,这里就不一一述说了,毕竟本篇文章仅仅是一个穿针引线。

问题总结

问题 1:权限问题

如果你的 npm token 没有足够的权限发布包,你可能会遇到权限错误。[参考](#获取Access Token)

解决方案:确保你的 npm token 有发布包的权限。通常,这意味着你需要在 npm 网站上生成一个具有适当权限的 token。

问题 2:网络问题

如果你的 CI/CD 服务器无法访问 npm registry,发布可能会失败。一般在github上不会出现该问题,可能在本地使用了代理或者切换了npm源会出现这个问题。参考

解决方案:检查你的 CI/CD 服务器的网络设置,确保它可以无障碍地访问 https://registry.npmjs.org/

问题 3:Workflow 配置错误

如果你的 workflow 配置有误,它可能不会按预期触发。

解决方案:仔细检查 workflow 文件的语法和配置,特别是触发条件和 secret 的使用。

问题 4:.npmrc问题

如果你的 .npmrc 文件没有被正确地添加到项目根目录或内容不正确,那么可能导致发布失败。参考

解决方案:确保 .npmrc 文件被正确添加到你的版本控制系统,并且格式正确无误。

通过以上步骤和解决方案,你可以确保 npm 包的自动化发布流程顺畅运行。

参考

Using private packages in a CI/CD workflow | npm Docs
Working with the npm registry - GitHub Docs
Variables - GitHub Docs