Skip to content

Commit

Permalink
Cli fix pipeline logs (#3913)
Browse files Browse the repository at this point in the history
Co-authored-by: Thomas Anderson <127358482+zc-devs@users.noreply.github.com>
Co-authored-by: 6543 <6543@obermui.de>
  • Loading branch information
3 people authored Jul 18, 2024
1 parent 7b7c83d commit 49c2029
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 21 deletions.
44 changes: 44 additions & 0 deletions cli/internal/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,47 @@ func ParseKeyPair(p []string) map[string]string {
}
return params
}

/*
ParseStep parses the step id form a string which may either be the step PID (step number) or a step name.
These rules apply:
- Step ID take precedence over step name when searching for a match.
- First match is used, when there are multiple steps with the same name.
Strictly speaking, this is not parsing, but a lookup.
TODO: Use PID instead of StepID
*/
func ParseStep(client woodpecker.Client, repoID, number int64, stepArg string) (stepID int64, err error) {
pipeline, err := client.Pipeline(repoID, number)
if err != nil {
return 0, err
}

stepID, err = strconv.ParseInt(stepArg, 10, 64)
// TODO: for 3.0 do "stepPID, err := strconv.ParseInt(stepArg, 10, 64)"
if err == nil {
return stepID, nil
/*
// TODO: for 3.0
for _, wf := range pipeline.Workflows {
for _, step := range wf.Children {
if int64(step.PID) == stepPID {
return step.ID, nil
}
}
}
*/
}

for _, wf := range pipeline.Workflows {
for _, step := range wf.Children {
if step.Name == stepArg {
return step.ID, nil
}
}
}

return 0, fmt.Errorf("no step with number or name '%s' found", stepArg)
}
62 changes: 54 additions & 8 deletions cli/pipeline/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@ package pipeline
import (
"context"
"fmt"
"os"
"strconv"
"text/template"

"github.com/urfave/cli/v3"

"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)

var pipelineLogsCmd = &cli.Command{
Name: "logs",
Usage: "show pipeline logs",
ArgsUsage: "<repo-id|repo-full-name> [pipeline] [stepID]",
Action: pipelineLogs,
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-id|step-name]",
// TODO: for v3.0 do `ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-number|step-name]",`
Action: pipelineLogs,
}

func pipelineLogs(ctx context.Context, c *cli.Command) error {
Expand All @@ -37,31 +41,73 @@ func pipelineLogs(ctx context.Context, c *cli.Command) error {
if err != nil {
return err
}
if len(repoIDOrFullName) == 0 {
return fmt.Errorf("missing required argument repo-id / repo-full-name")
}
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
if err != nil {
return err
return fmt.Errorf("invalid repo '%s': %w ", repoIDOrFullName, err)
}

pipelineArg := c.Args().Get(1)
if len(pipelineArg) == 0 {
return fmt.Errorf("missing required argument pipeline")
}
number, err := strconv.ParseInt(pipelineArg, 10, 64)
if err != nil {
return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
}

stepArg := c.Args().Get(2) //nolint:mnd
if len(stepArg) == 0 {
return showPipelineLog(client, repoID, number)
}

step, err := internal.ParseStep(client, repoID, number, stepArg)
if err != nil {
return fmt.Errorf("invalid step '%s': %w", stepArg, err)
}
return showStepLog(client, repoID, number, step)
}

numberArgIndex := 1
number, err := strconv.ParseInt(c.Args().Get(numberArgIndex), 10, 64)
func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
pipeline, err := client.Pipeline(repoID, number)
if err != nil {
return err
}

stepArgIndex := 2
step, err := strconv.ParseInt(c.Args().Get(stepArgIndex), 10, 64)
tmpl, err := template.New("_").Parse(tmplPipelineLogs + "\n")
if err != nil {
return err
}

for _, workflow := range pipeline.Workflows {
for _, step := range workflow.Children {
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
return err
}
err := showStepLog(client, repoID, number, step.ID)
if err != nil {
return err
}
}
}

return nil
}

func showStepLog(client woodpecker.Client, repoID, number, step int64) error {
logs, err := client.StepLogEntries(repoID, number, step)
if err != nil {
return err
}

for _, log := range logs {
fmt.Print(string(log.Data))
fmt.Println(string(log.Data))
}

return nil
}

// template for pipeline ps information.
var tmplPipelineLogs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m"
24 changes: 14 additions & 10 deletions cli/pipeline/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package pipeline

import (
"context"
"fmt"
"os"
"strconv"
"text/template"
Expand All @@ -29,7 +30,7 @@ import (
var pipelinePsCmd = &cli.Command{
Name: "ps",
Usage: "show pipeline steps",
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
ArgsUsage: "<repo-id|repo-full-name> <pipeline>",
Action: pipelinePs,
Flags: []cli.Flag{common.FormatFlag(tmplPipelinePs)},
}
Expand All @@ -42,7 +43,7 @@ func pipelinePs(ctx context.Context, c *cli.Command) error {
}
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
if err != nil {
return err
return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
}

pipelineArg := c.Args().Get(1)
Expand All @@ -59,7 +60,7 @@ func pipelinePs(ctx context.Context, c *cli.Command) error {
} else {
number, err = strconv.ParseInt(pipelineArg, 10, 64)
if err != nil {
return err
return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
}
}

Expand All @@ -73,9 +74,9 @@ func pipelinePs(ctx context.Context, c *cli.Command) error {
return err
}

for _, step := range pipeline.Workflows {
for _, child := range step.Children {
if err := tmpl.Execute(os.Stdout, child); err != nil {
for _, workflow := range pipeline.Workflows {
for _, step := range workflow.Children {
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
return err
}
}
Expand All @@ -84,8 +85,11 @@ func pipelinePs(ctx context.Context, c *cli.Command) error {
return nil
}

// Template for pipeline ps information.
var tmplPipelinePs = "\x1b[33mStep #{{ .PID }} \x1b[0m" + `
Step: {{ .Name }}
State: {{ .State }}
// template for pipeline ps information.
var tmplPipelinePs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m" + `
Step: {{ .step.Name }}
Started: {{ .step.Started }}
Stopped: {{ .step.Stopped }}
Type: {{ .step.Type }}
State: {{ .step.State }}
`
9 changes: 6 additions & 3 deletions docs/versioned_docs/version-2.7/40-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,12 @@ Message: {{ .Message }}

show pipeline steps

**--format**="": format output (default: Step #{{ .PID }} 
Step: {{ .Name }}
State: {{ .State }}
**--format**="": format output (default: {{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):
Step: {{ .step.Name }}
Started: {{ .step.Started }}
Stopped: {{ .step.Stopped }}
Type: {{ .step.Type }}
State: {{ .step.State }}
)

### create
Expand Down

0 comments on commit 49c2029

Please sign in to comment.