diff --git a/.github/workflows/c-check.yml b/.github/workflows/c-check.yml deleted file mode 100644 index b5e2e55..0000000 --- a/.github/workflows/c-check.yml +++ /dev/null @@ -1,40 +0,0 @@ -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/go-check.yml b/.github/workflows/go-check.yml new file mode 100644 index 0000000..bc0226e --- /dev/null +++ b/.github/workflows/go-check.yml @@ -0,0 +1,53 @@ +name: Static Go Check + +on: + pull_request: + branches: [main] + +jobs: + go_check: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: '1.23.0' + + - name: Install dependencies + run: | + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + go install golang.org/x/tools/cmd/goimports@latest + + - name: Go mod tidy & download + run: | + go mod tidy + go mod download + + - name: Check formatting (gofmt) + run: | + if [ -n "$(gofmt -l .)" ]; then + echo "Файлы не отформатированы. Запустите 'gofmt -w .'" + gofmt -l . + exit 1 + fi + + - name: Check imports (goimports) + run: | + if [ -n "$(goimports -l .)" ]; then + echo "Неверный импорт. Запустите 'goimports -w .'" + goimports -l . + exit 1 + fi + + - name: Lint (golangci-lint) + run: | + make lint + + - name: Build binary + run: | + mkdir -p bin + make build diff --git a/Makefile b/Makefile index bcc80b9..1a0e2c1 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,20 @@ -bindir = bin +.PHONY: fmt lint test -BUILDIN_MAIN = main.c -BUILDIN_COMMIT = commit.c -BUILDIN_DETECT = detect.c -BUILDIN_DIFF = diff.c -BUILDIN_FILE = file.c -BUILDIN_GIT_ROOT = git-root.c -BUILDIN_PARSER = parser.c -BUILDIN_STRINGS = stdlib/strings.c +fmt: + gofmt -w . + goimports -w . -MAIN_OUT = "$(bindir)/auto-commit" - -UNAME_S := $(shell uname -s) - -CC = gcc - -ifeq ($(OS),Windows_NT) - MKDIR = mkdir $(bindir) || echo "Directory already exists" - REMOVE_EXT = mv $(MAIN_OUT).exe $(MAIN_OUT) -else - MKDIR = mkdir -p $(bindir) - OS_TYPE = $(shell uname -s) - REMOVE_EXT = true -endif +lint: + golangci-lint run +check: fmt lint test + @echo "All checks passed!" build: - $(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) + @echo "Running build..." + @go build -o bin/auto-commit . - $(REMOVE_EXT) +test: + @go test -v ./... -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) +run: build + @./bin/auto-commit diff --git a/bin/auto-commit b/bin/auto-commit index a92a4fb..5a1cb4a 100644 Binary files a/bin/auto-commit and b/bin/auto-commit differ diff --git a/commit.c b/commit.c deleted file mode 100644 index d3b5f9e..0000000 --- a/commit.c +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include -#include - -#include "stdlib/strings.h" -#include "strings.h" -#include "define.h" -#include "file.h" - -char* build_commit(char a_funcs[][MAX_FUNC_NAME], int a_funcs_count, char d_funcs[][MAX_FUNC_NAME], int d_funcs_count) { - int add_count, del_count, rn_count, ch_count; - - char** added = ad_f(&add_count); - char** deleted = del_f(&del_count); - char** renamed = rn_f(&rn_count); - char** changed = ch_f(&ch_count); - - char* commit_message = malloc(MAX_LINE_LENGTH * sizeof(char)); - if (!commit_message) return NULL; - - commit_message[0] = '\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 < a_funcs_count; ++i) { - funcs_ptr[i] = a_funcs[i]; - } - 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); - free(funcs_str); - - strcat(commit_message, " and "); - strcat(commit_message, last_func); - strcat(commit_message, " functionality"); - } - } - - if (add_count > 0) { - char* added_str = join_strings(added, add_count, ", "); - if (commit_message[0] != '\0') { - strcat(commit_message, " | including "); - } else { - strcat(commit_message, "including "); - } - - strcat(commit_message, added_str); - - remove_all_spaces(added_str); - free(added_str); - } - - if (del_count > 0) { - char* deleted_str = join_strings(deleted, del_count, ", "); - if (commit_message[0] != '\0') { - strcat(commit_message, " | deleted "); - } else { - strcat(commit_message, "deleted "); - } - - strcat(commit_message, deleted_str); - - remove_all_spaces(deleted_str); - free(deleted_str); - } - - if (rn_count > 0) { - char* renamed_str = join_strings(renamed, rn_count, ", "); - if (commit_message[0] != '\0') { - strcat(commit_message, " | renamed "); - } else { - strcat(commit_message, "renamed "); - } - - strcat(commit_message, renamed_str); - - remove_all_spaces(renamed_str); - free(renamed_str); - } - - if (ch_count > 0) { - char* changed_str = join_strings(changed, ch_count, ", "); - if (commit_message[0] != '\0') { - strcat(commit_message, " | changed "); - } else { - strcat(commit_message, "changed "); - } - - strcat(commit_message, changed_str); - - remove_all_spaces(changed_str); - free(changed_str); - } - - if (commit_message[0] == '\0') { - free(commit_message); - return strdup("auto commit (github@git-auto-commit)"); - } - - if (strlen(commit_message) > COMMIT_LENGTH) { - free(commit_message); - - if (a_funcs_count > 0) { - char* funcs_ptr[MAX_FUNC_COUNT]; - for (int i = 0; i < a_funcs_count; ++i) { - funcs_ptr[i] = a_funcs[i]; - } - 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); - free(funcs_str); - - remove_all_spaces(short_commit); - return short_commit; - } - if (add_count > 0) { - char* added_str = join_strings(added, add_count, ", "); - char* short_commit = malloc(strlen("including ") + strlen(added_str) + 2); - if (!short_commit) return NULL; - sprintf(short_commit, "including %s", added_str); - free(added_str); - - remove_all_spaces(short_commit); - return short_commit; - } - if (del_count > 0) { - char* del_str = join_strings(deleted, del_count, ", "); - char* short_commit = malloc(strlen("deleted ") + strlen(del_str) + 2); - if (!short_commit) return NULL; - sprintf(short_commit, "deleted %s", del_str); - free(del_str); - - remove_all_spaces(short_commit); - return short_commit; - } - if (rn_count > 0) { - char* renamed_str = join_strings(renamed, rn_count, ", "); - char* short_commit = malloc(strlen("renamed ") + strlen(renamed_str) + 2); - if (!short_commit) return NULL; - sprintf(short_commit, "renamed %s", renamed_str); - free(renamed_str); - - remove_all_spaces(short_commit); - return short_commit; - } - if (ch_count > 0) { - char* changed_str = join_strings(changed, ch_count, ", "); - char* short_commit = malloc(strlen("changed ") + strlen(changed_str) + 2); - if (!short_commit) return NULL; - sprintf(short_commit, "changed %s", changed_str); - free(changed_str); - - remove_all_spaces(short_commit); - return short_commit; - } - } - - 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; -} - -int git_commit(const char* message) { - char cmd[1024]; - snprintf(cmd, sizeof(cmd), "git commit -m \"%s\"", message); - - return system(cmd); -} diff --git a/commit.go b/commit.go new file mode 100644 index 0000000..9a54009 --- /dev/null +++ b/commit.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + "os/exec" +) + +func Commit(commitMsg string) error { + fmt.Printf("\033[0;34m[git auto-commit] commit is: %s\033[0m\n", commitMsg) + + cmd := exec.Command("git", "commit", "-m", commitMsg) + return cmd.Run() +} diff --git a/commit.h b/commit.h deleted file mode 100644 index 60c623f..0000000 --- a/commit.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef COMMIT_H -#define COMMIT_H - -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); - -#endif diff --git a/define.go b/define.go new file mode 100644 index 0000000..c8df55a --- /dev/null +++ b/define.go @@ -0,0 +1,10 @@ +package main + +const ( + MAX_BUFFER uint32 = 100000 + MAX_FUNC_COUNT uint8 = 128 + MAX_FUNC_NAME uint8 = 255 + MAX_LINE_LENGTH uint16 = 1024 + MAX_STRING_LENGTH uint16 = 1024 + COMMIT_LENGTH uint8 = 255 +) diff --git a/define.h b/define.h deleted file mode 100644 index fdfdc08..0000000 --- a/define.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DEFINE_H -#define DEFINE_H - -#define MAX_BUFFER 100000 - -#define MAX_FUNC_COUNT 128 -#define MAX_FUNC_NAME 256 - -#define MAX_LINE_LENGTH 1024 -#define COMMIT_LENGTH 255 - -#endif diff --git a/detect.c b/detect.c deleted file mode 100644 index 52df47e..0000000 --- a/detect.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include - -#include "define.h" - -const char* detect_language(const char* filename) { - const char* ext = strrchr(filename, '.'); - if (!ext) return ""; - - if (strcmp(ext, ".go") == 0) return "go"; - if (strcmp(ext, ".py") == 0) return "python"; - if (strcmp(ext, ".js") == 0) return "javascript"; - if (strcmp(ext, ".ts") == 0) return "typescript"; - if (strcmp(ext, ".cpp") == 0) return "cpp"; - if (strcmp(ext, ".c") == 0) return "c"; - if (strcmp(ext, ".h") == 0) return "c"; - if (strcmp(ext, ".java") == 0) return "java"; - if (strcmp(ext, ".cs") == 0) return "csharp"; - if (strcmp(ext, ".rs") == 0) return "rust"; - if (strcmp(ext, ".scala") == 0) return "scala"; - - return ""; -} diff --git a/detect.h b/detect.h deleted file mode 100644 index c75abb9..0000000 --- a/detect.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef LANGUAGE_H -#define LANGUAGE_H - -const char* detect_language(const char* filename); - -#endif diff --git a/detected.go b/detected.go new file mode 100644 index 0000000..f21a77a --- /dev/null +++ b/detected.go @@ -0,0 +1,35 @@ +package main + +import ( + "path/filepath" + "strings" +) + +func DetectLanguage(filename string) string { + ext := strings.ToLower(filepath.Ext(filename)) + + switch ext { + case ".go": + return "go" + case ".py": + return "python" + case ".js": + return "javascript" + case ".ts": + return "typescript" + case ".cpp": + return "cpp" + case ".c", ".h": + return "c" + case ".java": + return "java" + case ".cs": + return "csharp" + case ".rs": + return "rust" + case ".scala": + return "scala" + default: + return "" + } +} diff --git a/diff.c b/diff.c deleted file mode 100644 index 69c3372..0000000 --- a/diff.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include - -#include "define.h" -#include "git-root.h" - -char* get_diff(const char* file) { - char* git_root = get_git_root(); - - char cmd[512]; - snprintf(cmd, sizeof(cmd), "git diff --cached -- %s/%s", git_root, file); - - FILE* fp = _popen(cmd, "r"); - if (!fp) return NULL; - - char* buffer = malloc(100000); - buffer[0] = '\0'; - - while (fgets(cmd, sizeof(cmd), fp)) { - strcat(buffer, cmd); - } - - _pclose(fp); - return buffer; -} - -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]; - - 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(a_funcs[*a_func_count], fname); - (*a_func_count)++; - } - } - } - - // --- Golang --- - else if (strcmp(lang, "golang") == 0) { - if (strstr(buffer, "+func ")) { - if (sscanf(buffer, "+func %127[^ (]", fname) == 1) { - strcpy(a_funcs[*a_func_count], fname); - (*a_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(a_funcs[*a_func_count], fname); - (*a_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(a_funcs[*a_func_count], fname); - (*a_func_count)++; - } - } - } - - // --- Rust --- - else if (strcmp(lang, "rust") == 0) { - if (strstr(buffer, "+fn ")) { - if (sscanf(buffer, "+fn %127[^ (]", fname) == 1) { - strcpy(a_funcs[*a_func_count], fname); - (*a_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(a_funcs[*a_func_count], fname); - (*a_func_count)++; - } - } else { - if (sscanf(buffer, "+%127[^ =:(]", fname) == 1 && - strchr(buffer, '(') && strchr(buffer, ')')) { - 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)++; - } - } - } - } - - line += strlen(buffer); - while (*line == '\n' || *line == '\r') line++; - } -} - -char** get_staged_files(int* count) { - FILE* fp = _popen("git diff --cached --name-only", "r"); - if (!fp) return NULL; - - char** files = malloc(128 * sizeof(char*)); - char line[512]; - int i = 0; - - while (fgets(line, sizeof(line), fp)) { - line[strcspn(line, "\r\n")] = 0; - files[i] = strdup(line); - i++; - } - - _pclose(fp); - *count = i; - return files; -} diff --git a/diff.go b/diff.go new file mode 100644 index 0000000..0e78030 --- /dev/null +++ b/diff.go @@ -0,0 +1,54 @@ +package main + +import ( + "bufio" + "bytes" + "fmt" + "os/exec" +) + +func GetDiff(file string) (string, error) { + root, err := GetGitRoot(); + if err != nil { + return "", err + } + + cmd := exec.Command("git", "diff", "--cached", "--", fmt.Sprintf("%s/%s", root, file)) + var out bytes.Buffer + + cmd.Stdout = &out + if err := cmd.Run(); err != nil { + return "", err + } + + return out.String(), nil +} + +func GetStagedFiles() ([]string, error) { + cmd := exec.Command("git", "diff", "--cached", "--name-only") + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + + if err := cmd.Start(); err != nil { + return nil, err + } + + var files []string + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + files = append(files, scanner.Text()) + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + if err := cmd.Wait(); err != nil { + return nil, err + } + + return files, nil +} diff --git a/diff.h b/diff.h deleted file mode 100644 index d5e83ec..0000000 --- a/diff.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DIFF_H -#define DIFF_H - -char* get_diff(const char* file); - -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); - -#endif diff --git a/fclass.go b/fclass.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/fclass.go @@ -0,0 +1 @@ +package main diff --git a/ffunction.go b/ffunction.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/ffunction.go @@ -0,0 +1 @@ +package main diff --git a/file.c b/file.c deleted file mode 100644 index 8ffc97f..0000000 --- a/file.c +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include - -#include "define.h" - -char* exec_command(const char* cmd) { - FILE *fp; - char *output = malloc(MAX_LINE_LENGTH); - if (output == NULL) { - perror("Failed to allocate memory"); - return NULL; - } - - fp = popen(cmd, "r"); - if (fp == NULL) { - perror("Failed to run command"); - free(output); - return NULL; - } - - size_t len = 0; - while (fgets(output + len, MAX_LINE_LENGTH - len, fp)) { - len += strlen(output + len); - if (len >= MAX_LINE_LENGTH - 1) { - break; - } - } - fclose(fp); - - return output; -} - -char** ad_f(int* count) { - char* cmd_output = exec_command("git diff --cached --name-status"); - if (cmd_output == NULL) { - *count = 0; - return NULL; - } - - char** add = malloc(MAX_LINE_LENGTH * sizeof(char*)); - if (add == NULL) { - perror("Failed to allocate memory for added files"); - *count = 0; - free(cmd_output); - return NULL; - } - - *count = 0; - char* line = strtok(cmd_output, "\n"); - while (line != NULL) { - if (line[0] == 'A') { - add[*count] = strdup(line + 2); - (*count)++; - } - - line = strtok(NULL, "\n"); - } - - free(cmd_output); - return add; -} - -char** del_f(int* count) { - char* cmd_output = exec_command("git diff --cached --name-status"); - if (cmd_output == NULL) { - *count = 0; - return NULL; - } - - char** del = malloc(MAX_LINE_LENGTH * sizeof(char*)); - if (del == NULL) { - perror("Failed to allocate memory for deleted files"); - *count = 0; - free(cmd_output); - return NULL; - } - - *count = 0; - char* line = strtok(cmd_output, "\n"); - while (line != NULL) { - if (line[0] == 'D') { - del[*count] = strdup(line + 2); - (*count)++; - } - - line = strtok(NULL, "\n"); - } - - free(cmd_output); - return del; -} - -char** rn_f(int* count) { - char* cmd_output = exec_command("git diff --cached --name-status"); - if (cmd_output == NULL) { - *count = 0; - return NULL; - } - - char** rn = malloc(MAX_LINE_LENGTH * sizeof(char*)); - if (rn == NULL) { - perror("Failed to allocate memory for renamed files"); - *count = 0; - free(cmd_output); - return NULL; - } - - *count = 0; - char* line = strtok(cmd_output, "\n"); - while (line != NULL) { - if (line[0] == 'R') { - char oldFile[256], newFile[256]; - sscanf(line, "R %s %s", oldFile, newFile); - - char* rename_msg = malloc(strlen(oldFile) + strlen(newFile) + 5); - sprintf(rename_msg, "%s -> %s", oldFile, newFile); - - rn[*count] = rename_msg; - (*count)++; - } - - line = strtok(NULL, "\n"); - } - - free(cmd_output); - return rn; -} - -char** ch_f(int* count) { - char* cmd_output = exec_command("git status --porcelain"); - if (cmd_output == NULL) { - *count = 0; - return NULL; - } - - char** ch = malloc(MAX_LINE_LENGTH * sizeof(char*)); - if (ch == NULL) { - perror("Failed to allocate memory for changed files"); - *count = 0; - free(cmd_output); - return NULL; - } - - *count = 0; - char* line = strtok(cmd_output, "\n"); - while (line != NULL) { - if (strlen(line) >= 4) { - ch[*count] = strdup(line + 3); - (*count)++; - } - - line = strtok(NULL, "\n"); - } - - free(cmd_output); - return ch; -} - -void free_file_array(char** arr, int count) { - for (int i = 0; i < count; i++) { - free(arr[i]); - } - free(arr); -} diff --git a/file.h b/file.h deleted file mode 100644 index 6ac954b..0000000 --- a/file.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef FILE_H -#define FILE_H - -char** ad_f(int* count); - -char** del_f(int* count); - -char** rn_f(int* count); - -char** ch_f(int* count); - -#endif diff --git a/files.go b/files.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/files.go @@ -0,0 +1 @@ +package main diff --git a/flogic.go b/flogic.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/flogic.go @@ -0,0 +1 @@ +package main diff --git a/fstructure.go b/fstructure.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/fstructure.go @@ -0,0 +1 @@ +package main diff --git a/fvariables.go b/fvariables.go new file mode 100644 index 0000000..abeebad --- /dev/null +++ b/fvariables.go @@ -0,0 +1,85 @@ +package main + +import ( + "fmt" + "git-auto-commit/types" + "regexp" + "strings" +) + +func ParseToStrcutVariable(line, lang string) *types.Variable { + switch lang { + case "python": + reg := regexp.MustCompile(`^\s*(\w+)\s*=\s*(.+)`) + m := reg.FindStringSubmatch(line) + if m == nil { + return nil + } + + return &types.Variable{Type: "", Name: m[1], Value: strings.TrimSpace(m[2])} + case "typescript", "javascript": + reg := regexp.MustCompile(`^\s*(let|const|var)\s+(\w+)(\s*:\s*(\w+))?\s*=\s*(.+);?`) + m := reg.FindStringSubmatch(line) + if m == nil { + return nil + } + + typ := "" + + if len(m) > 4 { + typ = m[4] + } + + return &types.Variable{Type: typ, Name: m[2], Value: strings.TrimSpace(m[5])} + case "go": + reg := regexp.MustCompile(`^\s*([\w\s,]+):=\s*(.+)`) + m := reg.FindStringSubmatch(line) + if m != nil { + names := strings.Split(m[1], ",") + value := strings.TrimSpace(m[2]) + return &types.Variable{Type: "", Name: strings.TrimSpace(names[0]), Value: value} + } + + return nil + default: + reg := regexp.MustCompile(`^\s*(\w+)\s+(\w+)\s*=\s*([^;]+);`) + + m := reg.FindStringSubmatch(line) + if m == nil { + return nil + } + + return &types.Variable{Type: m[1], Name: m[2], Value: strings.TrimSpace(m[3])} + } +} + +func FormattedVariables(diff, lang string) (string, error) { + var oldVar, newVar *types.Variable + + lines := strings.Split(diff, "\n") + for _, line := range lines { + if strings.HasPrefix(line, "-") { + oldVar = ParseToStrcutVariable(line[1:], lang) + } else if strings.HasPrefix(line, "+") { + newVar = ParseToStrcutVariable(line[1:], lang) + } + + if oldVar != nil && newVar != nil { + if oldVar.Name == newVar.Name && oldVar.Type != newVar.Type { + return fmt.Sprintf("changed %s -> %s", oldVar.Type, newVar.Type), nil + } + + if oldVar.Type == newVar.Type && oldVar.Value == newVar.Value && oldVar.Name != newVar.Name { + return fmt.Sprintf("changed %s -> %s", oldVar.Name, newVar.Name), nil + } + + if oldVar.Name == newVar.Name && oldVar.Type == newVar.Type && oldVar.Value != newVar.Value { + return fmt.Sprintf("changed value in %s", oldVar.Name), nil + } + + oldVar, oldVar = nil, nil + } + } + + return "", nil +} diff --git a/git-root.c b/git-root.c deleted file mode 100644 index aa5dd63..0000000 --- a/git-root.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include - -char* get_git_root() { - FILE* fp = _popen("git rev-parse --show-toplevel", "r"); - if (!fp) return NULL; - - char* root = malloc(512); - if (!root) return NULL; - - if (fgets(root, 512, fp) == NULL) { - free(root); - _pclose(fp); - return NULL; - } - - root[strcspn(root, "\n")] = '\0'; - - _pclose(fp); - return root; -} diff --git a/git-root.h b/git-root.h deleted file mode 100644 index 8917d94..0000000 --- a/git-root.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef GIT_ROOT_H -#define GIT_ROOT_H - -char* get_git_root(); - -#endif diff --git a/git.go b/git.go new file mode 100644 index 0000000..373b537 --- /dev/null +++ b/git.go @@ -0,0 +1,20 @@ +package main + +import ( + "bytes" + "os/exec" + "strings" +) + +func GetGitRoot() (string, error) { + cmd := exec.Command("git", "rev-parse", "--show-toplevel") + var out bytes.Buffer + cmd.Stdout = &out + + if err := cmd.Run(); err != nil { + return "", err + } + + root := strings.TrimSpace(out.String()) + return root, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..12e1b8b --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git-auto-commit + +go 1.23.0 diff --git a/issues.go b/issues.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/issues.go @@ -0,0 +1 @@ +package main diff --git a/main.c b/main.c deleted file mode 100644 index a0a7414..0000000 --- a/main.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include - -#include "define.h" -#include "detect.h" -#include "commit.h" -#include "parser.h" -#include "diff.h" - -int main() { - int file_count = 0; - char** files = get_staged_files(&file_count); - - if (file_count == 0) { - printf("No files staged for commit.\n"); - return 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]); - if (lang == NULL) continue; - - char* diff = get_diff(files[i]); - if (diff != NULL) { - 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(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(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); - } - - for (int i = 0; i < file_count; i++) { - free(files[i]); - } - free(files); - - return 0; -} diff --git a/main.go b/main.go new file mode 100644 index 0000000..efe39f7 --- /dev/null +++ b/main.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +func main() { + // Изменения + files, err := GetStagedFiles() + if err != nil { + fmt.Println("Error getting staged files:", err) + return + } + + if len(files) == 0 { + fmt.Println("No files staged for commit.") + return + } + + // Парсер + parserMsg, err := Parser(files) + if err != nil { + fmt.Println(err.Error()) + return + } + + fmt.Println(parserMsg) +} diff --git a/parser.c b/parser.c deleted file mode 100644 index 300a13f..0000000 --- a/parser.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#include - -#include "define.h" -#include "parser.h" - -char* ct_prepare(const char* str) { - for (size_t i = 0; i < keyword_count; i++) { - if (strstr(str, keywords[i]) != NULL) { - size_t len = snprintf(NULL, 0, "added new %s module in %s", keywords[i], str); - char* result = malloc(len + 1); - - if (result) { - snprintf(result, len + 1, "added new %s module in %s", keywords[i], str); - } - - return result; - } - } - - return NULL; -} - -char* tb_keywords(char funcs[][MAX_FUNC_NAME], size_t func_count) { - size_t total_len = 1; - char* result = malloc(total_len); - if (!result) return NULL; - result[0] = '\0'; - - for (size_t i = 0; i < func_count; i++) { - char* commit_msg = ct_prepare(funcs[i]); - if (commit_msg) { - size_t new_len = total_len + strlen(commit_msg) + 2; - char* temp = realloc(result, new_len); - if (!temp) { - free(result); - free(commit_msg); - return NULL; - } - - result = temp; - if (total_len > 1) { - strcat(result, ", "); - } - - strcat(result, commit_msg); - free(commit_msg); - total_len = new_len - 1; - } - } - - return result; -} diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..b62fa21 --- /dev/null +++ b/parser.go @@ -0,0 +1,34 @@ +package main + +import "fmt" + +func Parser(files []string) (string, error) { + var commitMsg string = "" + + for _, file := range files { + diff, err := GetDiff(file) + if err != nil { + return "", err + } + + lang := DetectLanguage(file) + if lang == "" { + continue // README.md, etc. + } + + formattedVar, err := FormattedVariables(diff, lang) + if err != nil { + return "", err + } + + if formattedVar != "" { + if len(commitMsg) == 0 { + commitMsg = formattedVar + } else { + commitMsg = fmt.Sprintf(" and %s", formattedVar) + } + } // else -> continue + } + + return commitMsg, nil +} diff --git a/parser.h b/parser.h deleted file mode 100644 index ccbbcf7..0000000 --- a/parser.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef PARSER_H -#define PARSER_H - -static const char* keywords[] = {"test", "tests", "testing", "http", "https", "image", "resource"}; -static const size_t keyword_count = sizeof(keywords) / sizeof(keywords[0]); - -typedef struct { - char type[32]; - char name[64]; -} VarStruct; - -char* ct_prepare(const char* str); - -char* tb_keywords(char funcs[][MAX_FUNC_NAME], size_t func_count); - -#endif diff --git a/stdlib/strings.c b/stdlib/strings.c deleted file mode 100644 index 8a3a751..0000000 --- a/stdlib/strings.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -char* concat_strings(const char* str1, const char* str2) { - char* result = malloc(strlen(str1) + strlen(str2) + 1); - strcpy(result, str1); - strcat(result, str2); - - return result; -} - -char* join_strings(char* arr[], int len, const char* separator) { - char* result = malloc(1); - result[0] = '\0'; - - for (int i = 0; i < len; i++) { - result = concat_strings(result, arr[i]); - if (i < len - 1) { - result = concat_strings(result, separator); - } - } - - return result; -} - -void remove_all_spaces(char* str) { - char* dst = str; - int in_space = 0; - - while (*str) { - if (*str != ' ') { - *dst++ = *str; - in_space = 0; - } else if (!in_space) { - *dst++ = ' '; - in_space = 1; - } - str++; - } - *dst = '\0'; - - if (*dst == ' ' && dst != str) { - memmove(str, str + 1, strlen(str)); - } -} diff --git a/stdlib/strings.h b/stdlib/strings.h deleted file mode 100644 index ef84dba..0000000 --- a/stdlib/strings.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef STRINGS_H -#define STRINGS_H - -char* concat_strings(const char* str1, const char* str2); - -char* join_strings(char* arr[], int len, const char* separator); - -void remove_all_spaces(char* str); - -#endif diff --git a/types/types.go b/types/types.go new file mode 100644 index 0000000..8c4f45e --- /dev/null +++ b/types/types.go @@ -0,0 +1,7 @@ +package types + +type Variable struct { + Type string + Name string + Value string +}