概述
npm包自动发布有如下的好处:
- 自动化操作,节省人力
- 可使用docker等环境为每次发布准备干净的环境,避免误提交文件
- 可使用统一账号,简化权限控制
- 可以在web端控制直接发包,不依赖命令行
- 可实现npm包版本的准确控制,有迹可查
那么如何实现npm包的自动发布呢?
答案就是 CI/CD。
Github中的配置
在Github中,有很多的免费的CI/CD服务可以利用。如Travis CI、Circle CI等,我采用的是 Travis CI。
安装Travis CI
Travis CI在github中为开源项目提供免费的CI/CD服务,可以通过github的marketplace页面安装它。
安装过程中可能会涉及到对现有项目的授权,操作比较简单,travis也有对应的文档,此处略过不表。
配置 Travis CI
Travis CI使用 .travis.yml 文件进行配置。具体的配置规则可以参考其官方文档。
先看下一个示例文件
language: node_js
node_js:
- '8'
script: npm run lint && npm test
before_deploy: npm run build
deploy:
provider: npm
email: [email protected]
skip_cleanup: true
api_key:
secure: your secret token
on:
tags: true
branch: master
tag: latest
在这个示例文件中,language: node_js
指明了要使用nodejs的环境,node_js: 8
则指明了使用 node 8的版本
这两个变量合起来,就决定了travis在ci过程中会采用的docker环境。你也可以指定多个node版本,这样就会在每个版本中各自执行一次,因为我们是要用它发包,只执行一次就可以,所以只需要设置一个合适的node版本即可。
Travis中有多个执行阶段,script: npm run lint && npm test
就是指明travis固定运行的脚本,这个步骤一般用来进行测试,我在此处执行的操作是 lint 检查代码规范,及 test 进行测试。相应的npm script需要在package.json中预先定义好,略过不表。
before_deploy
和deploy
可以自解释其含义,因为我的项目中发布时需要先build一下,所以加了 npm run build
操作在deploy之前。
这里需要注意的是,在deploy之前,travis默认会进行清理。因此before_deploy
中产生的文件,并不能直接被deploy
操作使用到,要保持住这些文件的话,就需要设置 skip_cleanup
为 true。
api_key
是比较重要的一个字段,npm使用它来进行鉴权。这个数据源自于npm的token管理,并使用travis提供的命令行工具进行加密。具体操作可以参考 travis 的官方文档 https://docs.travis-ci.com/us...。
on:
选项控制的是什么条件会触发deploy,我设置的是master分支或tags,也可以设置为仅tags。即只有在新建tag的时候才会触发构建。这样每当我们新建一个tag时,就会自动发布npm包了。
自动修改版本及创建tag
请跳到本文最后关于npm版本管理。
Gitlab中的配置
另一个常用的Git服务中Gitlab,很多公司选择基于gitlab实现私有的代码仓库。
Gitlab中有自带的CI/CD服务,我们可以基于gitlab-ci实现npm包的自动发布。
配置 gitlab-ci
Gitlab CI需要先配置runner,然后再编写一个 .gitlab-ci.yml 配置文件。
Gitlab对此有文档,略过不表。大概可以参考 github 中的操作。
后面我会假定已经有可用的runner和docker环境,并基于它们进行npm包的自动发布。
stages:
- publish
# 发布到npm
publish:
stage: publish
only:
- tags
tags:
- your-runner-tag
script:
- docker run --name npm-publisher --rm -v $(pwd):/home/node/code --workdir="/home/node/code" --env NPM_TOKEN=${NPM_TOKEN} node:8-alpine sh publish.sh
这个文件相对来说更简单了一些。它的 only: tags
选项规定了只有在tag操作时才会进行publish
script
即为npm发布的过程,这里我用的方式是
- docker run node:8-alpine 镜像,生成一个新的容器
- 挂载当前目录(即代码所在目录)到容器中的 /home/node/code中,这个位置可以随便写
- 设置 workdir 为挂载目录 /home/node/code
- 将当前环境中的 NPM_TOKEN变量作为环境变量发送到容器中
- 最后,执行
sh publish.sh
脚本,在脚本中进行发布动作
publish.sh脚本的内容如下:
rm -rf /tmp/publisher \
&& mkdir -p /tmp/publisher \
&& cp -r . /tmp/publisher \
&& cd /tmp/publisher \
&& npm install \
&& npm run build \
&& npm test \
&& echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' >> .npmrc \
&& npm publish
这里在发布之前,将代码复现到了 /tmp/publisher,主要是为了避免docker中生成的node_modules影响到宿主机上的代码目录,造成一些权限问题。
发布操作是 npm install && npm run build && npm test && npm publish
这里比较重要的是创建出 .npmrc 文件,将token等信息写入配置文件中。我们使用的是 ${NPM_TOKEN} 这样的环境变量,它来自于 docker run命令中 --env 参数提供的参数,那么docker run命令中的${NPM_TOKEN}来自于哪呢?这就要看Gitlab CI中的变量设置了。
Gitlab CI中的变量设置
Gitlab中可以为CI设置变量(Travis中其实也可以),不过它相对比较特殊一些,所以单独讲一下。
在项目的Settings -> CI/CD中,有Variables一节,可以用来设置CI中用到的环境变量。
注意这里有个 Protected 选项,它是用来做什么的呢?(贸然打开它可能导致获取不到变量)
Protected的变量,简单说,就是只对Protected的分支或Tag对应的CI任务才有效,这样就起到了保护密码的作用。即使别人修改了.gitlab-ci.yml,加入了echo操作,也无法输出密码。
要使用Protected这个特性的话,就需要将tag的创建设置为Protected操作。可以在Settings->Repository->protected tags中设置,如下图所示:
这样就可以正常地在gitlab ci中使用定义好的NPM_TOKEN变量了。
npm 版本管理
一般来说,我们会采用semver的方式进行版本的管理。
也就是三段的版本,分别是 major.minor.patch
npm 工具提供了 version 命令,可以用来方便地修改 package.json中的版本号,并自动commit,以及在本地创建对应的tag。
当有大版本更新,或不兼容之前版本时,应升级major字段 npm version major
当有小版本更新,加入新功能时,可升级 minor 版本 npm version minor
当有bug修复,小的调整时,则升级patch版本 npm version patch
npm version会同时创建时 v版本号
形式的tag,将tag push上去就可以自动触发构建了。
也可以简化这步操作,在npm version操作后自动 push
在 package.json中加入下面的代码,即可实现npm version操作后,自动push代码及tag,也就自动触发了 npm 发布操作。
"scripts": {
"postversion": "git push --follow-tags"
}
参阅
https://blog.npmjs.org/post/1...
https://docs.travis-ci.com/us...
https://docs.gitlab.com/ee/ci...
https://docs.gitlab.com/ee/ci...