Repository: PagerDuty/go-pagerduty
Pull request #494 (2023-09-02 00:06:03)

adding support for license and licenses allocated based operations #480
Following a similar approach to listing existing pagerduty resources from the pagerduty api, this PR adds the ability to list available licenses as well as licenses allocated. #480 

gerardocorea: > Thank you for putting up this PR. If we can get the method signatures reworked to properly handle the request context [comment here](https://github.com/PagerDuty/go-pagerduty/pull/494/files#r1329067020) we should be looking alright.

Appreciate the feedback, made the requested changes.

Patch:
diff --git a/license.go b/license.go
new file mode 100644
index 0000000..042e020
--- /dev/null
+++ b/license.go
@@ -0,0 +1,84 @@
+package pagerduty
+
+import (
+	"context"
+
+	"github.com/google/go-querystring/query"
+)
+
+type License struct {
+	APIObject
+	Name                 string   `json:"name"`
+	Description          string   `json:"description"`
+	ValidRoles           []string `json:"valid_roles"`
+	RoleGroup            string   `json:"role_group"`
+	Summary              string   `json:"summary"`
+	CurrentValue         int      `json:"current_value"`
+	AllocationsAvailable int      `json:"allocations_available"`
+}
+
+type LicenseAllocated struct {
+	APIObject
+	Name        string   `json:"name"`
+	Description string   `json:"description"`
+	ValidRoles  []string `json:"valid_roles"`
+	RoleGroup   string   `json:"role_group"`
+	Summary     string   `json:"summary"`
+}
+
+type LicenseAllocation struct {
+	AllocatedAt string `json:"allocated_at"`
+	User        APIObject
+	License     LicenseAllocated `json:"license"`
+}
+
+type ListLicensesResponse struct {
+	Licenses []License `json:"licenses"`
+}
+
+type ListLicenseAllocationsResponse struct {
+	APIListObject
+	LicenseAllocations []LicenseAllocation `json:"license_allocations"`
+}
+
+type ListLicenseAllocationsOptions struct {
+	Limit  int `url:"limit,omitempty"`
+	Offset int `url:"offset,omitempty"`
+}
+
+func (c *Client) ListLicensesWithContext(ctx context.Context) (*ListLicensesResponse, error) {
+
+	resp, err := c.get(ctx, "/licenses")
+	if err != nil {
+		return nil, err
+	}
+
+	var result ListLicensesResponse
+	err = c.decodeJSON(resp, &result)
+	if err != nil {
+		return nil, err
+	}
+
+	return &result, nil
+}
+
+func (c *Client) ListLicenseAllocationsWithContext(ctx context.Context, o ListLicenseAllocationsOptions) (*ListLicenseAllocationsResponse, error) {
+
+	v, err := query.Values(o)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := c.get(ctx, "/license_allocations?"+v.Encode())
+	if err != nil {
+		return nil, err
+	}
+
+	var result ListLicenseAllocationsResponse
+	err = c.decodeJSON(resp, &result)
+	if err != nil {
+		return nil, err
+	}
+
+	return &result, nil
+}


Test patch:
diff --git a/license_test.go b/license_test.go
new file mode 100644
index 0000000..553d791
--- /dev/null
+++ b/license_test.go
@@ -0,0 +1,139 @@
+package pagerduty
+
+import (
+	"context"
+	"net/http"
+	"testing"
+)
+
+func TestLicenses_List(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/licenses", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		_, _ = w.Write([]byte(`{ "licenses": [ { "id": "PIP248G", "name": "Business (Full User)", "description": "Event Intelligence", "current_value": 234, "allocations_available": 4766, "valid_roles": [ "owner", "admin", "user", "limited_user", "observer", "restricted_access" ], "role_group": "FullUser", "summary": "Business (Full User)", "type": "license", "self": null, "html_url": null } ] }`))
+	})
+
+	client := defaultTestClient(server.URL, "foo")
+
+	res, err := client.ListLicensesWithContext(context.Background())
+
+	want := &ListLicensesResponse{
+		Licenses: []License{
+			{
+
+				APIObject: APIObject{
+					ID:   "PIP248G",
+					Type: "license",
+				},
+				Name:                 "Business (Full User)",
+				Description:          "Event Intelligence",
+				CurrentValue:         234,
+				AllocationsAvailable: 4766,
+				ValidRoles: []string{
+					"owner",
+					"admin",
+					"user",
+					"limited_user",
+					"observer",
+					"restricted_access",
+				},
+				RoleGroup: "FullUser",
+				Summary:   "Business (Full User)",
+			},
+		},
+	}
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	testEqual(t, want, res)
+}
+
+func TestLicenseAllocations_List(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/license_allocations", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		_, _ = w.Write([]byte(`{
+			"license_allocations": [
+			  {
+				"license": {
+				  "id": "PIP248G",
+				  "name": "Business (Full User)",
+				  "description": "Event Intelligence",
+				  "valid_roles": [
+					"owner",
+					"admin",
+					"user",
+					"limited_user",
+					"observer",
+					"restricted_access"
+				  ],
+				  "role_group": "FullUser",
+				  "summary": "Business (Full User)",
+				  "type": "license",
+				  "self": null,
+				  "html_url": null
+				},
+				"user": {
+				  "id": "PIP248H",
+				  "type": "user_reference"
+				},
+				"allocated_at": "2021-06-01T00:00:00-05:00"
+			  }
+			],
+			"offset": 0,
+			"limit": 1,
+			"more": false,
+			"total": 2
+		  }`))
+	})
+
+	client := defaultTestClient(server.URL, "foo")
+
+	res, err := client.ListLicenseAllocationsWithContext(context.Background(), ListLicenseAllocationsOptions{})
+
+	want := &ListLicenseAllocationsResponse{
+		APIListObject: APIListObject{
+			Offset: 0,
+			Limit:  1,
+			More:   false,
+			Total:  2,
+		},
+		LicenseAllocations: []LicenseAllocation{
+			{
+				License: LicenseAllocated{
+					APIObject: APIObject{
+						ID:   "PIP248G",
+						Type: "license",
+					},
+					Name:        "Business (Full User)",
+					Description: "Event Intelligence",
+					ValidRoles: []string{
+						"owner",
+						"admin",
+						"user",
+						"limited_user",
+						"observer",
+						"restricted_access",
+					},
+					RoleGroup: "FullUser",
+					Summary:   "Business (Full User)",
+				},
+				AllocatedAt: "2021-06-01T00:00:00-05:00",
+				User: APIObject{
+					ID:   "PIP248H",
+					Type: "user_reference",
+				},
+			},
+		},
+	}
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	testEqual(t, want, res)
+}