diff --git a/examples/renderedfields/main.go b/examples/renderedfields/main.go
new file mode 100644
index 0000000..ab23420
--- /dev/null
+++ b/examples/renderedfields/main.go
@@ -0,0 +1,66 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "net/http"
+ "os"
+ "strings"
+ "syscall"
+
+ jira "github.com/andygrunwald/go-jira"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+func main() {
+ r := bufio.NewReader(os.Stdin)
+
+ fmt.Print("Jira URL: ")
+ jiraURL, _ := r.ReadString('\n')
+
+ fmt.Print("Jira Issue key: ")
+ key, _ := r.ReadString('\n')
+ key = strings.TrimSpace(key)
+
+ fmt.Print("Jira Username: ")
+ username, _ := r.ReadString('\n')
+
+ fmt.Print("Jira Password: ")
+ bytePassword, _ := terminal.ReadPassword(int(syscall.Stdin))
+ password := string(bytePassword)
+
+ var tp *http.Client
+
+ if strings.TrimSpace(username) == "" {
+ tp = nil
+ } else {
+
+ ba := jira.BasicAuthTransport{
+ Username: strings.TrimSpace(username),
+ Password: strings.TrimSpace(password),
+ }
+ tp = ba.Client()
+ }
+
+ client, err := jira.NewClient(tp, strings.TrimSpace(jiraURL))
+ if err != nil {
+ fmt.Printf("\nerror: %v\n", err)
+ return
+ }
+
+ fmt.Printf("Targetting %s for issue %s\n", strings.TrimSpace(jiraURL), key)
+
+ options := &jira.GetQueryOptions{Expand: "renderedFields"}
+ u, _, err := client.Issue.Get(key, options)
+
+ if err != nil {
+ fmt.Printf("\n==> error: %v\n", err)
+ return
+ }
+
+ fmt.Printf("RenderedFields: %+v\n", *u.RenderedFields)
+
+ for _, c := range u.RenderedFields.Comments.Comments {
+ fmt.Printf(" %+v\n", c)
+ }
+}
diff --git a/issue.go b/issue.go
index c29b7b0..0c57b5a 100644
--- a/issue.go
+++ b/issue.go
@@ -31,12 +31,13 @@ type IssueService struct {
// Issue represents a JIRA issue.
type Issue struct {
- Expand string `json:"expand,omitempty" structs:"expand,omitempty"`
- ID string `json:"id,omitempty" structs:"id,omitempty"`
- Self string `json:"self,omitempty" structs:"self,omitempty"`
- Key string `json:"key,omitempty" structs:"key,omitempty"`
- Fields *IssueFields `json:"fields,omitempty" structs:"fields,omitempty"`
- Changelog *Changelog `json:"changelog,omitempty" structs:"changelog,omitempty"`
+ Expand string `json:"expand,omitempty" structs:"expand,omitempty"`
+ ID string `json:"id,omitempty" structs:"id,omitempty"`
+ Self string `json:"self,omitempty" structs:"self,omitempty"`
+ Key string `json:"key,omitempty" structs:"key,omitempty"`
+ Fields *IssueFields `json:"fields,omitempty" structs:"fields,omitempty"`
+ RenderedFields *IssueRenderedFields `json:"renderedFields,omitempty" structs:"renderedFields,omitempty"`
+ Changelog *Changelog `json:"changelog,omitempty" structs:"changelog,omitempty"`
}
// ChangelogItems reflects one single changelog item of a history item
@@ -196,6 +197,23 @@ func (i *IssueFields) UnmarshalJSON(data []byte) error {
}
+// IssueRenderedFields represents rendered fields of a JIRA issue.
+// Not all IssueFields are rendered.
+type IssueRenderedFields struct {
+ // TODO Missing fields
+ // * "aggregatetimespent": null,
+ // * "workratio": -1,
+ // * "lastViewed": null,
+ // * "aggregatetimeoriginalestimate": null,
+ // * "aggregatetimeestimate": null,
+ // * "environment": null,
+ Resolutiondate string `json:"resolutiondate,omitempty" structs:"resolutiondate,omitempty"`
+ Created string `json:"created,omitempty" structs:"created,omitempty"`
+ Duedate string `json:"duedate,omitempty" structs:"duedate,omitempty"`
+ Updated string `json:"updated,omitempty" structs:"updated,omitempty"`
+ Comments *Comments `json:"comment,omitempty" structs:"comment,omitempty"`
+}
+
// IssueType represents a type of a JIRA issue.
// Typical types are "Request", "Bug", "Story", ...
type IssueType struct {
diff --git a/issue_test.go b/issue_test.go
index 453d664..8a378b7 100644
--- a/issue_test.go
+++ b/issue_test.go
@@ -273,6 +273,37 @@ func TestIssueService_Get_Fields(t *testing.T) {
}
}
+func TestIssueService_Get_RenderedFields(t *testing.T) {
+ setup()
+ defer teardown()
+ testMux.HandleFunc("/rest/api/2/issue/10002", func(w http.ResponseWriter, r *http.Request) {
+ testMethod(t, r, "GET")
+ testRequestURL(t, r, "/rest/api/2/issue/10002")
+
+ fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"labels":["test"],"watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"epic": {"id": 19415,"key": "EPIC-77","self": "https://example.atlassian.net/rest/agile/1.0/epic/19415","name": "Epic Name","summary": "Do it","color": {"key": "color_11"},"done": false},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"comment":"I did some work here.","updated":"2016-03-16T04:22:37.471+0000","visibility":{"type":"group","value":"jira-developers"},"started":"2016-03-16T04:22:37.471+0000","timeSpent":"3h 20m","timeSpentSeconds":12000,"id":"100028","issueId":"10002"}]},"updated":"2016-04-06T02:36:53.594-0700","duedate":"2018-01-19","timetracking":{"originalEstimate":"10m","remainingEstimate":"3m","timeSpent":"6m","originalEstimateSeconds":600,"remainingEstimateSeconds":200,"timeSpentSeconds":400}},"names":{"watcher":"watcher","attachment":"attachment","sub-tasks":"sub-tasks","description":"description","project":"project","comment":"comment","issuelinks":"issuelinks","worklog":"worklog","updated":"updated","timetracking":"timetracking"},"schema":{},"renderedFields":{"resolutiondate":"In 1 week","updated":"2 hours ago","comment":{"comments":[{"body":"This is HTML"}]}}}`)
+ })
+
+ issue, _, err := testClient.Issue.Get("10002", nil)
+ if issue == nil {
+ t.Error("Expected issue. Issue is nil")
+ }
+ if issue.RenderedFields.Updated != "2 hours ago" {
+ t.Error("Expected updated to equla '2 hours ago' for rendered field")
+ }
+
+ if len(issue.RenderedFields.Comments.Comments) != 1 {
+ t.Errorf("Expected one comment, %v found", len(issue.RenderedFields.Comments.Comments))
+ }
+ comment := issue.RenderedFields.Comments.Comments[0]
+ if comment.Body != "This is HTML" {
+ t.Errorf("Wrong comment body returned in RenderedField. Got %s", comment.Body)
+ }
+
+ if err != nil {
+ t.Errorf("Error given: %s", err)
+ }
+}
+
func TestIssueService_DownloadAttachment(t *testing.T) {
var testAttachment = "Here is an attachment"