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
27 changes: 27 additions & 0 deletions docs/azdo_help_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,33 @@ Aliases
view, status
```

### `azdo pipelines pool`

Manage agent pools

Aliases

```
pools
```

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

Show details of an agent pool

```
-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.
-r, --raw Dump raw pool object to stderr
-t, --template string Format JSON output using a Go template; see "azdo help formatting"
```

Aliases

```
view, status
```

### `azdo pipelines variable-group`

Manage Azure DevOps variable groups
Expand Down
1 change: 1 addition & 0 deletions docs/azdo_pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Manage Azure DevOps pipelines
### Available commands

* [azdo pipelines agent](./azdo_pipelines_agent.md)
* [azdo pipelines pool](./azdo_pipelines_pool.md)
* [azdo pipelines variable-group](./azdo_pipelines_variable-group.md)

### ALIASES
Expand Down
30 changes: 30 additions & 0 deletions docs/azdo_pipelines_pool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Command `azdo pipelines pool`

Manage Azure DevOps agent pools. Agent pools are logical groupings
of agents that target build, release, and other pipeline jobs.


### Available commands

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

### ALIASES

- `pools`

### Examples

```bash
# Show a pool by ID
azdo pipelines pool show 42

# Show a pool by name
azdo pipelines pool show 'Default'

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

### See also

* [azdo pipelines](./azdo_pipelines.md)
56 changes: 56 additions & 0 deletions docs/azdo_pipelines_pool_show.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## Command `azdo pipelines pool show`

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

Display the details of a single Azure DevOps agent pool.
The pool 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.

* `-r`, `--raw`

Dump raw pool object to stderr

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

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


### ALIASES

- `view`
- `status`

### JSON Fields

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

### Examples

```bash
# Show a pool by ID
azdo pipelines pool show 42

# Show a pool by name
azdo pipelines pool show 'Default'

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

### See also

* [azdo pipelines pool](./azdo_pipelines_pool.md)
2 changes: 0 additions & 2 deletions internal/cmd/pipelines/agent/shared/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,6 @@ func TestResolveAgent_Ambiguous(t *testing.T) {
assert.Contains(t, err.Error(), "multiple agents")
}



func TestResolvePoolAgent_NegativePoolID(t *testing.T) {
t.Parallel()
ctrl := newCtrl(t)
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/pipelines/pipelines.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pipelines
import (
"github.com/spf13/cobra"
"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/agent"
"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/pool"
"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/variablegroup"
"github.com/tmeckel/azdo-cli/internal/cmd/util"
)
Expand All @@ -16,5 +17,6 @@ func NewCmd(ctx util.CmdContext) *cobra.Command {

cmd.AddCommand(variablegroup.NewCmd(ctx))
cmd.AddCommand(agent.NewCmd(ctx))
cmd.AddCommand(pool.NewCmd(ctx))
return cmd
}
34 changes: 34 additions & 0 deletions internal/cmd/pipelines/pool/pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package pool

import (
"github.com/MakeNowJust/heredoc/v2"
"github.com/spf13/cobra"

"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/pool/show"
"github.com/tmeckel/azdo-cli/internal/cmd/util"
)

func NewCmd(ctx util.CmdContext) *cobra.Command {
cmd := &cobra.Command{
Use: "pool",
Short: "Manage agent pools",
Long: heredoc.Doc(`
Manage Azure DevOps agent pools. Agent pools are logical groupings
of agents that target build, release, and other pipeline jobs.
`),
Example: heredoc.Doc(`
# Show a pool by ID
azdo pipelines pool show 42

# Show a pool by name
azdo pipelines pool show 'Default'

# Show a pool in a specific organization
azdo pipelines pool show 'myorg/Default'
`),
Aliases: []string{"pools"},
}

cmd.AddCommand(show.NewCmd(ctx))
return cmd
}
146 changes: 146 additions & 0 deletions internal/cmd/pipelines/pool/show/show.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package show

import (
_ "embed"
"fmt"

"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"

agentShared "github.com/tmeckel/azdo-cli/internal/cmd/pipelines/agent/shared"
"github.com/tmeckel/azdo-cli/internal/cmd/util"
"github.com/tmeckel/azdo-cli/internal/template"
"github.com/tmeckel/azdo-cli/internal/types"
)

type templateData struct {
Pool *taskagent.TaskAgentPool
}

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/]POOL",
Short: "Show details of an agent pool",
Long: heredoc.Doc(`
Display the details of a single Azure DevOps agent pool.
The pool is identified by integer ID or name, with an
optional organization prefix.
`),
Example: heredoc.Doc(`
# Show a pool by ID
azdo pipelines pool show 42

# Show a pool by name
azdo pipelines pool show 'Default'

# Show a pool in a specific organization
azdo pipelines pool show 'myorg/Default'
`),
Aliases: []string{"view", "status"},
Args: util.ExactArgs(1, "pool 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 pool object to stderr")
util.AddJSONFlags(cmd, &opts.exporter, []string{
"id", "name", "poolType", "isHosted", "isLegacy",
"autoProvision", "autoUpdate", "createdOn", "createdBy",
"owner", "options", "properties", "scope", "size", "targetSize",
})

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.ParseTargetWithDefaultOrganization(cmdCtx, opts.targetArg)
if err != nil {
return util.FlagErrorWrap(err)
}

if len(scope.Targets) == 0 {
return util.FlagErrorf("pool target is required")
}
poolTarget := scope.Targets[0]

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

poolID, err := agentShared.ResolvePool(cmdCtx, taskClient, poolTarget)
if err != nil {
return err
}

zap.L().Debug(
"fetching pool",
zap.String("organization", scope.Organization),
zap.Int("poolId", poolID),
)

pool, err := taskClient.GetAgentPool(cmdCtx.Context(), taskagent.GetAgentPoolArgs{
PoolId: types.ToPtr(poolID),
})
if err != nil {
return fmt.Errorf("failed to get pool: %w", err)
}
if pool == nil {
return fmt.Errorf("pool %q not found", poolTarget)
}

if opts.raw {
ios.StopProgressIndicator()
spew.Dump(pool)
return nil
}

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

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(templateData{Pool: pool})
}
22 changes: 22 additions & 0 deletions internal/cmd/pipelines/pool/show/show.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{bold "id:"}} {{.Pool.Id}}
{{bold "name:"}} {{s .Pool.Name}}
{{if hasText (s .Pool.PoolType)}}{{bold "type:"}} {{.Pool.PoolType}}
{{end -}}
{{if hasText (u .Pool.Scope)}}{{bold "scope:"}} {{u .Pool.Scope}}
{{end -}}
{{if .Pool.Size}}{{bold "size:"}} {{.Pool.Size}}
{{end -}}
{{if .Pool.IsHosted}}{{bold "is hosted:"}} {{.Pool.IsHosted}}
{{end -}}
{{if .Pool.IsLegacy}}{{bold "is legacy:"}} {{.Pool.IsLegacy}}
{{end -}}
{{if .Pool.AutoProvision}}{{bold "auto provision:"}} {{.Pool.AutoProvision}}
{{end -}}
{{if .Pool.AutoUpdate}}{{bold "auto update:"}} {{.Pool.AutoUpdate}}
{{end -}}
{{if .Pool.CreatedOn}}{{bold "created on:"}} {{timeago .Pool.CreatedOn.Time}} ({{timefmt "2006-01-02 15:04 MST" .Pool.CreatedOn.Time}})
{{end -}}
{{if .Pool.CreatedBy}}{{if hasText (s .Pool.CreatedBy.DisplayName)}}{{bold "created by:"}} {{s .Pool.CreatedBy.DisplayName}} ({{s .Pool.CreatedBy.UniqueName}})
{{end}}{{end -}}
{{if .Pool.Owner}}{{if hasText (s .Pool.Owner.DisplayName)}}{{bold "owner:"}} {{s .Pool.Owner.DisplayName}} ({{s .Pool.Owner.UniqueName}})
{{end}}{{end -}}
Loading
Loading