feat: first commit
This commit is contained in:
commit
faebaa970a
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# Archivos de respaldo creados por editores de texto
|
||||
*~
|
||||
|
||||
# Archivos temporales
|
||||
*.tmp
|
||||
|
||||
# Directorios generados por sistemas operativos o IDEs
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Dependencias y módulos generados por herramientas de desarrollo
|
||||
node_modules/
|
||||
bower_components/
|
||||
vendor/
|
||||
temp/
|
||||
|
||||
# Archivos de registro
|
||||
*.log
|
||||
|
||||
# Archivos de compilación y resultados de pruebas
|
||||
build/
|
||||
dist/
|
||||
out/
|
||||
coverage/
|
||||
log/
|
7
.npmignore
Normal file
7
.npmignore
Normal file
@ -0,0 +1,7 @@
|
||||
# Dependencias y módulos generados por herramientas de desarrollo
|
||||
node_modules/
|
||||
src/
|
||||
|
||||
esbuild.js
|
||||
.gitignore
|
||||
tsconfig.json
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Dairo Carrasquilla
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
43
README.md
Normal file
43
README.md
Normal file
@ -0,0 +1,43 @@
|
||||

|
||||
# Gcommit-cli
|
||||
Git CLI Assistant is a command-line application (CLI) that facilitates the management of changes in Git repositories.
|
||||
This tool provides an intuitive interface for performing common Git actions efficiently.
|
||||
|
||||
[](https://choosealicense.com/licenses/mit/)
|
||||
|
||||
## Features
|
||||
- Repository Initialization: Easily initialize a new Git repository in your project.
|
||||
- Change Management: Analyze changes in your repository and facilitate the preparation of files to be committed.
|
||||
- Commit Creation: Create commits with clear and descriptive messages to record your changes.
|
||||
|
||||
## Relationship between Commit Types and npm Versioning
|
||||
The version of your npm project is related to the type of commit you make.
|
||||
Here is the relationship between commit types and npm versioning:
|
||||
|
||||
- break: Indicates a change that breaks compatibility and correlates with a new major version (major) of npm.
|
||||
- feat: Indicates the addition of a new functionality and correlates with a new minor version (minor) of npm.
|
||||
- Other Commit Types: Commit types such as fix, docs, chore, refactor, style, test, among others, correlate with a new patch version (patch) of npm.
|
||||
|
||||
## Installation
|
||||
Install the CLI globally
|
||||
```bash
|
||||
sudo npm install -g gcommit-cli
|
||||
```
|
||||
|
||||
## Usage
|
||||
In your console, just type:
|
||||
```bash
|
||||
:~$ gcommit-cli
|
||||
```
|
||||
## Contribution
|
||||
Contributions are welcome! If you find any bugs or have suggestions to improve this application, feel free to open an issue or send a pull request.
|
||||
|
||||
## License
|
||||
This project is licensed under the MIT License. For more details, see the LICENSE file.
|
||||
|
||||
## Screenshots
|
||||

|
||||
|
||||

|
||||
|
||||

|
28
esbuild.mjs
Normal file
28
esbuild.mjs
Normal file
@ -0,0 +1,28 @@
|
||||
import { nodeExternalsPlugin } from 'esbuild-node-externals';
|
||||
import esbuildPluginClean from 'esbuild-plugin-clean';
|
||||
import esbuildPluginTsc from 'esbuild-plugin-tsc';
|
||||
import esbuild from 'esbuild';
|
||||
|
||||
esbuild.build({
|
||||
entryPoints: ['src/index.ts'],
|
||||
bundle: true,
|
||||
outfile: 'dist/main.bundle.js',
|
||||
platform: 'node',
|
||||
target: ['es2022'],
|
||||
tsconfig: 'tsconfig.json',
|
||||
logLevel: 'debug',
|
||||
format: 'cjs',
|
||||
plugins: [
|
||||
esbuildPluginClean({ patterns: 'dist/*' }),
|
||||
esbuildPluginTsc(),
|
||||
nodeExternalsPlugin({
|
||||
packagePath: 'package.json',
|
||||
allowList: [
|
||||
'boxen',
|
||||
'execa',
|
||||
'ora'
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
.catch((err) => process.exit(1));
|
2414
package-lock.json
generated
Normal file
2414
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
62
package.json
Normal file
62
package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "gcommit-cli",
|
||||
"version": "1.0.0",
|
||||
"description": "Git CLI Assistant is a command-line application (CLI)",
|
||||
"author": {
|
||||
"name": "cdairo22",
|
||||
"email": "cdairo2204@gmail.com"
|
||||
},
|
||||
"main": "dist/main.bundle.js",
|
||||
"type": "commonjs",
|
||||
"bin": {
|
||||
"gcommit-cli": "node ./dist/main.bundle.js"
|
||||
},
|
||||
"preferGlobal": true,
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MrDiro/gcommit-cli.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node dist/main.bundle.js",
|
||||
"build": "node esbuild.mjs"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
],
|
||||
"keywords": [
|
||||
"git",
|
||||
"commit",
|
||||
"cli",
|
||||
"command",
|
||||
"line",
|
||||
"application",
|
||||
"assistant"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@inquirer/prompts": "^5.0.1",
|
||||
"boxen": "^7.1.1",
|
||||
"chalk": "^4.1.2",
|
||||
"console-table-printer": "^2.12.0",
|
||||
"execa": "^8.0.1",
|
||||
"figlet": "^1.7.0",
|
||||
"file-size": "^1.0.0",
|
||||
"modilitejs": "^1.0.3",
|
||||
"ora": "^8.0.1",
|
||||
"wait": "^0.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/figlet": "^1.5.8",
|
||||
"@types/file-size": "^1.0.3",
|
||||
"@types/node": "^20.14.8",
|
||||
"esbuild": "^0.21.5",
|
||||
"esbuild-node-externals": "^1.13.1",
|
||||
"esbuild-plugin-clean": "^1.0.1",
|
||||
"esbuild-plugin-copy": "^2.1.1",
|
||||
"esbuild-plugin-tsc": "^0.4.0",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
210
src/app/app.component.ts
Normal file
210
src/app/app.component.ts
Normal file
@ -0,0 +1,210 @@
|
||||
import { editor, input, select, confirm } from '@inquirer/prompts';
|
||||
import { readFileSync, existsSync, writeFileSync } from 'node:fs';
|
||||
import { FileFormat } from '../types/file-format.type';
|
||||
import { bold, greenBright, red, green } from 'chalk';
|
||||
import { printTable } from 'console-table-printer';
|
||||
import versionConfig from './version.config.json';
|
||||
import { AppService } from "./app.service";
|
||||
import { Component } from "modilitejs";
|
||||
import { $ } from 'execa';
|
||||
import wait from 'wait';
|
||||
import ora from 'ora';
|
||||
|
||||
@Component()
|
||||
export class AppComponent {
|
||||
private readonly spinner = ora();
|
||||
|
||||
constructor(private readonly service: AppService) {
|
||||
console.clear();
|
||||
console.log(this.service.getDisplay());
|
||||
this.addStorage();
|
||||
}
|
||||
|
||||
protected async addStorage() {
|
||||
try {
|
||||
this.spinner.start('Looking for changes ...');
|
||||
await wait(600);
|
||||
|
||||
const git_status = await $`git status -s`;
|
||||
const list_files = git_status.stdout.split('\n');
|
||||
const files_format: FileFormat[] = [];
|
||||
|
||||
if (list_files.length > 0 && list_files[0].length > 0) {
|
||||
for (const file of list_files) {
|
||||
const [prefix, filename] = file.trim().split(/\s+/);
|
||||
files_format.push({
|
||||
status: this.service.getPrefix(prefix),
|
||||
file: bold(filename),
|
||||
size: this.service.getFileSize(prefix, filename)
|
||||
});
|
||||
}
|
||||
|
||||
this.spinner.stop();
|
||||
printTable(files_format);
|
||||
await $`git add .`;
|
||||
await wait(300);
|
||||
console.log(greenBright('✔'),`${list_files.length} files added to staged 🚀`);
|
||||
|
||||
const typeSelected = await select({
|
||||
message: 'Select a type of commit to perform:',
|
||||
choices: versionConfig,
|
||||
loop: false,
|
||||
});
|
||||
|
||||
const versionCommit = this.service.getVersion(typeSelected);
|
||||
|
||||
const titleCommit = await input({
|
||||
message: 'Commit title'
|
||||
});
|
||||
|
||||
const messageCommit = await editor({
|
||||
message: 'Commit description',
|
||||
default: 'No description for this commit'
|
||||
});
|
||||
|
||||
const npmVersion = await $`npm version ${[versionCommit]} --no-git-tag-version`;
|
||||
|
||||
this.spinner.start('Generating commit ...');
|
||||
await wait(600);
|
||||
await $`git add .`;
|
||||
await $`git commit -m ${[`${typeSelected}: ${titleCommit} (${npmVersion.stdout})`]} -m ${[`${messageCommit}`]}`;
|
||||
this.spinner.succeed('Commit generated.');
|
||||
await wait(600);
|
||||
|
||||
const git_log = await $`git log --oneline -n ${['1']}`;
|
||||
console.log('🚀', bold(git_log.stdout));
|
||||
return;
|
||||
}
|
||||
|
||||
this.spinner.succeed('All your changes are up to date.');
|
||||
}
|
||||
catch (err) {
|
||||
const message = (err as Error).message;
|
||||
|
||||
if (/not a git repository/ig.test(message)) {
|
||||
this.spinner.stopAndPersist({
|
||||
text: 'Found an issue in your repository',
|
||||
symbol: red('✖'),
|
||||
});
|
||||
|
||||
this.createGitRepository();
|
||||
return;
|
||||
}
|
||||
else if (/user force closed/ig.test(message)) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
this.spinner.stopAndPersist({
|
||||
text: 'An error ocurred',
|
||||
});
|
||||
|
||||
console.error(red('[error]'), bold(message));
|
||||
console.dir(err);
|
||||
}
|
||||
}
|
||||
|
||||
private async createGitRepository() {
|
||||
const pkgFile = './package.json';
|
||||
|
||||
try {
|
||||
this.spinner.start('Analyzing repository ...');
|
||||
await wait(600);
|
||||
|
||||
this.spinner.fail('No git repository found in your project . 😒');
|
||||
await wait(600);
|
||||
|
||||
const isConfirm = await confirm({
|
||||
message: 'Do you want to add your project to git?',
|
||||
default: true,
|
||||
});
|
||||
|
||||
if (isConfirm) {
|
||||
await wait(600);
|
||||
|
||||
const branchName = await input({
|
||||
message: 'What do you want to name your main branch:',
|
||||
default: 'main',
|
||||
theme: {
|
||||
prefix: green('?'),
|
||||
},
|
||||
});
|
||||
|
||||
this.spinner.start(bold('Creating git repository ...'));
|
||||
await wait(600);
|
||||
|
||||
if (!existsSync(pkgFile)) {
|
||||
await $`npm init --init-version ${['0.0.0']} -y`;
|
||||
}
|
||||
else {
|
||||
await $`npm version ${['0.0.0']} --allow-same-version`;
|
||||
}
|
||||
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(pkgFile).toString()
|
||||
);
|
||||
|
||||
this.createGitIgnoreFile();
|
||||
await $`git init -b ${[branchName]}`;
|
||||
await $`git add .`;
|
||||
await $`git commit -m ${[`"chore: first commit"`]} -m ${[`"First commit for the project ${pkg['name']}"`]}`
|
||||
await $`npm version ${['minor']}`;
|
||||
|
||||
this.spinner.succeed('Repository created.');
|
||||
|
||||
const { stdout } = await $`git log --oneline -n ${['1']}`;
|
||||
console.log('🚀', bold(stdout));
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
const message = (err as Error).message;
|
||||
|
||||
if (/user force closed/ig.test(message)) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
this.spinner.stopAndPersist({
|
||||
text: 'Found an issue in your repository',
|
||||
symbol: red('✖'),
|
||||
});
|
||||
|
||||
console.log(red('[error]'), bold(message));
|
||||
console.dir(err);
|
||||
}
|
||||
}
|
||||
|
||||
private createGitIgnoreFile() {
|
||||
const file = './gitignore';
|
||||
|
||||
if (!existsSync(file)) {
|
||||
writeFileSync(file, `
|
||||
# Backup files created by text editors
|
||||
*~
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
|
||||
# Directories generated by operating systems or IDEs
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Dependencies and modules generated by development tools
|
||||
node_modules/
|
||||
bower_components/
|
||||
vendor/
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
package-lock.json
|
||||
|
||||
# Build files and test results
|
||||
/build/
|
||||
/dist/
|
||||
/out/
|
||||
/coverage/
|
||||
/log/
|
||||
`.replace(/^\s+/gm, ''));
|
||||
}
|
||||
}
|
||||
}
|
13
src/app/app.module.ts
Normal file
13
src/app/app.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { AppComponent } from "./app.component";
|
||||
import { AppService } from "./app.service";
|
||||
import { Module } from "modilitejs";
|
||||
|
||||
@Module({
|
||||
components: [
|
||||
AppComponent
|
||||
],
|
||||
providers: [
|
||||
AppService
|
||||
]
|
||||
})
|
||||
export class AppModule {}
|
66
src/app/app.service.ts
Normal file
66
src/app/app.service.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { cyan, blue, yellow, red, green, bold } from 'chalk';
|
||||
import { Injectable } from "modilitejs";
|
||||
import { textSync } from "figlet";
|
||||
import fileSize from 'file-size';
|
||||
import { statSync } from 'fs';
|
||||
import boxen from 'boxen';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
private readonly title = 'Gcommit - CLI';
|
||||
|
||||
constructor() {}
|
||||
|
||||
public getDisplay() {
|
||||
const banner = textSync(this.title);
|
||||
const box = boxen(cyan(banner), {
|
||||
padding: 1.3,
|
||||
borderStyle: 'double',
|
||||
borderColor: 'yellowBright'
|
||||
});
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
public getPrefix(prefix: string) {
|
||||
let result = green(prefix);
|
||||
|
||||
if (/(m|r)/gi.test(prefix)) {
|
||||
result = blue(prefix);
|
||||
}
|
||||
else if (/(\?\?|u|t|c)/gi.test(prefix)) {
|
||||
result = yellow(prefix);
|
||||
}
|
||||
else if (/d/gi.test(prefix)) {
|
||||
result = red(prefix);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public getFileSize(prefix: string, filename:string) {
|
||||
let size = bold('0 Bytes');
|
||||
|
||||
if (!/d/gi.test(prefix)) {
|
||||
size = bold(fileSize(statSync(filename).size).human());
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public getVersion(type: string) {
|
||||
let version = '';
|
||||
|
||||
if (/break/gi.test(type)) {
|
||||
version = 'major';
|
||||
}
|
||||
else if (/feat/gi.test(type)) {
|
||||
version = 'minor';
|
||||
}
|
||||
else {
|
||||
version = 'patch';
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
57
src/app/version.config.json
Normal file
57
src/app/version.config.json
Normal file
@ -0,0 +1,57 @@
|
||||
[
|
||||
{
|
||||
"name": "break",
|
||||
"value": ".*",
|
||||
"description": "Breaks compatibility, correlates with a new version"
|
||||
},
|
||||
{
|
||||
"name": "chore",
|
||||
"value": "chore",
|
||||
"description": "Changes in the build process or auxiliary tools"
|
||||
},
|
||||
{
|
||||
"name": "docs",
|
||||
"value": "docs",
|
||||
"description": "Indicates changes in the documentation."
|
||||
},
|
||||
{
|
||||
"name": "feat",
|
||||
"value": "feat",
|
||||
"description": "Indicates the addition of a new feature."
|
||||
},
|
||||
{
|
||||
"name": "fix",
|
||||
"value": "fix",
|
||||
"description": "Describes bug fixes."
|
||||
},
|
||||
{
|
||||
"name": "merge",
|
||||
"value": "merge",
|
||||
"description": "Branch or commit merging."
|
||||
},
|
||||
{
|
||||
"name": "perf",
|
||||
"value": "perf",
|
||||
"description": "Changes that improve performance."
|
||||
},
|
||||
{
|
||||
"name": "revert",
|
||||
"value": "revert",
|
||||
"description": "Reverts a previous commit."
|
||||
},
|
||||
{
|
||||
"name": "refactor",
|
||||
"value": "refactor",
|
||||
"description": "Changes in the code that improve its structure or readability."
|
||||
},
|
||||
{
|
||||
"name": "style",
|
||||
"value": "style",
|
||||
"description": "Changes in code formatting or style."
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"value": "test",
|
||||
"description": "Adding tests or modifying existing ones."
|
||||
}
|
||||
]
|
18
src/index.ts
Normal file
18
src/index.ts
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { AppModule } from "./app/app.module";
|
||||
import { AppFactory } from "modilitejs";
|
||||
|
||||
function bootstrap() {
|
||||
AppFactory.create(AppModule)
|
||||
.then(() => {
|
||||
process.on('SIGINT', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
console.error(`[App] Error:`, err.message);
|
||||
});
|
||||
}
|
||||
|
||||
bootstrap();
|
4
src/types/figlet.d.ts
vendored
Normal file
4
src/types/figlet.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module 'figlet/importable-fonts/Standard' {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
5
src/types/file-format.type.ts
Normal file
5
src/types/file-format.type.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export type FileFormat = {
|
||||
status: string,
|
||||
file: string,
|
||||
size: string
|
||||
};
|
44
tsconfig.json
Normal file
44
tsconfig.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Language and Environment */
|
||||
"target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "CommonJS", /* Specify what module code is generated. */
|
||||
"resolveJsonModule": true,
|
||||
|
||||
/* JavaScript Support */
|
||||
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
|
||||
/* Emit */
|
||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||
"rootDir": "./src",
|
||||
"removeComments": true, /* Disable emitting comments. */
|
||||
|
||||
/* Interop Constraints */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
"strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
"strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
"strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
"noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
"noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
"noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
|
||||
/* Completeness */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
],
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user