Gitlab CI自动发布NPM的实践

3,026 阅读2分钟

背景

NPM包往往承担着一些公用业务或者逻辑,NPM的上线发布的自动化是我们的目标,如果能利用Gitlab CI之类的工具来完成自动化发布latest版本 + 生成/更新 CHANGE.LOG + 打tag这一系列的操作,会令我们的上线流程省心和规范化不少

话不多说

关于gitlab ci的介绍请看官方文档

首先了解下.gitlab-ci.yml官方文档 ,这里搬运一个官网的关于NPM的CI的示例代码:

# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/npm.gitlab-ci.yml

publish:
  image: node:latest # 表示使用的NODE镜像
  stage: deploy
  rules:             # 触发的规则
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^v\d+\.\d+\.\d+.*$/
      changes:
        - package.json
  script:           # 以下是运行脚本
    # If no .npmrc is included in the repo, generate a temporary one that is configured to publish to GitLab's NPM registry
    - |
      if [[ ! -f .npmrc ]]; then
        echo 'No .npmrc found! Creating one now. Please review the following link for more information: https://docs.gitlab.com/ee/user/packages/npm_registry/index.html#project-level-npm-endpoint-1'
        {
          echo "@${CI_PROJECT_ROOT_NAMESPACE}:registry=${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
          echo "${CI_API_V4_URL#http*:}/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=\${CI_JOB_TOKEN}"
        } >> .npmrc
      fi
    - echo "Created the following .npmrc:"; cat .npmrc

    ...

看起来还是比较复杂,我们关注下需要用到的部分:

  • image: 来指定镜像,我们如果指定了node镜像,里面其实是自带了npm,git等工具
  • rules: 用来指定触发规则,还有only字段等也是同样的作用
  • script: 用来执行自定义脚本,我们的发布逻辑会写在这里
  • variables: $CI_COMMIT_BRANCH,$CI_COMMIT_REF_NAME这些都是CI内部提供的变量,可以直接使用这些值,具体见官方文档CI变量

其次,我们需要在CI内执行NPM包的发布+ 打tag+ 生成CHANGE.LOG然后往git仓库推送,所以我们还需要新增两个自定义的CI变量NPM_TOKEN, GIT_PUSH_TOKEN,具体参考官方文档添加CI变量(需要的Maintainer权限)

最后愉快的开始我们的release分支自动发布之旅,standard-version的使用请参考上一篇文章,以下为核心代码实现及一些注释

代码

.gitlab-ci.yml配置

image: node:12.22.0 # 指定node镜像版本

stages:
    - publish # 定义了一个publish的stage
    
publish_job:
  stage: publish # 对应上面我们定义的publish的stage
  only:
    - release    # 只对release分支生效,我们将代码合并进去release分支会触发
  script:
    - npm set registry https://ucompany.xxx       # 配置npm源
    - git config --global user.email "uemail@com" # 配置git账号
    - git config --global user.name "uname"
    - echo "//npm.xxxx.io/:_authToken=${NPM_TOKEN}" > ~/.npmrc  # 将配置的NPM_TOKEN写入.npmrc文件
    - echo "unsafe-perm = true" >> ~/.npmrc  #由于ci里面用root账号发布,需要加这个
    - yarn install # or npm install
    - node build/publish ${CI_COMMIT_REF_NAME} ${GIT_PUSH_TOKEN} ${CI_COMMIT_MESSAGE} # 跑js代码

publish.js 发布代码

const shell = require('shelljs') // 这个非必需,可以用node自带的
const { join } = require('path')
const publishType = 'patch' // major, minor, patch

const rootPath = process.cwd()
const pkg = require(`${join(rootPath, 'package.json')}`)
const packageName = pkg.name

const CI_COMMIT_REF_NAME = process.env.CI_COMMIT_REF_NAME
const GIT_PUSH_TOKEN = process.env.GIT_PUSH_TOKEN // 推送commit用

try {
  const versionCommand = `npm run release -- --release-as ${publishType} --releaseCommitMessageFormat "chore(release): {{currentTag}} [skip ci] "`
  const publishCommand = 'npm run publish --registry https://ucompany.com'
  shell.exec(`${versionCommand} && ${publishCommand}`)

  console.log(`${packageName}发布完成:开始推送tag和changelog...`)
  const gitPushCommand = `git push https://gitlab-ci-token:${GIT_PUSH_TOKEN}@xxxxgit_address_xxxx.git/ HEAD:${CI_COMMIT_REF_NAME} --follow-tags`
  shell.exec(gitPushCommand)
} catch (e) {
  console.log(e)
  process.exit(1)
}

结束语

以上是关于ci自动发布的实践demo,非live环境的配置在上面省略了,可以自行定义,如有好的idea欢迎评论区交流~

感谢-_-