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
63 changes: 51 additions & 12 deletions pkg/cmd/agent/list.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,70 @@
package agent

import (
"os"

"github.com/MakeNowJust/heredoc"
"github.com/buildkite/cli/v3/internal/agent"
"github.com/buildkite/cli/v3/pkg/cmd/factory"
"github.com/buildkite/cli/v3/pkg/output"
buildkite "github.com/buildkite/go-buildkite/v4"
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
)

func NewCmdAgentList(f *factory.Factory) *cobra.Command {
var name, version, hostname string
var perpage int
var perpage, limit int

cmd := cobra.Command{
DisableFlagsInUseLine: true,
Use: "list",
Args: cobra.NoArgs,
Short: "List agents",
Long: heredoc.Doc(`
List all connected agents for the current organization.
List connected agents for the current organization.

By default, shows up to 100 agents. Use filters to narrow results, or increase the number of agents displayed with --limit.
`),
RunE: func(cmd *cobra.Command, args []string) error {
format, err := output.GetFormat(cmd.Flags())
if err != nil {
return err
}

if format != output.FormatText {
agents := []buildkite.Agent{}
page := 1

for len(agents) < limit && page < 50 {
opts := buildkite.AgentListOptions{
Name: name,
Hostname: hostname,
Version: version,
ListOptions: buildkite.ListOptions{
Page: page,
PerPage: perpage,
},
}

pageAgents, _, err := f.RestAPIClient.Agents.List(cmd.Context(), f.Config.OrganizationSlug(), &opts)
if err != nil {
return err
}

if len(pageAgents) == 0 {
break
}

agents = append(agents, pageAgents...)
page++
}

if len(agents) > limit {
agents = agents[:limit]
}

return output.Write(cmd.OutOrStdout(), agents, format)
}

loader := func(page int) tea.Cmd {
return func() tea.Msg {
opts := buildkite.AgentListOptions{
Expand Down Expand Up @@ -55,19 +96,17 @@ func NewCmdAgentList(f *factory.Factory) *cobra.Command {
model := agent.NewAgentList(loader, 1, perpage)

p := tea.NewProgram(model, tea.WithAltScreen())

if _, err := p.Run(); err != nil {
os.Exit(1)
}

return nil
_, err = p.Run()
return err
},
}

cmd.Flags().StringVar(&name, "name", "", "Filter agents by their name")
cmd.Flags().StringVar(&version, "version", "", "Filter agents by their agent version")
cmd.Flags().StringVar(&version, "version", "", "Filter agents by their version")
cmd.Flags().StringVar(&hostname, "hostname", "", "Filter agents by their hostname")
cmd.Flags().IntVar(&perpage, "per-page", 30, "Number of agents to fetch per API call")
cmd.Flags().IntVar(&perpage, "per-page", 30, "Number of agents per page")
cmd.Flags().IntVar(&limit, "limit", 100, "Maximum number of agents to return")
output.AddFlags(cmd.Flags())

return &cmd
}
118 changes: 118 additions & 0 deletions pkg/cmd/agent/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package agent_test

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/buildkite/cli/v3/internal/config"
"github.com/buildkite/cli/v3/pkg/cmd/agent"
"github.com/buildkite/cli/v3/pkg/cmd/factory"
buildkite "github.com/buildkite/go-buildkite/v4"
"github.com/spf13/afero"
)

func TestCmdAgentList(t *testing.T) {
t.Parallel()

t.Run("returns agents as JSON", func(t *testing.T) {
t.Parallel()

agents := []buildkite.Agent{
{ID: "123", Name: "my-agent"},
{ID: "456", Name: "another-agent"},
}

s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
page := r.URL.Query().Get("page")
if page == "" || page == "1" {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(agents)
} else {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode([]buildkite.Agent{})
}
}))
defer s.Close()

apiClient, err := buildkite.NewOpts(buildkite.WithBaseURL(s.URL))
if err != nil {
t.Fatal(err)
}

conf := config.New(afero.NewMemMapFs(), nil)
conf.SelectOrganization("test", true)

factory := &factory.Factory{
RestAPIClient: apiClient,
Config: conf,
}

cmd := agent.NewCmdAgentList(factory)
cmd.SetArgs([]string{"-o", "json"})

var buf bytes.Buffer
cmd.SetOut(&buf)

err = cmd.Execute()
if err != nil {
t.Fatal(err)
}

var result []buildkite.Agent
err = json.Unmarshal(buf.Bytes(), &result)
if err != nil {
t.Fatal(err)
}

if len(result) != 2 {
t.Errorf("got %d agents, want 2", len(result))
}

if result[0].Name != "my-agent" {
t.Errorf("got agent name %q, want %q", result[0].Name, "my-agent")
}
})

t.Run("empty result returns empty array", func(t *testing.T) {
t.Parallel()

s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("[]"))
}))
defer s.Close()

apiClient, err := buildkite.NewOpts(buildkite.WithBaseURL(s.URL))
if err != nil {
t.Fatal(err)
}

conf := config.New(afero.NewMemMapFs(), nil)
conf.SelectOrganization("test", true)

factory := &factory.Factory{
RestAPIClient: apiClient,
Config: conf,
}

cmd := agent.NewCmdAgentList(factory)
cmd.SetArgs([]string{"-o", "json"})

var buf bytes.Buffer
cmd.SetOut(&buf)

err = cmd.Execute()
if err != nil {
t.Fatal(err)
}

got := strings.TrimSpace(buf.String())
if got != "[]" {
t.Errorf("got %q, want %q", got, "[]")
}
})
}
1 change: 1 addition & 0 deletions pkg/cmd/job/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func NewCmdJob(f *factory.Factory) *cobra.Command {
PersistentPreRunE: validation.CheckValidConfiguration(f.Config),
}

cmd.AddCommand(NewCmdJobList(f))
cmd.AddCommand(NewCmdJobUnblock(f))
cmd.AddCommand(NewCmdJobRetry(f))

Expand Down
Loading