Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cdsctl): action usage command #5025

Merged
merged 2 commits into from
Mar 4, 2020
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
42 changes: 42 additions & 0 deletions cli/cdsctl/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"path"
"time"
"strings"

"github.com/spf13/cobra"

Expand All @@ -28,6 +29,7 @@ var actionBuiltinCmd = cli.Command{
func action() *cobra.Command {
return cli.NewCommand(actionCmd, nil, []*cobra.Command{
cli.NewListCommand(actionListCmd, actionListRun, nil),
cli.NewListCommand(actionUsageCmd, actionUsageRun, nil),
cli.NewGetCommand(actionShowCmd, actionShowRun, nil),
cli.NewCommand(actionDeleteCmd, actionDeleteRun, nil),
cli.NewCommand(actionDocCmd, actionDocRun, nil),
Expand Down Expand Up @@ -87,6 +89,46 @@ func actionListRun(v cli.Values) (cli.ListResult, error) {
return cli.AsListResult(ads), nil
}

var actionUsageCmd = cli.Command{
Name: "usage",
Short: "CDS action usage",
Args: []cli.Arg{
{Name: "action-path"},
},
}

func actionUsageRun(v cli.Values) (cli.ListResult, error) {
groupName, actionName, err := cli.ParsePath(v.GetString("action-path"))
if err != nil {
return nil, err
}

usages, err := client.ActionUsage(groupName, actionName)
if err != nil {
return nil, err
}

type ActionUsageDisplay struct {
Type string `cli:"Type"`
Path string `cli:"Path"`
}

au := []ActionUsageDisplay{}
for _, v := range usages.Pipelines {
au = append(au, ActionUsageDisplay{
Type: "pipeline",
Path: strings.Replace(fmt.Sprintf("%s - %s - %s", v.ProjectName, v.PipelineName, v.ActionName)," "," ",-1),
})
}
for _, v := range usages.Actions {
au = append(au, ActionUsageDisplay{
Type: "action",
Path: fmt.Sprintf("%s/%s", v.GroupName, v.ParentActionName),
})
}
return cli.AsListResult(au), nil
}

var actionShowCmd = cli.Command{
Name: "show",
Short: "Show a CDS action",
Expand Down
8 changes: 4 additions & 4 deletions engine/api/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,8 @@ func (api *API) getActionBuiltinUsageHandler() service.Handler {
}
}

func getActionUsage(ctx context.Context, db gorp.SqlExecutor, store cache.Store, a *sdk.Action) (action.Usage, error) {
var usage action.Usage
func getActionUsage(ctx context.Context, db gorp.SqlExecutor, store cache.Store, a *sdk.Action) (sdk.ActionUsages, error) {
var usage sdk.ActionUsages
var err error
usage.Pipelines, err = action.GetPipelineUsages(db, group.SharedInfraGroup.ID, a.ID)
if err != nil {
Expand All @@ -848,7 +848,7 @@ func getActionUsage(ctx context.Context, db gorp.SqlExecutor, store cache.Store,
mProjectIDs[ps[i].ID] = struct{}{}
}

filteredPipelines := make([]action.UsagePipeline, 0, len(usage.Pipelines))
filteredPipelines := make([]sdk.UsagePipeline, 0, len(usage.Pipelines))
for i := range usage.Pipelines {
if _, ok := mProjectIDs[usage.Pipelines[i].ProjectID]; ok {
filteredPipelines = append(filteredPipelines, usage.Pipelines[i])
Expand All @@ -863,7 +863,7 @@ func getActionUsage(ctx context.Context, db gorp.SqlExecutor, store cache.Store,
mGroupIDs[groupIDs[i]] = struct{}{}
}

filteredActions := make([]action.UsageAction, 0, len(usage.Actions))
filteredActions := make([]sdk.UsageAction, 0, len(usage.Actions))
for i := range usage.Actions {
if _, ok := mGroupIDs[usage.Actions[i].GroupID]; ok {
filteredActions = append(filteredActions, usage.Actions[i])
Expand Down
45 changes: 6 additions & 39 deletions engine/api/action/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,8 @@ import (
"github.com/ovh/cds/sdk"
)

// Usage for action.
type Usage struct {
Pipelines []UsagePipeline `json:"pipelines"`
Actions []UsageAction `json:"actions"`
}

// UsagePipeline represent a pipeline using an action.
type UsagePipeline struct {
ProjectID int64 `json:"project_id"`
ProjectKey string `json:"project_key"`
ProjectName string `json:"project_name"`
PipelineID int64 `json:"pipeline_id"`
PipelineName string `json:"pipeline_name"`
StageID int64 `json:"stage_id"`
StageName string `json:"stage_name"`
JobID int64 `json:"job_id"`
JobName string `json:"job_name"`
ActionID int64 `json:"action_id"`
ActionName string `json:"action_name"`
Warning bool `json:"warning"`
}

// GetPipelineUsages returns the list of pipelines using an action
func GetPipelineUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64) ([]UsagePipeline, error) {
func GetPipelineUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64) ([]sdk.UsagePipeline, error) {
rows, err := db.Query(`
SELECT DISTINCT
project.id, project.projectKey, project.name,
Expand All @@ -54,9 +32,9 @@ func GetPipelineUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64)
}
defer rows.Close()

us := []UsagePipeline{}
us := []sdk.UsagePipeline{}
for rows.Next() {
var u UsagePipeline
var u sdk.UsagePipeline
if err := rows.Scan(
&u.ProjectID, &u.ProjectKey, &u.ProjectName,
&u.PipelineID, &u.PipelineName,
Expand All @@ -73,19 +51,8 @@ func GetPipelineUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64)
return us, nil
}

// UsageAction represent a action using an action.
type UsageAction struct {
GroupID int64 `json:"group_id"`
GroupName string `json:"group_name"`
ParentActionID int64 `json:"parent_action_id"`
ParentActionName string `json:"parent_action_name"`
ActionID int64 `json:"action_id"`
ActionName string `json:"action_name"`
Warning bool `json:"warning"`
}

// GetActionUsages returns the list of actions using an action
func GetActionUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64) ([]UsageAction, error) {
func GetActionUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64) ([]sdk.UsageAction, error) {
rows, err := db.Query(`
SELECT DISTINCT
"group".id, "group".name,
Expand All @@ -104,9 +71,9 @@ func GetActionUsages(db gorp.SqlExecutor, sharedInfraGroupID, actionID int64) ([
}
defer rows.Close()

us := []UsageAction{}
us := []sdk.UsageAction{}
for rows.Next() {
var u UsageAction
var u sdk.UsageAction
if err := rows.Scan(
&u.GroupID, &u.GroupName,
&u.ParentActionID, &u.ParentActionName,
Expand Down
33 changes: 33 additions & 0 deletions sdk/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,39 @@ type Action struct {
Editable bool `json:"editable,omitempty" db:"-"`
}

// UsageAction represent a action using an action.
type UsageAction struct {
GroupID int64 `json:"group_id"`
GroupName string `json:"group_name"`
ParentActionID int64 `json:"parent_action_id"`
ParentActionName string `json:"parent_action_name"`
ActionID int64 `json:"action_id"`
ActionName string `json:"action_name"`
Warning bool `json:"warning"`
}

// ActionUsages for action.
type ActionUsages struct {
Pipelines []UsagePipeline `json:"pipelines"`
Actions []UsageAction `json:"actions"`
}

// UsagePipeline represent a pipeline using an action.
type UsagePipeline struct {
ProjectID int64 `json:"project_id"`
ProjectKey string `json:"project_key"`
ProjectName string `json:"project_name"`
PipelineID int64 `json:"pipeline_id"`
PipelineName string `json:"pipeline_name"`
StageID int64 `json:"stage_id"`
StageName string `json:"stage_name"`
JobID int64 `json:"job_id"`
JobName string `json:"job_name"`
ActionID int64 `json:"action_id"`
ActionName string `json:"action_name"`
Warning bool `json:"warning"`
}

// Value returns driver.Value from action.
func (a Action) Value() (driver.Value, error) {
j, err := json.Marshal(a)
Expand Down
11 changes: 11 additions & 0 deletions sdk/cdsclient/client_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ func (c *client) ActionGet(groupName, name string, mods ...RequestModifier) (*sd
return &a, nil
}

func (c *client) ActionUsage(groupName, name string, mods ...RequestModifier) (*sdk.ActionUsages, error) {
var a sdk.ActionUsages

path := fmt.Sprintf("/action/%s/%s/usage", groupName, name)
if _, err := c.GetJSON(context.Background(), path, &a, mods...); err != nil {
return nil, err
}

return &a, nil
}

func (c *client) ActionList() ([]sdk.Action, error) {
actions := []sdk.Action{}
if _, err := c.GetJSON(context.Background(), "/action", &actions); err != nil {
Expand Down
1 change: 1 addition & 0 deletions sdk/cdsclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ type DownloadClient interface {
type ActionClient interface {
ActionDelete(groupName, name string) error
ActionGet(groupName, name string, mods ...RequestModifier) (*sdk.Action, error)
ActionUsage(groupName, name string, mods ...RequestModifier) (*sdk.ActionUsages, error)
ActionList() ([]sdk.Action, error)
ActionImport(content io.Reader, format string) error
ActionExport(groupName, name string, format string) ([]byte, error)
Expand Down
40 changes: 40 additions & 0 deletions sdk/cdsclient/mock_cdsclient/interface_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.