diff --git a/github/copilot.go b/github/copilot.go index 25f5969ebe8..7a7a13a6a2b 100644 --- a/github/copilot.go +++ b/github/copilot.go @@ -185,6 +185,24 @@ type CopilotMetrics struct { CopilotDotcomPullRequests *CopilotDotcomPullRequests `json:"copilot_dotcom_pull_requests,omitempty"` } +// CopilotMetricsReportOptions specifies the optional parameters for single-day metrics report endpoints. +type CopilotMetricsReportOptions struct { + Day string `url:"day"` // Required, format: YYYY-MM-DD +} + +// CopilotMetricsDailyReport represents the response from 1-day Copilot metrics report endpoints. +type CopilotMetricsDailyReport struct { + DownloadLinks []string `json:"download_links"` + ReportDay string `json:"report_day"` +} + +// CopilotMetricsReport represents the response from 28-day Copilot metrics report endpoints. +type CopilotMetricsReport struct { + DownloadLinks []string `json:"download_links"` + ReportStartDay string `json:"report_start_day"` + ReportEndDay string `json:"report_end_day"` +} + // UnmarshalJSON implements the json.Unmarshaler interface. func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error { // Using an alias to avoid infinite recursion when calling json.Unmarshal @@ -574,3 +592,195 @@ func (s *CopilotService) GetOrganizationTeamMetrics(ctx context.Context, org, te return metrics, resp, nil } + +// GetEnterpriseDailyMetricsReport gets a report containing Copilot metrics for a single day for an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-enterprise-usage-metrics-for-a-specific-day +// +//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/enterprise-1-day +func (s *CopilotService) GetEnterpriseDailyMetricsReport(ctx context.Context, enterprise string, opts *CopilotMetricsReportOptions) (*CopilotMetricsDailyReport, *Response, error) { + u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/enterprise-1-day", enterprise) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsDailyReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetEnterpriseMetricsReport gets a report containing Copilot metrics for a 28-day rolling window for an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-enterprise-usage-metrics +// +//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/enterprise-28-day/latest +func (s *CopilotService) GetEnterpriseMetricsReport(ctx context.Context, enterprise string) (*CopilotMetricsReport, *Response, error) { + u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/enterprise-28-day/latest", enterprise) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetEnterpriseUsersDailyMetricsReport gets a report containing Copilot user metrics for a single day for an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-users-usage-metrics-for-a-specific-day +// +//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/users-1-day +func (s *CopilotService) GetEnterpriseUsersDailyMetricsReport(ctx context.Context, enterprise string, opts *CopilotMetricsReportOptions) (*CopilotMetricsDailyReport, *Response, error) { + u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/users-1-day", enterprise) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsDailyReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetEnterpriseUsersMetricsReport gets a report containing Copilot user metrics for a 28-day rolling window for an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-users-usage-metrics +// +//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/users-28-day/latest +func (s *CopilotService) GetEnterpriseUsersMetricsReport(ctx context.Context, enterprise string) (*CopilotMetricsReport, *Response, error) { + u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/users-28-day/latest", enterprise) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetOrganizationDailyMetricsReport gets a report containing Copilot metrics for a single day for an organization. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-organization-usage-metrics-for-a-specific-day +// +//meta:operation GET /orgs/{org}/copilot/metrics/reports/organization-1-day +func (s *CopilotService) GetOrganizationDailyMetricsReport(ctx context.Context, org string, opts *CopilotMetricsReportOptions) (*CopilotMetricsDailyReport, *Response, error) { + u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/organization-1-day", org) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsDailyReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetOrganizationMetricsReport gets a report containing Copilot metrics for a 28-day rolling window for an organization. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-organization-usage-metrics +// +//meta:operation GET /orgs/{org}/copilot/metrics/reports/organization-28-day/latest +func (s *CopilotService) GetOrganizationMetricsReport(ctx context.Context, org string) (*CopilotMetricsReport, *Response, error) { + u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/organization-28-day/latest", org) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetOrganizationUsersDailyMetricsReport gets a report containing Copilot user metrics for a single day for an organization. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-organization-users-usage-metrics-for-a-specific-day +// +//meta:operation GET /orgs/{org}/copilot/metrics/reports/users-1-day +func (s *CopilotService) GetOrganizationUsersDailyMetricsReport(ctx context.Context, org string, opts *CopilotMetricsReportOptions) (*CopilotMetricsDailyReport, *Response, error) { + u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/users-1-day", org) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsDailyReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} + +// GetOrganizationUsersMetricsReport gets a report containing Copilot user metrics for a 28-day rolling window for an organization. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-usage-metrics#get-copilot-organization-users-usage-metrics +// +//meta:operation GET /orgs/{org}/copilot/metrics/reports/users-28-day/latest +func (s *CopilotService) GetOrganizationUsersMetricsReport(ctx context.Context, org string) (*CopilotMetricsReport, *Response, error) { + u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/users-28-day/latest", org) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var report *CopilotMetricsReport + resp, err := s.client.Do(ctx, req, &report) + if err != nil { + return nil, resp, err + } + + return report, resp, nil +} diff --git a/github/copilot_test.go b/github/copilot_test.go index 8c6ca23f09d..781dc0570a5 100644 --- a/github/copilot_test.go +++ b/github/copilot_test.go @@ -2509,3 +2509,363 @@ func TestCopilotService_GetOrganizationTeamMetrics(t *testing.T) { return resp, err }) } + +func TestCopilotService_GetEnterpriseDailyMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/copilot/metrics/reports/enterprise-1-day", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"day": "2025-07-01"}) + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_day": "2025-07-01" + }`) + }) + + ctx := t.Context() + opts := &CopilotMetricsReportOptions{Day: "2025-07-01"} + got, _, err := client.Copilot.GetEnterpriseDailyMetricsReport(ctx, "e", opts) + if err != nil { + t.Errorf("Copilot.GetEnterpriseDailyMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsDailyReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportDay: "2025-07-01", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetEnterpriseDailyMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetEnterpriseDailyMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetEnterpriseDailyMetricsReport(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetEnterpriseDailyMetricsReport(ctx, "e", opts) + if got != nil { + t.Errorf("Copilot.GetEnterpriseDailyMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetEnterpriseMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/copilot/metrics/reports/enterprise-28-day/latest", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_start_day": "2025-07-01", + "report_end_day": "2025-07-28" + }`) + }) + + ctx := t.Context() + got, _, err := client.Copilot.GetEnterpriseMetricsReport(ctx, "e") + if err != nil { + t.Errorf("Copilot.GetEnterpriseMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportStartDay: "2025-07-01", + ReportEndDay: "2025-07-28", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetEnterpriseMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetEnterpriseMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetEnterpriseMetricsReport(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetEnterpriseMetricsReport(ctx, "e") + if got != nil { + t.Errorf("Copilot.GetEnterpriseMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetEnterpriseUsersDailyMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/copilot/metrics/reports/users-1-day", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"day": "2025-07-01"}) + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_day": "2025-07-01" + }`) + }) + + ctx := t.Context() + opts := &CopilotMetricsReportOptions{Day: "2025-07-01"} + got, _, err := client.Copilot.GetEnterpriseUsersDailyMetricsReport(ctx, "e", opts) + if err != nil { + t.Errorf("Copilot.GetEnterpriseUsersDailyMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsDailyReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportDay: "2025-07-01", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetEnterpriseUsersDailyMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetEnterpriseUsersDailyMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetEnterpriseUsersDailyMetricsReport(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetEnterpriseUsersDailyMetricsReport(ctx, "e", opts) + if got != nil { + t.Errorf("Copilot.GetEnterpriseUsersDailyMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetEnterpriseUsersMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/copilot/metrics/reports/users-28-day/latest", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_start_day": "2025-07-01", + "report_end_day": "2025-07-28" + }`) + }) + + ctx := t.Context() + got, _, err := client.Copilot.GetEnterpriseUsersMetricsReport(ctx, "e") + if err != nil { + t.Errorf("Copilot.GetEnterpriseUsersMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportStartDay: "2025-07-01", + ReportEndDay: "2025-07-28", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetEnterpriseUsersMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetEnterpriseUsersMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetEnterpriseUsersMetricsReport(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetEnterpriseUsersMetricsReport(ctx, "e") + if got != nil { + t.Errorf("Copilot.GetEnterpriseUsersMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetOrganizationDailyMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/copilot/metrics/reports/organization-1-day", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"day": "2025-07-01"}) + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_day": "2025-07-01" + }`) + }) + + ctx := t.Context() + opts := &CopilotMetricsReportOptions{Day: "2025-07-01"} + got, _, err := client.Copilot.GetOrganizationDailyMetricsReport(ctx, "o", opts) + if err != nil { + t.Errorf("Copilot.GetOrganizationDailyMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsDailyReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportDay: "2025-07-01", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetOrganizationDailyMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationDailyMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetOrganizationDailyMetricsReport(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetOrganizationDailyMetricsReport(ctx, "o", opts) + if got != nil { + t.Errorf("Copilot.GetOrganizationDailyMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetOrganizationMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/copilot/metrics/reports/organization-28-day/latest", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_start_day": "2025-07-01", + "report_end_day": "2025-07-28" + }`) + }) + + ctx := t.Context() + got, _, err := client.Copilot.GetOrganizationMetricsReport(ctx, "o") + if err != nil { + t.Errorf("Copilot.GetOrganizationMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportStartDay: "2025-07-01", + ReportEndDay: "2025-07-28", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetOrganizationMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetOrganizationMetricsReport(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetOrganizationMetricsReport(ctx, "o") + if got != nil { + t.Errorf("Copilot.GetOrganizationMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetOrganizationUsersDailyMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/copilot/metrics/reports/users-1-day", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"day": "2025-07-01"}) + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_day": "2025-07-01" + }`) + }) + + ctx := t.Context() + opts := &CopilotMetricsReportOptions{Day: "2025-07-01"} + got, _, err := client.Copilot.GetOrganizationUsersDailyMetricsReport(ctx, "o", opts) + if err != nil { + t.Errorf("Copilot.GetOrganizationUsersDailyMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsDailyReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportDay: "2025-07-01", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetOrganizationUsersDailyMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationUsersDailyMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetOrganizationUsersDailyMetricsReport(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetOrganizationUsersDailyMetricsReport(ctx, "o", opts) + if got != nil { + t.Errorf("Copilot.GetOrganizationUsersDailyMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +} + +func TestCopilotService_GetOrganizationUsersMetricsReport(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/copilot/metrics/reports/users-28-day/latest", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "download_links": ["https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"], + "report_start_day": "2025-07-01", + "report_end_day": "2025-07-28" + }`) + }) + + ctx := t.Context() + got, _, err := client.Copilot.GetOrganizationUsersMetricsReport(ctx, "o") + if err != nil { + t.Errorf("Copilot.GetOrganizationUsersMetricsReport returned error: %v", err) + } + + want := &CopilotMetricsReport{ + DownloadLinks: []string{"https://example.com/copilot-usage-report-1.json", "https://example.com/copilot-usage-report-2.json"}, + ReportStartDay: "2025-07-01", + ReportEndDay: "2025-07-28", + } + + if !cmp.Equal(got, want) { + t.Errorf("Copilot.GetOrganizationUsersMetricsReport returned %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationUsersMetricsReport" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Copilot.GetOrganizationUsersMetricsReport(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Copilot.GetOrganizationUsersMetricsReport(ctx, "o") + if got != nil { + t.Errorf("Copilot.GetOrganizationUsersMetricsReport returned %+v, want nil", got) + } + return resp, err + }) +}