From 18969b05a0d2c9c476e5bde140f3876d83a7159e Mon Sep 17 00:00:00 2001
From: David Url <david@urld.io>
Date: Sun, 28 Apr 2019 19:10:41 +0200
Subject: [PATCH 1/2] Unify FixVersion and Version types

The FixVersion type was missing some fields. Now it is a complete copy
of the more complete Version struct, with the only difference that the
bool fields are pointers (for compatibility reasons).

Fixes #208
---
 issue.go | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/issue.go b/issue.go
index 9e21fba..f52072d 100644
--- a/issue.go
+++ b/issue.go
@@ -464,14 +464,16 @@ type Comment struct {
 
 // FixVersion represents a software release in which an issue is fixed.
 type FixVersion struct {
-	Archived        *bool  `json:"archived,omitempty" structs:"archived,omitempty"`
+	Self            string `json:"self,omitempty" structs:"self,omitempty"`
 	ID              string `json:"id,omitempty" structs:"id,omitempty"`
 	Name            string `json:"name,omitempty" structs:"name,omitempty"`
-	ProjectID       int    `json:"projectId,omitempty" structs:"projectId,omitempty"`
-	ReleaseDate     string `json:"releaseDate,omitempty" structs:"releaseDate,omitempty"`
+	Description     string `json:"description,omitempty" structs:"name,omitempty"`
+	Archived        *bool  `json:"archived,omitempty" structs:"archived,omitempty"`
 	Released        *bool  `json:"released,omitempty" structs:"released,omitempty"`
-	Self            string `json:"self,omitempty" structs:"self,omitempty"`
+	ReleaseDate     string `json:"releaseDate,omitempty" structs:"releaseDate,omitempty"`
 	UserReleaseDate string `json:"userReleaseDate,omitempty" structs:"userReleaseDate,omitempty"`
+	ProjectID       int    `json:"projectId,omitempty" structs:"projectId,omitempty"` // Unlike other IDs, this is returned as a number
+	StartDate       string `json:"startDate,omitempty" structs:"startDate,omitempty"`
 }
 
 // CommentVisibility represents he visibility of a comment.

From b1589c4b06cf896b8067ef750be5ea75335a859f Mon Sep 17 00:00:00 2001
From: David Url <david@urld.io>
Date: Sun, 28 Apr 2019 19:52:48 +0200
Subject: [PATCH 2/2] Add 'affects versions' to issue fields

---
 issue.go      | 76 +++++++++++++++++++++++++++------------------------
 issue_test.go | 40 +++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 36 deletions(-)

diff --git a/issue.go b/issue.go
index f52072d..19afa07 100644
--- a/issue.go
+++ b/issue.go
@@ -101,42 +101,43 @@ type IssueFields struct {
 	//      * "workratio": -1,
 	//      * "lastViewed": null,
 	//      * "environment": null,
-	Expand                        string        `json:"expand,omitempty" structs:"expand,omitempty"`
-	Type                          IssueType     `json:"issuetype,omitempty" structs:"issuetype,omitempty"`
-	Project                       Project       `json:"project,omitempty" structs:"project,omitempty"`
-	Resolution                    *Resolution   `json:"resolution,omitempty" structs:"resolution,omitempty"`
-	Priority                      *Priority     `json:"priority,omitempty" structs:"priority,omitempty"`
-	Resolutiondate                Time          `json:"resolutiondate,omitempty" structs:"resolutiondate,omitempty"`
-	Created                       Time          `json:"created,omitempty" structs:"created,omitempty"`
-	Duedate                       Date          `json:"duedate,omitempty" structs:"duedate,omitempty"`
-	Watches                       *Watches      `json:"watches,omitempty" structs:"watches,omitempty"`
-	Assignee                      *User         `json:"assignee,omitempty" structs:"assignee,omitempty"`
-	Updated                       Time          `json:"updated,omitempty" structs:"updated,omitempty"`
-	Description                   string        `json:"description,omitempty" structs:"description,omitempty"`
-	Summary                       string        `json:"summary,omitempty" structs:"summary,omitempty"`
-	Creator                       *User         `json:"Creator,omitempty" structs:"Creator,omitempty"`
-	Reporter                      *User         `json:"reporter,omitempty" structs:"reporter,omitempty"`
-	Components                    []*Component  `json:"components,omitempty" structs:"components,omitempty"`
-	Status                        *Status       `json:"status,omitempty" structs:"status,omitempty"`
-	Progress                      *Progress     `json:"progress,omitempty" structs:"progress,omitempty"`
-	AggregateProgress             *Progress     `json:"aggregateprogress,omitempty" structs:"aggregateprogress,omitempty"`
-	TimeTracking                  *TimeTracking `json:"timetracking,omitempty" structs:"timetracking,omitempty"`
-	TimeSpent                     int           `json:"timespent,omitempty" structs:"timespent,omitempty"`
-	TimeEstimate                  int           `json:"timeestimate,omitempty" structs:"timeestimate,omitempty"`
-	TimeOriginalEstimate          int           `json:"timeoriginalestimate,omitempty" structs:"timeoriginalestimate,omitempty"`
-	Worklog                       *Worklog      `json:"worklog,omitempty" structs:"worklog,omitempty"`
-	IssueLinks                    []*IssueLink  `json:"issuelinks,omitempty" structs:"issuelinks,omitempty"`
-	Comments                      *Comments     `json:"comment,omitempty" structs:"comment,omitempty"`
-	FixVersions                   []*FixVersion `json:"fixVersions,omitempty" structs:"fixVersions,omitempty"`
-	Labels                        []string      `json:"labels,omitempty" structs:"labels,omitempty"`
-	Subtasks                      []*Subtasks   `json:"subtasks,omitempty" structs:"subtasks,omitempty"`
-	Attachments                   []*Attachment `json:"attachment,omitempty" structs:"attachment,omitempty"`
-	Epic                          *Epic         `json:"epic,omitempty" structs:"epic,omitempty"`
-	Sprint                        *Sprint       `json:"sprint,omitempty" structs:"sprint,omitempty"`
-	Parent                        *Parent       `json:"parent,omitempty" structs:"parent,omitempty"`
-	AggregateTimeOriginalEstimate int           `json:"aggregatetimeoriginalestimate,omitempty" structs:"aggregatetimeoriginalestimate,omitempty"`
-	AggregateTimeSpent            int           `json:"aggregatetimespent,omitempty" structs:"aggregatetimespent,omitempty"`
-	AggregateTimeEstimate         int           `json:"aggregatetimeestimate,omitempty" structs:"aggregatetimeestimate,omitempty"`
+	Expand                        string            `json:"expand,omitempty" structs:"expand,omitempty"`
+	Type                          IssueType         `json:"issuetype,omitempty" structs:"issuetype,omitempty"`
+	Project                       Project           `json:"project,omitempty" structs:"project,omitempty"`
+	Resolution                    *Resolution       `json:"resolution,omitempty" structs:"resolution,omitempty"`
+	Priority                      *Priority         `json:"priority,omitempty" structs:"priority,omitempty"`
+	Resolutiondate                Time              `json:"resolutiondate,omitempty" structs:"resolutiondate,omitempty"`
+	Created                       Time              `json:"created,omitempty" structs:"created,omitempty"`
+	Duedate                       Date              `json:"duedate,omitempty" structs:"duedate,omitempty"`
+	Watches                       *Watches          `json:"watches,omitempty" structs:"watches,omitempty"`
+	Assignee                      *User             `json:"assignee,omitempty" structs:"assignee,omitempty"`
+	Updated                       Time              `json:"updated,omitempty" structs:"updated,omitempty"`
+	Description                   string            `json:"description,omitempty" structs:"description,omitempty"`
+	Summary                       string            `json:"summary,omitempty" structs:"summary,omitempty"`
+	Creator                       *User             `json:"Creator,omitempty" structs:"Creator,omitempty"`
+	Reporter                      *User             `json:"reporter,omitempty" structs:"reporter,omitempty"`
+	Components                    []*Component      `json:"components,omitempty" structs:"components,omitempty"`
+	Status                        *Status           `json:"status,omitempty" structs:"status,omitempty"`
+	Progress                      *Progress         `json:"progress,omitempty" structs:"progress,omitempty"`
+	AggregateProgress             *Progress         `json:"aggregateprogress,omitempty" structs:"aggregateprogress,omitempty"`
+	TimeTracking                  *TimeTracking     `json:"timetracking,omitempty" structs:"timetracking,omitempty"`
+	TimeSpent                     int               `json:"timespent,omitempty" structs:"timespent,omitempty"`
+	TimeEstimate                  int               `json:"timeestimate,omitempty" structs:"timeestimate,omitempty"`
+	TimeOriginalEstimate          int               `json:"timeoriginalestimate,omitempty" structs:"timeoriginalestimate,omitempty"`
+	Worklog                       *Worklog          `json:"worklog,omitempty" structs:"worklog,omitempty"`
+	IssueLinks                    []*IssueLink      `json:"issuelinks,omitempty" structs:"issuelinks,omitempty"`
+	Comments                      *Comments         `json:"comment,omitempty" structs:"comment,omitempty"`
+	FixVersions                   []*FixVersion     `json:"fixVersions,omitempty" structs:"fixVersions,omitempty"`
+	AffectsVersions               []*AffectsVersion `json:"versions,omitempty" structs:"versions,omitempty"`
+	Labels                        []string          `json:"labels,omitempty" structs:"labels,omitempty"`
+	Subtasks                      []*Subtasks       `json:"subtasks,omitempty" structs:"subtasks,omitempty"`
+	Attachments                   []*Attachment     `json:"attachment,omitempty" structs:"attachment,omitempty"`
+	Epic                          *Epic             `json:"epic,omitempty" structs:"epic,omitempty"`
+	Sprint                        *Sprint           `json:"sprint,omitempty" structs:"sprint,omitempty"`
+	Parent                        *Parent           `json:"parent,omitempty" structs:"parent,omitempty"`
+	AggregateTimeOriginalEstimate int               `json:"aggregatetimeoriginalestimate,omitempty" structs:"aggregatetimeoriginalestimate,omitempty"`
+	AggregateTimeSpent            int               `json:"aggregatetimespent,omitempty" structs:"aggregatetimespent,omitempty"`
+	AggregateTimeEstimate         int               `json:"aggregatetimeestimate,omitempty" structs:"aggregatetimeestimate,omitempty"`
 	Unknowns                      tcontainer.MarshalMap
 }
 
@@ -476,6 +477,9 @@ type FixVersion struct {
 	StartDate       string `json:"startDate,omitempty" structs:"startDate,omitempty"`
 }
 
+// AffectsVersion represents a software release which is affected by an issue.
+type AffectsVersion Version
+
 // CommentVisibility represents he visibility of a comment.
 // E.g. Type could be "role" and Value "Administrators"
 type CommentVisibility struct {
diff --git a/issue_test.go b/issue_test.go
index 5fc67a6..56fe34b 100644
--- a/issue_test.go
+++ b/issue_test.go
@@ -937,6 +937,14 @@ func TestIssueFields_MarshalJSON_Success(t *testing.T) {
 			ID:   "10000",
 			Key:  "EX",
 		},
+		AffectsVersions: []*AffectsVersion{
+			&AffectsVersion{
+				ID:          "10705",
+				Name:        "2.1.0-rc3",
+				Self:        "http://www.example.com/jira/rest/api/2/version/10705",
+				ReleaseDate: "2018-09-30",
+			},
+		},
 	}
 
 	bytes, err := json.Marshal(i)
@@ -1428,3 +1436,35 @@ func TestIssueService_Get_Fields_Changelog(t *testing.T) {
 		t.Errorf("Expected CreatedTime func return %v time, %v got", tm, ct)
 	}
 }
+func TestIssueService_Get_Fields_AffectsVersions(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, `{"fields":{"versions":[{"self":"http://www.example.com/jira/rest/api/2/version/10705","id":"10705","description":"test description","name":"2.1.0-rc3","archived":false,"released":false,"releaseDate":"2018-09-30"}]}}`)
+	})
+
+	issue, _, err := testClient.Issue.Get("10002", nil)
+	if issue == nil {
+		t.Error("Expected issue. Issue is nil")
+	}
+	if !reflect.DeepEqual(issue.Fields.AffectsVersions, []*AffectsVersion{
+		{
+			ID:          "10705",
+			Name:        "2.1.0-rc3",
+			Self:        "http://www.example.com/jira/rest/api/2/version/10705",
+			ReleaseDate: "2018-09-30",
+			Released:    false,
+			Archived:    false,
+			Description: "test description",
+		},
+	}) {
+		t.Error("Expected AffectsVersions for the returned issue")
+	}
+
+	if err != nil {
+		t.Errorf("Error given: %s", err)
+	}
+}