From 0b817c5ef25ad9f295eb0117134fe70069c82089 Mon Sep 17 00:00:00 2001 From: rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:27:33 +0800 Subject: [PATCH] feat: support to show the outputs in the pr comment Signed-off-by: rick <1450685+LinuxSuRen@users.noreply.github.com> --- cmd/argoworkflow/main.go | 15 +++++- cmd/argoworkflow/template/comment.go | 15 +++++- cmd/argoworkflow/template/comment_test.go | 31 ++++++++++++- cmd/argoworkflow/template/workflow-output.go | 19 ++++++++ cmd/argoworkflow/workflow-output.go | 48 ++++++++++++++++++++ 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 cmd/argoworkflow/template/workflow-output.go create mode 100644 cmd/argoworkflow/workflow-output.go diff --git a/cmd/argoworkflow/main.go b/cmd/argoworkflow/main.go index 9d049bf..956394a 100644 --- a/cmd/argoworkflow/main.go +++ b/cmd/argoworkflow/main.go @@ -158,6 +158,7 @@ func (e *DefaultPluginExecutor) Execute(args executor.ExecuteTemplateArgs, wf *w // find useless nodes var toRemoves []string for key, val := range wf.Status.Nodes { + // TODO add a filter to allow users to do this, and keep this as default if strings.HasSuffix(val.Name, ".onExit") || strings.Contains(val.Name, ".hooks.") { toRemoves = append(toRemoves, key) } @@ -190,7 +191,19 @@ func (e *DefaultPluginExecutor) Execute(args executor.ExecuteTemplateArgs, wf *w var message string message, err = template.RenderTemplate(tplText, wf) if err == nil { - err = pkg.CreateComment(ctx, repo, message, opt.Option.CommentIdentity) + outputs := GetOutputs(wf) + var outputsComment string + if len(outputs) > 0 { + outputsComment, err = template.RenderTemplate(template.OutputsTemplate, outputs) + } + + if err == nil { + if outputsComment != "" { + message = message + "\n" + outputsComment + } + + err = pkg.CreateComment(ctx, repo, message, opt.Option.CommentIdentity) + } } else { err = fmt.Errorf("failed to render comment template: %v", err) } diff --git a/cmd/argoworkflow/template/comment.go b/cmd/argoworkflow/template/comment.go index ab177ab..8eb6c52 100644 --- a/cmd/argoworkflow/template/comment.go +++ b/cmd/argoworkflow/template/comment.go @@ -2,7 +2,7 @@ package template // CommentTemplate is the default comment template const CommentTemplate = ` -[{{.Spec.WorkflowTemplateRef.Name}}]({{get .Annotations "workflow.templatelink"}}) is {{.Status.Phase}}. It takes {{duration .Status.FinishedAt .Status.StartedAt}}. Please check log output from [here]({{get .Annotations "workflow.link"}}). +[{{.Spec.WorkflowTemplateRef.Name}}]({{get .Annotations "workflow.templatelink"}}) is {{.Status.Phase}}. It started from {{date "01-02 15:04" .Status.StartedAt.Time}}, and took {{duration .Status.FinishedAt .Status.StartedAt}}. Please check log output from [here]({{get .Annotations "workflow.link"}}). | Stage | Status | Duration | |---|---|---| @@ -10,3 +10,16 @@ const CommentTemplate = ` | {{$status.DisplayName}} | {{$status.Phase}} | {{duration $status.FinishedAt $status.StartedAt}} | {{- end}} ` + +const OutputsTemplate = ` +Please feel free to check the following outputs: +| Output | +|---| +{{- range $name, $output := .}} +{{- if eq "file" (toString $output.Kind)}} +| [{{$name}}]({{$output.File}}) | +{{- else if eq "string" (toString $output.Kind)}} +| {{$name}} - {{$output.Value}} | +{{- end}} +{{- end}} +` diff --git a/cmd/argoworkflow/template/comment_test.go b/cmd/argoworkflow/template/comment_test.go index c96f65d..bd035ae 100644 --- a/cmd/argoworkflow/template/comment_test.go +++ b/cmd/argoworkflow/template/comment_test.go @@ -10,7 +10,12 @@ import ( ) func TestCommentTemlate(t *testing.T) { - startTime := v1.Now() + var layout string = "2006-01-02 15:04:05" + var timeStr string = "2019-12-12 15:22:12" + targetTime, err := time.ParseInLocation(layout, timeStr, time.Local) + assert.Nil(t, err) + + startTime := v1.Time{Time: targetTime} endTime := v1.Time{Time: startTime.Add(time.Second * 5)} node1 := map[string]interface{}{"Phase": "Success", "DisplayName": "node-1", "StartedAt": startTime, "FinishedAt": endTime, "StartedTime": "2023-01-06T07:49:07Z", "EndedTime": "2023-01-06T07:54:26Z"} @@ -46,7 +51,7 @@ func TestCommentTemlate(t *testing.T) { result, err := template.RenderTemplate(template.CommentTemplate, object) assert.Nil(t, err) assert.Equal(t, ` -[Sample](https://github.com/linxusuren/gogit.git) is Failed. It takes 5s. Please check log output from [here](https://github.com/linxusuren/gogit). +[Sample](https://github.com/linxusuren/gogit.git) is Failed. It started from 12-12 15:22, and took 5s. Please check log output from [here](https://github.com/linxusuren/gogit). | Stage | Status | Duration | |---|---|---| @@ -69,3 +74,25 @@ func TestCommentTemlate(t *testing.T) { | node-2 | Failed | 5m19s | `, result) } + +func TestOutput(t *testing.T) { + objects := map[string]template.OutputObject{} + objects["test"] = template.OutputObject{ + Kind: template.FileOutput, + File: "https://github.com", + } + objects["string"] = template.OutputObject{ + Kind: template.ValueOutput, + Value: "ghcr.io/linuxsuren/gogit", + } + + result, err := template.RenderTemplate(template.OutputsTemplate, objects) + assert.Nil(t, err) + assert.Equalf(t, ` +Please feel free to check the following outputs: +| Output | +|---| +| string - ghcr.io/linuxsuren/gogit | +| [test](https://github.com) | +`, result, result) +} diff --git a/cmd/argoworkflow/template/workflow-output.go b/cmd/argoworkflow/template/workflow-output.go new file mode 100644 index 0000000..d8d3a0f --- /dev/null +++ b/cmd/argoworkflow/template/workflow-output.go @@ -0,0 +1,19 @@ +package template + +// OutputObject represents a output object +type OutputObject struct { + Kind OutputObjectKind + File string + Value string +} + +// OutputObjectKind represents the type of the outout object. +// This is a type alias of string. +type OutputObjectKind string + +const ( + // FileOutput represetnts a file path + FileOutput OutputObjectKind = "file" + // ValueOutput represents a string value + ValueOutput OutputObjectKind = "string" +) diff --git a/cmd/argoworkflow/workflow-output.go b/cmd/argoworkflow/workflow-output.go new file mode 100644 index 0000000..b2db245 --- /dev/null +++ b/cmd/argoworkflow/workflow-output.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" + "github.com/linuxsuren/gogit/argoworkflow/template" +) + +// GetOutputs returns the outputs in map format. +// Key is the node name, value is the output link. +// The output link address does not have the host part. +func GetOutputs(wf *wfv1.Workflow) (outputs map[string]template.OutputObject) { + outputs = map[string]template.OutputObject{} + nodes := wf.Status.Nodes + for _, node := range nodes { + if node.Outputs == nil { + continue + } + + var outputObject *template.OutputObject + for _, artifact := range node.Outputs.Artifacts { + key := fmt.Sprintf("%s-%s", node.Name, artifact.Name) + + if artifact.Path != "" { + // TODO assume this is a artifact file + outputObject = &template.OutputObject{ + Kind: template.FileOutput, + File: fmt.Sprintf("/artifact-files/%s/workflows/%s/%s/outputs/%s", wf.Namespace, wf.Name, node.Name, artifact.Name), + } + outputs[key] = *outputObject + } + } + + for _, param := range node.Outputs.Parameters { + key := fmt.Sprintf("%s-%s", node.Name, param.Name) + + if param.Value != nil && param.Value.String() != "" { + outputObject = &template.OutputObject{ + Kind: template.ValueOutput, + Value: param.Value.String(), + } + outputs[key] = *outputObject + } + } + } + return +}