Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/azdo_help_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,25 @@ Aliases
pools
```

#### `azdo pipelines pool list [ORGANIZATION] [flags]`

List agent pools

```
-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.
--max-items int Optional client-side cap on results
--name string Filter pools by name
--pool-type string Filter pools by type: {automation|deployment}
-t, --template string Format JSON output using a Go template; see "azdo help formatting"
```

Aliases

```
ls, l
```

#### `azdo pipelines pool show [ORGANIZATION/]POOL [flags]`

Show details of an agent pool
Expand Down
7 changes: 7 additions & 0 deletions docs/azdo_pipelines_pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ of agents that target build, release, and other pipeline jobs.

### Available commands

* [azdo pipelines pool list](./azdo_pipelines_pool_list.md)
* [azdo pipelines pool show](./azdo_pipelines_pool_show.md)

### ALIASES
Expand All @@ -23,6 +24,12 @@ azdo pipelines pool show 'Default'

# Show a pool in a specific organization
azdo pipelines pool show 'myorg/Default'

# List pools in the default organization
azdo pipelines pool list

# List pools in a specific organization
azdo pipelines pool list myorg
```

### See also
Expand Down
68 changes: 68 additions & 0 deletions docs/azdo_pipelines_pool_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
## Command `azdo pipelines pool list`

```
azdo pipelines pool list [ORGANIZATION] [flags]
```

List Azure DevOps agent pools for an organization.


### 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.

* `--max-items` `int` (default `0`)

Optional client-side cap on results

* `--name` `string`

Filter pools by name

* `--pool-type` `string`

Filter pools by type: {automation|deployment}

* `-t`, `--template` `string`

Format JSON output using a Go template; see "azdo help formatting"


### ALIASES

- `ls`
- `l`

### JSON Fields

`agentCloudId`, `autoProvision`, `autoSize`, `autoUpdate`, `createdBy`, `createdOn`, `id`, `isHosted`, `isLegacy`, `name`, `options`, `owner`, `poolType`, `properties`, `scope`, `size`, `targetSize`

### Examples

```bash
# List all pools in the default organization
azdo pipelines pool list

# List pools in a specific organization
azdo pipelines pool list myorg

# List pools filtered by name
azdo pipelines pool list myorg --name Default

# List deployment pools
azdo pipelines pool list myorg --pool-type deployment

# Output as JSON
azdo pipelines pool list myorg --json
```

### See also

* [azdo pipelines pool](./azdo_pipelines_pool.md)
165 changes: 165 additions & 0 deletions internal/cmd/pipelines/pool/list/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package list

import (
"fmt"
"strings"

"github.com/MakeNowJust/heredoc/v2"
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/taskagent"
"github.com/spf13/cobra"
"go.uber.org/zap"

"github.com/tmeckel/azdo-cli/internal/cmd/util"
"github.com/tmeckel/azdo-cli/internal/types"
)

type opts struct {
orgArg string
name string
poolType string
maxItems int
exporter util.Exporter
}

func NewCmd(ctx util.CmdContext) *cobra.Command {
opts := &opts{}

cmd := &cobra.Command{
Use: "list [ORGANIZATION]",
Short: "List agent pools",
Long: heredoc.Doc(`
List Azure DevOps agent pools for an organization.
`),
Example: heredoc.Doc(`
# List all pools in the default organization
azdo pipelines pool list

# List pools in a specific organization
azdo pipelines pool list myorg

# List pools filtered by name
azdo pipelines pool list myorg --name Default

# List deployment pools
azdo pipelines pool list myorg --pool-type deployment

# Output as JSON
azdo pipelines pool list myorg --json
`),
Aliases: []string{
"ls",
"l",
},
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
opts.orgArg = args[0]
}
return run(ctx, opts)
},
}

cmd.Flags().StringVar(&opts.name, "name", "", "Filter pools by name")
util.StringEnumFlag(cmd, &opts.poolType, "pool-type", "", "", []string{
string(taskagent.TaskAgentPoolTypeValues.Automation),
string(taskagent.TaskAgentPoolTypeValues.Deployment),
}, "Filter pools by type")
cmd.Flags().IntVar(&opts.maxItems, "max-items", 0, "Optional client-side cap on results")
util.AddJSONFlags(cmd, &opts.exporter, []string{
"id", "isHosted", "isLegacy", "name", "options", "poolType",
"scope", "size", "agentCloudId", "autoProvision", "autoSize",
"autoUpdate", "createdBy", "createdOn", "owner", "properties",
"targetSize",
})

return cmd
}

func run(cmdCtx util.CmdContext, opts *opts) error {
ios, err := cmdCtx.IOStreams()
if err != nil {
return err
}
ios.StartProgressIndicator()
defer ios.StopProgressIndicator()

if opts.maxItems < 0 {
return util.FlagErrorf("invalid --max-items value %d; must be >= 0", opts.maxItems)
}

organization, err := util.ParseOrganizationArg(cmdCtx, opts.orgArg)
if err != nil {
return util.FlagErrorWrap(err)
}

taskClient, err := cmdCtx.ClientFactory().TaskAgent(cmdCtx.Context(), organization)
if err != nil {
return fmt.Errorf("failed to create task agent client: %w", err)
}

var poolType *taskagent.TaskAgentPoolType
if trimmed := strings.TrimSpace(opts.poolType); trimmed != "" {
value := taskagent.TaskAgentPoolType(strings.ToLower(trimmed))
poolType = &value
}

args := taskagent.GetAgentPoolsArgs{
PoolName: types.NotZeroPtrOrNil(strings.TrimSpace(opts.name)),
PoolType: poolType,
}

zap.L().Debug(
"listing agent pools",
zap.String("organization", organization),
zap.String("poolName", types.GetValue(args.PoolName, "")),
zap.String("poolType", string(types.GetValue(args.PoolType, taskagent.TaskAgentPoolType("")))),
)

resp, err := taskClient.GetAgentPools(cmdCtx.Context(), args)
if err != nil {
return fmt.Errorf("failed to list pools: %w", err)
}

pools := []taskagent.TaskAgentPool{}
if resp != nil {
pools = *resp
}

if opts.maxItems > 0 && len(pools) > opts.maxItems {
zap.L().Debug("truncating result set to max-items", zap.Int("maxItems", opts.maxItems))
pools = pools[:opts.maxItems]
}

ios.StopProgressIndicator()

if opts.exporter != nil {
return opts.exporter.Write(ios, pools)
}

tp, err := cmdCtx.Printer("list")
if err != nil {
return err
}

tp.AddColumns("ID", "NAME", "POOL TYPE", "SCOPE", "SIZE", "IS HOSTED", "IS LEGACY", "AUTO PROVISION", "CREATED ON")

for _, pool := range pools {
scope := ""
if pool.Scope != nil {
scope = pool.Scope.String()
}

tp.AddField(fmt.Sprintf("%d", types.GetValue(pool.Id, 0)))
tp.AddField(types.GetValue(pool.Name, ""))
tp.AddField(string(types.GetValue(pool.PoolType, "")))
tp.AddField(scope)
tp.AddField(fmt.Sprintf("%d", types.GetValue(pool.Size, 0)))
tp.AddField(fmt.Sprintf("%v", types.GetValue(pool.IsHosted, false)))
tp.AddField(fmt.Sprintf("%v", types.GetValue(pool.IsLegacy, false)))
tp.AddField(fmt.Sprintf("%v", types.GetValue(pool.AutoProvision, false)))
tp.AddField(util.FormatTimeShort(pool.CreatedOn))
tp.EndRow()
}

return tp.Render()
}
Loading
Loading