Explain how to integrate a common bash script into the NPM ecosystem, using a recently encountered CR submission script as an example.

background

Merge Request as a programmer, you’ve all used the Merge Request function on GitHub at one point or another. Of course, in addition to such Code Review methods, many companies have their own Code Review platforms, and our company is no exception. We use tools similar to Gerrit, and here we refer to it as Gerrit. Due to the recent governance project, it is necessary to use Gerrit for CR submission. Git push: git push: git push: git push: git push: git push: git push: git push: git push: git push As a siege lion, this is a bit hard to bear!!

appeal

Is there a separate command for me to submit Gerrit directly?

Is there a command line tool that I can use by installing it directly?

3. After git push, commit Gerrit on demand after git hook intercept.

To solve

Is there a separate command for me to submit Gerrit directly?

A: Yes, a colleague forwarded a bash script to me when I was having a hard time submitting Gerrit: copy it to the /usr/local/bin directory and use Gerrit directly.

branch=$(git symbolic-ref --short -q HEAD)
git push origin HEAD:refs/for/${branch}
Copy the code

Is there a command line tool that I can use by installing it directly?

A: Yes, since there are scripts, as front-end development, must use beloved Node.js package a command line tool, only two steps can be used: first execute NPM i@dd /gerrit-cli -g; Then execute gerrit in the project directory to use it.

3. After git push, commit Gerrit on demand after git hook intercept.

A: Yes, if you still feel that installing the global command line is too much trouble, or you are afraid that new people will come in and be confused. Git hooks can also be used for interception, and the user only needs to perform git push “mindlessly”. Of course, there is a ready-made Git hook in the front part, which is the beloved Husky by everyone. As for other language ecology, we should find some.

Let’s take a look at how to encapsulate the above script!

implementation

1. Configure commands

How can someone install your NPM package and run the command line from the terminal? Simply add the bin field to your NPM package package.json:

{
  "name": "your-first-cli-package"."version": "1.0.0"."description": "Your first command-line tool."."main": "index.js"."bin": {
    "yourCommand": "index.js"}},Copy the code

When someone else uses NPM i-g your-first-cli-package, you can execute yourCommand in the terminal to call your index.js logic. If a partial installation is used, that is, NPM I your-first-CLI-package, the command line will be installed under node_modules/.bin/yourCommand, whose contents are the contents of index.js. The NPM scripts call can be edited at this point.

2. Invoke the declaration

Since we are using node.js, the command line entry js file (in this case index.js) needs to declare that the current file is executed using Node:

#! /usr/bin/env node
// Write the logic for yourCommand here
Copy the code

3. Write logic

The implementation here is rough, with only one command at the moment, so no packages like ARgs have been introduced.

#! /usr/bin/env node

const execa = require('execa')
const chalk = require('chalk')

const run = async() = > {let branch = ' '
  let result = ' '

  try {
    console.log(chalk.gray('Get the current branch... `))
    const { stdout } = await execa.command('git symbolic-ref --short -q HEAD')

    branch = stdout
    console.log(chalk.gray('The current branch is:${branch}`))}catch (error) {
    console.log(chalk.red('Failed to get branch:${error.message}`))
    process.exit(1) // Exit with a failure code, which is used to identify git hooks
  }

  try {
    console.log(chalk.gray('Check whether the current branch pushes through the remote repository... `))
    await execa.command(`git rev-parse --abbrev-ref ${branch}@{upstream}`)
    console.log(chalk.gray('The current branch exists in${branch}Remote warehouse... `))}catch (error) {
    console.log(
      chalk.yellow('Current branch${branch}The remote repository is not pushed${error.message}`),try {
      console.log(chalk.green('Try pushing the branch${branch}To remote warehouse))
      const { stderr } = await execa.command(
        `git push --set-upstream origin ${branch} --no-verify`,
      )

      result = stderr
    } catch (error) {
      console.log(chalk.red('Failed to submit gerrit:${error.message}`))
      process.exit(1)}}try {
    console.log(chalk.gray(` to branch${branch}Submit gerrit... `))
    const { stderr } = await execa.command(
      `git push origin HEAD:refs/for/${branch} --no-verify`,
    )

    result = stderr
  } catch (error) {
    console.log(chalk.red('Failed to submit gerrit:${error.message}`))
    process.exit(1)}console.log(chalk.green(`${branch}Gerrit was submitted successfully with the following message: \n${result}`))

  process.exit(0) // Exit with a success code, which is identified by git hooks
}

run()
Copy the code

use

Global use (recommended for non-front-end engineering)

The installation

npm i @dd/gerrit-cli -g

perform

Make sure you are in the Git project directory

gerrit

The sample

Local use of JavaScript engineering (recommended for front-end engineering)

The installation

npm i @dd/gerrit-cli --save-dev

Add Gerrit scripts to package.json

"scripts": {..."cr": "gerrit". },Copy the code

perform

Make sure you are in the Git project directory

npm run cr

The sample

andhuskyTogether with

Add Gerrit scripts to package.json

"scripts": {..."cr": "gerrit". },"husky": {
  "hooks": {
    "pre-push": "npm run cr"}},Copy the code

perform

Make sure you are in the Git project directory

git push

The sample

TODO

  • Added subcommands to support generating gerrit configuration files
  • Print the documentation link for the CR specification, otherwise newcomers will be overwhelmed
  • Packaged as an SDK for other tools to call

conclusion

We’ll be more or less in a similar situation, encapsulating it from an engineering point of view, allowing bash scripts outside the NPM ecosystem to be invisible as well!