From 5b02f9abc0631562b1cabf1ecf47fff0a05ae771 Mon Sep 17 00:00:00 2001 From: BagToad <47394200+BagToad@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:34:28 -0600 Subject: [PATCH] Record attachment invocation telemetry Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- internal/attachments/flags.go | 19 ++++++++++ internal/attachments/flags_test.go | 54 +++++++++++++++++++++++++++ pkg/cmd/issue/comment/comment.go | 5 ++- pkg/cmd/issue/comment/comment_test.go | 17 ++++++++- pkg/cmd/issue/create/create.go | 5 ++- pkg/cmd/issue/create/create_test.go | 19 +++++++++- pkg/cmd/issue/edit/edit.go | 5 ++- pkg/cmd/issue/edit/edit_test.go | 17 ++++++++- pkg/cmd/issue/issue.go | 9 +++-- pkg/cmd/pr/comment/comment.go | 5 ++- pkg/cmd/pr/comment/comment_test.go | 17 ++++++++- pkg/cmd/pr/create/create.go | 5 ++- pkg/cmd/pr/create/create_test.go | 17 ++++++++- pkg/cmd/pr/edit/edit.go | 5 ++- pkg/cmd/pr/edit/edit_test.go | 17 ++++++++- pkg/cmd/pr/pr.go | 9 +++-- pkg/cmd/root/root.go | 4 +- 17 files changed, 206 insertions(+), 23 deletions(-) diff --git a/internal/attachments/flags.go b/internal/attachments/flags.go index c47117c79fc..10e42fd6fca 100644 --- a/internal/attachments/flags.go +++ b/internal/attachments/flags.go @@ -6,6 +6,7 @@ import ( "os" "strings" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -39,6 +40,24 @@ func (f *Flag) Changed() bool { return f.flag.Changed } +// RecordTelemetry records how many attachment flags were provided. +func (f *Flag) RecordTelemetry(command string, recorder ghtelemetry.CommandRecorder) { + if recorder == nil || !f.Changed() { + return + } + + recorder.SetSampleRate(ghtelemetry.SAMPLE_ALL) + recorder.Record(ghtelemetry.Event{ + Type: "attachment_invocation", + Dimensions: ghtelemetry.Dimensions{ + "command": command, + }, + Measures: ghtelemetry.Measures{ + "attach_count": int64(len(f.values)), + }, + }) +} + // UserAssets validates the files named by the attachment flag, keeping them in // the order they were written. It returns nothing when the flag was not passed. func (f *Flag) UserAssets() ([]UserAsset, error) { diff --git a/internal/attachments/flags_test.go b/internal/attachments/flags_test.go index 1238acc1519..af22157715e 100644 --- a/internal/attachments/flags_test.go +++ b/internal/attachments/flags_test.go @@ -7,6 +7,8 @@ import ( "strings" "testing" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" + "github.com/cli/cli/v2/internal/telemetry" "github.com/google/shlex" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -88,6 +90,58 @@ func TestAddFlag(t *testing.T) { } } +func TestFlagRecordTelemetry(t *testing.T) { + tests := []struct { + name string + input string + wantEvent bool + wantCount int64 + }{ + { + name: "flag not passed", + input: "", + }, + { + name: "one attachment", + input: "--attach ./first.png", + wantEvent: true, + wantCount: 1, + }, + { + name: "several attachments before validation", + input: "--attach ./first.png --attach ./second.png --attach ./third.png", + wantEvent: true, + wantCount: 3, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, attachFlag := attachCmd(t, tt.input) + recorder := &telemetry.CommandRecorderSpy{} + + attachFlag.RecordTelemetry("gh issue comment", recorder) + + if !tt.wantEvent { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + return + } + + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Equal(t, []ghtelemetry.Event{{ + Type: "attachment_invocation", + Dimensions: ghtelemetry.Dimensions{ + "command": "gh issue comment", + }, + Measures: ghtelemetry.Measures{ + "attach_count": tt.wantCount, + }, + }}, recorder.Events) + }) + } +} + func TestFlagUserAssets(t *testing.T) { tests := []struct { name string diff --git a/pkg/cmd/issue/comment/comment.go b/pkg/cmd/issue/comment/comment.go index c85f17d20ae..3c972d14f20 100644 --- a/pkg/cmd/issue/comment/comment.go +++ b/pkg/cmd/issue/comment/comment.go @@ -3,6 +3,7 @@ package comment import ( "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/internal/attachments" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/pkg/cmd/issue/shared" issueShared "github.com/cli/cli/v2/pkg/cmd/issue/shared" @@ -11,7 +12,7 @@ import ( "github.com/spf13/cobra" ) -func NewCmdComment(f *cmdutil.Factory, runF func(*prShared.CommentableOptions) error) *cobra.Command { +func NewCmdComment(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, runF func(*prShared.CommentableOptions) error) *cobra.Command { opts := &prShared.CommentableOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, @@ -58,6 +59,8 @@ func NewCmdComment(f *cmdutil.Factory, runF func(*prShared.CommentableOptions) e `), Args: cobra.ExactArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { + opts.AttachFlag.RecordTelemetry(cmd.CommandPath(), telemetry) + opts.RetrieveCommentable = func() (prShared.Commentable, ghrepo.Interface, error) { // TODO wm: more testing issueNumber, parsedBaseRepo, err := shared.ParseIssueFromArg(args[0]) diff --git a/pkg/cmd/issue/comment/comment_test.go b/pkg/cmd/issue/comment/comment_test.go index af7ff54f271..08ad22e7757 100644 --- a/pkg/cmd/issue/comment/comment_test.go +++ b/pkg/cmd/issue/comment/comment_test.go @@ -14,7 +14,9 @@ import ( "github.com/cli/cli/v2/internal/browser" "github.com/cli/cli/v2/internal/config" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/internal/telemetry" "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -408,7 +410,8 @@ func TestNewCmdComment(t *testing.T) { assert.NoError(t, err) var gotOpts *shared.CommentableOptions - cmd := NewCmdComment(f, func(opts *shared.CommentableOptions) error { + recorder := &telemetry.CommandRecorderSpy{} + cmd := NewCmdComment(f, recorder, func(opts *shared.CommentableOptions) error { gotOpts = opts return nil }) @@ -420,6 +423,18 @@ func TestNewCmdComment(t *testing.T) { cmd.SetErr(&bytes.Buffer{}) _, err = cmd.ExecuteC() + if cmd.Flags().Changed("attach") { + values, flagErr := cmd.Flags().GetStringArray("attach") + require.NoError(t, flagErr) + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Len(t, recorder.Events, 1) + assert.Equal(t, "attachment_invocation", recorder.Events[0].Type) + assert.Equal(t, cmd.CommandPath(), recorder.Events[0].Dimensions["command"]) + assert.Equal(t, int64(len(values)), recorder.Events[0].Measures["attach_count"]) + } else { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + } if tt.wantsErr { assert.Error(t, err) if tt.wantsErrContains != "" { diff --git a/pkg/cmd/issue/create/create.go b/pkg/cmd/issue/create/create.go index 0fd18db0dd6..c0e6adfa481 100644 --- a/pkg/cmd/issue/create/create.go +++ b/pkg/cmd/issue/create/create.go @@ -13,6 +13,7 @@ import ( "github.com/cli/cli/v2/internal/browser" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/internal/text" @@ -61,7 +62,7 @@ type CreateOptions struct { Assets []attachments.UserAsset } -func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Command { +func NewCmdCreate(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, runF func(*CreateOptions) error) *cobra.Command { opts := &CreateOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, @@ -120,6 +121,8 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co Args: cmdutil.NoArgsQuoteReminder, Aliases: []string{"new"}, RunE: func(cmd *cobra.Command, args []string) error { + opts.AttachFlag.RecordTelemetry(cmd.CommandPath(), telemetry) + // support `-R, --repo` override opts.BaseRepo = f.BaseRepo opts.HasRepoOverride = cmd.Flags().Changed("repo") diff --git a/pkg/cmd/issue/create/create_test.go b/pkg/cmd/issue/create/create_test.go index 3f6971ec998..e0463fb9504 100644 --- a/pkg/cmd/issue/create/create_test.go +++ b/pkg/cmd/issue/create/create_test.go @@ -18,9 +18,11 @@ import ( "github.com/cli/cli/v2/internal/config" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/internal/run" + "github.com/cli/cli/v2/internal/telemetry" prShared "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -311,7 +313,8 @@ func TestNewCmdCreate(t *testing.T) { } var opts *CreateOptions - cmd := NewCmdCreate(f, func(o *CreateOptions) error { + recorder := &telemetry.CommandRecorderSpy{} + cmd := NewCmdCreate(f, recorder, func(o *CreateOptions) error { opts = o return nil }) @@ -322,6 +325,18 @@ func TestNewCmdCreate(t *testing.T) { cmd.SetOut(io.Discard) cmd.SetErr(io.Discard) _, err = cmd.ExecuteC() + if cmd.Flags().Changed("attach") { + values, flagErr := cmd.Flags().GetStringArray("attach") + require.NoError(t, flagErr) + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Len(t, recorder.Events, 1) + assert.Equal(t, "attachment_invocation", recorder.Events[0].Type) + assert.Equal(t, cmd.CommandPath(), recorder.Events[0].Dimensions["command"]) + assert.Equal(t, int64(len(values)), recorder.Events[0].Measures["attach_count"]) + } else { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + } if tt.wantsErr { require.Error(t, err) if tt.wantsErrMsg != "" { @@ -1450,7 +1465,7 @@ func runCommandWithRootDirOverridden(rt http.RoundTripper, isTTY bool, cli strin Prompter: pm, } - cmd := NewCmdCreate(factory, func(opts *CreateOptions) error { + cmd := NewCmdCreate(factory, &telemetry.NoOpService{}, func(opts *CreateOptions) error { opts.RootDirOverride = rootDir opts.Detector = &fd.EnabledDetectorMock{} return createRun(opts) diff --git a/pkg/cmd/issue/edit/edit.go b/pkg/cmd/issue/edit/edit.go index 1329e1a5c58..3b8557abee6 100644 --- a/pkg/cmd/issue/edit/edit.go +++ b/pkg/cmd/issue/edit/edit.go @@ -15,6 +15,7 @@ import ( "github.com/cli/cli/v2/internal/attachments" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/text" issueShared "github.com/cli/cli/v2/pkg/cmd/issue/shared" @@ -57,7 +58,7 @@ type EditOptions struct { prShared.Editable } -func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command { +func NewCmdEdit(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, runF func(*EditOptions) error) *cobra.Command { opts := &EditOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, @@ -122,6 +123,8 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman `), Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + opts.AttachFlag.RecordTelemetry(cmd.CommandPath(), telemetry) + issueNumbers, baseRepo, err := issueShared.ParseIssuesFromArgs(args) if err != nil { return err diff --git a/pkg/cmd/issue/edit/edit_test.go b/pkg/cmd/issue/edit/edit_test.go index 54040de3d40..5e80ddc57a3 100644 --- a/pkg/cmd/issue/edit/edit_test.go +++ b/pkg/cmd/issue/edit/edit_test.go @@ -20,8 +20,10 @@ import ( "github.com/cli/cli/v2/internal/config" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/run" + "github.com/cli/cli/v2/internal/telemetry" prShared "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -455,7 +457,8 @@ func TestNewCmdEdit(t *testing.T) { assert.NoError(t, err) var gotOpts *EditOptions - cmd := NewCmdEdit(f, func(opts *EditOptions) error { + recorder := &telemetry.CommandRecorderSpy{} + cmd := NewCmdEdit(f, recorder, func(opts *EditOptions) error { gotOpts = opts return nil }) @@ -467,6 +470,18 @@ func TestNewCmdEdit(t *testing.T) { cmd.SetErr(&bytes.Buffer{}) _, err = cmd.ExecuteC() + if cmd.Flags().Changed("attach") { + values, flagErr := cmd.Flags().GetStringArray("attach") + require.NoError(t, flagErr) + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Len(t, recorder.Events, 1) + assert.Equal(t, "attachment_invocation", recorder.Events[0].Type) + assert.Equal(t, cmd.CommandPath(), recorder.Events[0].Dimensions["command"]) + assert.Equal(t, int64(len(values)), recorder.Events[0].Measures["attach_count"]) + } else { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + } if tt.wantsErr { require.Error(t, err) if tt.wantsErrMsg != "" { diff --git a/pkg/cmd/issue/issue.go b/pkg/cmd/issue/issue.go index eceea35c6df..65f43929cee 100644 --- a/pkg/cmd/issue/issue.go +++ b/pkg/cmd/issue/issue.go @@ -2,6 +2,7 @@ package issue import ( "github.com/MakeNowJust/heredoc" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" cmdClose "github.com/cli/cli/v2/pkg/cmd/issue/close" cmdComment "github.com/cli/cli/v2/pkg/cmd/issue/comment" cmdCreate "github.com/cli/cli/v2/pkg/cmd/issue/create" @@ -20,7 +21,7 @@ import ( "github.com/spf13/cobra" ) -func NewCmdIssue(f *cmdutil.Factory) *cobra.Command { +func NewCmdIssue(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder) *cobra.Command { cmd := &cobra.Command{ Use: "issue ", Short: "Manage issues", @@ -44,16 +45,16 @@ func NewCmdIssue(f *cmdutil.Factory) *cobra.Command { cmdutil.AddGroup(cmd, "General commands", cmdList.NewCmdList(f, nil), - cmdCreate.NewCmdCreate(f, nil), + cmdCreate.NewCmdCreate(f, telemetry, nil), cmdStatus.NewCmdStatus(f, nil), ) cmdutil.AddGroup(cmd, "Targeted commands", cmdView.NewCmdView(f, nil), - cmdComment.NewCmdComment(f, nil), + cmdComment.NewCmdComment(f, telemetry, nil), cmdClose.NewCmdClose(f, nil), cmdReopen.NewCmdReopen(f, nil), - cmdEdit.NewCmdEdit(f, nil), + cmdEdit.NewCmdEdit(f, telemetry, nil), cmdDevelop.NewCmdDevelop(f, nil), cmdLock.NewCmdLock(f, cmd.Name(), nil), cmdLock.NewCmdUnlock(f, cmd.Name(), nil), diff --git a/pkg/cmd/pr/comment/comment.go b/pkg/cmd/pr/comment/comment.go index cd9c7927edb..e7f7d504674 100644 --- a/pkg/cmd/pr/comment/comment.go +++ b/pkg/cmd/pr/comment/comment.go @@ -3,13 +3,14 @@ package comment import ( "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/internal/attachments" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/spf13/cobra" ) -func NewCmdComment(f *cmdutil.Factory, runF func(*shared.CommentableOptions) error) *cobra.Command { +func NewCmdComment(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, runF func(*shared.CommentableOptions) error) *cobra.Command { opts := &shared.CommentableOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, @@ -56,6 +57,8 @@ func NewCmdComment(f *cmdutil.Factory, runF func(*shared.CommentableOptions) err `), Args: cobra.MaximumNArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { + opts.AttachFlag.RecordTelemetry(cmd.CommandPath(), telemetry) + if repoOverride, _ := cmd.Flags().GetString("repo"); repoOverride != "" && len(args) == 0 { return cmdutil.FlagErrorf("argument required when using the --repo flag") } diff --git a/pkg/cmd/pr/comment/comment_test.go b/pkg/cmd/pr/comment/comment_test.go index 52b17bee118..c09c83cb32d 100644 --- a/pkg/cmd/pr/comment/comment_test.go +++ b/pkg/cmd/pr/comment/comment_test.go @@ -14,7 +14,9 @@ import ( "github.com/cli/cli/v2/internal/browser" "github.com/cli/cli/v2/internal/config" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/internal/telemetry" "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -430,7 +432,8 @@ func TestNewCmdComment(t *testing.T) { assert.NoError(t, err) var gotOpts *shared.CommentableOptions - cmd := NewCmdComment(f, func(opts *shared.CommentableOptions) error { + recorder := &telemetry.CommandRecorderSpy{} + cmd := NewCmdComment(f, recorder, func(opts *shared.CommentableOptions) error { gotOpts = opts return nil }) @@ -442,6 +445,18 @@ func TestNewCmdComment(t *testing.T) { cmd.SetErr(&bytes.Buffer{}) _, err = cmd.ExecuteC() + if cmd.Flags().Changed("attach") { + values, flagErr := cmd.Flags().GetStringArray("attach") + require.NoError(t, flagErr) + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Len(t, recorder.Events, 1) + assert.Equal(t, "attachment_invocation", recorder.Events[0].Type) + assert.Equal(t, cmd.CommandPath(), recorder.Events[0].Dimensions["command"]) + assert.Equal(t, int64(len(values)), recorder.Events[0].Measures["attach_count"]) + } else { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + } if tt.wantsErr { assert.Error(t, err) if tt.wantsErrContains != "" { diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index 11706462d28..c365fadebab 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -21,6 +21,7 @@ import ( "github.com/cli/cli/v2/internal/browser" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/internal/text" @@ -195,7 +196,7 @@ type CreateContext struct { GitClient *git.Client } -func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Command { +func NewCmdCreate(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, runF func(*CreateOptions) error) *cobra.Command { opts := &CreateOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, @@ -274,6 +275,8 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co Args: cmdutil.NoArgsQuoteReminder, Aliases: []string{"new"}, RunE: func(cmd *cobra.Command, args []string) error { + opts.AttachFlag.RecordTelemetry(cmd.CommandPath(), telemetry) + opts.Finder = shared.NewFinder(f) opts.TitleProvided = cmd.Flags().Changed("title") diff --git a/pkg/cmd/pr/create/create_test.go b/pkg/cmd/pr/create/create_test.go index cf5b4ea3c38..e6ecc1047a4 100644 --- a/pkg/cmd/pr/create/create_test.go +++ b/pkg/cmd/pr/create/create_test.go @@ -21,9 +21,11 @@ import ( "github.com/cli/cli/v2/internal/config" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/internal/run" + "github.com/cli/cli/v2/internal/telemetry" "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -335,7 +337,8 @@ func TestNewCmdCreate(t *testing.T) { } var opts *CreateOptions - cmd := NewCmdCreate(f, func(o *CreateOptions) error { + recorder := &telemetry.CommandRecorderSpy{} + cmd := NewCmdCreate(f, recorder, func(o *CreateOptions) error { opts = o return nil }) @@ -346,6 +349,18 @@ func TestNewCmdCreate(t *testing.T) { cmd.SetOut(stderr) cmd.SetErr(stderr) _, err = cmd.ExecuteC() + if cmd.Flags().Changed("attach") { + values, flagErr := cmd.Flags().GetStringArray("attach") + require.NoError(t, flagErr) + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Len(t, recorder.Events, 1) + assert.Equal(t, "attachment_invocation", recorder.Events[0].Type) + assert.Equal(t, cmd.CommandPath(), recorder.Events[0].Dimensions["command"]) + assert.Equal(t, int64(len(values)), recorder.Events[0].Measures["attach_count"]) + } else { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + } if tt.wantsErr { if tt.wantsErrMsg != "" { if tt.wantErrIsNotExist { diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index fb4dc268e8a..fb8161f823c 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -14,6 +14,7 @@ import ( "github.com/cli/cli/v2/internal/attachments" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" shared "github.com/cli/cli/v2/pkg/cmd/pr/shared" @@ -46,7 +47,7 @@ type EditOptions struct { shared.Editable } -func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command { +func NewCmdEdit(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, runF func(*EditOptions) error) *cobra.Command { opts := &EditOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, @@ -134,6 +135,8 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman `), Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + opts.AttachFlag.RecordTelemetry(cmd.CommandPath(), telemetry) + opts.Finder = shared.NewFinder(f) // support `-R, --repo` override diff --git a/pkg/cmd/pr/edit/edit_test.go b/pkg/cmd/pr/edit/edit_test.go index 64e49e63afb..98cbd60b2d9 100644 --- a/pkg/cmd/pr/edit/edit_test.go +++ b/pkg/cmd/pr/edit/edit_test.go @@ -15,7 +15,9 @@ import ( "github.com/cli/cli/v2/internal/config" fd "github.com/cli/cli/v2/internal/featuredetection" "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/internal/telemetry" shared "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -354,7 +356,8 @@ func TestNewCmdEdit(t *testing.T) { assert.NoError(t, err) var gotOpts *EditOptions - cmd := NewCmdEdit(f, func(opts *EditOptions) error { + recorder := &telemetry.CommandRecorderSpy{} + cmd := NewCmdEdit(f, recorder, func(opts *EditOptions) error { gotOpts = opts return nil }) @@ -366,6 +369,18 @@ func TestNewCmdEdit(t *testing.T) { cmd.SetErr(&bytes.Buffer{}) _, err = cmd.ExecuteC() + if cmd.Flags().Changed("attach") { + values, flagErr := cmd.Flags().GetStringArray("attach") + require.NoError(t, flagErr) + require.Equal(t, ghtelemetry.SAMPLE_ALL, recorder.LastSampleRate) + require.Len(t, recorder.Events, 1) + assert.Equal(t, "attachment_invocation", recorder.Events[0].Type) + assert.Equal(t, cmd.CommandPath(), recorder.Events[0].Dimensions["command"]) + assert.Equal(t, int64(len(values)), recorder.Events[0].Measures["attach_count"]) + } else { + assert.Empty(t, recorder.Events) + assert.Zero(t, recorder.LastSampleRate) + } if tt.wantsErr { assert.Error(t, err) return diff --git a/pkg/cmd/pr/pr.go b/pkg/cmd/pr/pr.go index e73193084c0..225b62ca7b7 100644 --- a/pkg/cmd/pr/pr.go +++ b/pkg/cmd/pr/pr.go @@ -2,6 +2,7 @@ package pr import ( "github.com/MakeNowJust/heredoc" + "github.com/cli/cli/v2/internal/gh/ghtelemetry" cmdLock "github.com/cli/cli/v2/pkg/cmd/issue/lock" cmdCheckout "github.com/cli/cli/v2/pkg/cmd/pr/checkout" cmdChecks "github.com/cli/cli/v2/pkg/cmd/pr/checks" @@ -23,7 +24,7 @@ import ( "github.com/spf13/cobra" ) -func NewCmdPR(f *cmdutil.Factory) *cobra.Command { +func NewCmdPR(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder) *cobra.Command { cmd := &cobra.Command{ Use: "pr ", Short: "Manage pull requests", @@ -48,7 +49,7 @@ func NewCmdPR(f *cmdutil.Factory) *cobra.Command { cmdutil.AddGroup(cmd, "General commands", cmdList.NewCmdList(f, nil), - cmdCreate.NewCmdCreate(f, nil), + cmdCreate.NewCmdCreate(f, telemetry, nil), cmdStatus.NewCmdStatus(f, nil), ) @@ -61,11 +62,11 @@ func NewCmdPR(f *cmdutil.Factory) *cobra.Command { cmdMerge.NewCmdMerge(f, nil), cmdUpdateBranch.NewCmdUpdateBranch(f, nil), cmdReady.NewCmdReady(f, nil), - cmdComment.NewCmdComment(f, nil), + cmdComment.NewCmdComment(f, telemetry, nil), cmdClose.NewCmdClose(f, nil), cmdReopen.NewCmdReopen(f, nil), cmdRevert.NewCmdRevert(f, nil), - cmdEdit.NewCmdEdit(f, nil), + cmdEdit.NewCmdEdit(f, telemetry, nil), cmdLock.NewCmdLock(f, cmd.Name(), nil), cmdLock.NewCmdUnlock(f, cmd.Name(), nil), ) diff --git a/pkg/cmd/root/root.go b/pkg/cmd/root/root.go index df90bb249f9..985a0d82a41 100644 --- a/pkg/cmd/root/root.go +++ b/pkg/cmd/root/root.go @@ -166,9 +166,9 @@ func NewCmdRoot(f *cmdutil.Factory, telemetry ghtelemetry.CommandRecorder, versi cmd.AddCommand(agentTaskCmd.NewCmdAgentTask(&repoResolvingCmdFactory)) cmd.AddCommand(browseCmd.NewCmdBrowse(&repoResolvingCmdFactory, nil)) cmd.AddCommand(discussionCmd.NewCmdDiscussion(&repoResolvingCmdFactory)) - cmd.AddCommand(prCmd.NewCmdPR(&repoResolvingCmdFactory)) + cmd.AddCommand(prCmd.NewCmdPR(&repoResolvingCmdFactory, telemetry)) cmd.AddCommand(orgCmd.NewCmdOrg(&repoResolvingCmdFactory)) - cmd.AddCommand(issueCmd.NewCmdIssue(&repoResolvingCmdFactory)) + cmd.AddCommand(issueCmd.NewCmdIssue(&repoResolvingCmdFactory, telemetry)) cmd.AddCommand(releaseCmd.NewCmdRelease(&repoResolvingCmdFactory)) cmd.AddCommand(repoCmd.NewCmdRepo(&repoResolvingCmdFactory)) cmd.AddCommand(rulesetCmd.NewCmdRuleset(&repoResolvingCmdFactory))