diff --git a/cli/admin/admin.go b/cli/admin/admin.go index 110c210d4..0c2464154 100644 --- a/cli/admin/admin.go +++ b/cli/admin/admin.go @@ -18,6 +18,7 @@ import ( "github.com/urfave/cli/v3" "go.woodpecker-ci.org/woodpecker/v3/cli/admin/loglevel" + "go.woodpecker-ci.org/woodpecker/v3/cli/admin/org" "go.woodpecker-ci.org/woodpecker/v3/cli/admin/registry" "go.woodpecker-ci.org/woodpecker/v3/cli/admin/secret" "go.woodpecker-ci.org/woodpecker/v3/cli/admin/user" @@ -29,6 +30,7 @@ var Command = &cli.Command{ Usage: "manage server settings", Commands: []*cli.Command{ loglevel.Command, + org.Command, registry.Command, secret.Command, user.Command, diff --git a/cli/admin/org/org_list.go b/cli/admin/org/org_list.go new file mode 100644 index 000000000..e5f50068e --- /dev/null +++ b/cli/admin/org/org_list.go @@ -0,0 +1,71 @@ +package org + +import ( + "context" + "os" + "strings" + "text/template" + + "github.com/urfave/cli/v3" + + "go.woodpecker-ci.org/woodpecker/v3/cli/common" + "go.woodpecker-ci.org/woodpecker/v3/cli/internal" + "go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker" +) + +var Command = &cli.Command{ + Name: "org", + Usage: "manage organizations", + Commands: []*cli.Command{ + orgListCmd, + }, +} + +var orgListCmd = &cli.Command{ + Name: "ls", + Usage: "list organizations", + ArgsUsage: "", + Action: orgList, + Flags: []cli.Flag{ + common.FormatFlag(tmplOrgList, true), + }, +} + +func orgList(ctx context.Context, c *cli.Command) error { + format := c.String("format") + "\n" + + client, err := internal.NewClient(ctx, c) + if err != nil { + return err + } + + opt := woodpecker.ListOptions{} + + list, err := client.OrgList(opt) + if err != nil { + return err + } + + tmpl, err := template.New("_").Funcs(orgFuncMap).Parse(format) + if err != nil { + return err + } + + for _, org := range list { + if err := tmpl.Execute(os.Stdout, org); err != nil { + return err + } + } + return nil +} + +// Template for org list items. +var tmplOrgList = "\x1b[33m{{ .Name }} \x1b[0m" + ` +Organization ID: {{ .ID }} +` + +var orgFuncMap = template.FuncMap{ + "list": func(s []string) string { + return strings.Join(s, ", ") + }, +} diff --git a/woodpecker-go/woodpecker/interface.go b/woodpecker-go/woodpecker/interface.go index 4f29717fd..cad1c460c 100644 --- a/woodpecker-go/woodpecker/interface.go +++ b/woodpecker-go/woodpecker/interface.go @@ -186,6 +186,9 @@ type Client interface { // OrgLookup returns an organization id by name. OrgLookup(orgName string) (*Org, error) + // OrgList returns a list of all organizations. + OrgList(opt ListOptions) ([]*Org, error) + // OrgSecret returns an organization secret by name. OrgSecret(orgID int64, secret string) (*Secret, error) diff --git a/woodpecker-go/woodpecker/mocks/client.go b/woodpecker-go/woodpecker/mocks/client.go index 14472581c..d94b4500b 100644 --- a/woodpecker-go/woodpecker/mocks/client.go +++ b/woodpecker-go/woodpecker/mocks/client.go @@ -707,6 +707,36 @@ func (_m *Client) Org(orgID int64) (*woodpecker.Org, error) { return r0, r1 } +// OrgList provides a mock function with given fields: opt +func (_m *Client) OrgList(opt woodpecker.ListOptions) ([]*woodpecker.Org, error) { + ret := _m.Called(opt) + + if len(ret) == 0 { + panic("no return value specified for OrgList") + } + + var r0 []*woodpecker.Org + var r1 error + if rf, ok := ret.Get(0).(func(woodpecker.ListOptions) ([]*woodpecker.Org, error)); ok { + return rf(opt) + } + if rf, ok := ret.Get(0).(func(woodpecker.ListOptions) []*woodpecker.Org); ok { + r0 = rf(opt) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*woodpecker.Org) + } + } + + if rf, ok := ret.Get(1).(func(woodpecker.ListOptions) error); ok { + r1 = rf(opt) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // OrgLookup provides a mock function with given fields: orgName func (_m *Client) OrgLookup(orgName string) (*woodpecker.Org, error) { ret := _m.Called(orgName) diff --git a/woodpecker-go/woodpecker/org.go b/woodpecker-go/woodpecker/org.go index 5d00b86d9..7e6f15895 100644 --- a/woodpecker-go/woodpecker/org.go +++ b/woodpecker-go/woodpecker/org.go @@ -8,6 +8,7 @@ import ( const ( pathOrg = "%s/api/orgs/%d" pathOrgLookup = "%s/api/orgs/lookup/%s" + pathOrgList = "%s/api/orgs" pathOrgSecrets = "%s/api/orgs/%d/secrets" pathOrgSecret = "%s/api/orgs/%d/secrets/%s" pathOrgRegistries = "%s/api/orgs/%d/registries" @@ -30,6 +31,14 @@ func (c *client) OrgLookup(name string) (*Org, error) { return out, err } +func (c *client) OrgList(opt ListOptions) ([]*Org, error) { + var out []*Org + uri, _ := url.Parse(fmt.Sprintf(pathOrgList, c.addr)) + uri.RawQuery = opt.getURLQuery().Encode() + err := c.get(uri.String(), &out) + return out, err +} + // OrgSecret returns an organization secret by name. func (c *client) OrgSecret(orgID int64, secret string) (*Secret, error) { out := new(Secret)