“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
- Add to command line, ok
npm install -g xxx
; - Set in the project directory
.env
File, custom commit- MSG and default commit branch; - Check whether it exists in the directory
.git
Directory, no prompt; - check
git
The command is installed or configured correctly. - Check whether the current branch is
.env
Configured branches; - The above checks are automatically executed after passing
add/commit/push
Command;
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: