因为懒,写了一个自动区分环境打tag的脚本

背景

可能大家在公司写业务的时候,可能都会涉及到不同环境的分支的上线部署。测试,预发,正式服也都是不同的分支,打不同的tag去触发CI/CD。我们可能会在测试服改很多次bug,打很多的tag,发布不同的测试版本。

我个人是个非常不喜欢记太多命令的人,于是为了偷懒,为什么这么多的操作何不去写个脚本,一行命令就搞定呢。由于这样的契机,写了这个针对多环境的tag触发脚本。

原理

  1. 通过写入的命令获取发布的环境,并判断环境和部署的分支名是否对应
  2. 打tag,更改 package.json 版本号
  3. git push

实现

实现方式为node,然后使用zx run shell cmd

zx的介绍参考# zx, 如何用Javascript优雅的书写脚本命令

script

首先我们在scripts文件夹下面建立我们的release脚本文件

然后思考,如何接受我们需要接受的环境变量env)呢?

于是我们可以在package.json中定义我们命令,通过命令的方式传入写入环境。

例如:

// package.json
"scripts": {
    "release:test": "zx scripts/release.mjs -- test",
    "release:pre": "zx scripts/release.mjs -- pre",
    "release:prod": "zx scripts/release.mjs -- prod"
}
复制代码

env

上面我们脚本命令传入参数,区别与不同的环境,于是我们接受环境变量(env

const [,,,, env] = process.argv // test or pre or prod
复制代码

这样我们就拿到了环境变量。但是出于严谨性判断,可能我们会在错误的分支上打tag,于是我们需要对命令发布的时机和当前分支做判断

首先我们建立环境变量和正确分支之前的映射关系

例如:

// 自行更改
const env2branch = {
    test: 'dev', // test 对应 dev 分支
    pre: 'pre', // pre 对应 pre 分支
    prod: 'master' // prod 对应 master 分支
}
复制代码

然后判断当前分支是否在映射表里。

如何查看当前分支呢?

很简单,我们使用zx 执行 git branch

image.png

我们发现当前分支前面有一个*进行标记,于是我们根据这一点,获取当前分支名。

const res = await $`git branch`
const branchs = res.stdout.split('\n')
const currentBranch = branchs.find(b => b.includes('*')).replace(/[\*|\s]*/g, '') // 当前分支名
复制代码

然后判断currentBranch是否是env所对应的正确分支。

newVersion

我们做了envbranch的判断,接下来我们需要生成下一次正确发布的版本。于是很简单 我们只需要对上一次的版本号进行+1操作就好了

如何获取上一次的发布的版本号呢? git tag这个命令就很符合我们的要求,他会列出所有的tag

于是 我们使用zx 执行 git tag

image.png

(截取一小部分)我们发现我们需要对tags进行env的过滤

image.png

我们还发现tags的排序也有问题,并不是按照正确的版本顺序排,我们还需要正确的sort一下。

根据个人情况而定。我司的tag都是 ${env}-${version}格式

获取env对应的所有versions

const res = await $`git tag`
const prefix = `${env}-`
const allVersions = res.stdout.split('\n').filter(tag => tag.includes(env)).map(tag => tag.replace(new RegExp(prefix), ''))
复制代码

然后在对veisons进行正确的排序,排序算法参考的别人的算法,待会见源码

const sortVersions = sortVersion(allVersions) // 排序
复制代码

这样sortVersions[sortVersions.length - 1]便是我们的最新的版本号

我们再进行+1操作,生成最新的版本号。

const latestVersion = sortVersions[sortVersions.length - 1]
const ltStr = latestVersion.split('.')
ltStr[ltStr.length - 1] = Number(ltStr[ltStr.length - 1]) + 1
return ltStr.join('.') // 最新的版本号, 也就是需要发布的版本号
复制代码

我们再去使用bumpp去更改我们package.jsonversion

runShell

功能已经全部完善了,最后我们再git push就好了

async function runShell(version) {
  const tag = `${env}-${version}`
  await $`git add .`
  await $`git commit -m "chore: release ${tag}"`
  await $`git tag ${tag}`
  await $`git push`
  await $`git push origin --tags`
  await $`clear`
  console.log(`release success for ${tag} !`)
}
复制代码

源码

// package.json
{
    "type": "module", // 需要开启
    "scripts": {
        "release:test": "zx scripts/release.mjs -- test", // 根据情况自己更改配置
        "release:pre": "zx scripts/release.mjs -- pre", // 根据情况自己更改配置
        "release:prod": "zx scripts/release.mjs -- prod" // 根据情况自己更改配置
    }
}
复制代码
// release.mjs
import { $ } from 'zx'

const env = getEnv()

run()

async function run() {
  const isRightBranch = await isEnvBranch(env)
  if (!isRightBranch) {
    console.log('不是正确的分支')
    return
  }

  const version = await generateVersion()

  await changeVersion(version)

  await runShell(version)
}

function getEnv() {
  const [,,,, env] = process.argv
  return env
}

async function generateVersion() {
  const [, lastVersion] = await getLatestTag(env)
  const ltStr = lastVersion.split('.')
  ltStr[ltStr.length - 1] = Number(ltStr[ltStr.length - 1]) + 1
  return ltStr.join('.')
}

async function changeVersion(v) {
  await $`pnpm exec bumpp ${v}`
}

async function runShell(version) {
  const tag = `${env}-${version}`
  await $`git add .`
  await $`git commit -m "chore: release ${tag}"`
  await $`git tag ${tag}`
  await $`git push`
  await $`git push origin --tags`
  await $`clear`
  console.log(`release success for ${tag} !`)
}

async function isEnvBranch(env) {
  // 根据情况自己更改配置
  const env2branch = {
    test: 'dev',
    pre: 'pre',
    prod: 'master'
  }
  const res = await $`git branch`
  const branchs = res.stdout.split('\n')
  const currentBranch = branchs.find(b => b.includes('*')).replace(/[\*|\s]*/g, '')

  const aimBranch = env2branch[env]
  await $`clear`
  return aimBranch === currentBranch
}

async function getLatestTag(env) {
  const res = await $`git tag`
  const prefix = `${env}-`
  const allVersions = res.stdout.split('\n').filter(tag => tag.includes(env)).map(tag => tag.replace(new RegExp(prefix), ''))
  const sortVersions = sortVersion(allVersions)
  await $`clear`
  return [prefix, sortVersions[sortVersions.length - 1]]
}

function sortVersion(arr) {
  const result = [...arr]
  result.sort((a, b) => {
    const items1 = a.split('.')

    const items2 = b.split('.')

    let k = 0

    for (const i in items1) {
      const a1 = items1[i]

      const b1 = items2[i]

      if (typeof a1 === 'undefined') {
        k = -1

        break
      } else if (typeof b1 === 'undefined') {
        k = 1

        break
      } else {
        if (a1 === b1)

          continue

        k = Number(a1) - Number(b1)

        break
      }
    }

    return k
  })

  return result
}

复制代码

不足

该脚本暂时只支持小版本号+1,如v1.0.1,使用脚本只能发v1.0.2,所以很局限性,大家可以根据自己的要求更改代码。好了,就这么多,欢迎使用。

Guess you like

Origin juejin.im/post/7074226838075408415