From 782156e34aeab47ef7ab5fa1c55dff6abb61a608 Mon Sep 17 00:00:00 2001 From: Hariom Paswan Date: Tue, 25 Aug 2026 12:47:27 +0530 Subject: [PATCH 1/2] feat: Add enterprise Visual Studio subscription licensing APIs --- github/enterprise_licenses.go | 92 +++++++++++++++++++ github/enterprise_licenses_test.go | 140 +++++++++++++++++++++++++++++ github/github-accessors.go | 64 +++++++++++++ github/github-accessors_test.go | 82 +++++++++++++++++ github/github-iterators.go | 35 ++++++++ github/github-iterators_test.go | 72 +++++++++++++++ 6 files changed, 485 insertions(+) diff --git a/github/enterprise_licenses.go b/github/enterprise_licenses.go index 73da6c5e66f..dbe4d96c3f9 100644 --- a/github/enterprise_licenses.go +++ b/github/enterprise_licenses.go @@ -89,6 +89,34 @@ type LastLicenseSyncProperties struct { Error string `json:"error"` } +// VisualStudioSubscriptionAssignment represents a user's Visual Studio subscription assignment. +type VisualStudioSubscriptionAssignment struct { + Email *string `json:"email,omitempty"` + SubscriptionID *string `json:"subscriptionId,omitempty"` + Username *string `json:"username,omitempty"` + ManualMatch *bool `json:"manual_match,omitempty"` +} + +// VisualStudioSubscriptions represents a list of Visual Studio subscriptions for an enterprise. +type VisualStudioSubscriptions struct { + TotalCount *int `json:"total_count,omitempty"` + VisualStudioSubscriptionAssignments []*VisualStudioSubscriptionAssignment `json:"visual_studio_subscription_assignments,omitempty"` +} + +// VisualStudioSubscriptionUserMatchRequest represents the request body to add or update a user match. +type VisualStudioSubscriptionUserMatchRequest struct { + UserIdentifier string `json:"user_identifier"` +} + +// ListVisualStudioSubscriptionsOptions specifies the optional parameters to +// EnterpriseService.ListVisualStudioSubscriptions. +type ListVisualStudioSubscriptionsOptions struct { + ListOptions + + // IsUnmatchedOnly filters results to return only unmatched subscriptions. + IsUnmatchedOnly bool `url:"is_unmatched_only,omitempty"` +} + // ListConsumedLicenses collect information about the number of consumed licenses and a collection with all the users with consumed enterprise licenses. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/licensing?apiVersion=2022-11-28#list-enterprise-consumed-licenses @@ -136,3 +164,67 @@ func (s *EnterpriseService) GetLicenseSyncStatus(ctx context.Context, enterprise return syncStatus, resp, nil } + +// ListVisualStudioSubscriptions gets a list of Visual Studio subscriptions for an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/licensing?apiVersion=2022-11-28#get-a-list-of-visual-studio-subscriptions-for-the-enterprise +// +//meta:operation GET /enterprises/{enterprise}/visual-studio-subscriptions +func (s *EnterpriseService) ListVisualStudioSubscriptions(ctx context.Context, enterprise string, opts *ListVisualStudioSubscriptionsOptions) (*VisualStudioSubscriptions, *Response, error) { + u := fmt.Sprintf("enterprises/%v/visual-studio-subscriptions", enterprise) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var subscriptions *VisualStudioSubscriptions + resp, err := s.client.Do(req, &subscriptions) + if err != nil { + return nil, resp, err + } + + return subscriptions, resp, nil +} + +// AddOrUpdateVisualStudioSubscriptionUserMatch adds or updates a manual match between a user and a Visual Studio subscription. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/licensing?apiVersion=2022-11-28#add-or-update-a-visual-studio-subscription-user-match +// +//meta:operation PUT /enterprises/{enterprise}/visual-studio-subscriptions/{visual_studio_subscription_id} +func (s *EnterpriseService) AddOrUpdateVisualStudioSubscriptionUserMatch(ctx context.Context, enterprise, subscriptionID string, body VisualStudioSubscriptionUserMatchRequest) (*VisualStudioSubscriptionAssignment, *Response, error) { + u := fmt.Sprintf("enterprises/%v/visual-studio-subscriptions/%v", enterprise, subscriptionID) + + req, err := s.client.NewRequest(ctx, "PUT", u, body) + if err != nil { + return nil, nil, err + } + + var assignment *VisualStudioSubscriptionAssignment + resp, err := s.client.Do(req, &assignment) + if err != nil { + return nil, resp, err + } + + return assignment, resp, nil +} + +// DeleteVisualStudioSubscriptionUserMatch deletes a manual match between a user and a Visual Studio subscription. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/licensing?apiVersion=2022-11-28#delete-a-visual-studio-subscription-user-match +// +//meta:operation DELETE /enterprises/{enterprise}/visual-studio-subscriptions/{visual_studio_subscription_id} +func (s *EnterpriseService) DeleteVisualStudioSubscriptionUserMatch(ctx context.Context, enterprise, subscriptionID string) (*Response, error) { + u := fmt.Sprintf("enterprises/%v/visual-studio-subscriptions/%v", enterprise, subscriptionID) + + req, err := s.client.NewRequest(ctx, "DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/github/enterprise_licenses_test.go b/github/enterprise_licenses_test.go index 288e8572e88..aa02c1c8c8e 100644 --- a/github/enterprise_licenses_test.go +++ b/github/enterprise_licenses_test.go @@ -180,3 +180,143 @@ func TestEnterpriseService_GetLicenseSyncStatus(t *testing.T) { return resp, err }) } + +func TestEnterpriseService_ListVisualStudioSubscriptions(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/visual-studio-subscriptions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"page": "1", "per_page": "10", "is_unmatched_only": "true"}) + fmt.Fprint(w, `{ + "total_count": 1, + "visual_studio_subscription_assignments": [{ + "email": "user@example.com", + "subscriptionId": "sub-123", + "username": "monalisa", + "manual_match": true + }] + }`) + }) + + opt := &ListVisualStudioSubscriptionsOptions{ + ListOptions: ListOptions{Page: 1, PerPage: 10}, + IsUnmatchedOnly: true, + } + ctx := t.Context() + subscriptions, _, err := client.Enterprise.ListVisualStudioSubscriptions(ctx, "e", opt) + if err != nil { + t.Errorf("Enterprise.ListVisualStudioSubscriptions returned error: %v", err) + } + + want := &VisualStudioSubscriptions{ + TotalCount: Ptr(1), + VisualStudioSubscriptionAssignments: []*VisualStudioSubscriptionAssignment{ + { + Email: Ptr("user@example.com"), + SubscriptionID: Ptr("sub-123"), + Username: Ptr("monalisa"), + ManualMatch: Ptr(true), + }, + }, + } + + if !cmp.Equal(subscriptions, want) { + t.Errorf("Enterprise.ListVisualStudioSubscriptions returned %+v, want %+v", subscriptions, want) + } + + const methodName = "ListVisualStudioSubscriptions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Enterprise.ListVisualStudioSubscriptions(ctx, "\n", opt) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.ListVisualStudioSubscriptions(ctx, "e", opt) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_AddOrUpdateVisualStudioSubscriptionUserMatch(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := VisualStudioSubscriptionUserMatchRequest{ + UserIdentifier: "monalisa", + } + + mux.HandleFunc("/enterprises/e/visual-studio-subscriptions/sub-123", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testJSONBody(t, r, input) + fmt.Fprint(w, `{ + "email": "user@example.com", + "subscriptionId": "sub-123", + "username": "monalisa", + "manual_match": true + }`) + }) + + ctx := t.Context() + assignment, _, err := client.Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123", input) + if err != nil { + t.Errorf("Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch returned error: %v", err) + } + + want := &VisualStudioSubscriptionAssignment{ + Email: Ptr("user@example.com"), + SubscriptionID: Ptr("sub-123"), + Username: Ptr("monalisa"), + ManualMatch: Ptr(true), + } + + if !cmp.Equal(assignment, want) { + t.Errorf("Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch returned %+v, want %+v", assignment, want) + } + + const methodName = "AddOrUpdateVisualStudioSubscriptionUserMatch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch(ctx, "\n", "sub-123", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123", input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_DeleteVisualStudioSubscriptionUserMatch(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/visual-studio-subscriptions/sub-123", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + resp, err := client.Enterprise.DeleteVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123") + if err != nil { + t.Errorf("Enterprise.DeleteVisualStudioSubscriptionUserMatch returned error: %v", err) + } + + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Enterprise.DeleteVisualStudioSubscriptionUserMatch status code = %v, want %v", resp.StatusCode, http.StatusNoContent) + } + + const methodName = "DeleteVisualStudioSubscriptionUserMatch" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Enterprise.DeleteVisualStudioSubscriptionUserMatch(ctx, "\n", "sub-123") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Enterprise.DeleteVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123") + }) +} diff --git a/github/github-accessors.go b/github/github-accessors.go index 25587473e22..88f732f1bc5 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -24022,6 +24022,14 @@ func (l *ListUserIssuesOptions) GetState() string { return l.State } +// GetIsUnmatchedOnly returns the IsUnmatchedOnly field. +func (l *ListVisualStudioSubscriptionsOptions) GetIsUnmatchedOnly() bool { + if l == nil { + return false + } + return l.IsUnmatchedOnly +} + // GetFilter returns the Filter field. func (l *ListWorkflowJobsOptions) GetFilter() string { if l == nil { @@ -45670,6 +45678,62 @@ func (u *UserUpdateRequest) GetTwitterUsername() string { return *u.TwitterUsername } +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptionAssignment) GetEmail() string { + if v == nil || v.Email == nil { + return "" + } + return *v.Email +} + +// GetManualMatch returns the ManualMatch field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptionAssignment) GetManualMatch() bool { + if v == nil || v.ManualMatch == nil { + return false + } + return *v.ManualMatch +} + +// GetSubscriptionID returns the SubscriptionID field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptionAssignment) GetSubscriptionID() string { + if v == nil || v.SubscriptionID == nil { + return "" + } + return *v.SubscriptionID +} + +// GetUsername returns the Username field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptionAssignment) GetUsername() string { + if v == nil || v.Username == nil { + return "" + } + return *v.Username +} + +// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptions) GetTotalCount() int { + if v == nil || v.TotalCount == nil { + return 0 + } + return *v.TotalCount +} + +// GetVisualStudioSubscriptionAssignments returns the VisualStudioSubscriptionAssignments slice if it's non-nil, nil otherwise. +func (v *VisualStudioSubscriptions) GetVisualStudioSubscriptionAssignments() []*VisualStudioSubscriptionAssignment { + if v == nil || v.VisualStudioSubscriptionAssignments == nil { + return nil + } + return v.VisualStudioSubscriptionAssignments +} + +// GetUserIdentifier returns the UserIdentifier field. +func (v *VisualStudioSubscriptionUserMatchRequest) GetUserIdentifier() string { + if v == nil { + return "" + } + return v.UserIdentifier +} + // GetEcosystem returns the Ecosystem field if it's non-nil, zero value otherwise. func (v *VulnerabilityPackage) GetEcosystem() string { if v == nil || v.Ecosystem == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 9d8632a71d8..40916cfd185 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -30131,6 +30131,14 @@ func TestListUserIssuesOptions_GetState(tt *testing.T) { l.GetState() } +func TestListVisualStudioSubscriptionsOptions_GetIsUnmatchedOnly(tt *testing.T) { + tt.Parallel() + l := &ListVisualStudioSubscriptionsOptions{} + l.GetIsUnmatchedOnly() + l = nil + l.GetIsUnmatchedOnly() +} + func TestListWorkflowJobsOptions_GetFilter(tt *testing.T) { tt.Parallel() l := &ListWorkflowJobsOptions{} @@ -57284,6 +57292,80 @@ func TestUserUpdateRequest_GetTwitterUsername(tt *testing.T) { u.GetTwitterUsername() } +func TestVisualStudioSubscriptionAssignment_GetEmail(tt *testing.T) { + tt.Parallel() + var zeroValue string + v := &VisualStudioSubscriptionAssignment{Email: &zeroValue} + v.GetEmail() + v = &VisualStudioSubscriptionAssignment{} + v.GetEmail() + v = nil + v.GetEmail() +} + +func TestVisualStudioSubscriptionAssignment_GetManualMatch(tt *testing.T) { + tt.Parallel() + var zeroValue bool + v := &VisualStudioSubscriptionAssignment{ManualMatch: &zeroValue} + v.GetManualMatch() + v = &VisualStudioSubscriptionAssignment{} + v.GetManualMatch() + v = nil + v.GetManualMatch() +} + +func TestVisualStudioSubscriptionAssignment_GetSubscriptionID(tt *testing.T) { + tt.Parallel() + var zeroValue string + v := &VisualStudioSubscriptionAssignment{SubscriptionID: &zeroValue} + v.GetSubscriptionID() + v = &VisualStudioSubscriptionAssignment{} + v.GetSubscriptionID() + v = nil + v.GetSubscriptionID() +} + +func TestVisualStudioSubscriptionAssignment_GetUsername(tt *testing.T) { + tt.Parallel() + var zeroValue string + v := &VisualStudioSubscriptionAssignment{Username: &zeroValue} + v.GetUsername() + v = &VisualStudioSubscriptionAssignment{} + v.GetUsername() + v = nil + v.GetUsername() +} + +func TestVisualStudioSubscriptions_GetTotalCount(tt *testing.T) { + tt.Parallel() + var zeroValue int + v := &VisualStudioSubscriptions{TotalCount: &zeroValue} + v.GetTotalCount() + v = &VisualStudioSubscriptions{} + v.GetTotalCount() + v = nil + v.GetTotalCount() +} + +func TestVisualStudioSubscriptions_GetVisualStudioSubscriptionAssignments(tt *testing.T) { + tt.Parallel() + zeroValue := []*VisualStudioSubscriptionAssignment{} + v := &VisualStudioSubscriptions{VisualStudioSubscriptionAssignments: zeroValue} + v.GetVisualStudioSubscriptionAssignments() + v = &VisualStudioSubscriptions{} + v.GetVisualStudioSubscriptionAssignments() + v = nil + v.GetVisualStudioSubscriptionAssignments() +} + +func TestVisualStudioSubscriptionUserMatchRequest_GetUserIdentifier(tt *testing.T) { + tt.Parallel() + v := &VisualStudioSubscriptionUserMatchRequest{} + v.GetUserIdentifier() + v = nil + v.GetUserIdentifier() +} + func TestVulnerabilityPackage_GetEcosystem(tt *testing.T) { tt.Parallel() var zeroValue string diff --git a/github/github-iterators.go b/github/github-iterators.go index 6be130a1ec1..ee6e3c4dcc7 100644 --- a/github/github-iterators.go +++ b/github/github-iterators.go @@ -3327,6 +3327,41 @@ func (s *EnterpriseService) ListTeamsIter(ctx context.Context, enterprise string } } +// ListVisualStudioSubscriptionsIter returns an iterator that paginates through all results of ListVisualStudioSubscriptions. +func (s *EnterpriseService) ListVisualStudioSubscriptionsIter(ctx context.Context, enterprise string, opts *ListVisualStudioSubscriptionsOptions) iter.Seq2[*VisualStudioSubscriptionAssignment, error] { + return func(yield func(*VisualStudioSubscriptionAssignment, error) bool) { + // Create a copy of opts to avoid mutating the caller's struct + if opts == nil { + opts = &ListVisualStudioSubscriptionsOptions{} + } else { + opts = Ptr(*opts) + } + + for { + results, resp, err := s.ListVisualStudioSubscriptions(ctx, enterprise, opts) + if err != nil { + yield(nil, err) + return + } + + var iterItems []*VisualStudioSubscriptionAssignment + if results != nil { + iterItems = results.VisualStudioSubscriptionAssignments + } + for _, item := range iterItems { + if !yield(item, nil) { + return + } + } + + if resp.NextPage == 0 { + break + } + opts.ListOptions.Page = resp.NextPage + } + } +} + // ListIter returns an iterator that paginates through all results of List. func (s *GistsService) ListIter(ctx context.Context, user string, opts *GistListOptions) iter.Seq2[*Gist, error] { return func(yield func(*Gist, error) bool) { diff --git a/github/github-iterators_test.go b/github/github-iterators_test.go index 00ea4167da9..2b722c7fa6b 100644 --- a/github/github-iterators_test.go +++ b/github/github-iterators_test.go @@ -7143,6 +7143,78 @@ func TestEnterpriseService_ListTeamsIter(t *testing.T) { } } +func TestEnterpriseService_ListVisualStudioSubscriptionsIter(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + var callNum int + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + callNum++ + switch callNum { + case 1: + w.Header().Set("Link", `; rel="next"`) + fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{},{}]}`) + case 2: + fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{},{},{}]}`) + case 3: + fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{}]}`) + case 4: + w.WriteHeader(http.StatusNotFound) + case 5: + fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{}]}`) + } + }) + + iter := client.Enterprise.ListVisualStudioSubscriptionsIter(t.Context(), "", nil) + var gotItems int + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 7; gotItems != want { + t.Errorf("client.Enterprise.ListVisualStudioSubscriptionsIter call 1 got %v items; want %v", gotItems, want) + } + + opts := &ListVisualStudioSubscriptionsOptions{} + iter = client.Enterprise.ListVisualStudioSubscriptionsIter(t.Context(), "", opts) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 2; gotItems != want { + t.Errorf("client.Enterprise.ListVisualStudioSubscriptionsIter call 2 got %v items; want %v", gotItems, want) + } + + iter = client.Enterprise.ListVisualStudioSubscriptionsIter(t.Context(), "", nil) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err == nil { + t.Error("expected error; got nil") + } + } + if gotItems != 1 { + t.Errorf("client.Enterprise.ListVisualStudioSubscriptionsIter call 3 got %v items; want 1 (an error)", gotItems) + } + + iter = client.Enterprise.ListVisualStudioSubscriptionsIter(t.Context(), "", nil) + gotItems = 0 + iter(func(item *VisualStudioSubscriptionAssignment, err error) bool { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + return false + }) + if gotItems != 1 { + t.Errorf("client.Enterprise.ListVisualStudioSubscriptionsIter call 4 got %v items; want 1 (an error)", gotItems) + } +} + func TestGistsService_ListIter(t *testing.T) { t.Parallel() client, mux, _ := setup(t) From 1db0976e596d32adcf7b5f24b1220a3f0207397a Mon Sep 17 00:00:00 2001 From: Hariom Paswan Date: Thu, 27 Aug 2026 11:24:02 +0530 Subject: [PATCH 2/2] refactor: Update Visual Studio Subscriptions schema and method names per review --- github/enterprise_licenses.go | 26 ++++++------- github/enterprise_licenses_test.go | 60 +++++++++++++++--------------- github/github-accessors.go | 40 ++++++++++---------- github/github-accessors_test.go | 51 +++++++++++++------------ github/github-iterators.go | 2 +- github/github-iterators_test.go | 8 ++-- 6 files changed, 95 insertions(+), 92 deletions(-) diff --git a/github/enterprise_licenses.go b/github/enterprise_licenses.go index dbe4d96c3f9..e1cc35c2fb2 100644 --- a/github/enterprise_licenses.go +++ b/github/enterprise_licenses.go @@ -91,21 +91,21 @@ type LastLicenseSyncProperties struct { // VisualStudioSubscriptionAssignment represents a user's Visual Studio subscription assignment. type VisualStudioSubscriptionAssignment struct { - Email *string `json:"email,omitempty"` - SubscriptionID *string `json:"subscriptionId,omitempty"` - Username *string `json:"username,omitempty"` - ManualMatch *bool `json:"manual_match,omitempty"` + VisualStudioSubscriptionEmail *string `json:"visual_studio_subscription_email,omitempty"` + SubscriptionID *string `json:"subscription_id,omitempty"` + Username *string `json:"username,omitempty"` + ManualMatch *bool `json:"manual_match,omitempty"` } // VisualStudioSubscriptions represents a list of Visual Studio subscriptions for an enterprise. type VisualStudioSubscriptions struct { - TotalCount *int `json:"total_count,omitempty"` - VisualStudioSubscriptionAssignments []*VisualStudioSubscriptionAssignment `json:"visual_studio_subscription_assignments,omitempty"` + TotalCount *int `json:"total_count,omitempty"` + VisualStudioSubscriptions []*VisualStudioSubscriptionAssignment `json:"visual_studio_subscriptions,omitempty"` } -// VisualStudioSubscriptionUserMatchRequest represents the request body to add or update a user match. -type VisualStudioSubscriptionUserMatchRequest struct { - UserIdentifier string `json:"user_identifier"` +// VisualStudioSubscriptionAssignmentRequest represents the request body to add or update a subscription assignment. +type VisualStudioSubscriptionAssignmentRequest struct { + UserIdentifier *string `json:"user_identifier,omitempty"` } // ListVisualStudioSubscriptionsOptions specifies the optional parameters to @@ -191,12 +191,12 @@ func (s *EnterpriseService) ListVisualStudioSubscriptions(ctx context.Context, e return subscriptions, resp, nil } -// AddOrUpdateVisualStudioSubscriptionUserMatch adds or updates a manual match between a user and a Visual Studio subscription. +// AddOrUpdateVisualStudioSubscriptionAssignment adds or updates a manual match between a user and a Visual Studio subscription. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/licensing?apiVersion=2022-11-28#add-or-update-a-visual-studio-subscription-user-match // //meta:operation PUT /enterprises/{enterprise}/visual-studio-subscriptions/{visual_studio_subscription_id} -func (s *EnterpriseService) AddOrUpdateVisualStudioSubscriptionUserMatch(ctx context.Context, enterprise, subscriptionID string, body VisualStudioSubscriptionUserMatchRequest) (*VisualStudioSubscriptionAssignment, *Response, error) { +func (s *EnterpriseService) AddOrUpdateVisualStudioSubscriptionAssignment(ctx context.Context, enterprise, subscriptionID string, body VisualStudioSubscriptionAssignmentRequest) (*VisualStudioSubscriptionAssignment, *Response, error) { u := fmt.Sprintf("enterprises/%v/visual-studio-subscriptions/%v", enterprise, subscriptionID) req, err := s.client.NewRequest(ctx, "PUT", u, body) @@ -213,12 +213,12 @@ func (s *EnterpriseService) AddOrUpdateVisualStudioSubscriptionUserMatch(ctx con return assignment, resp, nil } -// DeleteVisualStudioSubscriptionUserMatch deletes a manual match between a user and a Visual Studio subscription. +// DeleteVisualStudioSubscriptionAssignment deletes a manual match between a user and a Visual Studio subscription. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/licensing?apiVersion=2022-11-28#delete-a-visual-studio-subscription-user-match // //meta:operation DELETE /enterprises/{enterprise}/visual-studio-subscriptions/{visual_studio_subscription_id} -func (s *EnterpriseService) DeleteVisualStudioSubscriptionUserMatch(ctx context.Context, enterprise, subscriptionID string) (*Response, error) { +func (s *EnterpriseService) DeleteVisualStudioSubscriptionAssignment(ctx context.Context, enterprise, subscriptionID string) (*Response, error) { u := fmt.Sprintf("enterprises/%v/visual-studio-subscriptions/%v", enterprise, subscriptionID) req, err := s.client.NewRequest(ctx, "DELETE", u, nil) diff --git a/github/enterprise_licenses_test.go b/github/enterprise_licenses_test.go index aa02c1c8c8e..f6418c78d94 100644 --- a/github/enterprise_licenses_test.go +++ b/github/enterprise_licenses_test.go @@ -190,9 +190,9 @@ func TestEnterpriseService_ListVisualStudioSubscriptions(t *testing.T) { testFormValues(t, r, values{"page": "1", "per_page": "10", "is_unmatched_only": "true"}) fmt.Fprint(w, `{ "total_count": 1, - "visual_studio_subscription_assignments": [{ - "email": "user@example.com", - "subscriptionId": "sub-123", + "visual_studio_subscriptions": [{ + "visual_studio_subscription_email": "user@example.com", + "subscription_id": "sub-123", "username": "monalisa", "manual_match": true }] @@ -211,12 +211,12 @@ func TestEnterpriseService_ListVisualStudioSubscriptions(t *testing.T) { want := &VisualStudioSubscriptions{ TotalCount: Ptr(1), - VisualStudioSubscriptionAssignments: []*VisualStudioSubscriptionAssignment{ + VisualStudioSubscriptions: []*VisualStudioSubscriptionAssignment{ { - Email: Ptr("user@example.com"), - SubscriptionID: Ptr("sub-123"), - Username: Ptr("monalisa"), - ManualMatch: Ptr(true), + VisualStudioSubscriptionEmail: Ptr("user@example.com"), + SubscriptionID: Ptr("sub-123"), + Username: Ptr("monalisa"), + ManualMatch: Ptr(true), }, }, } @@ -240,50 +240,50 @@ func TestEnterpriseService_ListVisualStudioSubscriptions(t *testing.T) { }) } -func TestEnterpriseService_AddOrUpdateVisualStudioSubscriptionUserMatch(t *testing.T) { +func TestEnterpriseService_AddOrUpdateVisualStudioSubscriptionAssignment(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := VisualStudioSubscriptionUserMatchRequest{ - UserIdentifier: "monalisa", + input := VisualStudioSubscriptionAssignmentRequest{ + UserIdentifier: Ptr("monalisa"), } mux.HandleFunc("/enterprises/e/visual-studio-subscriptions/sub-123", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testJSONBody(t, r, input) fmt.Fprint(w, `{ - "email": "user@example.com", - "subscriptionId": "sub-123", + "visual_studio_subscription_email": "user@example.com", + "subscription_id": "sub-123", "username": "monalisa", "manual_match": true }`) }) ctx := t.Context() - assignment, _, err := client.Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123", input) + assignment, _, err := client.Enterprise.AddOrUpdateVisualStudioSubscriptionAssignment(ctx, "e", "sub-123", input) if err != nil { - t.Errorf("Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch returned error: %v", err) + t.Errorf("Enterprise.AddOrUpdateVisualStudioSubscriptionAssignment returned error: %v", err) } want := &VisualStudioSubscriptionAssignment{ - Email: Ptr("user@example.com"), - SubscriptionID: Ptr("sub-123"), - Username: Ptr("monalisa"), - ManualMatch: Ptr(true), + VisualStudioSubscriptionEmail: Ptr("user@example.com"), + SubscriptionID: Ptr("sub-123"), + Username: Ptr("monalisa"), + ManualMatch: Ptr(true), } if !cmp.Equal(assignment, want) { - t.Errorf("Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch returned %+v, want %+v", assignment, want) + t.Errorf("Enterprise.AddOrUpdateVisualStudioSubscriptionAssignment returned %+v, want %+v", assignment, want) } - const methodName = "AddOrUpdateVisualStudioSubscriptionUserMatch" + const methodName = "AddOrUpdateVisualStudioSubscriptionAssignment" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch(ctx, "\n", "sub-123", input) + _, _, err = client.Enterprise.AddOrUpdateVisualStudioSubscriptionAssignment(ctx, "\n", "sub-123", input) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Enterprise.AddOrUpdateVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123", input) + got, resp, err := client.Enterprise.AddOrUpdateVisualStudioSubscriptionAssignment(ctx, "e", "sub-123", input) if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -291,7 +291,7 @@ func TestEnterpriseService_AddOrUpdateVisualStudioSubscriptionUserMatch(t *testi }) } -func TestEnterpriseService_DeleteVisualStudioSubscriptionUserMatch(t *testing.T) { +func TestEnterpriseService_DeleteVisualStudioSubscriptionAssignment(t *testing.T) { t.Parallel() client, mux, _ := setup(t) @@ -301,22 +301,22 @@ func TestEnterpriseService_DeleteVisualStudioSubscriptionUserMatch(t *testing.T) }) ctx := t.Context() - resp, err := client.Enterprise.DeleteVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123") + resp, err := client.Enterprise.DeleteVisualStudioSubscriptionAssignment(ctx, "e", "sub-123") if err != nil { - t.Errorf("Enterprise.DeleteVisualStudioSubscriptionUserMatch returned error: %v", err) + t.Errorf("Enterprise.DeleteVisualStudioSubscriptionAssignment returned error: %v", err) } if resp.StatusCode != http.StatusNoContent { - t.Errorf("Enterprise.DeleteVisualStudioSubscriptionUserMatch status code = %v, want %v", resp.StatusCode, http.StatusNoContent) + t.Errorf("Enterprise.DeleteVisualStudioSubscriptionAssignment status code = %v, want %v", resp.StatusCode, http.StatusNoContent) } - const methodName = "DeleteVisualStudioSubscriptionUserMatch" + const methodName = "DeleteVisualStudioSubscriptionAssignment" testBadOptions(t, methodName, func() (err error) { - _, err = client.Enterprise.DeleteVisualStudioSubscriptionUserMatch(ctx, "\n", "sub-123") + _, err = client.Enterprise.DeleteVisualStudioSubscriptionAssignment(ctx, "\n", "sub-123") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Enterprise.DeleteVisualStudioSubscriptionUserMatch(ctx, "e", "sub-123") + return client.Enterprise.DeleteVisualStudioSubscriptionAssignment(ctx, "e", "sub-123") }) } diff --git a/github/github-accessors.go b/github/github-accessors.go index 27af4fbd2cb..04660db6914 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -45862,14 +45862,6 @@ func (u *UserUpdateRequest) GetTwitterUsername() string { return *u.TwitterUsername } -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (v *VisualStudioSubscriptionAssignment) GetEmail() string { - if v == nil || v.Email == nil { - return "" - } - return *v.Email -} - // GetManualMatch returns the ManualMatch field if it's non-nil, zero value otherwise. func (v *VisualStudioSubscriptionAssignment) GetManualMatch() bool { if v == nil || v.ManualMatch == nil { @@ -45894,6 +45886,22 @@ func (v *VisualStudioSubscriptionAssignment) GetUsername() string { return *v.Username } +// GetVisualStudioSubscriptionEmail returns the VisualStudioSubscriptionEmail field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptionAssignment) GetVisualStudioSubscriptionEmail() string { + if v == nil || v.VisualStudioSubscriptionEmail == nil { + return "" + } + return *v.VisualStudioSubscriptionEmail +} + +// GetUserIdentifier returns the UserIdentifier field if it's non-nil, zero value otherwise. +func (v *VisualStudioSubscriptionAssignmentRequest) GetUserIdentifier() string { + if v == nil || v.UserIdentifier == nil { + return "" + } + return *v.UserIdentifier +} + // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. func (v *VisualStudioSubscriptions) GetTotalCount() int { if v == nil || v.TotalCount == nil { @@ -45902,20 +45910,12 @@ func (v *VisualStudioSubscriptions) GetTotalCount() int { return *v.TotalCount } -// GetVisualStudioSubscriptionAssignments returns the VisualStudioSubscriptionAssignments slice if it's non-nil, nil otherwise. -func (v *VisualStudioSubscriptions) GetVisualStudioSubscriptionAssignments() []*VisualStudioSubscriptionAssignment { - if v == nil || v.VisualStudioSubscriptionAssignments == nil { +// GetVisualStudioSubscriptions returns the VisualStudioSubscriptions slice if it's non-nil, nil otherwise. +func (v *VisualStudioSubscriptions) GetVisualStudioSubscriptions() []*VisualStudioSubscriptionAssignment { + if v == nil || v.VisualStudioSubscriptions == nil { return nil } - return v.VisualStudioSubscriptionAssignments -} - -// GetUserIdentifier returns the UserIdentifier field. -func (v *VisualStudioSubscriptionUserMatchRequest) GetUserIdentifier() string { - if v == nil { - return "" - } - return v.UserIdentifier + return v.VisualStudioSubscriptions } // GetEcosystem returns the Ecosystem field if it's non-nil, zero value otherwise. diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 290dcc01def..83e70cf8055 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -57485,17 +57485,6 @@ func TestUserUpdateRequest_GetTwitterUsername(tt *testing.T) { u.GetTwitterUsername() } -func TestVisualStudioSubscriptionAssignment_GetEmail(tt *testing.T) { - tt.Parallel() - var zeroValue string - v := &VisualStudioSubscriptionAssignment{Email: &zeroValue} - v.GetEmail() - v = &VisualStudioSubscriptionAssignment{} - v.GetEmail() - v = nil - v.GetEmail() -} - func TestVisualStudioSubscriptionAssignment_GetManualMatch(tt *testing.T) { tt.Parallel() var zeroValue bool @@ -57529,6 +57518,28 @@ func TestVisualStudioSubscriptionAssignment_GetUsername(tt *testing.T) { v.GetUsername() } +func TestVisualStudioSubscriptionAssignment_GetVisualStudioSubscriptionEmail(tt *testing.T) { + tt.Parallel() + var zeroValue string + v := &VisualStudioSubscriptionAssignment{VisualStudioSubscriptionEmail: &zeroValue} + v.GetVisualStudioSubscriptionEmail() + v = &VisualStudioSubscriptionAssignment{} + v.GetVisualStudioSubscriptionEmail() + v = nil + v.GetVisualStudioSubscriptionEmail() +} + +func TestVisualStudioSubscriptionAssignmentRequest_GetUserIdentifier(tt *testing.T) { + tt.Parallel() + var zeroValue string + v := &VisualStudioSubscriptionAssignmentRequest{UserIdentifier: &zeroValue} + v.GetUserIdentifier() + v = &VisualStudioSubscriptionAssignmentRequest{} + v.GetUserIdentifier() + v = nil + v.GetUserIdentifier() +} + func TestVisualStudioSubscriptions_GetTotalCount(tt *testing.T) { tt.Parallel() var zeroValue int @@ -57540,23 +57551,15 @@ func TestVisualStudioSubscriptions_GetTotalCount(tt *testing.T) { v.GetTotalCount() } -func TestVisualStudioSubscriptions_GetVisualStudioSubscriptionAssignments(tt *testing.T) { +func TestVisualStudioSubscriptions_GetVisualStudioSubscriptions(tt *testing.T) { tt.Parallel() zeroValue := []*VisualStudioSubscriptionAssignment{} - v := &VisualStudioSubscriptions{VisualStudioSubscriptionAssignments: zeroValue} - v.GetVisualStudioSubscriptionAssignments() + v := &VisualStudioSubscriptions{VisualStudioSubscriptions: zeroValue} + v.GetVisualStudioSubscriptions() v = &VisualStudioSubscriptions{} - v.GetVisualStudioSubscriptionAssignments() + v.GetVisualStudioSubscriptions() v = nil - v.GetVisualStudioSubscriptionAssignments() -} - -func TestVisualStudioSubscriptionUserMatchRequest_GetUserIdentifier(tt *testing.T) { - tt.Parallel() - v := &VisualStudioSubscriptionUserMatchRequest{} - v.GetUserIdentifier() - v = nil - v.GetUserIdentifier() + v.GetVisualStudioSubscriptions() } func TestVulnerabilityPackage_GetEcosystem(tt *testing.T) { diff --git a/github/github-iterators.go b/github/github-iterators.go index ee6e3c4dcc7..86edb9a47af 100644 --- a/github/github-iterators.go +++ b/github/github-iterators.go @@ -3346,7 +3346,7 @@ func (s *EnterpriseService) ListVisualStudioSubscriptionsIter(ctx context.Contex var iterItems []*VisualStudioSubscriptionAssignment if results != nil { - iterItems = results.VisualStudioSubscriptionAssignments + iterItems = results.VisualStudioSubscriptions } for _, item := range iterItems { if !yield(item, nil) { diff --git a/github/github-iterators_test.go b/github/github-iterators_test.go index 2b722c7fa6b..2ebf3a55f40 100644 --- a/github/github-iterators_test.go +++ b/github/github-iterators_test.go @@ -7152,15 +7152,15 @@ func TestEnterpriseService_ListVisualStudioSubscriptionsIter(t *testing.T) { switch callNum { case 1: w.Header().Set("Link", `; rel="next"`) - fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{},{}]}`) + fmt.Fprint(w, `{"visual_studio_subscriptions": [{},{},{}]}`) case 2: - fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{},{},{}]}`) + fmt.Fprint(w, `{"visual_studio_subscriptions": [{},{},{},{}]}`) case 3: - fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{}]}`) + fmt.Fprint(w, `{"visual_studio_subscriptions": [{},{}]}`) case 4: w.WriteHeader(http.StatusNotFound) case 5: - fmt.Fprint(w, `{"visual_studio_subscription_assignments": [{},{}]}`) + fmt.Fprint(w, `{"visual_studio_subscriptions": [{},{}]}`) } })