From 5e89e14281e27fadef5ac06f4a88fc4700c31a1f Mon Sep 17 00:00:00 2001 From: Codex CLI Date: Tue, 16 Jun 2026 15:07:35 +0000 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E2=9C=A8add=20pipelines=20queue=20?= =?UTF-8?q?show=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add subcommand to display details for a single Azure DevOps agent queue. Supports lookup by numeric ID or name (with optional organization or project prefix), --raw dump, and JSON export via shared flags. Uses embedded template for formatted output and reuses existing target parsing utilities. --- internal/cmd/pipelines/queue/queue.go | 2 + internal/cmd/pipelines/queue/show/show.go | 170 +++++++++++++++++++++ internal/cmd/pipelines/queue/show/show.tpl | 4 + 3 files changed, 176 insertions(+) create mode 100644 internal/cmd/pipelines/queue/show/show.go create mode 100644 internal/cmd/pipelines/queue/show/show.tpl diff --git a/internal/cmd/pipelines/queue/queue.go b/internal/cmd/pipelines/queue/queue.go index 9300d526..f455fdc2 100644 --- a/internal/cmd/pipelines/queue/queue.go +++ b/internal/cmd/pipelines/queue/queue.go @@ -5,6 +5,7 @@ import ( "github.com/spf13/cobra" "github.com/tmeckel/azdo-cli/internal/cmd/pipelines/queue/list" + "github.com/tmeckel/azdo-cli/internal/cmd/pipelines/queue/show" "github.com/tmeckel/azdo-cli/internal/cmd/util" ) @@ -23,5 +24,6 @@ func NewCmd(ctx util.CmdContext) *cobra.Command { } cmd.AddCommand(list.NewCmd(ctx)) + cmd.AddCommand(show.NewCmd(ctx)) return cmd } diff --git a/internal/cmd/pipelines/queue/show/show.go b/internal/cmd/pipelines/queue/show/show.go new file mode 100644 index 00000000..690b9f4d --- /dev/null +++ b/internal/cmd/pipelines/queue/show/show.go @@ -0,0 +1,170 @@ +package show + +import ( + _ "embed" + "fmt" + "strconv" + "strings" + + "github.com/MakeNowJust/heredoc/v2" + "github.com/microsoft/azure-devops-go-api/azuredevops/v7/taskagent" + "github.com/spewerspew/spew" + "github.com/spf13/cobra" + "go.uber.org/zap" + + "github.com/tmeckel/azdo-cli/internal/cmd/util" + "github.com/tmeckel/azdo-cli/internal/template" + "github.com/tmeckel/azdo-cli/internal/types" +) + +type showOptions struct { + targetArg string + raw bool + exporter util.Exporter +} + +//go:embed show.tpl +var showTempl string + +func NewCmd(ctx util.CmdContext) *cobra.Command { + opts := &showOptions{} + + cmd := &cobra.Command{ + Use: "show [ORGANIZATION/]PROJECT/QUEUE", + Short: "Show details of an agent queue", + Long: heredoc.Doc(` + Display the details of a single Azure DevOps agent queue. + The queue is identified by integer ID or name, with an + optional organization prefix. + `), + Example: heredoc.Doc(` + # Show a queue by ID + azdo pipelines queue show Fabrikam/7 + + # Show a queue by name + azdo pipelines queue show 'Fabrikam/Default' + + # Show a queue in a specific organization + azdo pipelines queue show 'myorg/Fabrikam/Default' + `), + Aliases: []string{"view", "status"}, + Args: util.ExactArgs(1, "queue target is required"), + RunE: func(cmd *cobra.Command, args []string) error { + opts.targetArg = args[0] + return runShow(ctx, opts) + }, + } + + cmd.Flags().BoolVarP(&opts.raw, "raw", "r", false, "Dump raw queue object to stderr") + util.AddJSONFlags(cmd, &opts.exporter, []string{ + "id", "name", "pool", "projectId", + }) + + return cmd +} + +func runShow(cmdCtx util.CmdContext, opts *showOptions) error { + ios, err := cmdCtx.IOStreams() + if err != nil { + return err + } + ios.StartProgressIndicator() + defer ios.StopProgressIndicator() + + scope, err := util.ParseProjectTargetWithDefaultOrganization(cmdCtx, opts.targetArg) + if err != nil { + return util.FlagErrorWrap(err) + } + + if len(scope.Targets) == 0 { + return util.FlagErrorf("queue target is required") + } + taskClient, err := cmdCtx.ClientFactory().TaskAgent(cmdCtx.Context(), scope.Organization) + if err != nil { + return fmt.Errorf("failed to create task agent client: %w", err) + } + + queueID, err := strconv.Atoi(scope.Targets[0]) + if err == nil { + if queueID <= 0 { + return util.FlagErrorf("invalid queue id %d", queueID) + } + } else { + queues, listErr := taskClient.GetAgentQueues(cmdCtx.Context(), taskagent.GetAgentQueuesArgs{ + Project: types.ToPtr(scope.Project), + QueueName: types.ToPtr(scope.Targets[0]), + }) + if listErr != nil { + return fmt.Errorf("failed to list queues: %w", listErr) + } + + matchCount := 0 + for _, q := range types.GetValue(queues, []taskagent.TaskAgentQueue{}) { + if q.Name == nil || !strings.EqualFold(*q.Name, scope.Targets[0]) { + continue + } + if q.Id == nil { + return fmt.Errorf("queue %q returned without an ID", scope.Targets[0]) + } + queueID = *q.Id + matchCount++ + } + + switch { + case matchCount == 0: + return fmt.Errorf("queue %q not found", scope.Targets[0]) + case matchCount > 1: + return fmt.Errorf("multiple queues named %q found; specify the numeric ID", scope.Targets[0]) + } + } + + zap.L().Debug( + "fetching queue", + zap.String("organization", scope.Organization), + zap.String("project", scope.Project), + zap.Int("queueId", queueID), + ) + + queue, err := taskClient.GetAgentQueue(cmdCtx.Context(), taskagent.GetAgentQueueArgs{ + QueueId: types.ToPtr(queueID), + Project: types.ToPtr(scope.Project), + }) + if err != nil { + return fmt.Errorf("failed to get queue: %w", err) + } + if queue == nil { + return fmt.Errorf("queue %q not found", scope.Targets[0]) + } + + if opts.raw { + ios.StopProgressIndicator() + spew.Dump(queue) + return nil + } + + if opts.exporter != nil { + ios.StopProgressIndicator() + return opts.exporter.Write(ios, queue) + } + + ios.StopProgressIndicator() + + t := template.New( + ios.Out, + ios.TerminalWidth(), + ios.ColorEnabled(), + ). + WithTheme(ios.TerminalTheme()). + WithFuncs(map[string]any{ + "hasText": template.HasText, + "s": template.StringOrEmpty, + "u": template.UUIDString, + }) + + err = t.Parse(showTempl) + if err != nil { + return err + } + + return t.ExecuteData(queue) +} diff --git a/internal/cmd/pipelines/queue/show/show.tpl b/internal/cmd/pipelines/queue/show/show.tpl new file mode 100644 index 00000000..b44509d9 --- /dev/null +++ b/internal/cmd/pipelines/queue/show/show.tpl @@ -0,0 +1,4 @@ +{{bold "id:"}} {{.Id}} +{{bold "name:"}} {{s .Name}} +{{if .ProjectId}}{{bold "project id:"}} {{u .ProjectId}}{{end}} +{{if .Pool}}{{bold "pool:"}} {{if .Pool.Id}}{{.Pool.Id}}{{end}}{{if hasText (s .Pool.Name)}} ({{s .Pool.Name}}){{end}}{{end}} From 7c8560a88f85bde25699a6f7024c746eab843f22 Mon Sep 17 00:00:00 2001 From: Codex CLI Date: Tue, 16 Jun 2026 15:08:41 +0000 Subject: [PATCH 2/4] =?UTF-8?q?test(pipelines):=20=F0=9F=A7=AA=20add=20que?= =?UTF-8?q?ue=20show=20command=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/pipelines/queue/show/show_test.go | 408 ++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 internal/cmd/pipelines/queue/show/show_test.go diff --git a/internal/cmd/pipelines/queue/show/show_test.go b/internal/cmd/pipelines/queue/show/show_test.go new file mode 100644 index 00000000..afab8b43 --- /dev/null +++ b/internal/cmd/pipelines/queue/show/show_test.go @@ -0,0 +1,408 @@ +package show + +import ( + "bytes" + "context" + "fmt" + "regexp" + "strings" + "testing" + + "github.com/google/uuid" + "github.com/microsoft/azure-devops-go-api/azuredevops/v7/taskagent" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/tmeckel/azdo-cli/internal/cmd/util" + "github.com/tmeckel/azdo-cli/internal/iostreams" + "github.com/tmeckel/azdo-cli/internal/mocks" + "github.com/tmeckel/azdo-cli/internal/types" +) + +type dependencies struct { + cmd *mocks.MockCmdContext + clientFact *mocks.MockClientFactory + taskClient *mocks.MockTaskAgentClient + config *mocks.MockConfig + auth *mocks.MockAuthConfig + ios *iostreams.IOStreams + stdout *bytes.Buffer +} + +var ansiRegexp = regexp.MustCompile(`\x1b\[[0-9;]*m`) + +func cleanOutput(out *bytes.Buffer) string { + return ansiRegexp.ReplaceAllString(out.String(), "") +} + +func newDependencies(t *testing.T) *dependencies { + t.Helper() + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + + io, _, out, _ := iostreams.Test() + io.SetStdoutTTY(true) + io.SetStderrTTY(true) + + deps := &dependencies{ + cmd: mocks.NewMockCmdContext(ctrl), + clientFact: mocks.NewMockClientFactory(ctrl), + taskClient: mocks.NewMockTaskAgentClient(ctrl), + config: mocks.NewMockConfig(ctrl), + auth: mocks.NewMockAuthConfig(ctrl), + ios: io, + stdout: out, + } + + deps.cmd.EXPECT().IOStreams().Return(deps.ios, nil).AnyTimes() + deps.cmd.EXPECT().Context().Return(context.Background()).AnyTimes() + deps.cmd.EXPECT().ClientFactory().Return(deps.clientFact).AnyTimes() + + return deps +} + +func (d *dependencies) setupDefaultOrg(org string) { + d.cmd.EXPECT().Config().Return(d.config, nil).AnyTimes() + d.config.EXPECT().Authentication().Return(d.auth).AnyTimes() + d.auth.EXPECT().GetDefaultOrganization().Return(org, nil).AnyTimes() +} + +func sampleQueue() *taskagent.TaskAgentQueue { + return &taskagent.TaskAgentQueue{ + Id: types.ToPtr(7), + Name: types.ToPtr("Default"), + ProjectId: types.ToPtr(uuid.MustParse("11111111-1111-1111-1111-111111111111")), + Pool: &taskagent.TaskAgentPoolReference{ + Id: types.ToPtr(42), + Name: types.ToPtr("pool-1"), + }, + } +} + +func TestNewCmd_RegistersAsShowLeaf(t *testing.T) { + t.Parallel() + + cmd := NewCmd(nil) + assert.Equal(t, "show", cmd.Name()) + assert.Contains(t, cmd.Aliases, "view") + assert.Contains(t, cmd.Aliases, "status") + assert.True(t, strings.HasPrefix(cmd.Use, "show [ORGANIZATION/]PROJECT/QUEUE")) + assert.NotNil(t, cmd.RunE) +} + +func TestNewCmd_RequiresOneArg(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.setupDefaultOrg("myorg") + + cmd := NewCmd(deps.cmd) + cmd.SetArgs([]string{}) + err := cmd.Execute() + require.Error(t, err) + assert.Contains(t, err.Error(), "queue target is required") +} + +func TestRunShow_ResolveByPositiveInteger(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, args taskagent.GetAgentQueueArgs) (*taskagent.TaskAgentQueue, error) { + assert.Equal(t, 7, *args.QueueId) + return sampleQueue(), nil + }) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7"} + err := runShow(deps.cmd, opts) + require.NoError(t, err) +} + +func TestRunShow_ResolveByName(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + + queueList := []taskagent.TaskAgentQueue{ + {Id: types.ToPtr(7), Name: types.ToPtr("Default")}, + } + deps.taskClient.EXPECT().GetAgentQueues(gomock.Any(), gomock.Any()). + Return(&queueList, nil) + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, args taskagent.GetAgentQueueArgs) (*taskagent.TaskAgentQueue, error) { + assert.Equal(t, 7, *args.QueueId) + return sampleQueue(), nil + }) + + opts := &showOptions{targetArg: "myorg/Fabrikam/Default"} + err := runShow(deps.cmd, opts) + require.NoError(t, err) +} + +func TestRunShow_TemplateOutput_BasicFields(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, args taskagent.GetAgentQueueArgs) (*taskagent.TaskAgentQueue, error) { + assert.Equal(t, 7, *args.QueueId) + assert.Equal(t, "Fabrikam", *args.Project) + return sampleQueue(), nil + }) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7"} + err := runShow(deps.cmd, opts) + require.NoError(t, err) + + output := cleanOutput(deps.stdout) + assert.Contains(t, output, "id: 7") + assert.Contains(t, output, "name: Default") + assert.Contains(t, output, "project id: 11111111-1111-1111-1111-111111111111") +} + +func TestRunShow_InvalidQueueID(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/0"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid queue id 0") +} + +func TestRunShow_TemplateOutput_Pool_Nested(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + + q := sampleQueue() + q.Pool = &taskagent.TaskAgentPoolReference{ + Id: types.ToPtr(42), + Name: types.ToPtr("pool-1"), + } + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(q, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7"} + err := runShow(deps.cmd, opts) + require.NoError(t, err) + + output := cleanOutput(deps.stdout) + assert.Contains(t, output, "pool: 42 (pool-1)") +} + +func TestRunShow_TemplateOutput_NoPool(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + + q := sampleQueue() + q.Pool = nil + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(q, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7"} + err := runShow(deps.cmd, opts) + require.NoError(t, err) + + output := cleanOutput(deps.stdout) + assert.NotContains(t, output, "pool:") +} + +func TestRunShow_JSONOutput(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(sampleQueue(), nil) + + exporter := util.NewJSONExporter() + opts := &showOptions{targetArg: "myorg/Fabrikam/7", exporter: exporter} + err := runShow(deps.cmd, opts) + require.NoError(t, err) + + output := cleanOutput(deps.stdout) + assert.Contains(t, output, `"id":7`) + assert.Contains(t, output, `"name":"Default"`) + assert.Contains(t, output, `"projectId":"11111111-1111-1111-1111-111111111111"`) + assert.NotContains(t, output, `"url":`) + assert.NotContains(t, output, `"createdBy":`) +} + +func TestRunShow_RawFlag(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + + q := sampleQueue() + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(q, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7", raw: true} + err := runShow(deps.cmd, opts) + require.NoError(t, err) + assert.Empty(t, cleanOutput(deps.stdout)) +} + +func TestRunShow_ProjectScopeParsing(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + targetArg string + defaultOrg string + wantOrg string + wantErr string + }{ + { + name: "explicit org", + targetArg: "myorg/Fabrikam/7", + wantOrg: "myorg", + }, + { + name: "implicit org from config", + targetArg: "Fabrikam/7", + defaultOrg: "default-org", + wantOrg: "default-org", + }, + { + name: "invalid input with too many segments", + targetArg: "org/proj/extra/7", + wantErr: "invalid input", + }, + { + name: "missing project segment", + targetArg: "7", + wantErr: "invalid input", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + deps := newDependencies(t) + if tt.defaultOrg != "" { + deps.setupDefaultOrg(tt.defaultOrg) + } + + if tt.wantErr == "" { + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), tt.wantOrg).Return(deps.taskClient, nil) + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(sampleQueue(), nil) + } + + opts := &showOptions{targetArg: tt.targetArg} + err := runShow(deps.cmd, opts) + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestRunShow_ClientFactoryError(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + expectedErr := fmt.Errorf("connection failed") + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(nil, expectedErr) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.ErrorIs(t, err, expectedErr) +} + +func TestRunShow_ResolveByName_ListError(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + expectedErr := fmt.Errorf("list failed") + deps.taskClient.EXPECT().GetAgentQueues(gomock.Any(), gomock.Any()).Return(nil, expectedErr) + + opts := &showOptions{targetArg: "myorg/Fabrikam/Default"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.ErrorIs(t, err, expectedErr) +} + +func TestRunShow_ResolveByName_MultipleMatches(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + queueList := []taskagent.TaskAgentQueue{ + {Id: types.ToPtr(7), Name: types.ToPtr("Default")}, + {Id: types.ToPtr(8), Name: types.ToPtr("default")}, + } + deps.taskClient.EXPECT().GetAgentQueues(gomock.Any(), gomock.Any()).Return(&queueList, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/Default"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.Contains(t, err.Error(), "multiple queues named") +} + +func TestRunShow_ResolveByName_MissingID(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + queueList := []taskagent.TaskAgentQueue{ + {Name: types.ToPtr("Default")}, + } + deps.taskClient.EXPECT().GetAgentQueues(gomock.Any(), gomock.Any()).Return(&queueList, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/Default"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.Contains(t, err.Error(), `queue "Default" returned without an ID`) +} + +func TestRunShow_ResolveByName_NotFound(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + queueList := []taskagent.TaskAgentQueue{{Id: types.ToPtr(7), Name: types.ToPtr("Other")}} + deps.taskClient.EXPECT().GetAgentQueues(gomock.Any(), gomock.Any()).Return(&queueList, nil) + + opts := &showOptions{targetArg: "myorg/Fabrikam/Default"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.Contains(t, err.Error(), `queue "Default" not found`) +} + +func TestRunShow_SDKError(t *testing.T) { + t.Parallel() + + deps := newDependencies(t) + deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) + expectedErr := fmt.Errorf("API error") + deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(nil, expectedErr) + + opts := &showOptions{targetArg: "myorg/Fabrikam/7"} + err := runShow(deps.cmd, opts) + require.Error(t, err) + assert.ErrorIs(t, err, expectedErr) +} +func TestNewCmd_HasFlags(t *testing.T) { + t.Parallel() + + cmd := NewCmd(nil) + rawFlag := cmd.Flag("raw") + require.NotNil(t, rawFlag) + assert.Equal(t, "r", rawFlag.Shorthand) + + jsonFlag := cmd.Flag("json") + require.NotNil(t, jsonFlag) +} From 8a18f88078216a3edae54b3d88791e8af16dd883 Mon Sep 17 00:00:00 2001 From: Codex CLI Date: Tue, 16 Jun 2026 15:34:44 +0000 Subject: [PATCH 3/4] refactor(pipelines): remove raw flag from queue show command --- internal/cmd/pipelines/queue/show/show.go | 9 ------- .../cmd/pipelines/queue/show/show_test.go | 26 +++++-------------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/internal/cmd/pipelines/queue/show/show.go b/internal/cmd/pipelines/queue/show/show.go index 690b9f4d..454826cf 100644 --- a/internal/cmd/pipelines/queue/show/show.go +++ b/internal/cmd/pipelines/queue/show/show.go @@ -8,7 +8,6 @@ import ( "github.com/MakeNowJust/heredoc/v2" "github.com/microsoft/azure-devops-go-api/azuredevops/v7/taskagent" - "github.com/spewerspew/spew" "github.com/spf13/cobra" "go.uber.org/zap" @@ -19,7 +18,6 @@ import ( type showOptions struct { targetArg string - raw bool exporter util.Exporter } @@ -55,7 +53,6 @@ func NewCmd(ctx util.CmdContext) *cobra.Command { }, } - cmd.Flags().BoolVarP(&opts.raw, "raw", "r", false, "Dump raw queue object to stderr") util.AddJSONFlags(cmd, &opts.exporter, []string{ "id", "name", "pool", "projectId", }) @@ -136,12 +133,6 @@ func runShow(cmdCtx util.CmdContext, opts *showOptions) error { return fmt.Errorf("queue %q not found", scope.Targets[0]) } - if opts.raw { - ios.StopProgressIndicator() - spew.Dump(queue) - return nil - } - if opts.exporter != nil { ios.StopProgressIndicator() return opts.exporter.Write(ios, queue) diff --git a/internal/cmd/pipelines/queue/show/show_test.go b/internal/cmd/pipelines/queue/show/show_test.go index afab8b43..5de01fae 100644 --- a/internal/cmd/pipelines/queue/show/show_test.go +++ b/internal/cmd/pipelines/queue/show/show_test.go @@ -236,21 +236,6 @@ func TestRunShow_JSONOutput(t *testing.T) { assert.NotContains(t, output, `"createdBy":`) } -func TestRunShow_RawFlag(t *testing.T) { - t.Parallel() - - deps := newDependencies(t) - deps.clientFact.EXPECT().TaskAgent(gomock.Any(), "myorg").Return(deps.taskClient, nil) - - q := sampleQueue() - deps.taskClient.EXPECT().GetAgentQueue(gomock.Any(), gomock.Any()).Return(q, nil) - - opts := &showOptions{targetArg: "myorg/Fabrikam/7", raw: true} - err := runShow(deps.cmd, opts) - require.NoError(t, err) - assert.Empty(t, cleanOutput(deps.stdout)) -} - func TestRunShow_ProjectScopeParsing(t *testing.T) { t.Parallel() @@ -399,10 +384,13 @@ func TestNewCmd_HasFlags(t *testing.T) { t.Parallel() cmd := NewCmd(nil) - rawFlag := cmd.Flag("raw") - require.NotNil(t, rawFlag) - assert.Equal(t, "r", rawFlag.Shorthand) - jsonFlag := cmd.Flag("json") require.NotNil(t, jsonFlag) } + +func TestNewCmd_DoesNotExposeRawFlag(t *testing.T) { + t.Parallel() + + cmd := NewCmd(nil) + assert.Nil(t, cmd.Flag("raw")) +} From fe9d5c425e19a194fc95635cf45fa511c2477c2d Mon Sep 17 00:00:00 2001 From: Codex CLI Date: Tue, 16 Jun 2026 15:35:20 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs(pipelines):=20=F0=9F=93=84=20add=20doc?= =?UTF-8?q?umentation=20for=20pipelines=20queue=20show?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/azdo_help_reference.md | 16 ++++++++++ docs/azdo_pipelines_queue.md | 1 + docs/azdo_pipelines_queue_show.md | 52 +++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 docs/azdo_pipelines_queue_show.md diff --git a/docs/azdo_help_reference.md b/docs/azdo_help_reference.md index 75c724f2..e699a7a6 100644 --- a/docs/azdo_help_reference.md +++ b/docs/azdo_help_reference.md @@ -395,6 +395,22 @@ Aliases ls, l ``` +#### `azdo pipelines queue show [ORGANIZATION/]PROJECT/QUEUE [flags]` + +Show details of an agent queue + +``` +-q, --jq expression Filter JSON output using a jq expression + --json fields[=*] Output JSON with the specified fields. Prefix a field with '-' to exclude it. +-t, --template string Format JSON output using a Go template; see "azdo help formatting" +``` + +Aliases + +``` +view, status +``` + ### `azdo pipelines run [ORGANIZATION/]PROJECT/PIPELINE [flags]` Queue a pipeline run diff --git a/docs/azdo_pipelines_queue.md b/docs/azdo_pipelines_queue.md index 61ca5e61..aef5f5fb 100644 --- a/docs/azdo_pipelines_queue.md +++ b/docs/azdo_pipelines_queue.md @@ -7,6 +7,7 @@ and connect a project to an agent pool. ### Available commands * [azdo pipelines queue list](./azdo_pipelines_queue_list.md) +* [azdo pipelines queue show](./azdo_pipelines_queue_show.md) ### Examples diff --git a/docs/azdo_pipelines_queue_show.md b/docs/azdo_pipelines_queue_show.md new file mode 100644 index 00000000..2122cbc8 --- /dev/null +++ b/docs/azdo_pipelines_queue_show.md @@ -0,0 +1,52 @@ +## Command `azdo pipelines queue show` + +``` +azdo pipelines queue show [ORGANIZATION/]PROJECT/QUEUE [flags] +``` + +Display the details of a single Azure DevOps agent queue. +The queue is identified by integer ID or name, with an +optional organization prefix. + + +### Options + + +* `-q`, `--jq` `expression` + + Filter JSON output using a jq expression + +* `--json` `fields` + + Output JSON with the specified fields. Prefix a field with '-' to exclude it. + +* `-t`, `--template` `string` + + Format JSON output using a Go template; see "azdo help formatting" + + +### ALIASES + +- `view` +- `status` + +### JSON Fields + +`id`, `name`, `pool`, `projectId` + +### Examples + +```bash +# Show a queue by ID +azdo pipelines queue show Fabrikam/7 + +# Show a queue by name +azdo pipelines queue show 'Fabrikam/Default' + +# Show a queue in a specific organization +azdo pipelines queue show 'myorg/Fabrikam/Default' +``` + +### See also + +* [azdo pipelines queue](./azdo_pipelines_queue.md)