diff --git a/.gitignore b/.gitignore index d277b14..e6cbe87 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ go.work # Environment variables .env dist/ -config.yaml \ No newline at end of file +config.yaml +.idea \ No newline at end of file diff --git a/cmd/config.go b/cmd/config.go index 6da51ad..b0e95b0 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -6,21 +6,29 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" - "github.com/cocoide/commitify/util" "github.com/fatih/color" "github.com/spf13/cobra" + + "github.com/cocoide/commitify/internal/entity" ) var ( - configKey = [...]string{"api-key", "language", "format"} - configOption = [][]string{ + configKey = [...]string{"api-key", "language", "format", "ai-source"} + configOption = [][]int{ + {}, + {int(entity.EN), int(entity.JP)}, + {int(entity.NormalFormat), int(entity.EmojiFormat), int(entity.PrefixFormat)}, + {int(entity.Server), int(entity.Client), int(entity.Qdrant), int(entity.Gemini)}, + } + configOptionLabel = [][]string{ {}, - {"Japanese", "English"}, - {"Format 1", "Format 2"}, + {"English", "Japanese"}, + {"Normal Format", "Emoji Format", "PrefixFormat"}, + {"Wrap Server", "OpenAI API", "Qdrant Database", "Gemini API"}, } ) -type configModel struct { +type configCmdModel struct { configKeyIndex int configOptionIndex int configKeySelected bool @@ -28,21 +36,21 @@ type configModel struct { textInput textinput.Model } -func initConfigModel() configModel { +func initConfigModel() configCmdModel { ti := textinput.New() ti.Focus() - return configModel{ + return configCmdModel{ textInput: ti, err: nil, } } -func (cm configModel) Init() tea.Cmd { +func (cm configCmdModel) Init() tea.Cmd { return textinput.Blink } -func (cm configModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (cm configCmdModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch cm.configKeySelected { // 設定項目を選択する case false: @@ -75,7 +83,7 @@ func (cm configModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch msg.Type { case tea.KeyEnter: - saveConfig(cm) + entity.SaveConfig(cm.configKeyIndex, -1, cm.textInput.Value()) return cm, tea.Quit case tea.KeyCtrlC, tea.KeyEsc: return cm, tea.Quit @@ -102,7 +110,7 @@ func (cm configModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cm.configOptionIndex++ } case tea.KeyEnter: - saveConfig(cm) + entity.SaveConfig(cm.configKeyIndex, configOption[cm.configKeyIndex][cm.configOptionIndex], "") return cm, tea.Quit case tea.KeyCtrlC, tea.KeyEsc: return cm, tea.Quit @@ -114,23 +122,20 @@ func (cm configModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return cm, nil } -func (cm configModel) View() string { +func (cm configCmdModel) View() string { var b strings.Builder switch cm.configKeySelected { // 設定項目を選んでいない時 case false: - white := color.New(color.FgWhite).SprintFunc() - b.WriteString(white("設定項目を選んでください:\n")) - b.WriteString(white(" ↑↓の矢印キーで項目を移動、Enterで選択\n")) + b.WriteString(color.WhiteString("設定項目を選んでください:\n")) + b.WriteString(color.WhiteString(" ↑↓の矢印キーで項目を移動、Enterで選択\n")) for i, choice := range configKey { - cyan := color.New(color.FgCyan).SprintFunc() - hiCyan := color.New(color.FgHiCyan).SprintFunc() if i == cm.configKeyIndex { - b.WriteString(fmt.Sprintf(hiCyan("➡️ %s\n"), choice)) + b.WriteString(fmt.Sprintf(color.HiCyanString("➡️ %s\n"), choice)) } else { - b.WriteString(fmt.Sprintf(cyan(" %s\n"), choice)) + b.WriteString(fmt.Sprintf(color.CyanString(" %s\n"), choice)) } } @@ -139,26 +144,22 @@ func (cm configModel) View() string { // 選択肢のない項目はテキストエリアを表示 switch len(configOption[cm.configKeyIndex]) { case 0: - white := color.New(color.FgWhite).SprintFunc() - b.WriteString(white(fmt.Sprintf( + b.WriteString(color.WhiteString(fmt.Sprintf( "ここに%sを入力: %s\n", configKey[cm.configKeyIndex], cm.textInput.View(), ))) - b.WriteString(white(" Enterキーで確定")) + b.WriteString(color.WhiteString(" Enterキーで確定")) default: - white := color.New(color.FgWhite).SprintFunc() - b.WriteString(white("設定内容を選んでください:\n")) - b.WriteString(white(" ↑↓の矢印キーで項目を移動、Enterで選択\n")) + b.WriteString(color.WhiteString("設定内容を選んでください:\n")) + b.WriteString(color.WhiteString(" ↑↓の矢印キーで項目を移動、Enterで選択\n")) - for i, option := range configOption[cm.configKeyIndex] { - cyan := color.New(color.FgCyan).SprintFunc() - hiCyan := color.New(color.FgHiCyan).SprintFunc() + for i, option := range configOptionLabel[cm.configKeyIndex] { if i == cm.configOptionIndex { - b.WriteString(fmt.Sprintf(hiCyan("➡️ %s\n"), option)) + b.WriteString(fmt.Sprintf(color.HiCyanString("➡️ %s\n"), option)) } else { - b.WriteString(fmt.Sprintf(cyan(" %s\n"), option)) + b.WriteString(fmt.Sprintf(color.CyanString(" %s\n"), option)) } } } @@ -180,24 +181,3 @@ var configCmd = &cobra.Command{ func init() { rootCmd.AddCommand(configCmd) } - -func saveConfig(cm configModel) { - currentConfig, err := util.ReadConfig() - if err != nil { - fmt.Println(err) - } - - switch cm.configKeyIndex { - case 0: - currentConfig.ChatGptApiKey = cm.textInput.Value() - case 1: - currentConfig.UseLanguage = configOption[cm.configKeyIndex][cm.configOptionIndex] - case 2: - currentConfig.CommitFormat = configOption[cm.configKeyIndex][cm.configOptionIndex] - } - - err = util.WriteConfig(currentConfig) - if err != nil { - fmt.Println(err) - } -} diff --git a/cmd/docs.go b/cmd/docs.go index d7e40f9..09fb5f4 100644 --- a/cmd/docs.go +++ b/cmd/docs.go @@ -17,9 +17,9 @@ var docsCmd = &cobra.Command{ Short: "Document of commitify", Run: func(cmd *cobra.Command, args []string) { b, _ := static.Logo.ReadFile("logo.txt") - cyan := color.New(color.FgCyan).SprintFunc() - logo := cyan(string(b)) - fmt.Println(logo) + fmt.Println(color.CyanString(string(b))) + fmt.Println("\n ・Languageは日本語と英語が選択できます") + fmt.Println(" ・CodeFormatはPrefix (例: feat: A)とEmoji (例: 🐛 Bugix), Normal (例: Feat A)が選べます") }, } diff --git a/cmd/login.go b/cmd/login.go new file mode 100644 index 0000000..3c46be8 --- /dev/null +++ b/cmd/login.go @@ -0,0 +1,59 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "sync" + + "github.com/cocoide/commitify/internal/gateway" + "github.com/cocoide/commitify/internal/usecase" + "github.com/fatih/color" + "github.com/spf13/cobra" +) + +const ( + DeviceActivateURL = "https://github.com/login/device" +) + +var loginCmd = &cobra.Command{ + Use: "login", + Short: "login by github", + Long: `by login you can use auto pull request feature`, + Run: func(cmd *cobra.Command, args []string) { + httpClient := gateway.NewHttpClient() + u := usecase.NewLoginCmdUsecase(httpClient) + res, err := u.BeginGithubSSO() + if err != nil { + fmt.Printf("ログイン中にエラーが発生: %v", err) + } + + var wg sync.WaitGroup + wg.Add(1) + + errChan := make(chan error, 1) + + go func() { + defer wg.Done() + + req := &usecase.ScheduleVerifyAuthRequest{ + DeviceCode: res.DeviceCode, Interval: res.Interval, ExpiresIn: res.ExpiresIn} + err := u.ScheduleVerifyAuth(req) + errChan <- err + }() + fmt.Printf("以下のページで認証コード『%s』を入力して下さい。\n", res.UserCode) + fmt.Printf(color.HiCyanString("➡️ %s\n"), DeviceActivateURL) + wg.Wait() + err = <-errChan + if err != nil { + fmt.Printf("🚨認証エラーが発生: %v", err) + } else { + fmt.Printf("**🎉認証が正常に完了**\n") + } + }, +} + +func init() { + rootCmd.AddCommand(loginCmd) +} diff --git a/cmd/push.go b/cmd/push.go new file mode 100644 index 0000000..6ecbba2 --- /dev/null +++ b/cmd/push.go @@ -0,0 +1,265 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/textarea" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/gateway" + "github.com/cocoide/commitify/internal/usecase" + "github.com/fatih/color" + "github.com/spf13/cobra" + "golang.org/x/net/context" + "strings" +) + +type pushModel struct { + step PushCmdStep + selectBaseIndex int + baseList []string + pr *entity.PullRequest + pcu *usecase.PushCmdUsecase + loadMsg string + errMsg string + spinner spinner.Model + prInput *prInput +} + +type prInput struct { + titleInput textinput.Model + bodyInput textarea.Model +} + +type PushCmdStep int + +const ( + SelectBaseBranch PushCmdStep = iota + EditPRTitle + EditPRBody + SubmitPR +) + +var _ tea.Model = &pushModel{} + +func (m *pushModel) Init() tea.Cmd { + return nil +} + +type generatePRMsg struct { + pr *entity.PullRequest + err error +} + +func (m *pushModel) generatePRCmd() tea.Cmd { + return func() tea.Msg { + selectBranch := m.baseList[m.selectBaseIndex] + pr, err := m.pcu.GeneratePullRequest(selectBranch) + return generatePRMsg{pr, err} + } +} + +type submitPRMsg struct { + err error +} + +func (m *pushModel) submitPRCmd() tea.Cmd { + return func() tea.Msg { + err := m.pcu.SubmitPullRequest(m.pr) + return submitPRMsg{err} + } +} + +func (m *pushModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + switch msg := msg.(type) { + case spinner.TickMsg: + var cmd tea.Cmd + m.spinner, cmd = m.spinner.Update(msg) + return m, cmd + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC, tea.KeyEsc: + return m, tea.Quit + case tea.KeyCtrlE: + m.step-- + } + switch m.step { + case SelectBaseBranch: + switch msg.Type { + case tea.KeyUp: + if m.selectBaseIndex > 0 { + m.selectBaseIndex-- + } + case tea.KeyDown: + if m.selectBaseIndex < len(m.baseList)-1 { + m.selectBaseIndex++ + } + case tea.KeyEnter: + m.loadMsg = "PRを生成中..." + return m, m.generatePRCmd() + } + case EditPRTitle: + cmd = m.updateTitleInput(msg) + switch msg.Type { + case tea.KeyEnter: + m.pr.Title = m.prInput.titleInput.Value() + m.step = EditPRBody + m.focusInPRBody() + return m, cmd + } + case EditPRBody: + cmd = m.updateBodyInput(msg) + switch msg.Type { + case tea.KeyEnter: + m.pr.Body = m.prInput.bodyInput.Value() + m.step = SubmitPR + m.loadMsg = "PRを提出中..." + return m, m.submitPRCmd() + } + } + case generatePRMsg: + if msg.err != nil { + m.errMsg = fmt.Sprintf("🚨PR生成中にエラーが発生: %v", msg.err) + } else { + m.pr = msg.pr + m.step = EditPRTitle + m.focusInPRTitle() + } + m.finishLoading() + case submitPRMsg: + if msg.err != nil { + // リファクタ: github tokenがexpireした時は、loginコマンドを自動実行 + // → tokenがexpireしたときのエラーを調べないといけない... + m.errMsg = fmt.Sprintf("🚨PR提出中にエラーが発生: %v", msg.err) + } + m.finishLoading() + } + return m, nil +} + +func (m *pushModel) View() string { + if m.errMsg != "" { + return m.errMsg + } + if m.loadMsg != "" { + return fmt.Sprintf("\n %s %s\n\n", m.spinner.View(), textStyle(m.loadMsg)) + } + switch m.step { + case SelectBaseBranch: + return m.buildSelectBaseBranchText() + case EditPRTitle: + return color.HiWhiteString("\n\n") + fmt.Sprintf("Title:\n%s", m.prInput.titleInput.View()) + case EditPRBody: + return color.HiWhiteString("\n\n") + fmt.Sprintf("Body:\n%s", m.prInput.bodyInput.View()) + case SubmitPR: + return fmt.Sprintf("**🎉PRの作成に成功**") + } + return "" +} + +func NewPushModel() *pushModel { + ti := textinput.New() + ti.Focus() + var errMsg string + ctx := context.Background() + github := gateway.NewGithubGateway() + nlp := gateway.NewOpenAIGateway(ctx) + pcu := usecase.NewPushCmdUsecase(github, nlp) + baseList, err := pcu.GetRemoteBaseBranchCandidates() + if err != nil { + errMsg = "🚨Baseブランチを取得中にエラーが発生" + } + var maxBaseElements = 5 + var selectedBaseList []string + if len(baseList) < maxBaseElements { + selectedBaseList = baseList[:] + } else { + selectedBaseList = baseList[:maxBaseElements] + } + return &pushModel{ + step: SelectBaseBranch, + baseList: selectedBaseList, + pcu: pcu, + errMsg: errMsg, + loadMsg: "", + prInput: &prInput{ + titleInput: textinput.New(), + bodyInput: textarea.New(), + }, + } +} + +var pushCmd = &cobra.Command{ + Use: "push", + Short: "push and create pull request", + Run: func(cmd *cobra.Command, args []string) { + m := NewPushModel() + m.initSpinner() + p := tea.NewProgram(m) + p.Run() + }, +} + +func init() { + rootCmd.AddCommand(pushCmd) +} + +func (m *pushModel) buildSelectBaseBranchText() string { + var b strings.Builder + b.WriteString(color.HiWhiteString("📢Baseブランチ(Merge先)を選んで下さい\n")) + b.WriteString(color.WhiteString("click ↑↓ to navigate and press Enter to select.\n")) + + for i, base := range m.baseList { + if i == m.selectBaseIndex { + b.WriteString(fmt.Sprintf(color.HiCyanString("➡️ %s\n"), base)) + } else { + b.WriteString(fmt.Sprintf(color.CyanString(" %s\n"), base)) + } + } + return b.String() +} + +func (m *pushModel) finishLoading() { + m.loadMsg = "" +} + +func (m *pushModel) initSpinner() { + m.spinner = spinner.New() + m.spinner.Style = spinnerStyle + m.spinner.Spinner = spinner.Globe +} + +func (m *pushModel) focusInPRTitle() { + input := m.prInput.titleInput + input.Focus() + input.SetValue(m.pr.Title) + input.CharLimit = 100 + input.Width = 100 + m.prInput.titleInput = input +} + +func (m *pushModel) focusInPRBody() { + input := m.prInput.bodyInput + input.Focus() + input.SetValue(m.pr.Body) + input.CharLimit = 5000 + input.SetWidth(200) + m.prInput.bodyInput = input +} + +func (m *pushModel) updateTitleInput(msg tea.Msg) tea.Cmd { + var cmd tea.Cmd + m.prInput.titleInput, cmd = m.prInput.titleInput.Update(msg) + return cmd +} + +func (m *pushModel) updateBodyInput(msg tea.Msg) tea.Cmd { + var cmd tea.Cmd + m.prInput.bodyInput, cmd = m.prInput.bodyInput.Update(msg) + return cmd +} diff --git a/cmd/root.go b/cmd/root.go index f85848f..70fd15b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -8,13 +8,9 @@ import ( var rootCmd = &cobra.Command{ Use: "commitify", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Short: "CLI for thinking commit message", + Long: `By "commitify config" command, you can change commit message format or language, + ( To know details about format or language, enter commitify docs )`, } func Execute() { diff --git a/cmd/suggest.go b/cmd/suggest.go index b1dac8c..6c2acd9 100644 --- a/cmd/suggest.go +++ b/cmd/suggest.go @@ -1,115 +1,174 @@ package cmd import ( - "context" "fmt" + "log" + "os" "strings" - tea "github.com/charmbracelet/bubbletea" + "github.com/cocoide/commitify/internal/entity" "github.com/cocoide/commitify/internal/gateway" "github.com/cocoide/commitify/internal/service" - "github.com/cocoide/commitify/util" + "github.com/cocoide/commitify/internal/usecase" + "golang.org/x/net/context" + + "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" "github.com/fatih/color" "github.com/spf13/cobra" ) -type model struct { +var ( + textStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("252")).Render + spinnerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("69")) +) + +type suggestModel struct { choices []string currentIdx int errorMsg string isLoading bool - messages []string + isEditing bool + spinner spinner.Model + textInput textinput.Model + scs *usecase.SuggestCmdUsecase } -type generateMessages struct { - messages []string - errorMsg string -} - -func (m model) Init() tea.Cmd { - return func() tea.Msg { - ctx := context.Background() - og := gateway.NewOpenAIGateway(ctx) - ms := service.NewMessageService(og) - stagingCode := util.ExecGetStagingCode() - messages, err := ms.GenerateCommitMessage(stagingCode) +func (sm *suggestModel) Init() tea.Cmd { + go func() { + messages, err := sm.scs.GenerateCommitMessages() if err != nil { - return generateMessages{errorMsg: "メッセージの生成に失敗: " + err.Error()} + log.Fatal("コミットメッセージの生成に失敗: ", err) + os.Exit(-1) } - return generateMessages{messages: messages} - } + sm.choices = messages + sm.isLoading = false + }() + + return textinput.Blink } -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (sm *suggestModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + sm.textInput, cmd = sm.textInput.Update(msg) switch msg := msg.(type) { - case generateMessages: - if msg.errorMsg != "" { - m.errorMsg = msg.errorMsg - m.isLoading = false - return m, nil - } - m.choices = msg.messages - m.isLoading = false - return m, nil case tea.KeyMsg: switch msg.Type { + case tea.KeyTab: + sm.isEditing = true + sm.textInput.Focus() + sm.textInput.SetValue(sm.choices[sm.currentIdx]) + sm.textInput.CharLimit = 100 + sm.textInput.Width = 100 + return sm, cmd case tea.KeyUp: - if m.currentIdx > 0 { - m.currentIdx-- + if sm.currentIdx > 0 { + sm.currentIdx-- } case tea.KeyDown: - if m.currentIdx < len(m.choices)-1 { - m.currentIdx++ + if sm.currentIdx < len(sm.choices)-1 { + sm.currentIdx++ } case tea.KeyEnter: - if err := util.ExecCommitMessage(m.choices[m.currentIdx]); err != nil { - m.errorMsg = "コミットに失敗: " + err.Error() - return m, tea.Quit + if err := sm.scs.SubmitCommit(sm.choices[sm.currentIdx]); err != nil { + sm.errorMsg = "コミットに失敗: " + err.Error() + return sm, tea.Quit } - return m, tea.Quit + return sm, tea.Quit case tea.KeyCtrlC, tea.KeyEsc: - return m, tea.Quit + return sm, tea.Quit } + case spinner.TickMsg: + var cmd tea.Cmd + sm.spinner, cmd = sm.spinner.Update(msg) + return sm, cmd } - return m, nil + return sm, sm.spinner.Tick } -func (m model) View() string { - if m.errorMsg != "" { - red := color.New(color.FgRed).SprintFunc() - return fmt.Sprintf(red(m.errorMsg)) +func (sm *suggestModel) View() string { + if sm.errorMsg != "" { + return color.RedString(sm.errorMsg) } - if m.isLoading { - return "🌎 Generating commit messages ..." + if sm.isLoading { + s := fmt.Sprintf("\n %s %s\n\n", sm.spinner.View(), textStyle("コミットメッセージ生成中")) + return s } var b strings.Builder - if m.errorMsg != "" { - red := color.New(color.FgRed).SprintFunc() - b.WriteString(red(m.errorMsg) + "\n\n") + if sm.errorMsg != "" { + b.WriteString(color.RedString(sm.errorMsg) + "\n\n") + } + if sm.isEditing { + return sm.textInput.View() } - white := color.New(color.FgWhite).SprintFunc() - b.WriteString(white("🍕Please select an option:")) - b.WriteString(white("\n Use arrow ↑↓ to navigate and press Enter to select.\n\n")) - - for i, choice := range m.choices { - cyan := color.New(color.FgCyan).SprintFunc() - hiCyan := color.New(color.FgHiCyan).SprintFunc() - if i == m.currentIdx { - b.WriteString(fmt.Sprintf(hiCyan("➡️ %s\n"), choice)) + + b.WriteString(color.WhiteString("🍕 Please select and enter to commit")) + b.WriteString(color.WhiteString("\n Use arrow ↑↓ to navigate and press Enter to select.")) + b.WriteString(color.WhiteString("\n ( enter Tab key to edit message )\n\n")) + + for i, choice := range sm.choices { + if i == sm.currentIdx { + b.WriteString(fmt.Sprintf(color.HiCyanString("➡️ %s\n"), choice)) } else { - b.WriteString(fmt.Sprintf(cyan(" %s\n"), choice)) + b.WriteString(fmt.Sprintf(color.CyanString(" %s\n"), choice)) } } return b.String() } +// モデルの初期化処理 +func NewSuggestModel() *suggestModel { + ti := textinput.New() + ti.Focus() + + // suggestコマンドのサービスの取得 + github := gateway.NewGithubGateway() + var commitMessageService service.CommitMessageService + config, err := entity.ReadConfig() + if err != nil { + log.Fatalf("設定ファイルの読み込みができませんでした") + } + switch config.GptRequestLocation() { + case entity.Client: + nlp := gateway.NewOpenAIGateway(context.Background()) + commitMessageService = gateway.NewClientCommitMessageGateway(nlp) + case entity.Server: + commitMessageService = gateway.NewGrpcServerGateway() + case entity.Qdrant: + commitMessageService = gateway.NewQdrantServerGateway() + case entity.Gemini: + commitMessageService = gateway.NewGeminiServerGateway() + } + suggestCmdUsecase := usecase.NewSuggestCmdUsecase(commitMessageService, github) + + return &suggestModel{ + choices: []string{""}, + currentIdx: 0, + errorMsg: "", + isLoading: true, + isEditing: false, + textInput: ti, + scs: suggestCmdUsecase, + } +} + +// スピナーの初期化 +func (sm *suggestModel) initSpinner() { + sm.spinner = spinner.New() + sm.spinner.Style = spinnerStyle + sm.spinner.Spinner = spinner.Globe +} + var suggestCmd = &cobra.Command{ Use: "suggest", Short: "Suggestion of commit message for staging repository", Aliases: []string{"s", "suggest"}, Run: func(cmd *cobra.Command, args []string) { - m := model{isLoading: true} - p := tea.NewProgram(m) + sm := NewSuggestModel() + sm.initSpinner() + p := tea.NewProgram(sm) p.Run() }, } diff --git a/cmd/version.go b/cmd/version.go deleted file mode 100644 index af2b3fe..0000000 --- a/cmd/version.go +++ /dev/null @@ -1,35 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("version 0.9 -- HEAD") - }, -} - -func init() { - rootCmd.AddCommand(versionCmd) - rootCmd.Flags().BoolP("version", "v", false, "アプリのVersion") - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // versionCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // versionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/go.mod b/go.mod index 3ec8675..caa3f7d 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,17 @@ go 1.19 require ( github.com/charmbracelet/bubbles v0.16.1 github.com/charmbracelet/bubbletea v0.24.2 + github.com/charmbracelet/lipgloss v0.7.1 github.com/fatih/color v1.15.0 github.com/golang/mock v1.4.4 - github.com/sashabaranov/go-openai v1.15.1 + github.com/pkg/errors v0.9.1 + github.com/sashabaranov/go-openai v1.15.2 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 - google.golang.org/grpc v1.55.0 - google.golang.org/protobuf v1.30.0 + go.uber.org/mock v0.3.0 + golang.org/x/net v0.15.0 + google.golang.org/grpc v1.58.0 + google.golang.org/protobuf v1.31.0 ) require ( @@ -34,7 +38,6 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/lipgloss v0.7.1 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -46,10 +49,10 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect ) diff --git a/go.sum b/go.sum index 124cadd..b69ce55 100644 --- a/go.sum +++ b/go.sum @@ -179,6 +179,7 @@ github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -190,8 +191,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sashabaranov/go-openai v1.15.1 h1:BAV5LCVEzvZ3rN/Lh5NRVs2z6AahPt/jn5s2/cEEG0M= -github.com/sashabaranov/go-openai v1.15.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sashabaranov/go-openai v1.15.2 h1:0PW+ttxe+UNYKDkA1KTly7K6YhFBqnVBbblQ3t8AfY4= +github.com/sashabaranov/go-openai v1.15.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -213,8 +214,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -227,6 +229,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -299,8 +303,8 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -320,8 +324,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -361,11 +365,11 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -374,8 +378,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -492,8 +496,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -510,8 +514,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -524,8 +528,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/entity/config.go b/internal/entity/config.go index 226ac5a..999c68c 100644 --- a/internal/entity/config.go +++ b/internal/entity/config.go @@ -1,7 +1,158 @@ package entity +import ( + "encoding/json" + "fmt" + "os" + + pb "github.com/cocoide/commitify/proto/gen" + "github.com/spf13/viper" +) + +// コミットメッセージの言語の列挙型 +type Language int + +const ( + EN Language = iota + JP +) + +// コミットメッセージの形式の列挙型 +type CodeFormat int + +const ( + NormalFormat CodeFormat = iota + EmojiFormat + PrefixFormat +) + +// ChatGPTのAPIを叩く場所 +type GptRequestLocation int + +const ( + Server GptRequestLocation = iota + Client + Qdrant + Gemini +) + type Config struct { ChatGptApiKey string `json:"chatGptApiKey"` - UseLanguage string `json:"UseLanguage"` - CommitFormat string `json:"CommitFormat"` + UseLanguage int `json:"UseLanguage"` + CommitFormat int `json:"CommitFormat"` + AISource int `json:"AISource"` + GithubToken string `json:"GithubToken"` +} + +func (c *Config) Config2PbVars() (pb.CodeFormatType, pb.LanguageType) { + var codeFormatType pb.CodeFormatType + switch c.CommitFormat { + case int(EmojiFormat): + codeFormatType = pb.CodeFormatType_EMOJI + case int(PrefixFormat): + codeFormatType = pb.CodeFormatType_PREFIX + default: + codeFormatType = pb.CodeFormatType_NORMAL + } + + var languageType pb.LanguageType + switch c.UseLanguage { + case int(JP): + languageType = pb.LanguageType_JAPANESE + default: + languageType = pb.LanguageType_JAPANESE + } + + return codeFormatType, languageType +} + +func ReadConfig() (Config, error) { + var result Config + homePath, err := os.UserHomeDir() + if err != nil { + return result, err + } + + viper.AddConfigPath(homePath + "/.commitify") + viper.SetConfigName("config") + viper.SetConfigType("yaml") + if err := viper.ReadInConfig(); err != nil { + return result, fmt.Errorf("error reading config file, %s", err.Error()) + } + if err := viper.Unmarshal(&result); err != nil { + return result, fmt.Errorf("unable to decode into struct, %v", err.Error()) + } + return result, nil +} + +func (c Config) WriteConfig() error { + homePath, err := os.UserHomeDir() + if err != nil { + return err + } + + viper.AddConfigPath(homePath + "/.commitify") + viper.SetConfigName("config") + viper.SetConfigType("yaml") + configMap := make(map[string]interface{}) + configBytes, err := json.Marshal(c) + if err != nil { + return fmt.Errorf("error marshalling config: %s", err.Error()) + } + err = json.Unmarshal(configBytes, &configMap) + if err != nil { + return fmt.Errorf("error unmarshalling config: %s", err.Error()) + } + if err := viper.MergeConfigMap(configMap); err != nil { + return err + } + if err := viper.WriteConfig(); err != nil { + return fmt.Errorf("error saving config file, %s", err.Error()) + } + return nil +} + +func (c *Config) WithGithubToken(token string) *Config { + c.GithubToken = token + return c +} + +func SaveConfig(configIndex, updateConfigParamInt int, updateConfigParamStr string) error { + currentConfig, err := ReadConfig() + if err != nil { + return err + } + + switch configIndex { + case 0: + currentConfig.ChatGptApiKey = updateConfigParamStr + case 1: + currentConfig.UseLanguage = updateConfigParamInt + case 2: + currentConfig.CommitFormat = updateConfigParamInt + case 3: + currentConfig.AISource = updateConfigParamInt + } + + err = currentConfig.WriteConfig() + if err != nil { + return err + } + + return nil +} + +func (c *Config) GptRequestLocation() GptRequestLocation { + switch c.AISource { + case 0: + return Server + case 1: + return Client + case 2: + return Qdrant + case 3: + return Gemini + default: + return Server + } } diff --git a/internal/entity/github.go b/internal/entity/github.go new file mode 100644 index 0000000..4e1a602 --- /dev/null +++ b/internal/entity/github.go @@ -0,0 +1,12 @@ +package entity + +type PullRequest struct { + Owner string + Repo string + Title string + Body string + Head string + Base string +} + +type PullRequests []*PullRequest diff --git a/internal/gateway/clinet.go b/internal/gateway/clinet.go new file mode 100644 index 0000000..329a818 --- /dev/null +++ b/internal/gateway/clinet.go @@ -0,0 +1,41 @@ +package gateway + +import ( + "fmt" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + "regexp" + "strings" +) + +const ( + NormalMessagePrompt = "Generate up to 5 commit messages for [%s]. Each message should be separated by only space" +) + +var CommitMessageRegex = regexp.MustCompile(`^(\d.\s+)|^(-\s+)|^(\s+)`) + +type clientCommitMessageGateway struct { + nlp service.NLPService +} + +func NewClientCommitMessageGateway(nlp service.NLPService) service.CommitMessageService { + return &clientCommitMessageGateway{nlp: nlp} +} + +func (l *clientCommitMessageGateway) GenerateCommitMessageList(code string, conf entity.Config) ([]string, error) { + prompt := fmt.Sprintf(NormalMessagePrompt, code) + result, err := l.nlp.GetAnswerFromPrompt(prompt) + if err != nil { + return nil, err + } + messages := strings.Split(result, "\n") + messages = l.removeFromArrayByRegex(messages, CommitMessageRegex) + return messages, nil +} + +func (l *clientCommitMessageGateway) removeFromArrayByRegex(array []string, pattern *regexp.Regexp) []string { + for i, msg := range array { + array[i] = pattern.ReplaceAllString(msg, "") + } + return array +} diff --git a/internal/gateway/gemini.go b/internal/gateway/gemini.go new file mode 100644 index 0000000..8433213 --- /dev/null +++ b/internal/gateway/gemini.go @@ -0,0 +1,56 @@ +package gateway + +import ( + "encoding/json" + + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + "github.com/pkg/errors" +) + +type geminiServerGateway struct { + client *HttpClient +} + +func NewGeminiServerGateway() service.CommitMessageService { + c := NewHttpClient(). + WithBaseURL("http://suwageeks.org:5215"). + WithPath("/gemini"). + WithHeader("Content-Type", "application/json") + + return &geminiServerGateway{client: c} +} + +func (qs *geminiServerGateway) GenerateCommitMessageList(diff string, conf entity.Config) ([]string, error) { + if diff == "" { + return nil, errors.New("ステージされた変更がありません。") + } + + type geminiBody struct { + Diff string `json:"diff"` + } + + body := &geminiBody{ + Diff: diff, + } + b, err := json.Marshal(body) + if err != nil { + return nil, err + } + + res, err := qs.client.WithBody(b).Execute(POST) + if err != nil { + return nil, err + } + + type geminiResponse struct { + Messages []string `json:"messages"` + } + + values := new(geminiResponse) + if err = json.Unmarshal(res, values); err != nil { + return nil, err + } + + return values.Messages, nil +} diff --git a/internal/gateway/github.go b/internal/gateway/github.go new file mode 100644 index 0000000..66285b7 --- /dev/null +++ b/internal/gateway/github.go @@ -0,0 +1,125 @@ +package gateway + +import ( + "encoding/json" + "fmt" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + "github.com/pkg/errors" + "os/exec" + "strings" +) + +type githubGateway struct { + client *HttpClient +} + +func NewGithubGateway() service.GithubService { + return &githubGateway{client: NewHttpClient()} +} + +func (g *githubGateway) GetStagingCodeDiff() (string, error) { + // Gitが入ってるかどうかのチェックも入れる + // 入っていないなら専用のエラーメッセージを生成 + diff, err := exec.Command("git", "diff", "--staged").Output() + return string(diff), err +} + +func (g *githubGateway) GetCurrentRepoDetails() (*service.GetRepoDetailsResponse, error) { + _, err := exec.LookPath("git") + if err != nil { + return nil, errors.New("git is not installed on the system") + } + output, err := exec.Command("git", "config", "--get", "remote.origin.url").Output() + if err != nil { + return nil, err + } + url := strings.TrimSpace(string(output)) + parts := strings.Split(url, "/") + if len(parts) < 2 { + return nil, errors.New("unable to parse the repository URL") + } + repo := strings.TrimSuffix(parts[len(parts)-1], ".git") + owner := parts[len(parts)-2] + + return &service.GetRepoDetailsResponse{ + Owner: owner, + Repo: repo, + }, nil +} + +func (g *githubGateway) CreatePullRequest(req *entity.PullRequest, token string) error { + type Body struct { + Title string `json:"title"` + Body string `json:"body"` + Head string `json:"head"` + Base string `json:"base"` + } + body := &Body{ + Title: req.Title, + Body: req.Body, + Head: req.Head, + Base: req.Base, + } + b, err := json.Marshal(body) + if err != nil { + return err + } + // API参照ドキュメント: https://docs.github.com/ja/rest/pulls/pulls?apiVersion=2022-11-28#create-a-pull-request--code-samples + _, err = g.client. + WithBaseURL(fmt.Sprintf("https://api.github.com/repos/%s/%s/pulls", req.Owner, req.Repo)). + WithHeader("Accept", "application/vnd.github+json"). + WithHeader("X-GitHub-Api-Version", "2022-11-28"). + WithBearerToken(token). + WithBody(b). + Execute(POST) + return err +} + +func (g *githubGateway) GetCurrentBranch() (string, error) { + output, err := exec.Command("git", "branch", "--show-current").Output() + if err != nil { + return "", err + } + return strings.TrimSpace(strings.TrimSpace(string(output))), nil +} + +func (g *githubGateway) GetUnPushedCommits(base string) ([]string, error) { + head, err := g.GetCurrentBranch() + if err != nil { + return nil, err + } + output, err := exec.Command("git", "log", base+".."+head, "--pretty=format:%s").Output() + if err != nil { + return nil, err + } + commits := strings.Split(string(output), "\n") + return commits, nil +} + +func (g *githubGateway) GetRecentUpdatedBranch() ([]string, error) { + var result []string + output, err := exec.Command("git", "for-each-ref", "--sort=-committerdate", "refs/remotes/", "--format=%(refname:short)").Output() + if err != nil { + return nil, err + } + for _, line := range strings.Split(string(output), "\n") { + branch := strings.TrimPrefix(line, "origin/") + if branch == "origin" { + continue + } + result = append(result, branch) + } + return result, nil +} + +func (g *githubGateway) PushCurrentBranch() error { + head, err := g.GetCurrentBranch() + if err != nil { + return err + } + if _, err = exec.Command("git", "push", "origin", head).Output(); err != nil { + return fmt.Errorf("failed to push branch %s: %w", head, err) + } + return nil +} diff --git a/internal/gateway/github_test.go b/internal/gateway/github_test.go new file mode 100644 index 0000000..01f4f93 --- /dev/null +++ b/internal/gateway/github_test.go @@ -0,0 +1,25 @@ +package gateway + +import ( + "github.com/cocoide/commitify/internal/entity" + "log" + "testing" +) + +const ( + TestHeadBranch = "temp/test-auto-pr" +) + +func Test_CreatePullRequest(t *testing.T) { + conf, err := entity.ReadConfig() + if err != nil { + log.Fatal(err) + } + tkn := conf.GithubToken + pr := &entity.PullRequest{ + Owner: "cocoide", Repo: "commitify", Title: "test title", Body: "test body", Head: TestHeadBranch, Base: "main"} + u := NewGithubGateway() + if err := u.CreatePullRequest(pr, tkn); err != nil { + t.Error(err) + } +} diff --git a/internal/gateway/grpc.go b/internal/gateway/grpc.go new file mode 100644 index 0000000..4d436a8 --- /dev/null +++ b/internal/gateway/grpc.go @@ -0,0 +1,46 @@ +package gateway + +import ( + "crypto/tls" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + pb "github.com/cocoide/commitify/proto/gen" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "log" +) + +const ( + serverAddress = "commitify.fly.dev:443" +) + +type grpcServerGateway struct { + client pb.CommitMessageServiceClient +} + +func NewGrpcServerGateway() service.CommitMessageService { + conn, err := grpc.Dial( + serverAddress, + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})), + ) + if err != nil { + log.Fatalf("Failed to setup grpc connection: %v", err) + } + client := pb.NewCommitMessageServiceClient(conn) + return &grpcServerGateway{client: client} +} + +func (g *grpcServerGateway) GenerateCommitMessageList(code string, conf entity.Config) ([]string, error) { + formatType, languageType := conf.Config2PbVars() + req := &pb.CommitMessageRequest{ + CodeFormat: formatType, + Language: languageType, + InputCode: code, + } + res, err := g.client.GenerateCommitMessage(context.Background(), req) + if err != nil { + return nil, err + } + return res.Messages, nil +} diff --git a/internal/gateway/http_client.go b/internal/gateway/http_client.go new file mode 100644 index 0000000..7fdea78 --- /dev/null +++ b/internal/gateway/http_client.go @@ -0,0 +1,118 @@ +package gateway + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strconv" +) + +type HttpClient struct { + client *http.Client + endpoint string + headers map[string]string + params map[string]interface{} + body io.Reader +} + +func NewHttpClient() *HttpClient { + return &HttpClient{ + client: &http.Client{}, + headers: make(map[string]string), + params: make(map[string]interface{}), + } +} + +func (h *HttpClient) WithBaseURL(baseURL string) *HttpClient { + h.endpoint = baseURL + return h +} + +func (h *HttpClient) WithHeader(key, value string) *HttpClient { + h.headers[key] = value + return h +} + +func (h *HttpClient) WithBearerToken(token string) *HttpClient { + h.headers["Authorization"] = fmt.Sprintf("Bearer %s", token) + return h +} + +func (h *HttpClient) WithPath(path string) *HttpClient { + h.endpoint = h.endpoint + "/" + path + return h +} + +func (h *HttpClient) WithParam(key string, value interface{}) *HttpClient { + h.params[key] = value + return h +} + +type HttpMethod int + +const ( + GET HttpMethod = iota + 1 + POST + DELTE + PUT +) + +func (h *HttpClient) WithBody(values []byte) *HttpClient { + h.body = bytes.NewReader(values) + return h +} + +func (h *HttpClient) Execute(method HttpMethod) ([]byte, error) { + var methodName string + switch method { + case GET: + methodName = "GET" + case POST: + methodName = "POST" + case DELTE: + methodName = "DELETE" + case PUT: + methodName = "PUT" + } + client := h.client + + req, err := http.NewRequest(methodName, h.endpoint, h.body) + if err != nil { + return nil, err + } + + for k, v := range h.headers { + req.Header.Add(k, v) + } + + query := req.URL.Query() + for key, value := range h.params { + switch v := value.(type) { + case string: + query.Add(key, v) + case int: + query.Add(key, strconv.Itoa(v)) + case bool: + query.Add(key, strconv.FormatBool(v)) + default: + return nil, fmt.Errorf("Failed to parse param value: %v", value) + } + } + req.URL.RawQuery = query.Encode() + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, fmt.Errorf("request failed with status code: %d, resBody: %v", resp.StatusCode, string(body)) + } + return body, nil +} diff --git a/internal/gateway/open_ai.go b/internal/gateway/open_ai.go new file mode 100644 index 0000000..0aa5c7c --- /dev/null +++ b/internal/gateway/open_ai.go @@ -0,0 +1,43 @@ +package gateway + +import ( + "context" + "github.com/cocoide/commitify/internal/service" + "log" + + "github.com/cocoide/commitify/internal/entity" + "github.com/sashabaranov/go-openai" +) + +type openAIGateway struct { + client *openai.Client + ctx context.Context +} + +func NewOpenAIGateway(ctx context.Context) service.NLPService { + config, err := entity.ReadConfig() + if err != nil { + log.Fatalf("Failed to read config: %v", err) + } + client := openai.NewClient(config.ChatGptApiKey) + return &openAIGateway{client: client, ctx: ctx} +} + +func (og *openAIGateway) GetAnswerFromPrompt(prompt string) (string, error) { + req := openai.ChatCompletionRequest{ + Model: openai.GPT3Dot5Turbo, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleUser, + Content: prompt, + }, + }, + Temperature: 0.001, + } + res, err := og.client.CreateChatCompletion(og.ctx, req) + if err != nil { + return "", err + } + answer := res.Choices[0].Message.Content + return answer, nil +} diff --git a/internal/gateway/openai.go b/internal/gateway/openai.go deleted file mode 100644 index d86d304..0000000 --- a/internal/gateway/openai.go +++ /dev/null @@ -1,58 +0,0 @@ -package gateway - -import ( - "context" - "log" - - "github.com/cocoide/commitify/util" - "github.com/sashabaranov/go-openai" -) - -type OpenAIGateway interface { - GetAnswerFromPrompt(prompt string, variability float32) (string, error) - AsyncGetAnswerFromPrompt(prompt string, variability float32) <-chan string -} - -type openAIGateway struct { - client *openai.Client - ctx context.Context -} - -func NewOpenAIGateway(ctx context.Context) OpenAIGateway { - config, err := util.ReadConfig() - if err != nil { - log.Fatalf("Failed to read config: %v", err) - } - client := openai.NewClient(config.ChatGptApiKey) - return &openAIGateway{client: client, ctx: ctx} -} - -func (og *openAIGateway) GetAnswerFromPrompt(prompt string, variability float32) (string, error) { - req := openai.ChatCompletionRequest{ - Model: openai.GPT3Dot5Turbo, - Messages: []openai.ChatCompletionMessage{ - { - Role: openai.ChatMessageRoleUser, - Content: prompt, - }, - }, - Temperature: variability, - } - res, err := og.client.CreateChatCompletion(og.ctx, req) - if err != nil { - return "", err - } - answer := res.Choices[0].Message.Content - return answer, nil -} - -func (og *openAIGateway) AsyncGetAnswerFromPrompt(prompt string, variability float32) <-chan string { - responseCh := make(chan string, 1) - - go func() { - answer, _ := og.GetAnswerFromPrompt(prompt, variability) - responseCh <- answer - }() - - return responseCh -} diff --git a/internal/gateway/qdrant.go b/internal/gateway/qdrant.go new file mode 100644 index 0000000..7ff2a39 --- /dev/null +++ b/internal/gateway/qdrant.go @@ -0,0 +1,57 @@ +package gateway + +import ( + "encoding/json" + "errors" + + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" +) + +type qdrantServerGateway struct { + client *HttpClient +} + +func NewQdrantServerGateway() service.CommitMessageService { + c := NewHttpClient() + + return &qdrantServerGateway{client: c} +} + +func (qs *qdrantServerGateway) GenerateCommitMessageList(diff string, conf entity.Config) ([]string, error) { + if diff == "" { + return nil, errors.New("ステージされた変更がありません。") + } + + type qdrantBody struct { + Diff string `json:"diff"` + } + + body := &qdrantBody{ + Diff: diff, + } + b, err := json.Marshal(body) + if err != nil { + return nil, err + } + + res, err := qs.client. + WithBaseURL("http://suwageeks.org:5215"). + WithPath("/search"). + WithHeader("Content-Type", "application/json"). + WithBody(b).Execute(POST) + if err != nil { + return nil, err + } + + type qdrantResponse struct { + Messages []string `json:"messages"` + } + + values := new(qdrantResponse) + if err = json.Unmarshal(res, values); err != nil { + return nil, err + } + + return values.Messages, nil +} diff --git a/internal/service/commit_message.go b/internal/service/commit_message.go new file mode 100644 index 0000000..c03a649 --- /dev/null +++ b/internal/service/commit_message.go @@ -0,0 +1,7 @@ +package service + +import "github.com/cocoide/commitify/internal/entity" + +type CommitMessageService interface { + GenerateCommitMessageList(code string, config entity.Config) ([]string, error) +} diff --git a/internal/service/github.go b/internal/service/github.go new file mode 100644 index 0000000..d3bb211 --- /dev/null +++ b/internal/service/github.go @@ -0,0 +1,18 @@ +package service + +import "github.com/cocoide/commitify/internal/entity" + +type GetRepoDetailsResponse struct { + Owner string + Repo string +} + +type GithubService interface { + GetStagingCodeDiff() (string, error) + GetCurrentRepoDetails() (*GetRepoDetailsResponse, error) + CreatePullRequest(pr *entity.PullRequest, token string) error + GetCurrentBranch() (string, error) + GetUnPushedCommits(base string) ([]string, error) + GetRecentUpdatedBranch() ([]string, error) + PushCurrentBranch() error +} diff --git a/internal/service/message.go b/internal/service/message.go deleted file mode 100644 index bfc234f..0000000 --- a/internal/service/message.go +++ /dev/null @@ -1,41 +0,0 @@ -package service - -import ( - "fmt" - "strings" - - "github.com/cocoide/commitify/internal/gateway" -) - -const ( - CommitMessagePrompt = "Generate up to 5 commit messages for [%s]. Each message should be separated by only space" - FormatNotice = ", format commit as:\n- feat: [feature description]\n- bugfix: [bugfix description]" -) - -var PromptVariability float32 = 0.01 - -// メッセージの生成、加工に関するクラス -type MessageService interface { - GenerateCommitMessage(stagingCode string) ([]string, error) -} - -type messageService struct { - og gateway.OpenAIGateway -} - -func NewMessageService(og gateway.OpenAIGateway) MessageService { - return &messageService{og: og} -} - -func (s *messageService) GenerateCommitMessage(stagingCode string) ([]string, error) { - if len(stagingCode) < 1 { - return nil, fmt.Errorf("There is no staging code") - } - prompt := fmt.Sprintf(CommitMessagePrompt, stagingCode) - result, err := s.og.GetAnswerFromPrompt(prompt, PromptVariability) - if err != nil { - return nil, err - } - messages := strings.Split(result, "\n") - return messages, nil -} diff --git a/internal/service/message_test.go b/internal/service/message_test.go deleted file mode 100644 index e94b913..0000000 --- a/internal/service/message_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package service_test - -import ( - "fmt" - "reflect" - "testing" - - "github.com/cocoide/commitify/internal/service" - mock_gateway "github.com/cocoide/commitify/mock" - "github.com/golang/mock/gomock" -) - -func Test_GenerateCommitMessage(t *testing.T) { - stagingCode := "test" - type test struct { - ErrorCaseName string - ChatGptResult string - ModifiedResult []string - } - tests := []test{ - {"先頭にインデックスを含む", "1. test\n2. test", []string{"test", "test"}}, - {"先頭にハイフンを含む", "- test\n- test", []string{"test", "test"}}, - {"先頭にスペースを含む", " test\n test", []string{"test", "test"}}, - {"改行ができていない", "Add A function. Update B", []string{"Add A function", "Update B"}}, - // たまに, 改行せずピリオド『.』で文章を区切るパターンがある - } - ctrl := gomock.NewController(t) - og := mock_gateway.NewMockOpenAIGateway(ctrl) - ms := service.NewMessageService(og) - - for _, test := range tests { - prompt := fmt.Sprintf(service.CommitMessagePrompt, stagingCode) - og.EXPECT(). - GetAnswerFromPrompt(prompt, service.PromptVariability). - Return(test.ChatGptResult, nil) - - serviceResult, err := ms.GenerateCommitMessage(stagingCode) - if err != nil { - t.Error(err.Error()) - } - if !reflect.DeepEqual(test.ModifiedResult, serviceResult) { - fmt.Printf("FAIL: %s\n", test.ErrorCaseName) - t.Errorf("Exp: %v, Got: %v", test.ModifiedResult, serviceResult) - } - } -} diff --git a/internal/service/nlp.go b/internal/service/nlp.go new file mode 100644 index 0000000..2cf6f79 --- /dev/null +++ b/internal/service/nlp.go @@ -0,0 +1,5 @@ +package service + +type NLPService interface { + GetAnswerFromPrompt(prompt string) (string, error) +} diff --git a/internal/usecase/login_cmd.go b/internal/usecase/login_cmd.go new file mode 100644 index 0000000..fe76056 --- /dev/null +++ b/internal/usecase/login_cmd.go @@ -0,0 +1,120 @@ +package usecase + +import ( + "fmt" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/gateway" + "net/url" + "strconv" + "time" +) + +const ( + GithubClientID = "b27d87c28752d2363922" + GithubScope = "repo" + GrantType = "urn:ietf:params:oauth:grant-type:device_code" +) + +type LoginCmdUsecase struct { + http *gateway.HttpClient +} + +func NewLoginCmdUsecase(http *gateway.HttpClient) *LoginCmdUsecase { + http.WithBaseURL("https://github.com/login") + return &LoginCmdUsecase{http: http} +} + +type BeginGithubSSOResponse struct { + DeviceCode string + UserCode string + Interval int + ExpiresIn int +} + +func (u *LoginCmdUsecase) BeginGithubSSO() (*BeginGithubSSOResponse, error) { + b, err := u.http.WithPath("device/code"). + WithParam("client_id", GithubClientID). + WithParam("scope", GithubScope). + Execute(gateway.POST) + if err != nil { + return nil, err + } + values, err := url.ParseQuery(string(b)) + if err != nil { + return nil, err + } + deviceCode := values.Get("device_code") + userCode := values.Get("user_code") + expiresIn, err := strconv.Atoi(values.Get("expires_in")) + if err != nil { + return nil, err + } + interval, err := strconv.Atoi(values.Get("interval")) + if err != nil { + return nil, err + } + if deviceCode == "" || userCode == "" { + return nil, fmt.Errorf("failed to parse code") + } + return &BeginGithubSSOResponse{ + DeviceCode: deviceCode, + UserCode: userCode, + ExpiresIn: expiresIn, + Interval: interval, + }, nil +} + +type ScheduleVerifyAuthRequest struct { + DeviceCode string + Interval int + ExpiresIn int +} + +func (u *LoginCmdUsecase) ScheduleVerifyAuth(req *ScheduleVerifyAuthRequest) error { + u.http = gateway.NewHttpClient(). + WithBaseURL("https://github.com/login"). + WithPath("oauth/access_token"). + WithParam("client_id", GithubClientID). + WithParam("device_code", req.DeviceCode). + WithParam("grant_type", GrantType) + + timeout := time.After(time.Duration(req.ExpiresIn) * time.Second) + ticker := time.NewTicker(time.Duration(req.Interval) * time.Second) + defer ticker.Stop() + + for { + select { + case <-timeout: + return fmt.Errorf("認証プロセスがタイムアウトしました") + case <-ticker.C: + b, err := u.http.Execute(gateway.POST) + if err != nil { + return err + } + values, err := url.ParseQuery(string(b)) + if err != nil { + return err + } + accessToken := values.Get("access_token") + if accessToken != "" { + config, err := entity.ReadConfig() + if err != nil { + return err + } + config.WithGithubToken(accessToken) + if err := config.WriteConfig(); err != nil { + return err + } + return nil + } + if newIntervalStr := values.Get("interval"); newIntervalStr != "" { + newInterval, err := strconv.Atoi(newIntervalStr) + if err != nil { + return err + } + ticker.Stop() + ticker = time.NewTicker(time.Duration(newInterval) * time.Second) + } + } + } +} diff --git a/internal/usecase/push_cmd.go b/internal/usecase/push_cmd.go new file mode 100644 index 0000000..5d10127 --- /dev/null +++ b/internal/usecase/push_cmd.go @@ -0,0 +1,76 @@ +package usecase + +import ( + "fmt" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + "github.com/pkg/errors" + "strings" +) + +type PushCmdUsecase struct { + github service.GithubService + nlp service.NLPService +} + +const ( + GeneratePRFromCommitsPrompt = "generate pull request body from commit messages [%s] in Japanese" + GeneratePRTitleFromPRBody = "generate pull request title from pr body [%s] in Japanese as one sentence like 〇〇の機能追加" +) + +func NewPushCmdUsecase(github service.GithubService, nlp service.NLPService) *PushCmdUsecase { + return &PushCmdUsecase{github: github, nlp: nlp} +} + +func (u *PushCmdUsecase) GetRemoteBaseBranchCandidates() ([]string, error) { + return u.github.GetRecentUpdatedBranch() +} + +func (u *PushCmdUsecase) GeneratePullRequest(base string) (*entity.PullRequest, error) { + head, err := u.github.GetCurrentBranch() + if err != nil { + return nil, err + } + details, err := u.github.GetCurrentRepoDetails() + if err != nil { + return nil, err + } + commits, err := u.github.GetUnPushedCommits(base) + if err != nil { + return nil, err + } + prBodyPrompt := fmt.Sprintf(GeneratePRFromCommitsPrompt, strings.Join(commits, ", ")) + body, err := u.nlp.GetAnswerFromPrompt(prBodyPrompt) + if err != nil { + return nil, err + } + prTitlePrompt := fmt.Sprintf(GeneratePRTitleFromPRBody, body) + title, err := u.nlp.GetAnswerFromPrompt(prTitlePrompt) + if err != nil { + return nil, err + } + return &entity.PullRequest{ + Head: head, + Base: base, + Body: body, + Title: title, + Repo: details.Repo, + Owner: details.Owner, + }, nil +} + +func (u *PushCmdUsecase) SubmitPullRequest(pr *entity.PullRequest) error { + if err := u.github.PushCurrentBranch(); err != nil { + return err + } + // CurrentブランチにPRが作成されてる場合以下は実行しない仕様にしたい(エラーが発生するので) + config, err := entity.ReadConfig() + if err != nil { + return err + } + tkn := config.GithubToken + if tkn == "" { + return errors.New("github token not found") + } + return u.github.CreatePullRequest(pr, tkn) +} diff --git a/internal/usecase/suggest_cmd.go b/internal/usecase/suggest_cmd.go new file mode 100644 index 0000000..1782236 --- /dev/null +++ b/internal/usecase/suggest_cmd.go @@ -0,0 +1,39 @@ +package usecase + +import ( + "fmt" + "github.com/cocoide/commitify/internal/service" + "os/exec" + + "github.com/cocoide/commitify/internal/entity" +) + +type SuggestCmdUsecase struct { + message service.CommitMessageService + github service.GithubService +} + +func NewSuggestCmdUsecase(message service.CommitMessageService, github service.GithubService) *SuggestCmdUsecase { + return &SuggestCmdUsecase{message: message, github: github} +} + +func (u *SuggestCmdUsecase) GenerateCommitMessages() ([]string, error) { + stagingCodeDiff, err := u.github.GetStagingCodeDiff() + // stagingCodeを取捨選択する処理をここに入れる + if err != nil { + return nil, err + } + conf, err := entity.ReadConfig() + if err != nil { + return nil, fmt.Errorf("Failed to open config file: %v", err) + } + return u.message.GenerateCommitMessageList(stagingCodeDiff, conf) +} + +func (u *SuggestCmdUsecase) SubmitCommit(commitMessage string) error { + cmd := exec.Command("git", "commit", "-m", commitMessage) + if err := cmd.Run(); err != nil { + return err + } + return nil +} diff --git a/main.go b/main.go index fbd7bac..1c5eee1 100644 --- a/main.go +++ b/main.go @@ -9,9 +9,18 @@ import ( func main() { // configファイルがあるかどうかを確認 - _, err := os.Stat("config.yaml") + homePath, err := os.UserHomeDir() + if err != nil { + fmt.Printf("error of find user home dir, %v", err) + return + } + + _, err = os.Stat(homePath + "/.commitify/config.yaml") if os.IsNotExist(err) { - if _, err := os.Create("config.yaml"); err != nil { + if err := os.MkdirAll(homePath+"/.commitify", 0755); err != nil { + fmt.Printf("error of make directory, %v", err) + } + if _, err := os.Create(homePath + "/.commitify/config.yaml"); err != nil { fmt.Printf("error creating config file, %s", err.Error()) } } diff --git a/mock/commit_message.go b/mock/commit_message.go new file mode 100644 index 0000000..eafd041 --- /dev/null +++ b/mock/commit_message.go @@ -0,0 +1,54 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: commit_message.go +// +// Generated by this command: +// +// mockgen -source=commit_message.go -destination=../../mock/commit_message.go +// +// Package mock_service is a generated GoMock package. +package mock_service + +import ( + "github.com/golang/mock/gomock" + reflect "reflect" + + entity "github.com/cocoide/commitify/internal/entity" +) + +// MockCommitMessageService is a mock of CommitMessageService interface. +type MockCommitMessageService struct { + ctrl *gomock.Controller + recorder *MockCommitMessageServiceMockRecorder +} + +// MockCommitMessageServiceMockRecorder is the mock recorder for MockCommitMessageService. +type MockCommitMessageServiceMockRecorder struct { + mock *MockCommitMessageService +} + +// NewMockCommitMessageService creates a new mock instance. +func NewMockCommitMessageService(ctrl *gomock.Controller) *MockCommitMessageService { + mock := &MockCommitMessageService{ctrl: ctrl} + mock.recorder = &MockCommitMessageServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCommitMessageService) EXPECT() *MockCommitMessageServiceMockRecorder { + return m.recorder +} + +// GenerateCommitMessageList mocks base method. +func (m *MockCommitMessageService) GenerateCommitMessageList(code string, config entity.Config) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GenerateCommitMessageList", code, config) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GenerateCommitMessageList indicates an expected call of GenerateCommitMessageList. +func (mr *MockCommitMessageServiceMockRecorder) GenerateCommitMessageList(code, config any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateCommitMessageList", reflect.TypeOf((*MockCommitMessageService)(nil).GenerateCommitMessageList), code, config) +} diff --git a/mock/github.go b/mock/github.go new file mode 100644 index 0000000..6713c95 --- /dev/null +++ b/mock/github.go @@ -0,0 +1,143 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.go +// +// Generated by this command: +// +// mockgen -source=github.go -destination=../../mock/github.go +// +// Package mock_service is a generated GoMock package. +package mock_service + +import ( + reflect "reflect" + + entity "github.com/cocoide/commitify/internal/entity" + service "github.com/cocoide/commitify/internal/service" + "github.com/golang/mock/gomock" +) + +// MockGithubService is a mock of GithubService interface. +type MockGithubService struct { + ctrl *gomock.Controller + recorder *MockGithubServiceMockRecorder +} + +// MockGithubServiceMockRecorder is the mock recorder for MockGithubService. +type MockGithubServiceMockRecorder struct { + mock *MockGithubService +} + +// NewMockGithubService creates a new mock instance. +func NewMockGithubService(ctrl *gomock.Controller) *MockGithubService { + mock := &MockGithubService{ctrl: ctrl} + mock.recorder = &MockGithubServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockGithubService) EXPECT() *MockGithubServiceMockRecorder { + return m.recorder +} + +// CreatePullRequest mocks base method. +func (m *MockGithubService) CreatePullRequest(pr *entity.PullRequest, token string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePullRequest", pr, token) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreatePullRequest indicates an expected call of CreatePullRequest. +func (mr *MockGithubServiceMockRecorder) CreatePullRequest(pr, token any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePullRequest", reflect.TypeOf((*MockGithubService)(nil).CreatePullRequest), pr, token) +} + +// GetCurrentBranch mocks base method. +func (m *MockGithubService) GetCurrentBranch() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCurrentBranch") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCurrentBranch indicates an expected call of GetCurrentBranch. +func (mr *MockGithubServiceMockRecorder) GetCurrentBranch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentBranch", reflect.TypeOf((*MockGithubService)(nil).GetCurrentBranch)) +} + +// GetCurrentRepoDetails mocks base method. +func (m *MockGithubService) GetCurrentRepoDetails() (*service.GetRepoDetailsResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCurrentRepoDetails") + ret0, _ := ret[0].(*service.GetRepoDetailsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCurrentRepoDetails indicates an expected call of GetCurrentRepoDetails. +func (mr *MockGithubServiceMockRecorder) GetCurrentRepoDetails() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentRepoDetails", reflect.TypeOf((*MockGithubService)(nil).GetCurrentRepoDetails)) +} + +// GetRecentUpdatedBranch mocks base method. +func (m *MockGithubService) GetRecentUpdatedBranch() ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRecentUpdatedBranch") + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRecentUpdatedBranch indicates an expected call of GetRecentUpdatedBranch. +func (mr *MockGithubServiceMockRecorder) GetRecentUpdatedBranch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRecentUpdatedBranch", reflect.TypeOf((*MockGithubService)(nil).GetRecentUpdatedBranch)) +} + +// GetStagingCodeDiff mocks base method. +func (m *MockGithubService) GetStagingCodeDiff() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetStagingCodeDiff") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetStagingCodeDiff indicates an expected call of GetStagingCodeDiff. +func (mr *MockGithubServiceMockRecorder) GetStagingCodeDiff() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStagingCodeDiff", reflect.TypeOf((*MockGithubService)(nil).GetStagingCodeDiff)) +} + +// GetUnPushedCommits mocks base method. +func (m *MockGithubService) GetUnPushedCommits(base string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnPushedCommits", base) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnPushedCommits indicates an expected call of GetUnPushedCommits. +func (mr *MockGithubServiceMockRecorder) GetUnPushedCommits(base any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnPushedCommits", reflect.TypeOf((*MockGithubService)(nil).GetUnPushedCommits), base) +} + +// PushCurrentBranch mocks base method. +func (m *MockGithubService) PushCurrentBranch() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PushCurrentBranch") + ret0, _ := ret[0].(error) + return ret0 +} + +// PushCurrentBranch indicates an expected call of PushCurrentBranch. +func (mr *MockGithubServiceMockRecorder) PushCurrentBranch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushCurrentBranch", reflect.TypeOf((*MockGithubService)(nil).PushCurrentBranch)) +} diff --git a/mock/nlp.go b/mock/nlp.go new file mode 100644 index 0000000..6a445bd --- /dev/null +++ b/mock/nlp.go @@ -0,0 +1,53 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: nlp.go +// +// Generated by this command: +// +// mockgen -source=nlp.go -destination=../../mock/nlp.go +// +// Package mock_service is a generated GoMock package. +package mock_service + +import ( + reflect "reflect" + + "github.com/golang/mock/gomock" +) + +// MockNLPService is a mock of NLPService interface. +type MockNLPService struct { + ctrl *gomock.Controller + recorder *MockNLPServiceMockRecorder +} + +// MockNLPServiceMockRecorder is the mock recorder for MockNLPService. +type MockNLPServiceMockRecorder struct { + mock *MockNLPService +} + +// NewMockNLPService creates a new mock instance. +func NewMockNLPService(ctrl *gomock.Controller) *MockNLPService { + mock := &MockNLPService{ctrl: ctrl} + mock.recorder = &MockNLPServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNLPService) EXPECT() *MockNLPServiceMockRecorder { + return m.recorder +} + +// GetAnswerFromPrompt mocks base method. +func (m *MockNLPService) GetAnswerFromPrompt(prompt string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAnswerFromPrompt", prompt) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAnswerFromPrompt indicates an expected call of GetAnswerFromPrompt. +func (mr *MockNLPServiceMockRecorder) GetAnswerFromPrompt(prompt any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAnswerFromPrompt", reflect.TypeOf((*MockNLPService)(nil).GetAnswerFromPrompt), prompt) +} diff --git a/mock/openai.go b/mock/openai.go deleted file mode 100644 index 78f7b68..0000000 --- a/mock/openai.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: openai.go - -// Package mock_gateway is a generated GoMock package. -package mock_gateway - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockOpenAIGateway is a mock of OpenAIGateway interface. -type MockOpenAIGateway struct { - ctrl *gomock.Controller - recorder *MockOpenAIGatewayMockRecorder -} - -// MockOpenAIGatewayMockRecorder is the mock recorder for MockOpenAIGateway. -type MockOpenAIGatewayMockRecorder struct { - mock *MockOpenAIGateway -} - -// NewMockOpenAIGateway creates a new mock instance. -func NewMockOpenAIGateway(ctrl *gomock.Controller) *MockOpenAIGateway { - mock := &MockOpenAIGateway{ctrl: ctrl} - mock.recorder = &MockOpenAIGatewayMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockOpenAIGateway) EXPECT() *MockOpenAIGatewayMockRecorder { - return m.recorder -} - -// AsyncGetAnswerFromPrompt mocks base method. -func (m *MockOpenAIGateway) AsyncGetAnswerFromPrompt(prompt string, variability float32) <-chan string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AsyncGetAnswerFromPrompt", prompt, variability) - ret0, _ := ret[0].(<-chan string) - return ret0 -} - -// AsyncGetAnswerFromPrompt indicates an expected call of AsyncGetAnswerFromPrompt. -func (mr *MockOpenAIGatewayMockRecorder) AsyncGetAnswerFromPrompt(prompt, variability interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AsyncGetAnswerFromPrompt", reflect.TypeOf((*MockOpenAIGateway)(nil).AsyncGetAnswerFromPrompt), prompt, variability) -} - -// GetAnswerFromPrompt mocks base method. -func (m *MockOpenAIGateway) GetAnswerFromPrompt(prompt string, variability float32) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAnswerFromPrompt", prompt, variability) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAnswerFromPrompt indicates an expected call of GetAnswerFromPrompt. -func (mr *MockOpenAIGatewayMockRecorder) GetAnswerFromPrompt(prompt, variability interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAnswerFromPrompt", reflect.TypeOf((*MockOpenAIGateway)(nil).GetAnswerFromPrompt), prompt, variability) -} diff --git a/proto/gen/code_type.pb.go b/proto/gen/code_type.pb.go new file mode 100644 index 0000000..a101a56 --- /dev/null +++ b/proto/gen/code_type.pb.go @@ -0,0 +1,191 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.24.4 +// source: code_type.proto + +package src + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// CodeFormatType specifies the type of commit message to generate +type CodeFormatType int32 + +const ( + CodeFormatType_UNKNOWN_FORMAT CodeFormatType = 0 + CodeFormatType_NORMAL CodeFormatType = 1 + CodeFormatType_PREFIX CodeFormatType = 2 + CodeFormatType_EMOJI CodeFormatType = 3 +) + +// Enum value maps for CodeFormatType. +var ( + CodeFormatType_name = map[int32]string{ + 0: "UNKNOWN_FORMAT", + 1: "NORMAL", + 2: "PREFIX", + 3: "EMOJI", + } + CodeFormatType_value = map[string]int32{ + "UNKNOWN_FORMAT": 0, + "NORMAL": 1, + "PREFIX": 2, + "EMOJI": 3, + } +) + +func (x CodeFormatType) Enum() *CodeFormatType { + p := new(CodeFormatType) + *p = x + return p +} + +func (x CodeFormatType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CodeFormatType) Descriptor() protoreflect.EnumDescriptor { + return file_code_type_proto_enumTypes[0].Descriptor() +} + +func (CodeFormatType) Type() protoreflect.EnumType { + return &file_code_type_proto_enumTypes[0] +} + +func (x CodeFormatType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CodeFormatType.Descriptor instead. +func (CodeFormatType) EnumDescriptor() ([]byte, []int) { + return file_code_type_proto_rawDescGZIP(), []int{0} +} + +// LanguageType specifies the language of the commit message to generate +type LanguageType int32 + +const ( + LanguageType_UNKNOWN_LANGUAGE LanguageType = 0 + LanguageType_ENGLISH LanguageType = 1 + LanguageType_JAPANESE LanguageType = 2 +) + +// Enum value maps for LanguageType. +var ( + LanguageType_name = map[int32]string{ + 0: "UNKNOWN_LANGUAGE", + 1: "ENGLISH", + 2: "JAPANESE", + } + LanguageType_value = map[string]int32{ + "UNKNOWN_LANGUAGE": 0, + "ENGLISH": 1, + "JAPANESE": 2, + } +) + +func (x LanguageType) Enum() *LanguageType { + p := new(LanguageType) + *p = x + return p +} + +func (x LanguageType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LanguageType) Descriptor() protoreflect.EnumDescriptor { + return file_code_type_proto_enumTypes[1].Descriptor() +} + +func (LanguageType) Type() protoreflect.EnumType { + return &file_code_type_proto_enumTypes[1] +} + +func (x LanguageType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LanguageType.Descriptor instead. +func (LanguageType) EnumDescriptor() ([]byte, []int) { + return file_code_type_proto_rawDescGZIP(), []int{1} +} + +var File_code_type_proto protoreflect.FileDescriptor + +var file_code_type_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x47, 0x0a, 0x0e, + 0x43, 0x6f, 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, + 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x50, 0x52, 0x45, 0x46, 0x49, 0x58, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x4d, + 0x4f, 0x4a, 0x49, 0x10, 0x03, 0x2a, 0x3f, 0x0a, 0x0c, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x5f, 0x4c, 0x41, 0x4e, 0x47, 0x55, 0x41, 0x47, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x4e, 0x47, 0x4c, 0x49, 0x53, 0x48, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4a, 0x41, 0x50, 0x41, + 0x4e, 0x45, 0x53, 0x45, 0x10, 0x02, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x73, 0x72, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_code_type_proto_rawDescOnce sync.Once + file_code_type_proto_rawDescData = file_code_type_proto_rawDesc +) + +func file_code_type_proto_rawDescGZIP() []byte { + file_code_type_proto_rawDescOnce.Do(func() { + file_code_type_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_type_proto_rawDescData) + }) + return file_code_type_proto_rawDescData +} + +var file_code_type_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_code_type_proto_goTypes = []interface{}{ + (CodeFormatType)(0), // 0: code_type.CodeFormatType + (LanguageType)(0), // 1: code_type.LanguageType +} +var file_code_type_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_code_type_proto_init() } +func file_code_type_proto_init() { + if File_code_type_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_code_type_proto_rawDesc, + NumEnums: 2, + NumMessages: 0, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_code_type_proto_goTypes, + DependencyIndexes: file_code_type_proto_depIdxs, + EnumInfos: file_code_type_proto_enumTypes, + }.Build() + File_code_type_proto = out.File + file_code_type_proto_rawDesc = nil + file_code_type_proto_goTypes = nil + file_code_type_proto_depIdxs = nil +} diff --git a/pb/commit_message_service.pb.go b/proto/gen/commit_message_service.pb.go similarity index 51% rename from pb/commit_message_service.pb.go rename to proto/gen/commit_message_service.pb.go index fe6d734..a82a577 100644 --- a/pb/commit_message_service.pb.go +++ b/proto/gen/commit_message_service.pb.go @@ -1,10 +1,10 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.31.0 -// protoc v4.24.2 +// protoc v4.24.4 // source: commit_message_service.proto -package pb +package src import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -20,103 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// CodeFormatType specifies the type of commit message to generate -type CodeFormatType int32 - -const ( - CodeFormatType_EMOJI CodeFormatType = 0 - CodeFormatType_PREFIX CodeFormatType = 1 - CodeFormatType_NORMAL CodeFormatType = 2 -) - -// Enum value maps for CodeFormatType. -var ( - CodeFormatType_name = map[int32]string{ - 0: "EMOJI", - 1: "PREFIX", - 2: "NORMAL", - } - CodeFormatType_value = map[string]int32{ - "EMOJI": 0, - "PREFIX": 1, - "NORMAL": 2, - } -) - -func (x CodeFormatType) Enum() *CodeFormatType { - p := new(CodeFormatType) - *p = x - return p -} - -func (x CodeFormatType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (CodeFormatType) Descriptor() protoreflect.EnumDescriptor { - return file_commit_message_service_proto_enumTypes[0].Descriptor() -} - -func (CodeFormatType) Type() protoreflect.EnumType { - return &file_commit_message_service_proto_enumTypes[0] -} - -func (x CodeFormatType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use CodeFormatType.Descriptor instead. -func (CodeFormatType) EnumDescriptor() ([]byte, []int) { - return file_commit_message_service_proto_rawDescGZIP(), []int{0} -} - -// LanguageType specifies the language of the commit message to generate -type LanguageType int32 - -const ( - LanguageType_ENGLISH LanguageType = 0 - LanguageType_JAPANESE LanguageType = 1 -) - -// Enum value maps for LanguageType. -var ( - LanguageType_name = map[int32]string{ - 0: "ENGLISH", - 1: "JAPANESE", - } - LanguageType_value = map[string]int32{ - "ENGLISH": 0, - "JAPANESE": 1, - } -) - -func (x LanguageType) Enum() *LanguageType { - p := new(LanguageType) - *p = x - return p -} - -func (x LanguageType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (LanguageType) Descriptor() protoreflect.EnumDescriptor { - return file_commit_message_service_proto_enumTypes[1].Descriptor() -} - -func (LanguageType) Type() protoreflect.EnumType { - return &file_commit_message_service_proto_enumTypes[1] -} - -func (x LanguageType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use LanguageType.Descriptor instead. -func (LanguageType) EnumDescriptor() ([]byte, []int) { - return file_commit_message_service_proto_rawDescGZIP(), []int{1} -} - // CommitMessageRequest is the request format for generating messages type CommitMessageRequest struct { state protoimpl.MessageState @@ -124,8 +27,8 @@ type CommitMessageRequest struct { unknownFields protoimpl.UnknownFields InputCode string `protobuf:"bytes,1,opt,name=inputCode,proto3" json:"inputCode,omitempty"` - CodeFormat CodeFormatType `protobuf:"varint,2,opt,name=codeFormat,proto3,enum=commit_message.CodeFormatType" json:"codeFormat,omitempty"` - Language LanguageType `protobuf:"varint,3,opt,name=language,proto3,enum=commit_message.LanguageType" json:"language,omitempty"` + CodeFormat CodeFormatType `protobuf:"varint,2,opt,name=codeFormat,proto3,enum=code_type.CodeFormatType" json:"codeFormat,omitempty"` + Language LanguageType `protobuf:"varint,3,opt,name=language,proto3,enum=code_type.LanguageType" json:"language,omitempty"` } func (x *CommitMessageRequest) Reset() { @@ -171,14 +74,14 @@ func (x *CommitMessageRequest) GetCodeFormat() CodeFormatType { if x != nil { return x.CodeFormat } - return CodeFormatType_EMOJI + return CodeFormatType_UNKNOWN_FORMAT } func (x *CommitMessageRequest) GetLanguage() LanguageType { if x != nil { return x.Language } - return LanguageType_ENGLISH + return LanguageType_UNKNOWN_LANGUAGE } // CommitMessageResponse returns generated commit messages @@ -234,37 +137,31 @@ var File_commit_message_service_proto protoreflect.FileDescriptor var file_commit_message_service_proto_rawDesc = []byte{ 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xae, - 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x46, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x46, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x46, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x38, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, - 0x33, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x2a, 0x33, 0x0a, 0x0e, 0x43, 0x6f, 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6d, - 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x4d, 0x4f, 0x4a, 0x49, 0x10, - 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x52, 0x45, 0x46, 0x49, 0x58, 0x10, 0x01, 0x12, 0x0a, 0x0a, - 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x02, 0x2a, 0x29, 0x0a, 0x0c, 0x4c, 0x61, 0x6e, - 0x67, 0x75, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x47, - 0x4c, 0x49, 0x53, 0x48, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4a, 0x41, 0x50, 0x41, 0x4e, 0x45, - 0x53, 0x45, 0x10, 0x01, 0x32, 0x7c, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x15, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0f, + 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0xa4, 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x46, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x12, 0x33, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, + 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x6c, 0x61, + 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x33, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x32, 0x7c, 0x0a, 0x14, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x73, 0x72, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -279,19 +176,18 @@ func file_commit_message_service_proto_rawDescGZIP() []byte { return file_commit_message_service_proto_rawDescData } -var file_commit_message_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_commit_message_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_commit_message_service_proto_goTypes = []interface{}{ - (CodeFormatType)(0), // 0: commit_message.CodeFormatType - (LanguageType)(0), // 1: commit_message.LanguageType - (*CommitMessageRequest)(nil), // 2: commit_message.CommitMessageRequest - (*CommitMessageResponse)(nil), // 3: commit_message.CommitMessageResponse + (*CommitMessageRequest)(nil), // 0: commit_message.CommitMessageRequest + (*CommitMessageResponse)(nil), // 1: commit_message.CommitMessageResponse + (CodeFormatType)(0), // 2: code_type.CodeFormatType + (LanguageType)(0), // 3: code_type.LanguageType } var file_commit_message_service_proto_depIdxs = []int32{ - 0, // 0: commit_message.CommitMessageRequest.codeFormat:type_name -> commit_message.CodeFormatType - 1, // 1: commit_message.CommitMessageRequest.language:type_name -> commit_message.LanguageType - 2, // 2: commit_message.CommitMessageService.GenerateCommitMessage:input_type -> commit_message.CommitMessageRequest - 3, // 3: commit_message.CommitMessageService.GenerateCommitMessage:output_type -> commit_message.CommitMessageResponse + 2, // 0: commit_message.CommitMessageRequest.codeFormat:type_name -> code_type.CodeFormatType + 3, // 1: commit_message.CommitMessageRequest.language:type_name -> code_type.LanguageType + 0, // 2: commit_message.CommitMessageService.GenerateCommitMessage:input_type -> commit_message.CommitMessageRequest + 1, // 3: commit_message.CommitMessageService.GenerateCommitMessage:output_type -> commit_message.CommitMessageResponse 3, // [3:4] is the sub-list for method output_type 2, // [2:3] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name @@ -304,6 +200,7 @@ func file_commit_message_service_proto_init() { if File_commit_message_service_proto != nil { return } + file_code_type_proto_init() if !protoimpl.UnsafeEnabled { file_commit_message_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CommitMessageRequest); i { @@ -335,14 +232,13 @@ func file_commit_message_service_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_commit_message_service_proto_rawDesc, - NumEnums: 2, + NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 1, }, GoTypes: file_commit_message_service_proto_goTypes, DependencyIndexes: file_commit_message_service_proto_depIdxs, - EnumInfos: file_commit_message_service_proto_enumTypes, MessageInfos: file_commit_message_service_proto_msgTypes, }.Build() File_commit_message_service_proto = out.File diff --git a/pb/commit_message_service_grpc.pb.go b/proto/gen/commit_message_service_grpc.pb.go similarity index 98% rename from pb/commit_message_service_grpc.pb.go rename to proto/gen/commit_message_service_grpc.pb.go index 65a91f3..3bd3153 100644 --- a/pb/commit_message_service_grpc.pb.go +++ b/proto/gen/commit_message_service_grpc.pb.go @@ -1,10 +1,10 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.2 +// - protoc v4.24.4 // source: commit_message_service.proto -package pb +package src import ( context "context" diff --git a/proto/gen/separate_commit_service.pb.go b/proto/gen/separate_commit_service.pb.go new file mode 100644 index 0000000..96c736a --- /dev/null +++ b/proto/gen/separate_commit_service.pb.go @@ -0,0 +1,640 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.24.4 +// source: separate_commit_service.proto + +package src + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// ChangeType specifies the type of +type ChangeType int32 + +const ( + ChangeType_UNKNOWN_CHANGE ChangeType = 0 + ChangeType_CREATE ChangeType = 1 + ChangeType_UPDATE ChangeType = 2 + ChangeType_DELETE ChangeType = 3 +) + +// Enum value maps for ChangeType. +var ( + ChangeType_name = map[int32]string{ + 0: "UNKNOWN_CHANGE", + 1: "CREATE", + 2: "UPDATE", + 3: "DELETE", + } + ChangeType_value = map[string]int32{ + "UNKNOWN_CHANGE": 0, + "CREATE": 1, + "UPDATE": 2, + "DELETE": 3, + } +) + +func (x ChangeType) Enum() *ChangeType { + p := new(ChangeType) + *p = x + return p +} + +func (x ChangeType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ChangeType) Descriptor() protoreflect.EnumDescriptor { + return file_separate_commit_service_proto_enumTypes[0].Descriptor() +} + +func (ChangeType) Type() protoreflect.EnumType { + return &file_separate_commit_service_proto_enumTypes[0] +} + +func (x ChangeType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ChangeType.Descriptor instead. +func (ChangeType) EnumDescriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{0} +} + +// SeparateCommitRequest is the request format for generating messages +type SeparateCommitRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FileChanges []*FileChange `protobuf:"bytes,1,rep,name=fileChanges,proto3" json:"fileChanges,omitempty"` + CodeFormat CodeFormatType `protobuf:"varint,2,opt,name=codeFormat,proto3,enum=code_type.CodeFormatType" json:"codeFormat,omitempty"` + Language LanguageType `protobuf:"varint,3,opt,name=language,proto3,enum=code_type.LanguageType" json:"language,omitempty"` +} + +func (x *SeparateCommitRequest) Reset() { + *x = SeparateCommitRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_separate_commit_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SeparateCommitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SeparateCommitRequest) ProtoMessage() {} + +func (x *SeparateCommitRequest) ProtoReflect() protoreflect.Message { + mi := &file_separate_commit_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SeparateCommitRequest.ProtoReflect.Descriptor instead. +func (*SeparateCommitRequest) Descriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{0} +} + +func (x *SeparateCommitRequest) GetFileChanges() []*FileChange { + if x != nil { + return x.FileChanges + } + return nil +} + +func (x *SeparateCommitRequest) GetCodeFormat() CodeFormatType { + if x != nil { + return x.CodeFormat + } + return CodeFormatType_UNKNOWN_FORMAT +} + +func (x *SeparateCommitRequest) GetLanguage() LanguageType { + if x != nil { + return x.Language + } + return LanguageType_UNKNOWN_LANGUAGE +} + +type LineDiff struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Index int32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Line string `protobuf:"bytes,2,opt,name=line,proto3" json:"line,omitempty"` +} + +func (x *LineDiff) Reset() { + *x = LineDiff{} + if protoimpl.UnsafeEnabled { + mi := &file_separate_commit_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LineDiff) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LineDiff) ProtoMessage() {} + +func (x *LineDiff) ProtoReflect() protoreflect.Message { + mi := &file_separate_commit_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LineDiff.ProtoReflect.Descriptor instead. +func (*LineDiff) Descriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{1} +} + +func (x *LineDiff) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *LineDiff) GetLine() string { + if x != nil { + return x.Line + } + return "" +} + +type CodeDiff struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Added []*LineDiff `protobuf:"bytes,1,rep,name=added,proto3" json:"added,omitempty"` + Deleted []*LineDiff `protobuf:"bytes,2,rep,name=deleted,proto3" json:"deleted,omitempty"` +} + +func (x *CodeDiff) Reset() { + *x = CodeDiff{} + if protoimpl.UnsafeEnabled { + mi := &file_separate_commit_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CodeDiff) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CodeDiff) ProtoMessage() {} + +func (x *CodeDiff) ProtoReflect() protoreflect.Message { + mi := &file_separate_commit_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CodeDiff.ProtoReflect.Descriptor instead. +func (*CodeDiff) Descriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{2} +} + +func (x *CodeDiff) GetAdded() []*LineDiff { + if x != nil { + return x.Added + } + return nil +} + +func (x *CodeDiff) GetDeleted() []*LineDiff { + if x != nil { + return x.Deleted + } + return nil +} + +type FileChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CodeDiff *CodeDiff `protobuf:"bytes,1,opt,name=codeDiff,proto3" json:"codeDiff,omitempty"` + Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` + ChangeType ChangeType `protobuf:"varint,3,opt,name=changeType,proto3,enum=separate_commit.ChangeType" json:"changeType,omitempty"` +} + +func (x *FileChange) Reset() { + *x = FileChange{} + if protoimpl.UnsafeEnabled { + mi := &file_separate_commit_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FileChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FileChange) ProtoMessage() {} + +func (x *FileChange) ProtoReflect() protoreflect.Message { + mi := &file_separate_commit_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FileChange.ProtoReflect.Descriptor instead. +func (*FileChange) Descriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{3} +} + +func (x *FileChange) GetCodeDiff() *CodeDiff { + if x != nil { + return x.CodeDiff + } + return nil +} + +func (x *FileChange) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *FileChange) GetChangeType() ChangeType { + if x != nil { + return x.ChangeType + } + return ChangeType_UNKNOWN_CHANGE +} + +// SeparateCommitResponse returns generated and separated commit messages +type SeparateCommitResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SeparatedCommits []*SeparatedCommitMessages `protobuf:"bytes,1,rep,name=separatedCommits,proto3" json:"separatedCommits,omitempty"` +} + +func (x *SeparateCommitResponse) Reset() { + *x = SeparateCommitResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_separate_commit_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SeparateCommitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SeparateCommitResponse) ProtoMessage() {} + +func (x *SeparateCommitResponse) ProtoReflect() protoreflect.Message { + mi := &file_separate_commit_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SeparateCommitResponse.ProtoReflect.Descriptor instead. +func (*SeparateCommitResponse) Descriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{4} +} + +func (x *SeparateCommitResponse) GetSeparatedCommits() []*SeparatedCommitMessages { + if x != nil { + return x.SeparatedCommits + } + return nil +} + +type SeparatedCommitMessages struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Messages []string `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` + Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` + ChangeType ChangeType `protobuf:"varint,3,opt,name=changeType,proto3,enum=separate_commit.ChangeType" json:"changeType,omitempty"` +} + +func (x *SeparatedCommitMessages) Reset() { + *x = SeparatedCommitMessages{} + if protoimpl.UnsafeEnabled { + mi := &file_separate_commit_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SeparatedCommitMessages) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SeparatedCommitMessages) ProtoMessage() {} + +func (x *SeparatedCommitMessages) ProtoReflect() protoreflect.Message { + mi := &file_separate_commit_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SeparatedCommitMessages.ProtoReflect.Descriptor instead. +func (*SeparatedCommitMessages) Descriptor() ([]byte, []int) { + return file_separate_commit_service_proto_rawDescGZIP(), []int{5} +} + +func (x *SeparatedCommitMessages) GetMessages() []string { + if x != nil { + return x.Messages + } + return nil +} + +func (x *SeparatedCommitMessages) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *SeparatedCommitMessages) GetChangeType() ChangeType { + if x != nil { + return x.ChangeType + } + return ChangeType_UNKNOWN_CHANGE +} + +var File_separate_commit_service_proto protoreflect.FileDescriptor + +var file_separate_commit_service_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x1a, 0x0f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xc6, 0x01, 0x0a, 0x15, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x0b, 0x66, + 0x69, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x66, + 0x69, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x6f, + 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x46, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x46, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x33, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x2e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x34, 0x0a, 0x08, 0x4c, 0x69, + 0x6e, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, + 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, + 0x22, 0x70, 0x0a, 0x08, 0x43, 0x6f, 0x64, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x2f, 0x0a, 0x05, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, + 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x4c, 0x69, + 0x6e, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x33, 0x0a, + 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x0a, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x12, 0x35, 0x0a, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x44, 0x69, 0x66, 0x66, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x08, + 0x63, 0x6f, 0x64, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x65, 0x70, 0x61, 0x72, + 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x6e, 0x0a, 0x16, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x10, 0x73, + 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, + 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, + 0x10, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x64, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x65, 0x70, 0x61, + 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x2a, 0x44, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, 0x48, 0x41, 0x4e, + 0x47, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, + 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, + 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x32, 0x89, 0x01, 0x0a, 0x15, 0x53, 0x65, 0x70, + 0x61, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x70, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73, 0x65, + 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x53, 0x65, + 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x72, + 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_separate_commit_service_proto_rawDescOnce sync.Once + file_separate_commit_service_proto_rawDescData = file_separate_commit_service_proto_rawDesc +) + +func file_separate_commit_service_proto_rawDescGZIP() []byte { + file_separate_commit_service_proto_rawDescOnce.Do(func() { + file_separate_commit_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_separate_commit_service_proto_rawDescData) + }) + return file_separate_commit_service_proto_rawDescData +} + +var file_separate_commit_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_separate_commit_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_separate_commit_service_proto_goTypes = []interface{}{ + (ChangeType)(0), // 0: separate_commit.ChangeType + (*SeparateCommitRequest)(nil), // 1: separate_commit.SeparateCommitRequest + (*LineDiff)(nil), // 2: separate_commit.LineDiff + (*CodeDiff)(nil), // 3: separate_commit.CodeDiff + (*FileChange)(nil), // 4: separate_commit.FileChange + (*SeparateCommitResponse)(nil), // 5: separate_commit.SeparateCommitResponse + (*SeparatedCommitMessages)(nil), // 6: separate_commit.SeparatedCommitMessages + (CodeFormatType)(0), // 7: code_type.CodeFormatType + (LanguageType)(0), // 8: code_type.LanguageType +} +var file_separate_commit_service_proto_depIdxs = []int32{ + 4, // 0: separate_commit.SeparateCommitRequest.fileChanges:type_name -> separate_commit.FileChange + 7, // 1: separate_commit.SeparateCommitRequest.codeFormat:type_name -> code_type.CodeFormatType + 8, // 2: separate_commit.SeparateCommitRequest.language:type_name -> code_type.LanguageType + 2, // 3: separate_commit.CodeDiff.added:type_name -> separate_commit.LineDiff + 2, // 4: separate_commit.CodeDiff.deleted:type_name -> separate_commit.LineDiff + 3, // 5: separate_commit.FileChange.codeDiff:type_name -> separate_commit.CodeDiff + 0, // 6: separate_commit.FileChange.changeType:type_name -> separate_commit.ChangeType + 6, // 7: separate_commit.SeparateCommitResponse.separatedCommits:type_name -> separate_commit.SeparatedCommitMessages + 0, // 8: separate_commit.SeparatedCommitMessages.changeType:type_name -> separate_commit.ChangeType + 1, // 9: separate_commit.SeparateCommitService.GenerateMultipleCommitMessage:input_type -> separate_commit.SeparateCommitRequest + 5, // 10: separate_commit.SeparateCommitService.GenerateMultipleCommitMessage:output_type -> separate_commit.SeparateCommitResponse + 10, // [10:11] is the sub-list for method output_type + 9, // [9:10] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_separate_commit_service_proto_init() } +func file_separate_commit_service_proto_init() { + if File_separate_commit_service_proto != nil { + return + } + file_code_type_proto_init() + if !protoimpl.UnsafeEnabled { + file_separate_commit_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SeparateCommitRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_separate_commit_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LineDiff); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_separate_commit_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CodeDiff); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_separate_commit_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FileChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_separate_commit_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SeparateCommitResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_separate_commit_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SeparatedCommitMessages); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_separate_commit_service_proto_rawDesc, + NumEnums: 1, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_separate_commit_service_proto_goTypes, + DependencyIndexes: file_separate_commit_service_proto_depIdxs, + EnumInfos: file_separate_commit_service_proto_enumTypes, + MessageInfos: file_separate_commit_service_proto_msgTypes, + }.Build() + File_separate_commit_service_proto = out.File + file_separate_commit_service_proto_rawDesc = nil + file_separate_commit_service_proto_goTypes = nil + file_separate_commit_service_proto_depIdxs = nil +} diff --git a/proto/gen/separate_commit_service_grpc.pb.go b/proto/gen/separate_commit_service_grpc.pb.go new file mode 100644 index 0000000..3fc3840 --- /dev/null +++ b/proto/gen/separate_commit_service_grpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.24.4 +// source: separate_commit_service.proto + +package src + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + SeparateCommitService_GenerateMultipleCommitMessage_FullMethodName = "/separate_commit.SeparateCommitService/GenerateMultipleCommitMessage" +) + +// SeparateCommitServiceClient is the client API for SeparateCommitService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type SeparateCommitServiceClient interface { + GenerateMultipleCommitMessage(ctx context.Context, in *SeparateCommitRequest, opts ...grpc.CallOption) (*SeparateCommitResponse, error) +} + +type separateCommitServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewSeparateCommitServiceClient(cc grpc.ClientConnInterface) SeparateCommitServiceClient { + return &separateCommitServiceClient{cc} +} + +func (c *separateCommitServiceClient) GenerateMultipleCommitMessage(ctx context.Context, in *SeparateCommitRequest, opts ...grpc.CallOption) (*SeparateCommitResponse, error) { + out := new(SeparateCommitResponse) + err := c.cc.Invoke(ctx, SeparateCommitService_GenerateMultipleCommitMessage_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SeparateCommitServiceServer is the server API for SeparateCommitService service. +// All implementations must embed UnimplementedSeparateCommitServiceServer +// for forward compatibility +type SeparateCommitServiceServer interface { + GenerateMultipleCommitMessage(context.Context, *SeparateCommitRequest) (*SeparateCommitResponse, error) + mustEmbedUnimplementedSeparateCommitServiceServer() +} + +// UnimplementedSeparateCommitServiceServer must be embedded to have forward compatible implementations. +type UnimplementedSeparateCommitServiceServer struct { +} + +func (UnimplementedSeparateCommitServiceServer) GenerateMultipleCommitMessage(context.Context, *SeparateCommitRequest) (*SeparateCommitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateMultipleCommitMessage not implemented") +} +func (UnimplementedSeparateCommitServiceServer) mustEmbedUnimplementedSeparateCommitServiceServer() {} + +// UnsafeSeparateCommitServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SeparateCommitServiceServer will +// result in compilation errors. +type UnsafeSeparateCommitServiceServer interface { + mustEmbedUnimplementedSeparateCommitServiceServer() +} + +func RegisterSeparateCommitServiceServer(s grpc.ServiceRegistrar, srv SeparateCommitServiceServer) { + s.RegisterService(&SeparateCommitService_ServiceDesc, srv) +} + +func _SeparateCommitService_GenerateMultipleCommitMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SeparateCommitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SeparateCommitServiceServer).GenerateMultipleCommitMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SeparateCommitService_GenerateMultipleCommitMessage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SeparateCommitServiceServer).GenerateMultipleCommitMessage(ctx, req.(*SeparateCommitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// SeparateCommitService_ServiceDesc is the grpc.ServiceDesc for SeparateCommitService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var SeparateCommitService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "separate_commit.SeparateCommitService", + HandlerType: (*SeparateCommitServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GenerateMultipleCommitMessage", + Handler: _SeparateCommitService_GenerateMultipleCommitMessage_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "separate_commit_service.proto", +} diff --git a/proto/src/code_type.proto b/proto/src/code_type.proto new file mode 100644 index 0000000..c7c5b42 --- /dev/null +++ b/proto/src/code_type.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option go_package = "proto/src"; + +package code_type; + + +// CodeFormatType specifies the type of commit message to generate +enum CodeFormatType { + UNKNOWN_FORMAT = 0; + NORMAL = 1; + PREFIX = 2; + EMOJI = 3; +} + +// LanguageType specifies the language of the commit message to generate +enum LanguageType { + UNKNOWN_LANGUAGE = 0; + ENGLISH =1; + JAPANESE =2; +} \ No newline at end of file diff --git a/proto/src/commit_message_service.proto b/proto/src/commit_message_service.proto new file mode 100644 index 0000000..f9bcd93 --- /dev/null +++ b/proto/src/commit_message_service.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +option go_package = "proto/src"; + +package commit_message; + +import "code_type.proto"; + +// CommitMessageService provides methods to generate commit messages +service CommitMessageService { + rpc GenerateCommitMessage(CommitMessageRequest) returns (CommitMessageResponse); +} + +// CommitMessageRequest is the request format for generating messages +message CommitMessageRequest { + string inputCode = 1; + code_type.CodeFormatType codeFormat = 2; + code_type.LanguageType language = 3; +} + +// CommitMessageResponse returns generated commit messages +message CommitMessageResponse { + repeated string messages = 1; +} \ No newline at end of file diff --git a/proto/src/separate_commit_service.proto b/proto/src/separate_commit_service.proto new file mode 100644 index 0000000..26b9f8a --- /dev/null +++ b/proto/src/separate_commit_service.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +option go_package = "proto/src"; + +package separate_commit; + +import "code_type.proto"; + +service SeparateCommitService { + rpc GenerateMultipleCommitMessage(SeparateCommitRequest) returns (SeparateCommitResponse); +} + +// SeparateCommitRequest is the request format for generating messages +message SeparateCommitRequest { + repeated FileChange fileChanges = 1; + code_type.CodeFormatType codeFormat = 2; + code_type.LanguageType language = 3; +} + +message LineDiff { + int32 index = 1; + string line = 2; +} + +message CodeDiff { + repeated LineDiff added = 1; + repeated LineDiff deleted = 2; +} + +message FileChange { + CodeDiff codeDiff = 1; + string filename = 2; + ChangeType changeType = 3; +} + +// ChangeType specifies the type of +enum ChangeType { + UNKNOWN_CHANGE = 0; + CREATE = 1; + UPDATE = 2; + DELETE = 3; +} + +// SeparateCommitResponse returns generated and separated commit messages +message SeparateCommitResponse { + repeated SeparatedCommitMessages separatedCommits = 1; +} + +message SeparatedCommitMessages { + repeated string messages = 1; + string filename = 2; + ChangeType changeType = 3; +} diff --git a/util/config.go b/util/config.go deleted file mode 100644 index ba9e8ca..0000000 --- a/util/config.go +++ /dev/null @@ -1,46 +0,0 @@ -package util - -import ( - "encoding/json" - "fmt" - - "github.com/cocoide/commitify/internal/entity" - "github.com/spf13/viper" -) - -func ReadConfig() (*entity.Config, error) { - var result entity.Config - - viper.AddConfigPath(".") - viper.SetConfigName("config") - viper.SetConfigType("yaml") - if err := viper.ReadInConfig(); err != nil { - return &result, fmt.Errorf("error reading config file, %s", err.Error()) - } - if err := viper.Unmarshal(&result); err != nil { - return &result, fmt.Errorf("unable to decode into struct, %v", err.Error()) - } - return &result, nil -} - -func WriteConfig(config *entity.Config) error { - viper.AddConfigPath(".") - viper.SetConfigName("config") - viper.SetConfigType("yaml") - configMap := make(map[string]interface{}) - configBytes, err := json.Marshal(config) - if err != nil { - return fmt.Errorf("error marshalling config: %s", err.Error()) - } - err = json.Unmarshal(configBytes, &configMap) - if err != nil { - return fmt.Errorf("error unmarshalling config: %s", err.Error()) - } - if err := viper.MergeConfigMap(configMap); err != nil { - return err - } - if err := viper.WriteConfig(); err != nil { - return fmt.Errorf("error saving config file, %s", err.Error()) - } - return nil -} diff --git a/util/exec.go b/util/exec.go deleted file mode 100644 index 5d5fba3..0000000 --- a/util/exec.go +++ /dev/null @@ -1,24 +0,0 @@ -package util - -import ( - "fmt" - "log" - "os/exec" -) - -func ExecGetStagingCode() string { - code, err := exec.Command("git", "diff", "--staged").Output() - if err != nil { - fmt.Printf("Gitでエラーが発生") - log.Fatal(err.Error()) - } - return string(code) -} - -func ExecCommitMessage(msg string) error { - cmd := exec.Command("git", "commit", "-m", msg) - if err := cmd.Run(); err != nil { - return err - } - return nil -}