Skip to content

Commit

Permalink
Merge branch 'release/0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Praveen Premaratne committed Mar 5, 2020
2 parents ded0a84 + 1ea18fa commit f319746
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 7 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,20 @@ given the user knows the issue reference
```
This tool can be used to log time spent on a specific Jira ticket on a project.
-d string
OPTIONAL: The date on which the worklog effort was started in DD-MM-YYYY format. Default 02-03-2020
OPTIONAL: The date on which the worklog effort was started in DD-MM-YYYY format. Default 05-03-2020
-e string
HELP: Base64 encode the given credentials. Format: email:token;domain. e.g. example@example.com:abcThisIsFake;xyz.atlassian.net
-h HELP: Print usage
HELP: Base64 encode the given credentials. Format: email:token;domain. e.g. example@example.com:abcThisIsFake;xyz.atlassian.net
-h HELP: Print usage
-history
Print the timesheet of the day
-m string
OPTIONAL: A comment about the worklog
OPTIONAL: A comment about the worklog
-r string
REQUIRED: Jira ticket reference. E.g. ABC-1
REQUIRED: Jira ticket reference. E.g. DDSP-4
-remaining
Time remaining
-t string
REQUIRED: The time spent as days (#d), hours (#h), or minutes (#m or #). E.g. 8h
REQUIRED: The time spent as days (#d), hours (#h), or minutes (#m or #). E.g. 8h
```

## Requirements
Expand Down
6 changes: 6 additions & 0 deletions argparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ func (app *App) Parser() {
"OPTIONAL: A comment about the worklog")
flag.StringVar(&app.Encode, "e", "", "HELP: Base64 encode the given credentials."+
" Format: email:token;domain. e.g. example@example.com:abcThisIsFake;xyz.atlassian.net")
flag.BoolVar(&app.TimeRemaining, "remaining", false, "Print how many hour can be book for the current day.")
flag.BoolVar(&app.History, "history", false, "Print the timesheet of the day")
flag.Parse()
app.validate()
}
Expand All @@ -43,6 +45,10 @@ func (app *App) validate() {
os.Exit(0)
}

if app.TimeRemaining {
return
}

if app.Encode != "" {
app.CredentialEncode()
os.Exit(0)
Expand Down
144 changes: 143 additions & 1 deletion atlassian.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
* Created on: 01/03/2020 18:34
*/

var secondsInDay = 28800

type TimeLog struct {
Started string `json:"started"`
TimeSpent string `json:"timeSpent"`
Expand All @@ -40,6 +42,32 @@ type Response struct {
ErrorMessages []string `json:"errorMessages"`
}

type JiraSearchResult struct {
Issues []struct {
Id string `json:"id"`
Key string `json:"key"`
Fields struct {
Summary string `json:"summary"`
} `json:"fields"`
} `json:"issues"`
}

type WorkLogs struct {
Key string
Summary string
Total int `json:"total"`
Worklogs []Worklog `json:"worklogs"`
}

type Worklog struct {
TimeSpentSeconds int `json:"timeSpentSeconds"`
IssueId string `json:"issueId"`
Author struct {
EmailAddress string `json:"emailAddress"`
DisplayName string `json:"displayName"`
} `json:"author"`
}

func LogTime(reference string, time string, started string, comment string, domain string, auth string) {
var slot = TimeLog{}
slot.TimeSpent = time
Expand Down Expand Up @@ -70,10 +98,115 @@ func LogTime(reference string, time string, started string, comment string, doma
fmt.Printf("%s booked to issue %s\n", slot.TimeSpent, reference)
}

func (app *App) GetTimeRemaining(domain string, auth string) {
var totalTimeSpent int
var timeRemaining float64
userEmail, _ := basicAuth(auth)
issuesOfTheDay, iErr := getIssuesUpdatedToday(domain, auth)
if iErr != nil {
panic(iErr)
}

worklogs, wErr := issuesOfTheDay.getWorklogs(domain, auth)
if wErr != nil {
panic(wErr)
}

for _, wLog := range worklogs {
if wLog.Total > 0 {
for _, log := range wLog.Worklogs {
if log.Author.EmailAddress == userEmail {
if app.History {
fmt.Println("Timesheet history:")
fmt.Printf("\t%s: %s\n\t%s: %s\n\t%s: %s\n\t%s: %.2fh\n\n",
"Key", wLog.Key,
"Summary", wLog.Summary,
"Author", log.Author.DisplayName,
"Time spent", getInHours(log.TimeSpentSeconds))
}
totalTimeSpent += log.TimeSpentSeconds
}
}
}
}

timeRemaining = getInHours(secondsInDay - totalTimeSpent)
if timeRemaining < 0 {
fmt.Printf("oops... Looks like you've booked %.2f hours more that what you supposed to!", timeRemaining)
} else {
fmt.Printf("You've %.2f hours ramaining!\n", timeRemaining)
}

}

func getIssuesUpdatedToday(domain string, auth string) (*JiraSearchResult, error) {
var client = &http.Client{}
var query = "jql=worklogDate%20>%3D%20startOfDay()%20AND%20worklogDate%20<%3D%20endOfDay()"
var url = fmt.Sprintf("https://%s/rest/api/3/search?%s", strings.TrimSuffix(domain, "\n"), query)
req, reqErr := http.NewRequest("GET", url, nil)
if reqErr != nil {
panic(reqErr)
}

req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(basicAuth(auth))

resp, err := client.Do(req)
if err != nil {
return nil, err
}

defer resp.Body.Close()

var response = new(JiraSearchResult)
decodeErr := json.NewDecoder(resp.Body).Decode(&response)
if decodeErr != nil {
panic(decodeErr)
}
return response, nil
}

func (issues *JiraSearchResult) getWorklogs(domain string, auth string) ([]WorkLogs, error) {
var worklogs []WorkLogs
for _, issue := range issues.Issues {
var client = &http.Client{}
var url = fmt.Sprintf("https://%s/rest/api/3/issue/%s/worklog", strings.TrimSuffix(domain, "\n"), issue.Key)

req, reqErr := http.NewRequest("GET", url, nil)
if reqErr != nil {
panic(reqErr)
}

req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(basicAuth(auth))

resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
panic(resp.Status)
}

var response = WorkLogs{}
response.Key = issue.Key
response.Summary = issue.Fields.Summary
decodeErr := json.NewDecoder(resp.Body).Decode(&response)
if decodeErr != nil {
panic(decodeErr)
}

worklogs = append(worklogs, response)

}
return worklogs, nil
}

func (slot *TimeLog) post(issueId string, domain string, auth string) (*Response, error) {
client := &http.Client{}
var url = fmt.Sprintf("https://%s/rest/api/3/issue/%s/worklog", strings.TrimSuffix(domain, "\n"), issueId)
//fmt.Println(url)

req, reqErr := http.NewRequest("POST", url, bytes.NewBuffer(slot.json()))
if reqErr != nil {
Expand Down Expand Up @@ -106,3 +239,12 @@ func (slot *TimeLog) json() []byte {
}
return body
}

func basicAuth(token string) (string, string) {
var loginDetails = strings.Split(token, ":")
return loginDetails[0], loginDetails[1]
}

func getInHours(seconds int) float64 {
return float64(seconds) / float64(3600)
}
7 changes: 7 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type App struct {
TimeSpent string
Help bool
Encode string
TimeRemaining bool
History bool
Configuration struct {
Auth string
Domain string
Expand All @@ -57,6 +59,11 @@ func main() {
app.Parser()
app.loadConf()

if app.TimeRemaining {
app.GetTimeRemaining(app.Configuration.Domain, app.Configuration.Auth)
os.Exit(0)
}

LogTime(app.Ticket, app.TimeSpent, app.Started, app.Comment, app.Configuration.Domain, app.Configuration.Auth)

}

0 comments on commit f319746

Please sign in to comment.