From d5368bada940f45640354e2deccdfe7830f64825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=92=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 4 May 2025 21:25:45 +0500 Subject: [PATCH 1/5] changed readme file and rename files scripts --- README.md | 27 ++++++++++++------- ...commit.sh => install-linux-auto-commit.sh} | 0 ...it.ps1 => install-windows-auto-commit.ps1} | 4 +-- 3 files changed, 20 insertions(+), 11 deletions(-) rename scripts/{auto-commit.sh => install-linux-auto-commit.sh} (100%) rename scripts/{auto-commit.ps1 => install-windows-auto-commit.ps1} (82%) diff --git a/README.md b/README.md index b128315..c878206 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,32 @@ -# Git auto-commit +# Git auto-commit - automatic commit generation tool -`git auto-commit` is a simple and powerful tool for automating commits in Git. With it, you will no longer have to think and write committees. `git auto-commit` will do it for you! +Git Auto-Commit is an extension for the Git version control system designed to automatically generate meaningful and context—sensitive commit messages based on changes made to the codebase. The tool simplifies developers' workflows by allowing them to focus on the content of edits rather than on the formulation of descriptions for commits. -This is an open source project, which is covered by the Mit License version 1 (some parts of it are released under other licenses compatible with GPLv2). +The development is conducted as an open source project and is distributed under the MIT license (or other compatible licensing, depending on the implementation). Git Auto-Commit can be integrated into CI/CD pipelines, hook scripts, or used manually via the command line. + +Main features: + +- Analysis of changes in the work tree and automatic generation of commit messages in natural language. +- Integration with Git via the `git auto` sub-command or configuration of user aliases. +- Support for templates and configurations for configuring the message structure in accordance with project standards (Conventional Commits, Semantic Commit Messages, etc.). +- Scalability: works both in small projects and in large monorepositories. ## Install -You will need two things for installation +### If you're on windows -- If you're on windows +Go to the root of the project and run the command. ```bash -iex ((New-Object Net.WebClient).DownloadString('https://github.com/thefuture-industries/git-auto-commit/blob/main/scripts/auto-commit.ps1?raw=true')) +iex ((New-Object Net.WebClient).DownloadString('https://github.com/thefuture-industries/git-auto-commit/blob/main/scripts/install-windows-auto-commit.ps1?raw=true')) ``` -- If you're on linux +### If you're on linux + +Go to the root of the project and run the command. ```bash -bash <(curl -s https://github.com/thefuture-industries/git-auto-commit/blob/main/scripts/auto-commit.sh?raw=true) +bash <(curl -s https://github.com/thefuture-industries/git-auto-commit/blob/main/scripts/install-linux-auto-commit.sh?raw=true) ``` ## Setting up @@ -28,6 +37,6 @@ Everything is ready now, after making changes to the code, just run: ```bash git add . -git ac +git auto git push ``` diff --git a/scripts/auto-commit.sh b/scripts/install-linux-auto-commit.sh similarity index 100% rename from scripts/auto-commit.sh rename to scripts/install-linux-auto-commit.sh diff --git a/scripts/auto-commit.ps1 b/scripts/install-windows-auto-commit.ps1 similarity index 82% rename from scripts/auto-commit.ps1 rename to scripts/install-windows-auto-commit.ps1 index f33dc65..d8e3145 100644 --- a/scripts/auto-commit.ps1 +++ b/scripts/install-windows-auto-commit.ps1 @@ -24,5 +24,5 @@ try { return } -git config --local alias.ac "!./.git/hooks/auto-commit" -Write-Host "[+] Git alias 'git ac' configured. Now you can run: git ac" +git config --local alias.auto "!./.git/hooks/auto-commit" +Write-Host "[+] Git alias 'git auto' configured. Now you can run: git auto" From ad39da59ac6df07dc04a184a0e01a0c5f17fb797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=92=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 4 May 2025 21:28:21 +0500 Subject: [PATCH 2/5] changed readme file and rename files scripts --- SECURITY.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..1a3baf1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,34 @@ +# Security Policy + +Thanks for helping make Litestar safe for everyone. + +## Security + +Litestar takes the security of our projects and services seriously, including all of the repositories managed by the [litestar organization](https://github.com/litestar-org). + +We will ensure that your finding gets escalated to the appropriate maintainer(s) for remediation. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +[Click to Open a Security Advisory Privately](https://github.com/litestar-org/litestar/security/advisories/new) + +If you believe you have found a security vulnerability in any Litestar-managed repository, please report it to us through coordinated disclosure: + +- In the affected repository, browse to the **Security** tab, select **Advisories**, select "Report a vulnerability" + - ![image](https://user-images.githubusercontent.com/45884264/217041010-8fd6b96b-329d-4d8e-8838-9b5bf4e1a78d.png) +- Please do **NOT** create an issue in the affected repository +- Please do **NOT** send a private message to and/or tag the "@maintainer" role on our [Discord server](https://discord.gg/MmcwxztmQb) + +Please include as much of the information listed below as you can to help us better understand and resolve the issue: + +- The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) +- Full paths of source file(s) related to the manifestation of the issue +- The location of the affected source code (tag/branch/commit or direct URL) +- Any special configuration required to reproduce the issue +- Step-by-step instructions to reproduce the issue +- Proof-of-concept or exploit code (if possible) +- Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. From cc945d97159bef16077de491eefcb74b51530af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=92=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 4 May 2025 22:02:08 +0500 Subject: [PATCH 3/5] added c-check and bin workflows --- .github/workflows/bin.yml | 25 +++++++++++++++++ .github/workflows/c-check.yml | 40 +++++++++++++++++++++++++++ .github/workflows/release.yml | 4 ++- Makefile | 12 +++++++- bin/auto-commit | Bin 160390 -> 160390 bytes scripts/install-linux-auto-commit.sh | 22 +++++++++------ 6 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/bin.yml create mode 100644 .github/workflows/c-check.yml diff --git a/.github/workflows/bin.yml b/.github/workflows/bin.yml new file mode 100644 index 0000000..ba9233f --- /dev/null +++ b/.github/workflows/bin.yml @@ -0,0 +1,25 @@ +name: Check bin/auto-commit + +on: + pull_request: + branches: [main] + +jobs: + validate-binary: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Check that bin/auto-commit exists + run: | + if [ ! -f "bin/auto-commit" ]; then + echo "[-] bin/auto-commit not found." + exit 1 + fi + echo "[+] bin/auto-commit exists." + + - name: (Optional) Run binary with --help or version + run: | + ./bin/auto-commit --help || echo "Help output not available (optional check)." diff --git a/.github/workflows/c-check.yml b/.github/workflows/c-check.yml new file mode 100644 index 0000000..b5e2e55 --- /dev/null +++ b/.github/workflows/c-check.yml @@ -0,0 +1,40 @@ +name: Static C Check + +on: + pull_request: + branches: [main] + +jobs: + c_check: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Cache apt dependencies + uses: actions/cache@v3 + with: + path: | + /var/cache/apt + /var/lib/apt/lists + key: ${{ runner.os }}-apt-${{ hashFiles('**/Makefile') }} + restore-keys: | + ${{ runner.os }}-apt- + + - name: Install tools + run: | + sudo apt-get update + sudo apt-get install -y cppcheck clang clang-tools flawfinder mingw-w64 + + - name: Cppcheck analysis + run: | + cppcheck --enable=all --inconclusive --force --quiet ./ + + - name: Clang static analysis + run: | + scan-build --use-cc=x86_64-w64-mingw32-gcc gcc -c ./*.c + + - name: Security audit with Flawfinder + run: | + flawfinder ./ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7de5e60..112f4ec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -149,7 +149,9 @@ jobs: [©thefuture-industries](https://github.com/thefuture-industries) files: | - ./git-auto-commit/git-auto-commit + ./bin/auto-commit + ./scripts/install-linux-auto-commit.sh + ./install-windows-auto-commit.ps1 - name: Create new branch for next version run: | diff --git a/Makefile b/Makefile index c9e6569..d6b193b 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,20 @@ BUILDIN_STRINGS = stdlib/strings.c MAIN_OUT = "$(bindir)/auto-commit" +UNAME_S := $(shell uname -s) + CC = gcc +ifeq ($(OS),Windows_NT) + MKDIR = mkdir $(bindir) || echo "Directory already exists" + OS_TYPE = Windows +else + MKDIR = mkdir -p $(bindir) + OS_TYPE = $(shell uname -s) +endif + build: - @if not exist $(bindir) mkdir $(bindir) + $(MKDIR) $(CC) $(BUILDIN_MAIN) -o $(MAIN_OUT) $(BUILDIN_COMMIT) \ $(BUILDIN_DETECT) $(BUILDIN_DIFF) $(BUILDIN_FILE) \ $(BUILDIN_GET_STAGED) $(BUILDIN_STRINGS) $(BUILDIN_GIT_ROOT) \ diff --git a/bin/auto-commit b/bin/auto-commit index 4fa0a04d289a1d3e014b495f28e87c3e09dafcc4..2346bf09715829613e9a1e8454fa59adc100ccf5 100644 GIT binary patch delta 27 jcmZpB%Gvgmb3zBxk2w>&{Fq9L8gI4UV%&O*X-y#jx*ZKs delta 27 jcmZpB%Gvgmb3zA`wCBVwKc?w&jkj8FF>bxZw5AXMqZkYD diff --git a/scripts/install-linux-auto-commit.sh b/scripts/install-linux-auto-commit.sh index 415605e..c28034d 100644 --- a/scripts/install-linux-auto-commit.sh +++ b/scripts/install-linux-auto-commit.sh @@ -5,19 +5,25 @@ set -e HOME="$(git rev-parse --show-toplevel)" cd "$HOME" -BINARY_NAME="git-auto-commit" +BINARY_NAME="auto-commit" HOOKS_DIR=".git/hooks" -TARGET="$HOOKS_DIR/auto-commit" +HOOK_PATH="$HOOKS_DIR/$BINARY_NAME" + +URL="https://github.com/thefuture-industries/git-auto-commit/blob/main/bin/auto-commit?raw=true" if [ ! -d .git ]; then echo "[!] There is no .git. Run it in the root of the Git repository." exit 1 fi -cp "$BINARY_NAME" "$TARGET" -chmod +x "$TARGET" -echo "[+] The binary is copied to $TARGET" - -git config alias.ac '!f() { .git/hooks/auto-commit "$@"; }; f' +echo "Installing $URL..." +if curl -fsSL "$URL" -o "$HOOK_PATH"; then + chmod +x "$HOOK_PATH" + echo "File saved as $HOOK_PATH" +else + echo "Error: Failed to download the hook script." + exit 1 +fi -echo "[+] Git alias 'git ac' is configured. Now you can run: git ac" +git config --local alias.auto "!$HOOK_PATH" +echo "[+] Git alias 'git auto' is configured. Now you can run: git auto" From ef2ddd3fb9bd225af52eccbd38a90ebed5aecb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=92=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 4 May 2025 22:06:54 +0500 Subject: [PATCH 4/5] added c-check and bin workflows --- Makefile | 5 ++++- bin/auto-commit | Bin 160390 -> 160390 bytes 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d6b193b..acb8eb6 100644 --- a/Makefile +++ b/Makefile @@ -17,10 +17,11 @@ CC = gcc ifeq ($(OS),Windows_NT) MKDIR = mkdir $(bindir) || echo "Directory already exists" - OS_TYPE = Windows + REMOVE_EXT = mv $(MAIN_OUT).exe $(MAIN_OUT) else MKDIR = mkdir -p $(bindir) OS_TYPE = $(shell uname -s) + REMOVE_EXT = true endif build: @@ -29,3 +30,5 @@ build: $(BUILDIN_DETECT) $(BUILDIN_DIFF) $(BUILDIN_FILE) \ $(BUILDIN_GET_STAGED) $(BUILDIN_STRINGS) $(BUILDIN_GIT_ROOT) \ $(BUILDIN_PARSER) + + $(REMOVE_EXT) diff --git a/bin/auto-commit b/bin/auto-commit index 2346bf09715829613e9a1e8454fa59adc100ccf5..88da130093cb94410f1b2852cea137b984596ae1 100644 GIT binary patch delta 28 kcmZpB%Gvgmb3zBx`gs$({Frr0m>O@l-e%l-n`w0+0J&rg$p8QV delta 28 kcmZpB%Gvgmb3zBxk2w>&{FqCMm>X}m-e%l-n`w0+0K!HMR{#J2 From 8d456fadc16c674eb90e72e934cbee97fbc2a854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=92=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 4 May 2025 22:43:21 +0500 Subject: [PATCH 5/5] added build_commit, extract_added_functions and extract_deleted_functions functionality | deleted bin/auto-commit | changed Makefile, bin/auto-commit, commit.c, commit.h, diff.c, diff.h, main.c, parser.h --- Makefile | 7 +++ bin/auto-commit | Bin 160390 -> 163000 bytes commit.c | 78 ++++++++++++++++++++++++++-------- commit.h | 2 +- diff.c | 111 +++++++++++++++++++++++++++++++++++++++++------- diff.h | 4 +- main.c | 16 ++++--- parser.h | 2 +- 8 files changed, 179 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index acb8eb6..bcc80b9 100644 --- a/Makefile +++ b/Makefile @@ -32,3 +32,10 @@ build: $(BUILDIN_PARSER) $(REMOVE_EXT) + +buildt: + $(MKDIR) + $(CC) $(BUILDIN_MAIN) -o $(MAIN_OUT) $(BUILDIN_COMMIT) \ + $(BUILDIN_DETECT) $(BUILDIN_DIFF) $(BUILDIN_FILE) \ + $(BUILDIN_GET_STAGED) $(BUILDIN_STRINGS) $(BUILDIN_GIT_ROOT) \ + $(BUILDIN_PARSER) diff --git a/bin/auto-commit b/bin/auto-commit index 88da130093cb94410f1b2852cea137b984596ae1..8b23b5c227e34a4dc44cceb172877eabaa3140dc 100644 GIT binary patch delta 28538 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 AdH?_b delta 26936 zcmch930zgx_W#)%E&_^N2NaOuBB(gy7~+HjdT|P;!YNP$#Q|>uWocauc}X`6JL8Ld2yt6WsDaw;;pY9o4$rU9)QMwiJ zwdeXL)H1~qtav|FOgVvC?}sbZYvbCPoU53UxHhg;z}63#GM}%Fi`+1V2L|t%0k>vo z&r~00@x5%2;9i*n>hnoe6lag6b7vRLR+N$`RFt4T26V1^l|}Z~8brei;#D5_JJZx2 z%XCvq6Vz8ry@%8xJeE1duCcOw@1AnQihcFsn0>mmePLpT}U=5y{=w|R3atk z&KUn+nY|4C?e+Fi1yLwghv_d6Jwmy!aMR9|yp_r0rx%A>b20{5S?$W?j5I|l%7a-? zXqJcU-Odz;Qsyigu@{Xf^=mVkQh#bZgX6G2py6m)Zg$Hjb-Agz{#v5ea(BDBIUtNr z$W-?PjA*hM)%AmtRNkatN-_9x6{fFWfuoABZ!{8858_bDO->RWrWVi{=?Jt|n6?v8 zJ~F{lUv|5CXOmu?zrCNTLet9L4lP@QxN@xy{|-r7ccWv_DXYU4XmxatKd2sW62}$0 zdbLRudqr&;7Xf`UiEt0Ra+m`m0}J_gSjhAI7usP8QQT{glzu9 z<+7IZ`d`PP2mYP4zMUjL<)#fU1NvdCdS75Rds#gn7#%kYorvxWcw|Km8=rGA{oqBv zapj-aAH0oR4sQ9f8Wj{_Z*n_%wlQn@5A`Z)(#spr!)R!rp=hiWa*c*oGEYchG`(e+4ugrl$cpLbl;w^lV%?MJ`C|Bg_Ct$O^FKrhD-( z(zWU$yg0)6+->UapzbL_=*0n=Cys#98!WUe;7^xpZ!F~cwo~C#2h9NCGMakq2nhhG zZ!uMk4(^=uI#VvqMRM{g>yJ-?zUl3kptJHwB|OZyBWu>MnTJDTOCV54A0t@U9|AcV zKyB7P51UJ+T5=CxdJnCXAFTfnSY=+Nwe(6N=D=6W)fa+e_?yesw}Yej?Niimg7fXz zTU@o2BuAPhz5J}T{80VdeHEoV?WQB`rnU4)@{C!Br|v01yY+Vhw{|{at=N_T5puku z94*^#2ak`nLSx~oesUPZ^0EfhI5e=#Ssa0>w`>7|Mt!Es<=R6wmwvzmQI4i)@(Mh-R{5Dte%|mW-q#|7UeIjc88WNvG#%mN>L}J9&-Nyq@w^KUm)r zUXPaD07#$9-5eVKKa9tp6PZ$~DS0wN)+^pZQ#2K*rB9%vjXdTx&8b=Juo~6;7XH{q zb!u~~{d?gv^O7*}tShh7`NLFBIcs@^4PyEFWg1wv4eOZPx>{=;&d|}V5)Epjp;jH; zBGFcDH8fR6t0a0c9H_m#EE(`#1^?9F%%Bk{OCr6}14NYKV13pW;9-YO5%!j%lpdgH zl+ZOFBkj7titVyqOD{T2qpDlb1m3&CGJEda+_@HOdEi^AfpE6o1|PmgyQz6;fgYaG zqA~ce6y-0059{6~1+y3B7u|z)tW7SVJq+DUiVC00-5nZ_p*vU?s0Tu=S=k{^ zMfsFBt4hlTkO>Bl$iOn{)rvPA8m-81Su4`2@RWHZPoJ32M8HFNSt696qHZ>~O3
DBt+}MeTf6&kh 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 m?laI6Ro>EEOm>{&49?@BQw3Ca-nS 0) { - if (funcs_count == 1) { - strcat(commit_message, "| added "); - strcat(commit_message, funcs[0]); + if (a_funcs_count > 0) { + if (a_funcs_count == 1) { + // strcat(commit_message, "| added "); + if (commit_message[0] != '\0') { + strcat(commit_message, " | added "); + } else { + strcat(commit_message, "added "); + } + + strcat(commit_message, a_funcs[0]); strcat(commit_message, " functionality"); } else { char* funcs_ptr[MAX_FUNC_COUNT]; - for (int i = 0; i < funcs_count; ++i) { - funcs_ptr[i] = funcs[i]; + for (int i = 0; i < a_funcs_count; ++i) { + funcs_ptr[i] = a_funcs[i]; } - char* funcs_str = join_strings(funcs_ptr, funcs_count - 1, ", "); - char* last_func = funcs[funcs_count - 1]; + char* funcs_str = join_strings(funcs_ptr, a_funcs_count - 1, ", "); + char* last_func = a_funcs[a_funcs_count - 1]; strcat(commit_message, "added "); strcat(commit_message, funcs_str); @@ -45,7 +51,12 @@ char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count) { if (add_count > 0) { char* added_str = join_strings(added, add_count, ", "); - strcat(commit_message, " | including "); + if (commit_message[0] != '\0') { + strcat(commit_message, " | including "); + } else { + strcat(commit_message, "including "); + } + strcat(commit_message, added_str); remove_all_spaces(added_str); @@ -54,7 +65,12 @@ char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count) { if (del_count > 0) { char* deleted_str = join_strings(deleted, del_count, ", "); - strcat(commit_message, " | deleted "); + if (commit_message[0] != '\0') { + strcat(commit_message, " | deleted "); + } else { + strcat(commit_message, "deleted "); + } + strcat(commit_message, deleted_str); remove_all_spaces(deleted_str); @@ -63,7 +79,12 @@ char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count) { if (rn_count > 0) { char* renamed_str = join_strings(renamed, rn_count, ", "); - strcat(commit_message, " | renamed "); + if (commit_message[0] != '\0') { + strcat(commit_message, " | renamed "); + } else { + strcat(commit_message, "renamed "); + } + strcat(commit_message, renamed_str); remove_all_spaces(renamed_str); @@ -72,7 +93,12 @@ char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count) { if (ch_count > 0) { char* changed_str = join_strings(changed, ch_count, ", "); - strcat(commit_message, " | changed "); + if (commit_message[0] != '\0') { + strcat(commit_message, " | changed "); + } else { + strcat(commit_message, "changed "); + } + strcat(commit_message, changed_str); remove_all_spaces(changed_str); @@ -87,12 +113,12 @@ char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count) { if (strlen(commit_message) > COMMIT_LENGTH) { free(commit_message); - if (funcs_count > 0) { + if (a_funcs_count > 0) { char* funcs_ptr[MAX_FUNC_COUNT]; - for (int i = 0; i < funcs_count; ++i) { - funcs_ptr[i] = funcs[i]; + for (int i = 0; i < a_funcs_count; ++i) { + funcs_ptr[i] = a_funcs[i]; } - char* funcs_str = join_strings(funcs_ptr, funcs_count, ", "); + char* funcs_str = join_strings(funcs_ptr, a_funcs_count, ", "); char* short_commit = malloc(strlen("added ") + strlen(funcs_str) + 12); if (!short_commit) return NULL; sprintf(short_commit, "added %s functionality", funcs_str); @@ -143,6 +169,24 @@ char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count) { } } + if (d_funcs_count > 0) { + char* d_ptrs[MAX_FUNC_COUNT]; + for (int i = 0; i < d_funcs_count; ++i) { + d_ptrs[i] = d_funcs[i]; + } + + char* d_str = join_strings(d_ptrs, d_funcs_count, ", "); + const char* suffix = " | deleted functionality: "; + size_t extra_len = strlen(suffix) + strlen(d_str); + + if (strlen(commit_message) + extra_len < COMMIT_LENGTH) { + strcat(commit_message, suffix); + strcat(commit_message, d_str); + } + + free(d_str); + } + remove_all_spaces(commit_message); return commit_message; } diff --git a/commit.h b/commit.h index 3cfaf67..60c623f 100644 --- a/commit.h +++ b/commit.h @@ -1,7 +1,7 @@ #ifndef COMMIT_H #define COMMIT_H -char* build_commit(char funcs[][MAX_FUNC_NAME], int funcs_count); +char* build_commit(char a_funcs[][MAX_FUNC_NAME], int a_funcs_count, char d_funcs[][MAX_FUNC_NAME], int d_funcs_count); int git_commit(const char* message); diff --git a/diff.c b/diff.c index 47fd1f4..69c3372 100644 --- a/diff.c +++ b/diff.c @@ -25,7 +25,7 @@ char* get_diff(const char* file) { return buffer; } -void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC_NAME], int* func_count) { +void extract_added_functions(const char* diff, const char* lang, char a_funcs[][MAX_FUNC_NAME], int* a_func_count) { const char* line = diff; char buffer[1024]; @@ -38,8 +38,8 @@ void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC if (strcmp(lang, "c") == 0 || strcmp(lang, "cpp") == 0) { if (strchr(buffer, '(') && strchr(buffer, ')') && strchr(buffer, '{')) { if (sscanf(buffer, "+%*[^ ] %127[^ (]", fname) == 1) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; } } } @@ -48,8 +48,8 @@ void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC else if (strcmp(lang, "golang") == 0) { if (strstr(buffer, "+func ")) { if (sscanf(buffer, "+func %127[^ (]", fname) == 1) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; } } } @@ -58,8 +58,8 @@ void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC else if (strcmp(lang, "python") == 0 || strcmp(lang, "scala") == 0) { if (strstr(buffer, "+def ")) { if (sscanf(buffer, "+def %127[^ (]", fname) == 1) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; } } } @@ -68,8 +68,8 @@ void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC else if (strcmp(lang, "java") == 0 || strcmp(lang, "csharp") == 0) { if (strchr(buffer, '(') && strstr(buffer, "+public") || strstr(buffer, "+private") || strstr(buffer, "+protected")) { if (sscanf(buffer, "+%*s %*s %127[^ (]", fname) == 1) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; } } } @@ -78,8 +78,8 @@ void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC else if (strcmp(lang, "rust") == 0) { if (strstr(buffer, "+fn ")) { if (sscanf(buffer, "+fn %127[^ (]", fname) == 1) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; } } } @@ -88,14 +88,95 @@ void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC else if (strcmp(lang, "javascript") == 0 || strcmp(lang, "typescript") == 0) { if (strstr(buffer, "+function ")) { if (sscanf(buffer, "+function %127[^ (]", fname) == 1) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; } } else { if (sscanf(buffer, "+%127[^ =:(]", fname) == 1 && strchr(buffer, '(') && strchr(buffer, ')')) { - strcpy(funcs[*func_count], fname); - (*func_count)++; + strcpy(a_funcs[*a_func_count], fname); + (*a_func_count)++; + } + } + } + } + + line += strlen(buffer); + while (*line == '\n' || *line == '\r') line++; + } +} + +void extract_deleted_functions(const char* diff, const char* lang, char d_funcs[][MAX_FUNC_NAME], int* d_func_count) { + const char* line = diff; + char buffer[1024]; + + while (*line) { + sscanf(line, "%[^\n]\n", buffer); + if (strncmp(buffer, "-", 1) == 0) { + char fname[128]; + + // --- C / C++ --- + if (strcmp(lang, "c") == 0 || strcmp(lang, "cpp") == 0) { + if (strchr(buffer, '(') && strchr(buffer, ')') && strchr(buffer, '{')) { + if (sscanf(buffer, "+%*[^ ] %127[^ (]", fname) == 1) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; + } + } + } + + // --- Golang --- + else if (strcmp(lang, "golang") == 0) { + if (strstr(buffer, "+func ")) { + if (sscanf(buffer, "+func %127[^ (]", fname) == 1) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; + } + } + } + + // --- Python / Scala --- + else if (strcmp(lang, "python") == 0 || strcmp(lang, "scala") == 0) { + if (strstr(buffer, "+def ")) { + if (sscanf(buffer, "+def %127[^ (]", fname) == 1) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; + } + } + } + + // --- Java / C# --- + else if (strcmp(lang, "java") == 0 || strcmp(lang, "csharp") == 0) { + if (strchr(buffer, '(') && strstr(buffer, "+public") || strstr(buffer, "+private") || strstr(buffer, "+protected")) { + if (sscanf(buffer, "+%*s %*s %127[^ (]", fname) == 1) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; + } + } + } + + // --- Rust --- + else if (strcmp(lang, "rust") == 0) { + if (strstr(buffer, "+fn ")) { + if (sscanf(buffer, "+fn %127[^ (]", fname) == 1) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; + } + } + } + + // --- JavaScript / TypeScript --- + else if (strcmp(lang, "javascript") == 0 || strcmp(lang, "typescript") == 0) { + if (strstr(buffer, "+function ")) { + if (sscanf(buffer, "+function %127[^ (]", fname) == 1) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; + } + } else { + if (sscanf(buffer, "+%127[^ =:(]", fname) == 1 && + strchr(buffer, '(') && strchr(buffer, ')')) { + strcpy(d_funcs[*d_func_count], fname); + (*d_func_count)++; } } } diff --git a/diff.h b/diff.h index 90c6511..d5e83ec 100644 --- a/diff.h +++ b/diff.h @@ -3,7 +3,9 @@ char* get_diff(const char* file); -void extract_functions(const char* diff, const char* lang, char funcs[][MAX_FUNC_NAME], int* func_count); +void extract_added_functions(const char* diff, const char* lang, char a_funcs[][MAX_FUNC_NAME], int* a_func_count); + +void extract_deleted_functions(const char* diff, const char* lang, char d_funcs[][MAX_FUNC_NAME], int* d_func_count); char** get_staged_files(int* count); diff --git a/main.c b/main.c index 1bdf165..a0a7414 100644 --- a/main.c +++ b/main.c @@ -18,8 +18,11 @@ int main() { return 0; } - char funcs[MAX_FUNC_COUNT][MAX_FUNC_NAME]; - int func_count = 0; + char a_funcs[MAX_FUNC_COUNT][MAX_FUNC_NAME]; + int a_func_count = 0; + + char d_funcs[MAX_FUNC_COUNT][MAX_FUNC_NAME]; + int d_func_count = 0; for (int i = 0; i < file_count; i++) { const char* lang = detect_language(files[i]); @@ -27,20 +30,21 @@ int main() { char* diff = get_diff(files[i]); if (diff != NULL) { - extract_functions(diff, lang, funcs, &func_count); + extract_added_functions(diff, lang, a_funcs, &a_func_count); + extract_deleted_functions(diff, lang, d_funcs, &d_func_count); free(diff); } } - char* p_commit_msg = tb_keywords(funcs, file_count); + char* p_commit_msg = tb_keywords(a_funcs, file_count); if (p_commit_msg && strlen(p_commit_msg) > 0) { printf("[git auto-commit] commit is: %s\n", p_commit_msg); int result = git_commit(p_commit_msg); free(p_commit_msg); } else { - char* commit_msg = build_commit(funcs, func_count); - printf("[git auto-commit] commit is: %s\n", commit_msg); + char* commit_msg = build_commit(a_funcs, a_func_count, d_funcs, d_func_count); + printf("\033[0;34m[git auto-commit] commit is: %s\033[0m\n", commit_msg); int result = git_commit(commit_msg); free(commit_msg); diff --git a/parser.h b/parser.h index 8f75ce0..ccbbcf7 100644 --- a/parser.h +++ b/parser.h @@ -1,7 +1,7 @@ #ifndef PARSER_H #define PARSER_H -static const char* keywords[] = {"test", "tests", "testing", "http", "https", "struct", "class"}; +static const char* keywords[] = {"test", "tests", "testing", "http", "https", "image", "resource"}; static const size_t keyword_count = sizeof(keywords) / sizeof(keywords[0]); typedef struct {