diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e2a1cb8..21bf9e1 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,7 +13,7 @@ "ghcr.io/stuartleeks/dev-container-features/shell-history:0": {}, "ghcr.io/devcontainers/features/azure-cli:1": { "installBicep": true - }, + } // "ghcr.io/prulloac/devcontainer-features/ollama:1": { // "pull": "phi3" // } @@ -44,6 +44,35 @@ "files.insertFinalNewline": true, "github.copilot.enable": { "markdown": true + }, + "go.toolsManagement.checkForUpdates": "local", + "go.useLanguageServer": true, + "go.gopath": "/go", + "go.lintTool": "revive", + "go.goroot": "/usr/local/go", + "go.lintFlags": [ + "--fast" + ], + "[go]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "always" + }, + // Optional: Disable snippets, as they conflict with completion ranking. + "editor.snippetSuggestions": "none" + }, + "[go.mod]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "always" + } + }, + "gopls": { + // Add parameter placeholders when completing a function. + "usePlaceholders": true, + // If true, enable additional analyses with staticcheck. + // Warning: This will significantly increase memory usage. + "staticcheck": false } } } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1367fab..decc4a3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,6 +31,7 @@ jobs: test: name: Run Tests runs-on: ubuntu-latest + needs: lint steps: - name: Checkout Code uses: actions/checkout@v3 diff --git a/.gitignore b/.gitignore index c874551..641269a 100644 --- a/.gitignore +++ b/.gitignore @@ -36,5 +36,6 @@ # project .env .gic +gic dist/ diff --git a/.golangci.yml b/.golangci.yml index f78a138..b936129 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -17,6 +17,10 @@ linters-settings: revive: enable-all-rules: true + rules: + - name: "line-length-limit" + arguments: + - 120 staticcheck: checks: ["all"] @@ -45,6 +49,7 @@ issues: linters: enable: - govet + - revive - errcheck - staticcheck - gocyclo @@ -55,5 +60,5 @@ linters: output: formats: - - format: colored-line-number + - format: colored-tab sort-results: true diff --git a/.goreleaser.yaml b/.goreleaser.yaml index f0ff055..e40ad8a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,7 +13,7 @@ before: # You may remove this if you don't use go modules. - go mod tidy # you may remove this if you don't need go generate - - go generate ./... + # - go generate ./... builds: - env: diff --git a/.vscode/launch.json b/.vscode/launch.json index baa79bf..a999a91 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "go", "request": "launch", "mode": "auto", - "program": "cmd/gic/main.go", + "program": "main.go", "cwd": "/workspaces/gic" } ] diff --git a/cmd/gic/main.go b/cmd/gic/main.go deleted file mode 100644 index 46fd408..0000000 --- a/cmd/gic/main.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - - "github.com/jsburckhardt/gic/internal/config" - "github.com/jsburckhardt/gic/internal/git" - "github.com/jsburckhardt/gic/internal/llm" - "github.com/spf13/cobra" -) - -func main() { - var rootCmd = &cobra.Command{ - Use: "gic", - Short: "gic generates git commit messages based on staged changes.", - Run: func(cmd *cobra.Command, args []string) { - cfg, err := config.LoadConfig() - if err != nil { - log.Fatal(err) - } - - err = config.ValidateConfig(cfg) - if err != nil { - log.Fatal(err) - } - - gitDiff, err := git.GetStagedChanges() - if err != nil { - log.Fatal(err) - } - - // if diff is empty finish - if gitDiff == "" { - fmt.Println("No staged changes found.") - return - } - - // retrieve the commit message - commitMessage, err := llm.GenerateCommitMessage(cfg, gitDiff) - if err != nil { - log.Fatal(err) - } - - fmt.Println("Suggested Commit Message:", commitMessage) - }, - } - - if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } -} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..5144aac --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,78 @@ +// Package cmd provides the command-line interface for the gic application. +package cmd + +import ( + "fmt" + + "gic/internal/config" + "gic/internal/git" + "gic/internal/llm" + + "github.com/spf13/cobra" +) + +// const exitCodeFailure = 1 + +var ( + hash string + verbose bool + + rootCmd = &cobra.Command{ + Use: "gic", + Short: "gic", + Long: "gic generates git commit messages based on staged changes.", + } +) + +// Execute runs the root command of the application. +func Execute(version, commit string) error { + rootCmd.Version = version + hash = commit + + setVersion() + + rootCmd = &cobra.Command{ + Use: "gic", + Short: "gic generates git commit messages based on staged changes.", + RunE: func(cmd *cobra.Command, args []string) error { + _ = cmd + _ = args + cfg, err := config.LoadConfig() + if err != nil { + return err + } + + gitDiff, err := git.GetStagedChanges() + if err != nil { + return err + } + + // retrieve the commit message + commitMessage, err := llm.GenerateCommitMessage(cfg, gitDiff) + if err != nil { + return err + } + + _, _ = fmt.Println("Suggested Commit Message:", commitMessage) + return nil + }, + } + + // Execute the root command + if err := rootCmd.Execute(); err != nil { + // log.Fatal(err) + return err + // os.Exit(exitCodeFailure) + } + return nil +} + +func setVersion() { + template := fmt.Sprintf("gic version: %s commit: %s \n", rootCmd.Version, hash) + rootCmd.SetVersionTemplate(template) +} + +func init() { + cobra.OnInitialize() + rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "set logging level to verbose") +} diff --git a/go.mod b/go.mod index 84d842c..a677160 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/jsburckhardt/gic +module gic go 1.23.0 @@ -7,6 +7,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/joho/godotenv v1.5.1 + github.com/jsburckhardt/gic v1.0.0 github.com/openai/openai-go v0.1.0-alpha.9 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 diff --git a/go.sum b/go.sum index 9d57e44..d43257d 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jsburckhardt/gic v1.0.0 h1:0cV5NiWUJtjVNl3YEYT3ipBUKEDl/5/3x5MnLUIZs8w= +github.com/jsburckhardt/gic v1.0.0/go.mod h1:jM3MILCAIdDF4uftsIBDGEHFepFXKLrjYEFFlY96+Ts= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= diff --git a/internal/cli/cli.go b/internal/cli/cli.go index d09c00f..3988557 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -1,23 +1,31 @@ +// Package cli provides a command-line interface for the application. package cli import ( - "log" "os" "github.com/joho/godotenv" ) -func LoadEnv() { +// LoadEnv loads environment variables from a .env file. +// It attempts to load the .env file located in the current working directory. +// If the file is not found or there is an error loading the file, +// it will cause a fatal error. +func LoadEnv() error { err := godotenv.Load(".env") if err != nil { - log.Fatal("Error loading .env file") + return err } + return nil } +// GetAPIKey returns the API key from the environment variables. func GetAPIKey() string { return os.Getenv("API_KEY") } +// GetAzureOpenAIEndpoint returns the Azure OpenAI endpoint +// from the environment variables. func GetAzureOpenAIEndpoint() string { return os.Getenv("AZURE_OPENAI_ENDPOINT") } diff --git a/internal/config/config.go b/internal/config/config.go index 5d04105..dae216f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,3 +1,4 @@ +// Package config provides functionality for managing configuration settings. package config import ( @@ -7,9 +8,14 @@ import ( "github.com/spf13/viper" ) +const emptyString = "" +const zeroTokens = 0 +const defaultTokens = 4000 + +// Config represents the configuration structure for the application. type Config struct { ModelDeploymentName string `mapstructure:"model_deployment_name"` - ApiVersion string `mapstructure:"api_version"` + APIVersion string `mapstructure:"api_version"` LLMInstructions string `mapstructure:"llm_instructions"` ConnectionType string `mapstructure:"connection_type"` AzureEndpoint string `mapstructure:"azure_endpoint"` @@ -17,6 +23,8 @@ type Config struct { Tokens int `mapstructure:"tokens"` } +// LoadConfig loads the configuration from a YAML file and +// returns a Config struct. func LoadConfig() (Config, error) { var cfg Config @@ -32,13 +40,20 @@ func LoadConfig() (Config, error) { if err := viper.Unmarshal(&cfg); err != nil { return cfg, err } + if err := validateConfig(cfg); err != nil { + return cfg, err + } return cfg, nil } -func ValidateConfig(cfg Config) error { - if cfg.LLMInstructions == "" { - fmt.Println("LLMInstructions not set in config. Using default instructions.") - cfg.LLMInstructions = "You are a helpful assistant, that helps generating commit messages based on git diffs." +// ValidateConfig validates the configuration and returns an +// error if any validation fails. +func validateConfig(cfg Config) error { + _, _ = fmt.Println("Validating configuration...") + if cfg.LLMInstructions == emptyString { + _, _ = fmt.Println("LLMInstructions not set in config. Using default instructions.") + cfg.LLMInstructions = "You are a helpful assistant, " + + "that helps generating commit messages based on git diffs." } if err := validateAPIKey(cfg); err != nil { @@ -57,16 +72,12 @@ func ValidateConfig(cfg Config) error { return err } - if err := validateApiVersion(cfg); err != nil { - return err - } - - return nil + return validateAPIVersion(cfg) } func validateAPIKey(cfg Config) error { if cfg.ConnectionType == "azure" || cfg.ConnectionType == "openai" { - if os.Getenv("API_KEY") == "" { + if os.Getenv("API_KEY") == emptyString { return fmt.Errorf("API_KEY environment variable not set") } } @@ -75,7 +86,7 @@ func validateAPIKey(cfg Config) error { func validateAzureEndpoint(cfg Config) error { if cfg.ConnectionType == "azure" || cfg.ConnectionType == "azure_ad" { - if cfg.AzureEndpoint == "" { + if cfg.AzureEndpoint == emptyString { return fmt.Errorf("AzureEndpoint not set in config") } } @@ -83,25 +94,25 @@ func validateAzureEndpoint(cfg Config) error { } func validateTokens(cfg Config) error { - if cfg.Tokens == 0 { - fmt.Println("Tokens not set in config. Using default value 4000.") - cfg.Tokens = 4000 + if cfg.Tokens == zeroTokens { + _, _ = fmt.Println("Tokens not set in config. Using default value 4000.") + cfg.Tokens = defaultTokens } return nil } func validateModelDeploymentName(cfg Config) error { - if cfg.ModelDeploymentName == "" { - fmt.Println("ModelDeploymentName not set in config. Using default value gpt-4o.") + if cfg.ModelDeploymentName == emptyString { + _, _ = fmt.Println("ModelDeploymentName not set in config. Using default value gpt-4o.") cfg.ModelDeploymentName = "gpt-4o" } return nil } -func validateApiVersion(cfg Config) error { - if cfg.ApiVersion == "" { - fmt.Println("ApiVersion not set in config. Using default value 2024-02-15-preview.") - cfg.ApiVersion = "2024-02-15-preview" +func validateAPIVersion(cfg Config) error { + if cfg.APIVersion == emptyString { + _, _ = fmt.Println("ApiVersion not set in config. Using default value 2024-02-15-preview.") + cfg.APIVersion = "2024-02-15-preview" } return nil } diff --git a/internal/git/git.go b/internal/git/git.go index 3af66a3..99a33d6 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -1,14 +1,18 @@ +// Package git provides functions for interacting with Git repositories. package git import ( - "os/exec" + "os/exec" ) +// GetStagedChanges returns the staged changes in the git repository. +// It executes the "git diff --cached" command and returns the output as a string. +// If an error occurs during the execution of the command, it returns an empty string and the error. func GetStagedChanges() (string, error) { - cmd := exec.Command("git", "diff", "--cached") - out, err := cmd.Output() - if err != nil { - return "", err - } - return string(out), nil + cmd := exec.Command("git", "diff", "--cached") + out, err := cmd.Output() + if err != nil { + return "", err + } + return string(out), nil } diff --git a/internal/git/git_test.go b/internal/git/git_test.go index bbfeeec..d30edf2 100644 --- a/internal/git/git_test.go +++ b/internal/git/git_test.go @@ -3,7 +3,7 @@ package git_test import ( "testing" - "github.com/jsburckhardt/gic/internal/git" + "gic/internal/git" ) func TestGetStagedChanges(t *testing.T) { diff --git a/internal/llm/llm.go b/internal/llm/llm.go index 99e1b3f..8cadbd1 100644 --- a/internal/llm/llm.go +++ b/internal/llm/llm.go @@ -1,3 +1,4 @@ +// Package llm provides functionality for interacting with the Language Learning Model. package llm import ( @@ -6,16 +7,32 @@ import ( "log" "os" + "gic/internal/config" + "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" - "github.com/jsburckhardt/gic/internal/config" "github.com/openai/openai-go" "github.com/openai/openai-go/option" ) +const emptyString = "" +const responseMessage = 0 + +// GenerateCommitMessage generates a commit message based on the provided configuration and diff. +// It takes a config.Config object and a string representing the diff as input. +// The function returns a string containing the generated commit message and an error if any. +// The commit message is generated based on the connection type specified in the config.Config object. +// Supported connection types are "azure", "azure_ad", and "openai". +// If the connection type is not supported, the function returns an empty string and an error +// indicating the unsupported connection type. func GenerateCommitMessage(cfg config.Config, diff string) (string, error) { + // if diff is empty finish + if diff == emptyString { + return "### NO STAGED CHAGES ###", nil + } + apikey := os.Getenv("API_KEY") switch cfg.ConnectionType { case "azure": @@ -25,89 +42,70 @@ func GenerateCommitMessage(cfg config.Config, diff string) (string, error) { case "openai": return GenerateCommitMessageOpenAI(apikey, cfg, diff) default: - return "", fmt.Errorf("unsupported connection type: %s", cfg.ConnectionType) + return emptyString, fmt.Errorf("unsupported connection type: %s", cfg.ConnectionType) } } +// GenerateCommitMessageAzure generates a commit message using the Azure Language Learning Model. +// It takes an API key, a config.Config object, and a string representing the diff as input. func GenerateCommitMessageAzure(apikey string, cfg config.Config, diff string) (string, error) { - maxTokens := int32(cfg.Tokens) keyCredential := azcore.NewKeyCredential(apikey) - client, err := azopenai.NewClientWithKeyCredential(cfg.AzureEndpoint, keyCredential, nil) if err != nil { - log.Printf("ERROR: %s", err) - return "", err - } - - messages := []azopenai.ChatRequestMessageClassification{ - &azopenai.ChatRequestSystemMessage{Content: to.Ptr(cfg.LLMInstructions)}, - &azopenai.ChatRequestUserMessage{Content: azopenai.NewChatRequestUserMessageContent("git commit diff: " + diff)}, + return emptyString, err } - resp, err := client.GetChatCompletions(context.TODO(), azopenai.ChatCompletionsOptions{ - Messages: messages, - DeploymentName: &(cfg.ModelDeploymentName), - MaxTokens: &maxTokens, - }, nil) + return getChatCompletions(cfg, client, diff) +} +// GenerateCommitMessageAzureAD generates a commit message using +// the Azure Language Learning Model with Azure Active Directory +// authentication. +// It takes a config.Config object and a string representing +// the diff as input. +func GenerateCommitMessageAzureAD(cfg config.Config, diff string) (string, error) { + tokenCredential, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { - log.Printf("ERROR: %s", err) - return "", err + return emptyString, err } + client, err := azopenai.NewClient(cfg.AzureEndpoint, tokenCredential, nil) - // var choice azopenai.ChatChoice - var messageContent string - for _, choice := range resp.Choices { - if choice.ContentFilterResults != nil { - - if choice.ContentFilterResults.Error != nil { - fmt.Fprintf(os.Stderr, " Error:%v\n", choice.ContentFilterResults.Error) - } - - // TODO: Include in logger - // fmt.Fprintf(os.Stderr, "Content filter results\n") - // fmt.Fprintf(os.Stderr, " Hate: sev: %v, filtered: %v\n", *choice.ContentFilterResults.Hate.Severity, *choice.ContentFilterResults.Hate.Filtered) - // fmt.Fprintf(os.Stderr, " SelfHarm: sev: %v, filtered: %v\n", *choice.ContentFilterResults.SelfHarm.Severity, *choice.ContentFilterResults.SelfHarm.Filtered) - // fmt.Fprintf(os.Stderr, " Sexual: sev: %v, filtered: %v\n", *choice.ContentFilterResults.Sexual.Severity, *choice.ContentFilterResults.Sexual.Filtered) - // fmt.Fprintf(os.Stderr, " Violence: sev: %v, filtered: %v\n", *choice.ContentFilterResults.Violence.Severity, *choice.ContentFilterResults.Violence.Filtered) - } - - // TODO: Include in logger - // if choice.Message != nil && choice.Message.Content != nil { - // fmt.Fprintf(os.Stderr, "Content[%d]: %s\n", *choice.Index, *choice.Message.Content) - // } - - // TODO: Include in logger - // if choice.FinishReason != nil { - //// this choice's conversation is complete. - // fmt.Fprintf(os.Stderr, "Finish reason[%d]: %s\n", *choice.Index, *choice.FinishReason) - // } - messageContent = *choice.Message.Content + if err != nil { + return emptyString, err } - return messageContent, nil + return getChatCompletions(cfg, client, diff) } -func GenerateCommitMessageAzureAD(cfg config.Config, diff string) (string, error) { - maxTokens := int32(cfg.Tokens) - tokenCredential, err := azidentity.NewDefaultAzureCredential(nil) +// GenerateCommitMessageOpenAI generates a commit message using the OpenAI Language Learning Model. +// It takes an API key, a config.Config object, and a string representing the diff as input. +func GenerateCommitMessageOpenAI(apiKey string, cfg config.Config, diff string) (string, error) { + client := openai.NewClient( + option.WithAPIKey(apiKey), // defaults to os.LookupEnv("OPENAI_API_KEY") + ) + chatCompletion, err := client.Chat.Completions.New(context.TODO(), openai.ChatCompletionNewParams{ + Messages: openai.F([]openai.ChatCompletionMessageParamUnion{ + openai.UserMessage(diff), + }), + Model: openai.F(cfg.ModelDeploymentName), + }) if err != nil { - fmt.Printf("Failed to create the DefaultAzureCredential: %s", err) - os.Exit(1) + panic(err.Error()) } + return chatCompletion.Choices[responseMessage].Message.Content, nil +} - client, err := azopenai.NewClient(cfg.AzureEndpoint, tokenCredential, nil) - - if err != nil { - log.Printf("ERROR: %s", err) - return "", err - } +func getChatCompletions(cfg config.Config, client *azopenai.Client, diff string) (string, error) { + maxTokens := int32(cfg.Tokens) messages := []azopenai.ChatRequestMessageClassification{ - // You set the tone and rules of the conversation with a prompt as the system role. - &azopenai.ChatRequestSystemMessage{Content: to.Ptr(cfg.LLMInstructions)}, - &azopenai.ChatRequestUserMessage{Content: azopenai.NewChatRequestUserMessageContent("git commit diff: " + diff)}, + &azopenai.ChatRequestSystemMessage{ + Content: to.Ptr(cfg.LLMInstructions), + }, + &azopenai.ChatRequestUserMessage{ + Content: azopenai.NewChatRequestUserMessageContent("git commit diff: " + diff), + }, } resp, err := client.GetChatCompletions(context.TODO(), azopenai.ChatCompletionsOptions{ @@ -118,54 +116,18 @@ func GenerateCommitMessageAzureAD(cfg config.Config, diff string) (string, error if err != nil { log.Printf("ERROR: %s", err) - return "", err + return emptyString, err } - // var choice azopenai.ChatChoice var messageContent string for _, choice := range resp.Choices { if choice.ContentFilterResults != nil { - if choice.ContentFilterResults.Error != nil { - fmt.Fprintf(os.Stderr, " Error:%v\n", choice.ContentFilterResults.Error) + return emptyString, choice.ContentFilterResults.Error } - - // TODO: Include in logger - // fmt.Fprintf(os.Stderr, "Content filter results\n") - // fmt.Fprintf(os.Stderr, " Hate: sev: %v, filtered: %v\n", *choice.ContentFilterResults.Hate.Severity, *choice.ContentFilterResults.Hate.Filtered) - // fmt.Fprintf(os.Stderr, " SelfHarm: sev: %v, filtered: %v\n", *choice.ContentFilterResults.SelfHarm.Severity, *choice.ContentFilterResults.SelfHarm.Filtered) - // fmt.Fprintf(os.Stderr, " Sexual: sev: %v, filtered: %v\n", *choice.ContentFilterResults.Sexual.Severity, *choice.ContentFilterResults.Sexual.Filtered) - // fmt.Fprintf(os.Stderr, " Violence: sev: %v, filtered: %v\n", *choice.ContentFilterResults.Violence.Severity, *choice.ContentFilterResults.Violence.Filtered) } - - // TODO: Include in logger - // if choice.Message != nil && choice.Message.Content != nil { - // fmt.Fprintf(os.Stderr, "Content[%d]: %s\n", *choice.Index, *choice.Message.Content) - // } - - // TODO: Include in logger - // if choice.FinishReason != nil { - //// this choice's conversation is complete. - // fmt.Fprintf(os.Stderr, "Finish reason[%d]: %s\n", *choice.Index, *choice.FinishReason) - // } messageContent = *choice.Message.Content } return messageContent, nil } - -func GenerateCommitMessageOpenAI(apiKey string, cfg config.Config, diff string) (string, error) { - client := openai.NewClient( - option.WithAPIKey(apiKey), // defaults to os.LookupEnv("OPENAI_API_KEY") - ) - chatCompletion, err := client.Chat.Completions.New(context.TODO(), openai.ChatCompletionNewParams{ - Messages: openai.F([]openai.ChatCompletionMessageParamUnion{ - openai.UserMessage(diff), - }), - Model: openai.F(openai.ChatModelGPT4), - }) - if err != nil { - panic(err.Error()) - } - return chatCompletion.Choices[0].Message.Content, nil -} diff --git a/main.go b/main.go new file mode 100644 index 0000000..252ba8b --- /dev/null +++ b/main.go @@ -0,0 +1,18 @@ +// main package for the gic +package main + +import ( + "gic/cmd" +) + +var ( + version = "edge" + commit = "n/a" +) + +func main() { + err := cmd.Execute(version, commit) + if err != nil { + panic(err) + } +} diff --git a/makefile b/makefile index fe7b494..113d9f4 100644 --- a/makefile +++ b/makefile @@ -1,2 +1,5 @@ lint: golangci-lint run ./... + +fmt: + gofmt -l -w -s