feat: first commit

This commit is contained in:
MrDiro 2024-07-14 12:41:40 -05:00
commit faebaa970a
15 changed files with 3019 additions and 0 deletions

27
.gitignore vendored Normal file
View 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
View 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
View 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
View File

@ -0,0 +1,43 @@
![image](https://github.com/MrDiro/gcommit-cli/assets/77121383/dd1ebba7-f2c3-4db0-ae5f-7f936473a189)
# 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.
[![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](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
![image](https://github.com/MrDiro/gcommit-cli/assets/77121383/d190898c-4ed8-4e2e-8173-f500699f4238)
![image](https://github.com/MrDiro/gcommit-cli/assets/77121383/427ee8bf-8d62-4440-9a2b-025d78578fbe)
![image](https://github.com/MrDiro/gcommit-cli/assets/77121383/7fbf4a29-5058-4f5a-befe-299e6b50a0cc)

28
esbuild.mjs Normal file
View 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

File diff suppressed because it is too large Load Diff

62
package.json Normal file
View 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
View 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
View 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
View 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;
}
}

View 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
View 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
View File

@ -0,0 +1,4 @@
declare module 'figlet/importable-fonts/Standard' {
const value: any;
export default value;
}

View File

@ -0,0 +1,5 @@
export type FileFormat = {
status: string,
file: string,
size: string
};

44
tsconfig.json Normal file
View 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/**/*"
]
}