Skip to content

Commit

Permalink
Fix/shell (#3)
Browse files Browse the repository at this point in the history
* 'refactor(utils): simplify Shell command construction'

* refactor(utils): replace Shell with RunShell and RunOutput

* refactor(git): simplify git command execution and output handling

* refactor(utils): improve error handling in RunShell function

* refactor(utils): simplify RunShell function by using RunOutput

* refactor(utils): trim shell command result before logging

* refactor(bootstrap): simplify boot.go and extract config logic

* fix: barry 2025-01-04 22:08:28

* style: Reorder imports for better readability
  • Loading branch information
kooksee authored Jan 4, 2025
1 parent eb65eb6 commit 093df05
Show file tree
Hide file tree
Showing 13 changed files with 541 additions and 172 deletions.
140 changes: 28 additions & 112 deletions bootstrap/boot.go
Original file line number Diff line number Diff line change
@@ -1,145 +1,61 @@
package bootstrap

import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"sort"

"github.com/adrg/xdg"
_ "github.com/adrg/xdg"
_ "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/term"
"github.com/pubgo/dix"
"github.com/pubgo/dix/dix_internal"
"github.com/pubgo/fastcommit/cmds/fastcommit"
"github.com/pubgo/fastcommit/cmds/tagcmd"
"github.com/pubgo/fastcommit/cmds/versioncmd"
"github.com/pubgo/fastcommit/configs"
"github.com/pubgo/fastcommit/utils"
"github.com/pubgo/funk/assert"
"github.com/pubgo/funk/config"
"github.com/pubgo/funk/env"
"github.com/pubgo/funk/pathutil"
"github.com/pubgo/funk/recovery"
"github.com/pubgo/funk/running"
"github.com/pubgo/funk/version"
"github.com/pubgo/funk/typex"
"github.com/rs/zerolog"
"github.com/sashabaranov/go-openai"
_ "github.com/sashabaranov/go-openai"
"github.com/urfave/cli/v3"
"gopkg.in/yaml.v3"
)

var configPath = assert.Exit1(xdg.ConfigFile("fastcommit/config.yaml"))

//go:embed default.yaml
var defaultConfig []byte

func Main() {
defer recovery.Exit()

var branchName = string(assert.Exit1(utils.ShellOutput("git", "rev-parse", "--abbrev-ref", "HEAD")))

slog.Info("config path", "path", configPath)
if pathutil.IsNotExist(configPath) {
assert.Must(os.WriteFile(configPath, defaultConfig, 0644))
}
typex.DoBlock(func() {
if pathutil.IsNotExist(configPath) {
assert.Must(os.WriteFile(configPath, defaultConfig, 0644))
return
}

config.SetConfigPath(configPath)
var cfg ConfigProvider
config.LoadFromPath(&cfg, configPath)

var defaultCfg ConfigProvider
assert.Exit(yaml.Unmarshal(defaultConfig, &defaultCfg))
if cfg.Version == nil || cfg.Version.Name == "" || defaultCfg.Version.Name != cfg.Version.Name {
assert.Exit(os.WriteFile(configPath, defaultConfig, 0644))
}
})

config.SetConfigPath(configPath)
dix_internal.SetLogLevel(zerolog.InfoLevel)

var di = dix.New(dix.WithValuesNull())
di.Provide(versioncmd.New)
di.Provide(tagcmd.New)
di.Provide(config.Load[Config])
di.Provide(utils.NewOpenaiClient)

di.Inject(func(cmd []*cli.Command) {
app := &cli.Command{
Name: "fastcommit",
Suggest: true,
UseShortOptionHandling: true,
ShellComplete: cli.DefaultAppComplete,
Usage: "Intelligent generation of git commit message",
Version: version.Version(),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "config file path",
Value: config.GetConfigPath(),
Persistent: true,
Sources: cli.EnvVars(env.Key("fast_commit_config")),
Action: func(ctx context.Context, command *cli.Command, s string) error {
config.SetConfigPath(s)
return nil
},
},
&cli.BoolFlag{
Name: "debug",
Usage: "enable debug mode",
Persistent: true,
Value: running.IsDebug,
Destination: &running.IsDebug,
Sources: cli.EnvVars(env.Key("debug"), env.Key("enable_debug")),
},
},
Commands: cmd,
Action: func(ctx context.Context, command *cli.Command) error {
if utils.IsHelp() {
return cli.ShowAppHelp(command)
}

if !term.IsTerminal(os.Stdin.Fd()) {
return nil
}

generatePrompt := utils.GeneratePrompt("en", 50, utils.ConventionalCommitType)

repoPath := assert.Must1(utils.AssertGitRepo())
slog.Info("Git repository root", "path", repoPath)

assert.Exit(utils.Shell("git", "add", "--update").Run())

diff := assert.Must1(utils.GetStagedDiff(nil))

client := dix.Inject(di, new(struct {
*utils.OpenaiClient
}))
resp, err := client.Client.CreateChatCompletion(
context.Background(),
openai.ChatCompletionRequest{
Model: client.Cfg.Model,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Content: generatePrompt,
},
{
Role: openai.ChatMessageRoleUser,
Content: diff["diff"].(string),
},
},
},
)

if err != nil {
fmt.Printf("ChatCompletion error: %v\n", err)
}

if len(resp.Choices) == 0 {
return nil
}

msg := resp.Choices[0].Message.Content
assert.Must(utils.Shell("git", "commit", "-m", fmt.Sprintf("'%s'", msg)).Run())
assert.Must(utils.Shell("git", "push", "origin", branchName).Run())

return nil
},
di.Provide(func() *configs.Config {
return &configs.Config{
BranchName: branchName,
}

sort.Sort(cli.FlagsByName(app.Flags))
assert.Must(app.Run(utils.Context(), os.Args))
})
di.Provide(tagcmd.New)
di.Provide(config.Load[ConfigProvider])
di.Provide(utils.NewOpenaiClient)
di.Provide(fastcommit.New)
di.Inject(func(cmd *fastcommit.Command) { cmd.Run() })
}
18 changes: 16 additions & 2 deletions bootstrap/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
package bootstrap

import "github.com/pubgo/fastcommit/utils"
import (
_ "embed"

type Config struct {
"github.com/adrg/xdg"
"github.com/pubgo/fastcommit/configs"
"github.com/pubgo/fastcommit/utils"
"github.com/pubgo/funk/assert"
)

type ConfigProvider struct {
Version *configs.Version `yaml:"version"`
OpenaiConfig *utils.OpenaiConfig `yaml:"openai"`
}

var configPath = assert.Exit1(xdg.ConfigFile("fastcommit/config.yaml"))
var branchName = assert.Exit1(utils.RunOutput("git", "rev-parse", "--abbrev-ref", "HEAD"))

//go:embed default.yaml
var defaultConfig []byte
2 changes: 2 additions & 0 deletions bootstrap/default.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
version:
name: "v0.0.1"
openai:
api_key: ${OPENAI_API_KEY}
base_url: ${OPENAI_BASE_URL:-"https://api.deepseek.com/v1"}
Expand Down
132 changes: 132 additions & 0 deletions cmds/fastcommit/cmd.go
Original file line number Diff line number Diff line change
@@ -1 +1,133 @@
package fastcommit

import (
"context"
"fmt"
"log/slog"
"os"
"sort"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/term"
"github.com/pubgo/dix"
"github.com/pubgo/fastcommit/configs"
"github.com/pubgo/fastcommit/utils"
"github.com/pubgo/funk/assert"
"github.com/pubgo/funk/env"
"github.com/pubgo/funk/errors"
"github.com/pubgo/funk/recovery"
"github.com/pubgo/funk/running"
"github.com/pubgo/funk/version"
"github.com/sashabaranov/go-openai"
"github.com/urfave/cli/v3"
)

type Params struct {
Di *dix.Dix
Cmd []*cli.Command
Cfg *configs.Config
OpenaiClient *utils.OpenaiClient
}

func New(params Params) *Command {
app := &cli.Command{
Name: "fastcommit",
Suggest: true,
UseShortOptionHandling: true,
ShellComplete: cli.DefaultAppComplete,
Usage: "Intelligent generation of git commit message",
Version: version.Version(),
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "debug",
Usage: "enable debug mode",
Persistent: true,
Value: running.IsDebug,
Destination: &running.IsDebug,
Sources: cli.EnvVars(env.Key("debug"), env.Key("enable_debug")),
},
},
Commands: params.Cmd,
Action: func(ctx context.Context, command *cli.Command) error {
var cfg = params.Cfg
if utils.IsHelp() {
return cli.ShowAppHelp(command)
}

if !term.IsTerminal(os.Stdin.Fd()) {
return nil
}

generatePrompt := utils.GeneratePrompt("en", 50, utils.ConventionalCommitType)

repoPath := assert.Must1(utils.AssertGitRepo())
slog.Info("Git repository root", "path", repoPath)

assert.Exit(utils.RunShell("git", "add", "--update"))

diff := assert.Must1(utils.GetStagedDiff(nil))
if diff == nil {
return nil
}

if len(diff.Files) == 0 {
return nil
}

slog.Info(utils.GetDetectedMessage(diff.Files))

resp, err := params.OpenaiClient.Client.CreateChatCompletion(
context.Background(),
openai.ChatCompletionRequest{
Model: params.OpenaiClient.Cfg.Model,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Content: generatePrompt,
},
{
Role: openai.ChatMessageRoleUser,
Content: diff.Diff,
},
},
},
)

if err != nil {
slog.Error("failed to call openai", "err", err)
return errors.WrapCaller(err)
}

if len(resp.Choices) == 0 {
return nil
}

msg := resp.Choices[0].Message.Content
fmt.Println(msg)
var p1 = tea.NewProgram(InitialTextInputModel(msg))
mm := assert.Must1(p1.Run()).(model2)
if mm.isExit() {
return nil
}

msg = mm.Value()
assert.Must(utils.RunShell("git", "commit", "-m", fmt.Sprintf("'%s'", msg)))
assert.Must(utils.RunShell("git", "push", "origin", cfg.BranchName))

return nil
},
}

sort.Sort(cli.FlagsByName(app.Flags))
return &Command{cmd: app}
}

type Command struct {
cmd *cli.Command
}

func (c *Command) Run() {
defer recovery.Exit()
sort.Sort(cli.FlagsByName(c.cmd.Flags))
assert.Exit(c.cmd.Run(utils.Context(), os.Args))
}
Loading

0 comments on commit 093df05

Please sign in to comment.