Created
May 31, 2022 09:25
-
-
Save Rasukarusan/19c542490f126a023a10fbc0d90310e1 to your computer and use it in GitHub Desktop.
jira時間記録
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "bufio" | |
| "bytes" | |
| "encoding/json" | |
| "fmt" | |
| "io/ioutil" | |
| . "jt/types" | |
| "log" | |
| "net/http" | |
| "os" | |
| "regexp" | |
| "sort" | |
| "strconv" | |
| "strings" | |
| ) | |
| type Task struct { | |
| name string | |
| hour float64 | |
| } | |
| func contains(s []string, e string) bool { | |
| for _, v := range s { | |
| if e == v { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| func main() { | |
| // 標準入力から構造体に変換 | |
| tasks := setTasks() | |
| // チケット順にソート | |
| sort.Slice(tasks, func(i, j int) bool { | |
| return tasks[i].name < tasks[j].name | |
| }) | |
| // 時間記録実行 | |
| for _, t := range tasks { | |
| write(t) | |
| if !isIgnoreTask(t.name) { | |
| issueID := strings.Split(t.name, " ") | |
| i := getIssue(issueID[0]) | |
| b := createBody(i, t.hour) | |
| putIssue(i, b) | |
| } | |
| fmt.Print("\n") | |
| } | |
| } | |
| func setTasks() []Task { | |
| var tasks []Task | |
| var prevLine string | |
| s := bufio.NewScanner(os.Stdin) | |
| for s.Scan() { | |
| line := s.Text() | |
| if line != "" { | |
| prevLine = line | |
| tasks = createTasks(tasks, line) | |
| } else { | |
| tasks = createTasks(tasks, prevLine) | |
| } | |
| } | |
| return tasks | |
| } | |
| // 標準出力とファイルに書き込み | |
| func write(t Task) { | |
| if t.name == "退社" || t.name == "お昼" { | |
| return | |
| } | |
| file, err := os.OpenFile("time_record.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0600) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer file.Close() | |
| var line string | |
| if regexp.MustCompile(`[0-9]{4}年[0-9]{1,2}月[0-9]{1,2}日`).Match([]byte(t.name)) { | |
| line = "\n" + t.name | |
| } else { | |
| line = fmt.Sprintf("%s : \x1b[32m%0.1fh\x1b[0m", t.name, t.hour) | |
| } | |
| fmt.Print(line) | |
| file.WriteString(line + "\n") | |
| } | |
| func isIgnoreTask(name string) bool { | |
| return strings.Contains(name, "MYCOMPANY-616") || !strings.Contains(name, "MYCOMPANY-") | |
| } | |
| func createTasks(tasks []Task, name string) []Task { | |
| for i, task := range tasks { | |
| if task.name == name { | |
| tasks[i] = Task{name: name, hour: task.hour + 0.5} | |
| return tasks | |
| } | |
| } | |
| return append(tasks, Task{name: name, hour: 0.5}) | |
| } | |
| func createBody(i *Issue, hour float64) map[string]map[string]string { | |
| labels := i.Fields.Labels | |
| fields := map[string]string{} | |
| bizHour, _ := strconv.ParseFloat(i.Fields.Customfield10032, 64) | |
| personHour, _ := strconv.ParseFloat(i.Fields.Customfield10033, 64) | |
| if len(labels) == 1 && contains(labels, "法人") { | |
| fields["customfield_10032"] = strconv.FormatFloat(hour+bizHour, 'f', -1, 64) | |
| fmt.Printf(" (%.2f -> %.2f)", bizHour, hour+bizHour) | |
| } else if len(labels) == 1 && contains(labels, "個人") { | |
| fields["customfield_10033"] = strconv.FormatFloat(hour+personHour, 'f', -1, 64) | |
| fmt.Printf(" (%.2f -> %.2f)", bizHour, hour+bizHour) | |
| } else { | |
| hour := hour / 2 | |
| fields["customfield_10032"] = strconv.FormatFloat(hour+bizHour, 'f', -1, 64) | |
| fields["customfield_10033"] = strconv.FormatFloat(hour+personHour, 'f', -1, 64) | |
| fmt.Printf(" (%.2f -> %.2f, %.2f -> %.2f)", bizHour, hour+bizHour, personHour, hour+personHour) | |
| } | |
| return map[string]map[string]string{ | |
| "fields": fields, | |
| } | |
| } | |
| func putIssue(i *Issue, body map[string]map[string]string) { | |
| url := "https://yourcompany.atlassian.net/rest/api/3/issue/" + i.Key | |
| json, err := json.Marshal(body) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(json)) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| req.Header.Set("Authorization", "Basic YOUR_TOKEN") | |
| req.Header.Set("Content-Type", "application/json") | |
| client := new(http.Client) | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer resp.Body.Close() | |
| } | |
| func getIssue(id string) *Issue { | |
| url := "https://yourcompany.atlassian.net/rest/api/3/issue/" + id | |
| req, err := http.NewRequest(http.MethodGet, url, nil) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| req.Header.Set("Authorization", "Basic YOUR_TOKEN") | |
| req.Header.Set("Content-Type", "application/json") | |
| client := new(http.Client) | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer resp.Body.Close() | |
| byteArray, _ := ioutil.ReadAll(resp.Body) | |
| jsonBytes := ([]byte)(string(byteArray)) | |
| issue := new(Issue) | |
| if err := json.Unmarshal(jsonBytes, issue); err != nil { | |
| log.Fatal(err) | |
| } | |
| return issue | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
go.mod