Skip to content

Commit

Permalink
Add -E flag to exit with the pr sate on unix shell
Browse files Browse the repository at this point in the history
Add the -E or --exit-with-pipelinerun-error flag to tkn pr logs to exit
with the pipelinerun error after showing the logs.

Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com>
  • Loading branch information
chmouel committed Apr 30, 2024
1 parent f3422c7 commit a056a45
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 15 deletions.
19 changes: 10 additions & 9 deletions docs/cmd/tkn_pipelinerun_logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ Show the logs of PipelineRun named 'microservice-1' for all Tasks and steps (inc
### Options

```
-a, --all show all logs including init steps injected by tekton
-f, --follow stream live logs
-F, --fzf use fzf to select a PipelineRun
-h, --help help for logs
-L, --last show logs for last PipelineRun
--limit int lists number of PipelineRuns (default 5)
--prefix prefix each log line with the log source (task name and step name) (default true)
-t, --task strings show logs for mentioned Tasks only
--timestamps show logs with timestamp
-a, --all show all logs including init steps injected by tekton
-E, --exit-with-pipelinerun-error exit with pipelinerun to the unix shell, 0 if success, 1 if error, 2 if there is an unknown status
-f, --follow stream live logs
-F, --fzf use fzf to select a PipelineRun
-h, --help help for logs
-L, --last show logs for last PipelineRun
--limit int lists number of PipelineRuns (default 5)
--prefix prefix each log line with the log source (task name and step name) (default true)
-t, --task strings show logs for mentioned Tasks only
--timestamps show logs with timestamp
```

### Options inherited from parent commands
Expand Down
4 changes: 4 additions & 0 deletions docs/man/man1/tkn-pipelinerun-logs.1
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Show the logs of a PipelineRun
\fB\-a\fP, \fB\-\-all\fP[=false]
show all logs including init steps injected by tekton

.PP
\fB\-E\fP, \fB\-\-exit\-with\-pipelinerun\-error\fP[=false]
exit with pipelinerun to the unix shell, 0 if success, 1 if error, 2 if there is an unknown status

.PP
\fB\-f\fP, \fB\-\-follow\fP[=false]
stream live logs
Expand Down
28 changes: 28 additions & 0 deletions pkg/cmd/pipelinerun/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package pipelinerun

import (
"context"
"fmt"
"os"
"strings"
Expand All @@ -25,6 +26,8 @@ import (
"github.com/tektoncd/cli/pkg/log"
"github.com/tektoncd/cli/pkg/options"
pipelinerunpkg "github.com/tektoncd/cli/pkg/pipelinerun"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -82,6 +85,7 @@ Show the logs of PipelineRun named 'microservice-1' for all Tasks and steps (inc
c.Flags().BoolVarP(&opts.Follow, "follow", "f", false, "stream live logs")
c.Flags().BoolVarP(&opts.Timestamps, "timestamps", "", false, "show logs with timestamp")
c.Flags().BoolVarP(&opts.Prefixing, "prefix", "", true, "prefix each log line with the log source (task name and step name)")
c.Flags().BoolVarP(&opts.ExitWithPrError, "exit-with-pipelinerun-error", "E", false, "exit with pipelinerun to the unix shell, 0 if success, 1 if error, 2 if there is an unknown status")
c.Flags().StringSliceVarP(&opts.Tasks, "task", "t", []string{}, "show logs for mentioned Tasks only")
c.Flags().IntVarP(&opts.Limit, "limit", "", defaultLimit, "lists number of PipelineRuns")
return c
Expand Down Expand Up @@ -109,9 +113,33 @@ func Run(opts *options.LogOptions) error {

log.NewWriter(log.LogTypePipeline, opts.Prefixing).Write(opts.Stream, logC, errC)

// get pipelinerun status
if opts.ExitWithPrError {
clients, err := opts.Params.Clients()
if err != nil {
return err
}
ctx := context.Background()
pr, err := clients.Tekton.TektonV1().PipelineRuns(opts.Params.Namespace()).Get(ctx, opts.PipelineRunName, metav1.GetOptions{})
if err != nil {
return err
}
os.Exit(prStatusToUnixStatus(pr))
}

return nil
}

func prStatusToUnixStatus(pr *tektonv1.PipelineRun) int {
if len(pr.Status.Conditions) == 0 {
return 2
}
if pr.Status.Conditions[0].Status == corev1.ConditionFalse {
return 1
}
return 0
}

func askRunName(opts *options.LogOptions) error {
lOpts := metav1.ListOptions{}

Expand Down
65 changes: 59 additions & 6 deletions pkg/cmd/pipelinerun/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,65 @@ func TestLog_no_pipelinerun_argument(t *testing.T) {
}
}

func TestLog_PrStatusToUnixStatus(t *testing.T) {
testCases := []struct {
name string
pr *v1.PipelineRun
expected int
}{
{
name: "No conditions",
pr: &v1.PipelineRun{
Status: v1.PipelineRunStatus{
Status: duckv1.Status{
Conditions: duckv1.Conditions{},
},
},
},
expected: 2,
},
{
name: "Condition status is false",
pr: &v1.PipelineRun{
Status: v1.PipelineRunStatus{
Status: duckv1.Status{
Conditions: duckv1.Conditions{
{
Status: corev1.ConditionFalse,
},
},
},
},
},
expected: 1,
},
{
name: "Condition status true",
pr: &v1.PipelineRun{
Status: v1.PipelineRunStatus{
Status: duckv1.Status{
Conditions: duckv1.Conditions{
{
Status: corev1.ConditionTrue,
},
},
},
},
},
expected: 0,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := prStatusToUnixStatus(tc.pr)
if result != tc.expected {
t.Errorf("Expected %d, got %d", tc.expected, result)
}
})
}
}

func TestLog_run_found_v1beta1(t *testing.T) {
clock := test.FakeClock()
pdata := []*v1beta1.Pipeline{
Expand Down Expand Up @@ -1673,7 +1732,6 @@ func TestPipelinerunLog_follow_mode_v1beta1(t *testing.T) {
cb.UnstructuredV1beta1PR(prs[0], versionv1beta1),
cb.UnstructuredV1beta1P(pps[0], versionv1beta1),
)

if err != nil {
t.Errorf("unable to create dynamic client: %v", err)
}
Expand Down Expand Up @@ -1862,7 +1920,6 @@ func TestPipelinerunLog_follow_mode(t *testing.T) {
cb.UnstructuredPR(prs[0], version),
cb.UnstructuredP(pps[0], version),
)

if err != nil {
t.Errorf("unable to create dynamic client: %v", err)
}
Expand Down Expand Up @@ -2517,7 +2574,6 @@ func TestLog_pipelinerun_still_running_v1beta1(t *testing.T) {
updatePRv1beta1(finalPRs, watcher)

output, err := fetchLogs(prlo)

if err != nil {
t.Errorf("Unexpected error: %v", err)
}
Expand Down Expand Up @@ -2648,7 +2704,6 @@ func TestLog_pipelinerun_still_running(t *testing.T) {
updatePR(finalPRs, watcher)

output, err := fetchLogs(prlo)

if err != nil {
t.Errorf("Unexpected error: %v", err)
}
Expand Down Expand Up @@ -3502,7 +3557,6 @@ func TestPipelinerunLog_finally_v1beta1(t *testing.T) {
cb.UnstructuredV1beta1PR(prs[0], versionv1beta1),
cb.UnstructuredV1beta1P(pps[0], versionv1beta1),
)

if err != nil {
t.Errorf("unable to create dynamic client: %v", err)
}
Expand Down Expand Up @@ -3752,7 +3806,6 @@ func TestPipelinerunLog_finally(t *testing.T) {
cb.UnstructuredPR(prs[0], version),
cb.UnstructuredP(pps[0], version),
)

if err != nil {
t.Errorf("unable to create dynamic client: %v", err)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/options/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type LogOptions struct {
Tail int64
Timestamps bool
Prefixing bool
ExitWithPrError bool
// ActivityTimeout is the amount of time to wait for some activity
// (e.g. Pod ready) before giving up.
ActivityTimeout time.Duration
Expand Down

0 comments on commit a056a45

Please sign in to comment.