diff --git a/cmd/acb/main.go b/cmd/acb/main.go index d1d9d70..ca1e4a0 100644 --- a/cmd/acb/main.go +++ b/cmd/acb/main.go @@ -15,11 +15,19 @@ func main() { ghusername := os.Args[2] start := os.Args[3] end := os.Args[4] - DoPrs(proj, ghusername, start, end) - DoJira(start, end) + employeename := os.Args[5] + prs := DoPrs(proj, ghusername, start, end) + issues := DoJira(start, end) + summ, err := SummarizeData(employeename, prs, issues) + if err != nil { + fmt.Println(fmt.Errorf("error getting PRs: %w", err)) + os.Exit(1) + } + fmt.Println(summ) + } -func DoPrs(proj, ghusername, start, end string) { +func DoPrs(proj, ghusername, start, end string) map[string][]contributions.PullRequest { prs, err := contributions.GetPRs(proj, ghusername, start, end) if err != nil { @@ -38,11 +46,12 @@ func DoPrs(proj, ghusername, start, end string) { fmt.Println(fmt.Errorf("error writing out PRs: %w", err)) os.Exit(1) } + return prs } -func DoJira(start, end string) { +func DoJira(start, end string) []issues.Issue { host := os.Getenv("JIRA_HOST") user := os.Getenv("JIRA_TARGET_USER") - prs, err := issues.GetIssues(host, user, start, end) + issues, err := issues.GetIssues(host, user, start, end) if err != nil { fmt.Println(fmt.Errorf("error getting PRs: %w", err)) os.Exit(1) @@ -52,11 +61,13 @@ func DoJira(start, end string) { if err != nil { fmt.Println(fmt.Errorf("error creating PR file: %w", err)) os.Exit(1) + } enc := json.NewEncoder(ghf) - err = enc.Encode(prs) + err = enc.Encode(issues) if err != nil { fmt.Println(fmt.Errorf("error writing out PRs: %w", err)) os.Exit(1) } + return issues } diff --git a/cmd/acb/summarize.go b/cmd/acb/summarize.go index b9fb3cb..72550f5 100644 --- a/cmd/acb/summarize.go +++ b/cmd/acb/summarize.go @@ -7,13 +7,20 @@ import ( "io" "net/http" "os" - "strings" + + "o5r.ca/autocrossbow/contributions" + "o5r.ca/autocrossbow/issues" ) +const defaultPrompt = `I will provide you, for a given period, with an employee name and a list of Pull Request titles and summaries split by repository, and a list of Jira Issues an employee has worked on. I may also provide, optionally, the employee's self-assessment. If I do, integrate that. + +I'd like you to summarize the employee's accomplishments for the quarter +I'd like the summary for the accomplishments to be in prose form, in a few paragraphs separated based on areas of work. Keep answers to 500 words for the summary.` + // SummarizeData takes GitHub PRs and Jira issues data and sends it to an OpenAI-compatible endpoint for summarization. -func SummarizeData(prs map[string][]PullRequest, issues []Issue) (string, error) { +func SummarizeData(employeename string, prs map[string][]contributions.PullRequest, issues []issues.Issue) (string, error) { // Build a prompt string - prompt := "Summarize the following GitHub PRs and Jira issues:\n\n" + prompt := defaultPrompt + fmt.Sprintf("\n\nHere's the PRs and Tickets for the employee %s:\n\n", employeename) for repo, prList := range prs { prompt += fmt.Sprintf("Repository: %s\n", repo) for _, pr := range prList { @@ -21,23 +28,39 @@ func SummarizeData(prs map[string][]PullRequest, issues []Issue) (string, error) prompt += fmt.Sprintf(" Body: %s\n", pr.Body) } } + prompt += fmt.Sprintf("Issues:") for _, issue := range issues { - prompt += fmt.Sprintf("\nJira Issue: %s\n", issue.Key) prompt += fmt.Sprintf("Summary: %s\n", issue.Summary) prompt += fmt.Sprintf("Description: %s\n", issue.Description) + prompt += fmt.Sprintf("--------") } // Get OpenAI endpoint and token from environment variables openaiEndpoint := os.Getenv("OPENAI_ENDPOINT") openaiToken := os.Getenv("OPENAI_TOKEN") + openaiModel := os.Getenv("OPENAI_MODEL") if openaiEndpoint == "" || openaiToken == "" { return "", fmt.Errorf("OPENAI_ENDPOINT and OPENAI_TOKEN must be set in environment variables") } // Create a JSON payload for the OpenAI API - payload := map[string]string{"prompt": prompt} + payload := struct { + Model string `json:"model"` + Messages []struct { + Role string `json:"role"` + Content string `json:"content"` + } `json:"messages"` + }{ + Model: openaiModel, + Messages: []struct { + Role string `json:"role"` + Content string `json:"content"` + }{{Role: "system", Content: prompt}}, + } + jsonPayload, err := json.Marshal(payload) + fmt.Println(string(jsonPayload)) if err != nil { return "", err } @@ -62,5 +85,7 @@ func SummarizeData(prs map[string][]PullRequest, issues []Issue) (string, error) return "", err } + //parts := strings.Split(body, "think") + return string(body), nil } diff --git a/issues/jira.go b/issues/jira.go index d68c24c..937e380 100644 --- a/issues/jira.go +++ b/issues/jira.go @@ -39,14 +39,16 @@ type RespIssue struct { } func GetIssues(instance, user, from, to string) ([]Issue, error) { - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://%s/rest/api/2/search", instance), nil) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://%s/rest/api/3/search/jql", instance), nil) if err != nil { return nil, fmt.Errorf("error building jira search request: %w", err) } q := req.URL.Query() q.Add("jql", fmt.Sprintf("assignee was '%s' and resolved >= %s and resolved <= %s", user, from, to)) + q.Add("fields", "*all") req.URL.RawQuery = q.Encode() req.SetBasicAuth(os.Getenv("JIRA_USER"), os.Getenv("JIRA_TOKEN")) + req.Header.Add("Accept", "application/json") resp, err := jcl.Do(req) if err != nil { return nil, fmt.Errorf("error executing jira search request: %w", err) @@ -66,17 +68,18 @@ func GetIssues(instance, user, from, to string) ([]Issue, error) { for _, i := range jsr.Issues { iss := Issue{} if s, ok := i.Fields["summary"]; ok { + fmt.Println(s) iss.Summary, _ = s.(string) } if d, ok := i.Fields["description"]; ok { + fmt.Println(d) iss.Description, _ = d.(string) } - if comms, ok := i.Fields["comment"].(map[string]any); ok { - if c := comms["comments"].([]map[string]any); len(c) > 0 { - iss.Comments = make([]Comment, 0, len(c)) - for _, c2 := range c { - iss.Comments = append(iss.Comments, Comment{Author{DisplayName: c2["displayName"].(string), EmailAddress: c2["emailAddress"].(string)}, c2["body"].(string)}) - } + if comms, ok := i.Fields["comment"].([]map[string]any); ok && len(comms) > 0 { + iss.Comments = make([]Comment, 0, len(comms)) + for _, c2 := range comms { + iss.Comments = append(iss.Comments, Comment{Author{DisplayName: c2["displayName"].(string), EmailAddress: c2["emailAddress"].(string)}, c2["body"].(string)}) + } } out = append(out, iss)