likes
comments
collection
share

提高摸鱼时间效率:我开发了一个可配置、可编程的命令工作流工具 command-workflow

作者站长头像
站长
· 阅读数 13

前言

相信大家的公司都有很规范的 Git 流程,但是大部分情况下这些流程都是些重复操作,然后我司后端大佬写了一个 Shell 脚本来提升工作效率。受他的启发,我用 Nodejs 编写了一个可编程的命令工作流工具。

首先说一下我司的 Git 流程,以测试环境为例:

  1. 根据 master 分支创建自己的开发分支,例如:feature-XXX
  2. 开发完成后,merge 到 develop 分支
  3. 在 develop 分支构建 Tag,例:release-develop-XXX
  4. 根据 Tag 触发 Jenkins pipeline。

虽然流程没有多少,但是每次部署测试环境都要重复 2 ~ 3 步骤的操作,开发了 command-workflow 之后,就可以用这个工具来帮我完成这些枯燥无聊的重复流程。

介绍

command-workflow(以下简称 CWF) 是一个可配置、可编程的命令工作流工具,根据命令执行特定任务。 简单、灵活且易于扩展。你只需要编写一次配置,然后运行指定命令,CWF 就可以自动帮你执行你想执行的命令流程。

GitHub 地址

安装

npm install command-workflow -D

使用

基本使用

# create config file
touch cwf.config.js
// cwf.config.js
import { defineConfig } from 'command-workflow'

const filename = new Date().getTime()

export default defineConfig({
  steps: [{
    command: 'ls',
  }, {
    command: 'touch #{filename}',
    tags: {
      filename: () => {
        console.log('filename:', filename)
        return filename
      }
    }
  }, {
    command: 'vim #{filename}',
    tags: {
      filename: () => {
        return filename
      }
    }
  }],
})
# Run command 
npx cwf
# Run log
$ cwf
11:03:10 AM [CWF] Run command: ls
cwf.config.js           node_modules            package-lock.json       package.json
filename: 1690340590431
11:03:10 AM [CWF] Run command: touch 1690340590431
11:03:10 AM [CWF] Run command: vim 1690340590431
✨  Done in 1.99s.

CWF 允许你在命令字段中使用 #{tag} 格式来传入自定义标签。你可以在 tags 字段中使用标签名称作为键,将方法或字符串作为值传递给 CWF。CWF 将解析这些标签并将其应用于命令,然后执行相应操作。 当然 CWF 内置了一些 tag 方便你使用,查看

进阶使用

# create config file
touch cwf.config.js
// cwf.config.js
import { defineConfig } from 'command-workflow'

const filename = new Date().getTime()

export default defineConfig({
  firstCommand: {
    steps: [{
      command: 'ls',
    }, {
      command: 'touch #{filename}',
      tags: {
        filename: () => {
          console.log('filename:', filename)
          return filename
        }
      }
    }, {
      command: 'vim #{filename}',
      tags: {
        filename: () => {
          return filename
        }
      }
    }],
  }
})
# Run command 
npx cwf firstCommand
# Run log
$ cwf
11:03:10 AM [CWF] Run command: ls
cwf.config.js           node_modules            package-lock.json       package.json
filename: 1690340590431
11:03:10 AM [CWF] Run command: touch 1690340590431
11:03:10 AM [CWF] Run command: vim 1690340590431
✨  Done in 1.99s.

你可以在配置文件中自定义 CWF 子命令,并通过在 CWF 命令后追加自定义子命令来实现多个命令工作流。如上,在配置文件中定义了名为 firstCommand 的子命令,然后执行 cwf firstCommand 命令即可执行指定的工作流程。这样,你可以轻松地根据需要配置和执行多个命令工作流程。

使用 hooks

  • before: 在执行命令之前,可以通过一个回调函数对命令进行修改。该回调函数接受命令和标签集合作为参数,并允许在执行时对命令进行修改。一旦回调函数执行完毕,程序将执行回调函数返回的修改后的命令。
  • after: 在命令执行后,你可以通过回调函数获取执行的命令和执行结果。回调函数的参数包含命令和执行结果,没有返回值。你可以方便地查看最终执行的命令和相应的执行结果。
  • error: 当命令执行过程中出现错误时,可以使用回调函数来处理错误。回调函数将错误作为参数,并且没有返回值。这使你可以方便地处理命令执行期间发生的错误。
// cwf.config.js
export default defineConfig({
  steps: [{
    command: 'ls',
  }, {
    command: 'touch #{git_user_name}',
    before: (command, tags) => {
      console.log('before command: ', command)
      console.log('before tags: ', tags)
      return `${command}-murong`
    },
    after: (command, exec) => {
      console.log('after real command: ', command)
      console.log('after exec: ', exec)
    },
    // eslint-disable-next-line n/handle-callback-err
    error: (err) => {
      console.log('error:', error)
    }
  }],
})

内置 tag

Tag描述例子
#{timestamp}时间戳touch #{timestamp}
#{current_git_branch}当前 Git 分支git checkout -b #{current_git_branch}
#{current_git_commit}当前 Git commit 哈希git commit -m #{current_git_commit}
#{current_git_commit_message}当前 Git commit 描述git commit -m #{current_git_commit_message}
#{current_git_tag}当前 git taggit tag #{current_git_tag}
#{current_git_repo}当前 git 仓库git clone #{current_git_repo}
#{current_git_repo_url}当前 git 仓库 urlgit clone #{current_git_repo_url}
#{current_git_repo_name}当前 git 仓库名称echo #{current_git_repo_name}
#{current_git_repo_owner}当前 git 仓库所有者echo #{current_git_repo_owner}
#{git_user_name}本地 Git 用户名echo #{git_user_name}
#{git_user_email}本地 Git 邮箱echo #{git_user_email}

Config

UserConfig

名称描述类型默认值是否必填
steps工作流步骤Step[]
logLevel日志等级error warn info silentinfo
isSkipError是否跳过错误日志booleanfalse
isThrowErrorBreak是否出现错误不继续执行booleanfalse

Step

名称描述类型默认值是否必填
command需要执行的命令string
tagstag 集合[x: string]: (() => string)string
disabled是否禁止此命令执行boolean ((command: string, tags: Record<string, any>) => boolean)false
error错误回调,无返回值(error: Error) => void
before命令执行之前回调,返回值是你期望最终执行的命令,返回值不是必须(command: string, tags: Record<string, any>) => string
after命令执行之后回调,无返回值(command: string, buffer: Buffer) => void

Ending

分享一下我针对我司流程编写的配置。

const { defineConfig } = require("command-workflow");

module.exports = defineConfig({
  develop: () => {
    let currentBranch = "";
    let tagName = "";
    return {
      steps: [
        {
          command: "echo #{current_git_branch}",
          disabled: true,
          before: (_, tags) => {
            currentBranch = tags.current_git_branch;
          },
        },
        {
          command: "git checkout develop",
        },
        {
          command: "git pull origin develop",
        },
        {
          command: "git merge #{current_branch} --no-edit",
          tags: {
            current_branch: () => {
              return currentBranch;
            },
          },
        },
        {
          command: "git push origin develop",
        },
        {
          command: "git tag #{tag}",
          tags: {
            tag: () => {
              tagName = `release-develop-${new Date().getTime()}`;
              return tagName;
            },
          },
        },
        {
          command: "git push origin #{tag}",
          tags: {
            tag: () => {
              return tagName;
            },
          },
        },
        {
          command: "git checkout #{branch}",
          tags: {
            branch: () => {
              return currentBranch;
            },
          },
        },
      ],
    };
  },
});
# 运行命令
cwf develop