最近在把公司内部用的一个库发布到内网的npm私服上,仅仅是发布的话是比较简单的,但这个库是由多我的一块儿维护的,并且npm私服只有一套,因此生产环境和开发环境,用的是同一个,那么,咱们的需求来了:如何设计npm包的开发流程和自动化发布流程。 这一套流程咱们想要的达成以下目标javascript
先说下如何搭建npm私服和如何发包,不过这不是咱们这篇要讲的重点,因此咱们就简单介绍java
目前比较主流的有 nexus
和 Verdaccio
,由于 Verdaccio
要更轻量些,并且也知足咱们的需求,因此咱们选择它。 Verdaccio
搭建很是简单,直接使用默认配置就行node
npm install -g verdaccio
or
yarn global add verdaccio
verdaccio
复制代码
就这样,私服就搭建完成啦。git
有了私服,咱们先注册到本地的npm中 npm set registry http://localhost:4873
而后添加用户,若是是首次,则会新建用户 npm adduser --registry http://localhost:4873
最后是发布 npm publish
shell
设定版本号有两种方式,一种是人工修改 package.json
中的 version
npm
// package.json
{
"name": "project",
"version": "1.0.0",
}
复制代码
另外一种是经过 npm version
来修改版本号,提供有这以下参数json
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]
复制代码
详细解释以下:bash
newversion:自定义版本号,除了已经发布的版本号,想写啥写啥
major:升级主版本号 1.0.0 -> 2.0.0
minor:升级次版本号 1.0.0 -> 1.1.0
patch:升级补丁号 1.0.0 -> 1.0.1
premajor:预备主版本
preminor:预备次版本
prerelease:预发布版本
复制代码
在执行npm version
后,会产生一条新的提交记录,好比说执行 npm version 2.0.0
完后 ,查看log,会发现一条 commit message 为 2.0.0
的提交记录,至于为啥会生成这条记录呢?很简单,由于npm version
这行命令实际上是修改了 package.json 中的 version ,修改后并提交,因此就有这条新的提交记录。要是想自定义提交记录,能够这么写 npm version 2.0.0 -m "Upgrade to %s for reasons"
其中%s
就是修改后的版本号。并发
咱们打算使用 gitlab CI 来实现自动化发布,咱们也简单介绍下 gitlab CI 的一些步骤和配置项。函数
.gitlab-ci.yml
,写入配置,详细的配置能够查看 gtilab官网# 定义 stages
stages:
- build
定义 job
job1:
stage: build
script:
- echo 'xxx'
复制代码
咱们要说的重点来啦,经过画图的方式来给你们介绍咱们的设计思路。先来设定些约定
项目的分支的规划,设定三个分支
feature
分支:常规功能迭代master
分支:稳定分支hotfix
分支:当有紧急修改时,建立该分支,做为临时修复分支,这样能够不影响常规功能的开发咱们采用 大版本:小版本:次版本号
这种方式,每一次feature分支上的每次提交都触发此版本号升级,好比当前feature分支的版本号是 1.1.5
那么下一次提交就会升级为 1.1.6
并发布npm,小版本号跟着常规需求迭代往上升级,好比说当前是 1.1.8
,周期性的需求在明天上线,那么上线后,版本号就升级为 1.2.0
并发布npm,你们发现 1.1.8
和 1.2.0
是一样的代码,没错,之因此这么作是由于小版本号对应的是一个周期的常规修改,那么升级的 1.2.0
就是做为下一次的常规需求的版本号,这样一来,此版本号对应的是每一次提交,小版本号对应的是当前的开发阶段,这两个咱们均可以经过CI来触发修改,不须要人工参与 ,剩下还有个大版本号,这个只有在大改版的状况下才由人工修改,通常来讲升级大版本号的频率是比较低的,人工来来修改彻底是OK的。
你们会发现每一次提交就触发 npm version patch & npm publish
感受太频繁了,但为了能知足团队协做,只好作些小小的让步。因此此版本号在这里的做用并非用来区分版本的,小版本号才是真正用来作版本区分的,那么在引用这个npm就要这么来控制版本号,举个栗子
"my-package": "~1.2.0"
复制代码
锁定大版本号和小版本号,无论咱们开发过程当中提交了多少次,咱们引用都是最新的。
画了开发、发布的时序图,以下。
开发时序图以下
主要是CI的编码,以下
# .gitlab-ci.yml
# 定义 stages
stages:
- publish
# 定义 job
job2:
stage: publish
before_script:
- cd /home/node/MY #进到项目目录
- git checkout .
- git checkout $CI_COMMIT_REF_NAME || git checkout -b $CI_COMMIT_REF_NAME
- git pull -f -X theirs origin $CI_COMMIT_REF_NAME
- yarn
script:
- node publish.js
复制代码
// publish.js
var shell = require('shelljs');
var git = require('git-last-commit');
var featureBranchName = 'feature-npm';
// 判断文本是不是版本号格式
function checkCommitMessage(subject) {
return /^\d+.\d+.\d+$/g.test(subject)
}
// 获取最近一次提交,判断是不是版本号格式,若不是,则进行发布,
git.getLastCommit(function(err, commit) {
console.log(commit);
const { subject, sanitizedSubject } = commit;
shell.exec('echo $CI_COMMIT_REF_NAME');
if (!checkCommitMessage(subject)) {
if (sanitizedSubject.indexOf(`Merge-branch-${featureBranchName}-into-master`) > -1) {
shell.exec('git checkout .');
shell.exec(`git checkout ${featureBranchName} || git checkout -b ${featureBranchName}`);
shell.exec(`git pull -f -X theirs origin ${featureBranchName}`);
shell.exec('npm version minor');
shell.exec('npm publish');
shell.exec(`git push origin ${featureBranchName}`);
} else {
shell.exec('npm version patch');
shell.exec('npm publish');
shell.exec('git push origin $CI_COMMIT_REF_NAME');
}
}
});
复制代码
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"prepublish": "build script"
},
复制代码
发布脚本里有个函数 checkCommitMessage
用于判断最新的提交message是否是版本号格式,由于咱们最后会有一步push的操做,push后会再一次触发CI,因此为了防止死循环,咱们经过提交的message做为是否触发CI的依据,这么一来咱们就要规范message的格式,个人建议是按照这个格式 U ${修改的具体的内容}
。
这个方案不是个普适性的方案,毕竟每一个团队的开发流程都不同,目前这个方案是适合咱们目前的场景的。若是有小伙伴的场景跟咱们的一致,能够尝试下,若是小伙伴们有更好的方案,欢迎一块儿交流呀~