“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The background,

I don’t know if you have the same habit as me. You have a warehouse where you practice and study or record ideas. And this directory has been following you all the time and has been put on Github. After every practice, you need to save and commit to Git, but the commit is not very important, but you need to add/commit/push yourself every time.

Yes, I did, and I finally got sick of it, so I decided to write a tool for fast submission. NPM install -g: NPM install -g: NPM install -g: NPM install -g: NPM install -g: NPM install -g: NPM install -g

Second, clear requirements

  1. Add to command line, oknpm install -g xxx;
  2. Set in the project directory.envFile, custom commit- MSG and default commit branch;
  3. Check whether it exists in the directory.gitDirectory, no prompt;
  4. checkgitThe command is installed or configured correctly.
  5. Check whether the current branch is.envConfigured branches;
  6. The above checks are automatically executed after passingadd/commit/pushCommand;

Three, reserve knowledge

3.1 NPM account

It’s 2022, so if you haven’t already, register with your NPM account

3.2 Adding a VM to the CLI

Package. json file is a binary file that can be executed. This is a command that can be registered as a command.

The bin field is typically presented as an object, where key will be registered as a command name and value points to the corresponding executable file, as in the following example:

{
  "name": "fast-commit"."bin": {
    "rs7": "lib/index.js"
  },
  "productVersion": "1.2.10"
}
Copy the code

When the fast-commit package is installed globally: NPM install fast-commit -g, rs7 will be registered as global, rs7 will be registered as global, rs7 will be registered as global, rs7 will be registered as Terminal or CMD, rs7 will be registered as global Lib /index.js is the equivalent of node lib/index.js.

3.3. The env file

The.env configuration file, that is, to add a.env file to your project, contains some static configuration. Here is our static configuration:

# .env file
# default fast commit branch
FC_BRANCH=master

#default commit msg, date-time is default
FC_COMMIT_MSG=date
Copy the code

In the future, you can access the FC_BRANCH and FC_COMMIT_MSG properties on process.env; How did this happen? This thing is implemented through a Dotenv NPM package, which I won’t go into here;

3.4 Running Commands

Some of you might already have shelljs in mind, but node.js already provides the capability to invoke system commands using the child_process module, Use child_process. Spawn and child_process. Exec methods.

const runCommand = (cmd, args, needReturn) = > {
  return new Promise((resolve, reject) = > {
    if(! needReturn) {let executedCommand = cp.spawn(cmd, args, {
        shell: true.stdio: 'inherit'
      });
      executedCommand.on('error', reject);
      executedCommand.on('exit'.code= > +code === 0 ? resolve(code) : reject(code));
    } else {
      cp.exec(cmd, args, (err, stdo, stde) = > {
        if(err && err.code ! = =0) reject(err.code);
        else resolve({ code: 0.data: stdo })
      })
    }
  })
};
Copy the code

The method is mainly used to call system commands. NeedReturn identifies whether a return result of the current command is needed. For example, in some scenarios, we need to analyze the output result after command execution, so the command return result is required.

3.5 Cli Displays Beautiful Information

This ability is provided by NPM package Chalk, install it, I think the programmer who wrote this package must be very romantic, make your command line beautiful;

3.6 Executable files

File permissions: r, W, x, that is, read, write, execute. The x is short for excute to indicate that the file can be executed. The file we create eventually becomes a command, so it needs to have a permission that can be executed. Here we’ll be blunt:

$ chmod +x index.js 
Copy the code

This means that the file is given executable permission. If you don’t add the x permission, you’ll need to call node. /index.js like this. If you add x with the file #! The /usr/bin/env node header can be executed either with./index.js or by registering the bin command.

3.7 Local Debugging

You need something nice called the NPM link command

4. Code body

#! /usr/bin/env node
import chalk from 'chalk';
import * as readLine from 'readline';
import * as fs from 'fs';
import * as  path from 'path';
import * as cp from 'child_process';
import 'dotenv/config';

// Get the dot env configuration details
const { FC_BRANCH, FC_COMMIT_MSG = 'date-time' } = process.env

// Encapsulates methods that call system commands
const runCommand = (cmd, args, needReturn) = > {
  return new Promise((resolve, reject) = > {
    if(! needReturn) {let executedCommand = cp.spawn(cmd, args, {
        shell: true.stdio: 'inherit'
      });
      executedCommand.on('error', reject);
      executedCommand.on('exit'.code= > +code === 0 ? resolve(code) : reject(code));
    } else {
      cp.exec(cmd, args, (err, stdo, stde) = > {
        if(err && err.code ! = =0) reject(err.code);
        else resolve({ code: 0.data: stdo })
      })
    }
  })
};

// These two methods can write an interactive command line tool that outputs prompts on the command line and then reads the command line input to act on them
// But I am too lazy to write this and have to talk to the command line, which is not consistent with my purpose of one-click submission, but the method is put here
const readLineInterface = readLine.createInterface({
  input: process.stdin,
  output: process.stderr
});

const promiseQuestion = q= > {
  return new Promise((resolve, reject) = > {
    readLineInterface.question(q, answer= > {
      if (answer.trim()) resolve(answer);
      else promiseQuestion(q).then(resolve, reject)
    })
  })
};

// Because of the global installation, you need to know in which directory your footsteps are running, we only commit the contents in this directory
const cwd = process.cwd();

// Async self-executing functions To make it easier to use await, it will be nice if Node supports global await one day
// async iife for using await
(async() = > {// Check whether git is installed or git commands are configured correctly
  // check git is installed or .git dir existence
  let gitStatus
  let dotGitDir
  try {
    // Check if it is a git repository by checking if the.git directory exists
    dotGitDir = path.resolve(cwd, './.git')
    await fs.promises.stat(dotGitDir)
    console.log(chalk.green(`.git directory has been detected on path: ${dotGitDir}!!!!!!!!! `));
  } catch (e) {
    console.log(e);
    console.log(chalk.bgRed('.git directory does not exist on:', cwd));
    process.exit(2);
  }

  // console tips
  console.log(chalk.yellow('we will commit all changes /r/n/r/n/r... '));
  try {
    // Check whether the git command works properly
    await runCommand('git status');
  } catch (e) {
    console.error(chalk.bgRed('git installation check failed! '));
    console.error(chalk.bgRed('please install git, or config "git" command correctly!! '));
    process.exit(1);
  }

  // Read the configuration to check whether the branch is the same as the configuration branch
  const reg = /\*\s([^\n]+)/g;
  
  // Check out the current branch with git branch and grep *
  let curBranchData = await runCommand(`git branch | grep '*'`.null.1);
  let branch = reg.exec(curBranchData.data)[1]; // Check it out with the re
  if(branch ! == FC_BRANCH) {console.log(chalk.bgRed(`current branch is on ${branch}, please checkout to ${FC_BRANCH}`));
    process.exit(6);
  }

  / / calculate the commit - MSG
  let msg
  switch (FC_COMMIT_MSG) {
    case 'date':
      msg = new Date().toLocaleDateString();
      break;
    case 'date-time':
      msg = new Date().toLocaleTimeString();
      break;
    default:
      msg = FC_COMMIT_MSG
  }

  // Execute add commit push
  try {
    await runCommand('git add .');
    await runCommand(`git commit -m"${msg}"`);
    await runCommand(`git push origin ${branch || 'master'}`);
    console.log(chalk.green('FAST-COMMIT HAS PUSH YOU COMMIT TO MASTER'));
    process.exit(0);
  } catch (e) {
    if (/nothing to comit/igm.test(e)) {
      process.exit(0)}else {
      console.log(chalk.bgRed('FAST-COMMIT ENCOUNTER SOME ACCIDENT FOR '));
      process.exit(3)}console.error(e);
  }
})();
Copy the code

Five, the last

The NPM package didn’t get sent out for the simple reason that I forgot my NPM password. But, speaking of no irrigation, this thing can be used, above: