Repository: xanzy/go-gitlab
Pull request #1447 (2022-04-08 09:33:00)

Unmarshal namespace throws error when trial true
If a user either is in trial mode or the user's trial expired the namespace's "trial_ends_on" field is of type` ISO8601` instead of `RFC3339`. 
Eg:
```
{
   "id":*******,
   "name":"oana-group",
   "path":"oana-group",
   "kind":"group",
   "full_path":"oana-group",
   "parent_id":null,
   "avatar_url":null,
   "web_url":"https://gitlab.com/groups/oana-group",
   "members_count_with_descendants":1,
   "billable_members_count":1,
   "seats_in_use":1,
   "max_seats_used":0,
   "plan":"ultimate_trial",
   "trial_ends_on":"2022-05-08",
   "trial":true
}
```  
This leads to the following error when listing namespaces or when trying to get a specific namespace:
```
parsing time \"\\\"2019-04-25\\\"\" as \"\\\"2006-01-02T15:04:05Z07:00\\\"\": cannot parse \"\\\"\" as \"T\"
```

This PR changes the type of `Namespace.TrialEndsOn` from `*time.Time` to `*ISOTime`.


Patch:
diff --git a/namespaces.go b/namespaces.go
index 946ee4c..b7c8ccb 100644
--- a/namespaces.go
+++ b/namespaces.go
@@ -19,7 +19,6 @@ package gitlab
 import (
 	"fmt"
 	"net/http"
-	"time"
 )
 
 // NamespacesService handles communication with the namespace related methods
@@ -34,21 +33,21 @@ type NamespacesService struct {
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html
 type Namespace struct {
-	ID                          int        `json:"id"`
-	Name                        string     `json:"name"`
-	Path                        string     `json:"path"`
-	Kind                        string     `json:"kind"`
-	FullPath                    string     `json:"full_path"`
-	ParentID                    int        `json:"parent_id"`
-	AvatarURL                   *string    `json:"avatar_url"`
-	WebURL                      string     `json:"web_url"`
-	MembersCountWithDescendants int        `json:"members_count_with_descendants"`
-	BillableMembersCount        int        `json:"billable_members_count"`
-	Plan                        string     `json:"plan"`
-	TrialEndsOn                 *time.Time `json:"trial_ends_on"`
-	Trial                       bool       `json:"trial"`
-	MaxSeatsUsed                *int       `json:"max_seats_used"`
-	SeatsInUse                  *int       `json:"seats_in_use"`
+	ID                          int      `json:"id"`
+	Name                        string   `json:"name"`
+	Path                        string   `json:"path"`
+	Kind                        string   `json:"kind"`
+	FullPath                    string   `json:"full_path"`
+	ParentID                    int      `json:"parent_id"`
+	AvatarURL                   *string  `json:"avatar_url"`
+	WebURL                      string   `json:"web_url"`
+	MembersCountWithDescendants int      `json:"members_count_with_descendants"`
+	BillableMembersCount        int      `json:"billable_members_count"`
+	Plan                        string   `json:"plan"`
+	TrialEndsOn                 *ISOTime `json:"trial_ends_on"`
+	Trial                       bool     `json:"trial"`
+	MaxSeatsUsed                *int     `json:"max_seats_used"`
+	SeatsInUse                  *int     `json:"seats_in_use"`
 }
 
 func (n Namespace) String() string {


Test patch:
diff --git a/namespaces_test.go b/namespaces_test.go
index 80be019..6df32ac 100644
--- a/namespaces_test.go
+++ b/namespaces_test.go
@@ -21,12 +21,16 @@ import (
 	"net/http"
 	"reflect"
 	"testing"
+	"time"
 )
 
 func TestListNamespaces(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
+	trialEndsOn, _ := time.Parse(time.RFC3339, "2022-05-08T00:00:00Z")
+	trialEndsOnISOTime := ISOTime(trialEndsOn)
+
 	mux.HandleFunc("/api/v4/namespaces", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodGet)
 		fmt.Fprintf(w, `[
@@ -69,7 +73,20 @@ func TestListNamespaces(t *testing.T) {
 			  "plan": "default",
 			  "trial_ends_on": null,
 			  "trial": false
-			}
+			},
+			{
+				"id": 4,
+				"name": "group2",
+				"path": "group2",
+				"kind": "group",
+				"full_path": "group2",
+				"avatar_url": "https://gitlab.example.com/groups/group2",
+				"web_url": "https://gitlab.example.com/group2",
+				"billable_members_count": 1,
+				"plan": "default",
+				"trial_ends_on": "2022-05-08",
+				"trial": true
+			  }
 		  ]`)
 	})
 
@@ -133,6 +150,19 @@ func TestListNamespaces(t *testing.T) {
 					TrialEndsOn:                 nil,
 					Trial:                       false,
 				},
+				{
+					ID:                   4,
+					Name:                 "group2",
+					Path:                 "group2",
+					Kind:                 "group",
+					FullPath:             "group2",
+					AvatarURL:            String("https://gitlab.example.com/groups/group2"),
+					WebURL:               "https://gitlab.example.com/group2",
+					Plan:                 "default",
+					BillableMembersCount: 1,
+					TrialEndsOn:          &trialEndsOnISOTime,
+					Trial:                true,
+				},
 			}
 
 			if !reflect.DeepEqual(namespaces, want) {