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: support to show the outputs in the pr comment #22

Merged
merged 1 commit into from
Jan 16, 2023
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
15 changes: 14 additions & 1 deletion cmd/argoworkflow/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
15 changes: 14 additions & 1 deletion cmd/argoworkflow/template/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@ 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 |
|---|---|---|
{{- range $_, $status := .Status.Nodes}}
| {{$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}}
`
31 changes: 29 additions & 2 deletions cmd/argoworkflow/template/comment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand Down Expand Up @@ -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 |
|---|---|---|
Expand All @@ -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)
}
19 changes: 19 additions & 0 deletions cmd/argoworkflow/template/workflow-output.go
Original file line number Diff line number Diff line change
@@ -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"
)
48 changes: 48 additions & 0 deletions cmd/argoworkflow/workflow-output.go
Original file line number Diff line number Diff line change
@@ -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
}