diff --git a/docs/content/docs/install/settings.md b/docs/content/docs/install/settings.md index b9a2d98a5..0eaa95e96 100644 --- a/docs/content/docs/install/settings.md +++ b/docs/content/docs/install/settings.md @@ -250,6 +250,16 @@ A few settings are available to configure this feature: Set this to the root URL of your custom console. example: `https://mycorp.com` +* `custom-console-url-namespace` + + Set this to the URL where to view the details of the `Namespace`. + + The URL supports all the standard variables as exposed on the Pipelinerun (refer to + the documentation on [Authoring PipelineRuns](../authoringprs)) with the added + variable: + + * `{{ namespace }}`: The target namespace where the pipelinerun is executed + * `custom-console-url-pr-details` Set this to the URL where to view the details of the `PipelineRun`. This is diff --git a/pkg/consoleui/custom.go b/pkg/consoleui/custom.go index 8bff661fe..0894590f5 100644 --- a/pkg/consoleui/custom.go +++ b/pkg/consoleui/custom.go @@ -71,6 +71,20 @@ func (o *CustomConsole) DetailURL(pr *tektonv1.PipelineRun) string { return o.generateURL(o.Info.Pac.CustomConsolePRdetail, nm) } +func (o *CustomConsole) NameSpaceURL(pr *tektonv1.PipelineRun) string { + if o.Info.Pac.CustomConsoleNamespaceURL == "" { + return fmt.Sprintf("https://detailurl.setting.%s.is.not.configured", settings.CustomConsoleNamespaceURLKey) + } + nm := o.params + // make sure the map is not nil before setting this up + // there is a case where SetParams is not called before DetailURL and this would crash the container + if nm == nil { + nm = make(map[string]string) + } + nm["namespace"] = pr.GetNamespace() + return o.generateURL(o.Info.Pac.CustomConsoleNamespaceURL, nm) +} + func (o *CustomConsole) TaskLogURL(pr *tektonv1.PipelineRun, taskRunStatus *tektonv1.PipelineRunTaskRunStatus) string { if o.Info.Pac.CustomConsolePRTaskLog == "" { return fmt.Sprintf("https://tasklogurl.setting.%s.is.not.configured", settings.CustomConsolePRTaskLogKey) diff --git a/pkg/consoleui/custom_test.go b/pkg/consoleui/custom_test.go index f4f048caf..6a8f97578 100644 --- a/pkg/consoleui/custom_test.go +++ b/pkg/consoleui/custom_test.go @@ -92,16 +92,18 @@ func TestCustomGood(t *testing.T) { Info: &info.Info{ Pac: &info.PacOpts{ Settings: &settings.Settings{ - CustomConsoleName: consoleName, - CustomConsoleURL: consoleURL, - CustomConsolePRdetail: "{{ notthere}}", - CustomConsolePRTaskLog: "{{ notthere}}", + CustomConsoleName: consoleName, + CustomConsoleURL: consoleURL, + CustomConsolePRdetail: "{{ notthere}}", + CustomConsolePRTaskLog: "{{ notthere}}", + CustomConsoleNamespaceURL: "https://mycorp.console/{{ namespace }}", }, }, }, } assert.Assert(t, strings.Contains(o.DetailURL(pr), consoleURL)) assert.Assert(t, strings.Contains(o.TaskLogURL(pr, trStatus), consoleURL)) + assert.Assert(t, strings.Contains(o.NameSpaceURL(pr), "https://mycorp.console/ns")) } func TestCustomBad(t *testing.T) { @@ -122,4 +124,5 @@ func TestCustomBad(t *testing.T) { assert.Assert(t, strings.Contains(c.URL(), "is.not.configured")) assert.Assert(t, strings.Contains(c.DetailURL(pr), "is.not.configured")) assert.Assert(t, strings.Contains(c.TaskLogURL(pr, nil), "is.not.configured")) + assert.Assert(t, strings.Contains(c.NameSpaceURL(pr), "is.not.configured"), c.NameSpaceURL(pr)) } diff --git a/pkg/consoleui/interface.go b/pkg/consoleui/interface.go index 459fb9a96..002dee1be 100644 --- a/pkg/consoleui/interface.go +++ b/pkg/consoleui/interface.go @@ -13,6 +13,7 @@ const consoleIsnotConfiguredURL = "https://dashboard.is.not.configured" type Interface interface { DetailURL(pr *tektonv1.PipelineRun) string TaskLogURL(pr *tektonv1.PipelineRun, taskRunStatusstatus *tektonv1.PipelineRunTaskRunStatus) string + NameSpaceURL(pr *tektonv1.PipelineRun) string UI(ctx context.Context, kdyn dynamic.Interface) error URL() string GetName() string @@ -33,6 +34,10 @@ func (f FallBackConsole) TaskLogURL(_ *tektonv1.PipelineRun, _ *tektonv1.Pipelin return consoleIsnotConfiguredURL } +func (f FallBackConsole) NameSpaceURL(_ *tektonv1.PipelineRun) string { + return consoleIsnotConfiguredURL +} + func (f FallBackConsole) UI(_ context.Context, _ dynamic.Interface) error { return nil } diff --git a/pkg/consoleui/openshift.go b/pkg/consoleui/openshift.go index 8d9f14ada..6e116e58b 100644 --- a/pkg/consoleui/openshift.go +++ b/pkg/consoleui/openshift.go @@ -11,14 +11,15 @@ import ( ) const ( - openShiftConsoleNS = "openshift-console" - openShiftConsoleRouteName = "console" - openShiftPipelineDetailViewURL = "https://%s/k8s/ns/%s/tekton.dev~v1beta1~PipelineRun/%s" - openShiftPipelineTaskLogURL = "%s/logs/%s" - openShiftRouteGroup = "route.openshift.io" - openShiftRouteVersion = "v1" - openShiftRouteResource = "routes" - openshiftConsoleName = "OpenShift Console" + openShiftConsoleNS = "openshift-console" + openShiftConsoleRouteName = "console" + openShiftPipelineNamespaceViewURL = "https://%s/pipelines/ns/%s/pipeline-runs" + openShiftPipelineDetailViewURL = "https://%s/k8s/ns/%s/tekton.dev~v1beta1~PipelineRun/%s" + openShiftPipelineTaskLogURL = "%s/logs/%s" + openShiftRouteGroup = "route.openshift.io" + openShiftRouteVersion = "v1" + openShiftRouteResource = "routes" + openshiftConsoleName = "OpenShift Console" ) type OpenshiftConsole struct { @@ -44,6 +45,10 @@ func (o *OpenshiftConsole) TaskLogURL(pr *tektonv1.PipelineRun, taskRunStatus *t return fmt.Sprintf(openShiftPipelineTaskLogURL, o.DetailURL(pr), taskRunStatus.PipelineTaskName) } +func (o *OpenshiftConsole) NameSpaceURL(pr *tektonv1.PipelineRun) string { + return fmt.Sprintf(openShiftPipelineNamespaceViewURL, o.host, pr.GetNamespace()) +} + // UI use dynamic client to get the route of the openshift // console where we can point to. func (o *OpenshiftConsole) UI(ctx context.Context, kdyn dynamic.Interface) error { diff --git a/pkg/consoleui/openshift_test.go b/pkg/consoleui/openshift_test.go index d8a0b3626..783597b31 100644 --- a/pkg/consoleui/openshift_test.go +++ b/pkg/consoleui/openshift_test.go @@ -103,15 +103,16 @@ func TestOpenshiftConsoleUI(t *testing.T) { func TestOpenshiftConsoleURLs(t *testing.T) { pr := &tektonv1.PipelineRun{ ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns", + Namespace: "theNS", Name: "pr", }, } trStatus := &tektonv1.PipelineRunTaskRunStatus{ PipelineTaskName: "task", } - o := OpenshiftConsole{host: "http://fakeconsole"} - assert.Assert(t, o.URL() != "") - assert.Assert(t, o.DetailURL(pr) != "") - assert.Assert(t, o.TaskLogURL(pr, trStatus) != "") + o := OpenshiftConsole{host: "fakeconsole"} + assert.Equal(t, o.URL(), "https://fakeconsole") + assert.Equal(t, o.DetailURL(pr), "https://fakeconsole/k8s/ns/theNS/tekton.dev~v1beta1~PipelineRun/pr") + assert.Equal(t, o.TaskLogURL(pr, trStatus), "https://fakeconsole/k8s/ns/theNS/tekton.dev~v1beta1~PipelineRun/pr/logs/task") + assert.Equal(t, o.NameSpaceURL(pr), "https://fakeconsole/pipelines/ns/theNS/pipeline-runs") } diff --git a/pkg/consoleui/tektondashboard.go b/pkg/consoleui/tektondashboard.go index 8bbf7b60c..4c64021e1 100644 --- a/pkg/consoleui/tektondashboard.go +++ b/pkg/consoleui/tektondashboard.go @@ -22,6 +22,10 @@ func (t *TektonDashboard) DetailURL(pr *tektonv1.PipelineRun) string { return fmt.Sprintf("%s/#/namespaces/%s/pipelineruns/%s", t.BaseURL, pr.GetNamespace(), pr.GetName()) } +func (t *TektonDashboard) NameSpaceURL(pr *tektonv1.PipelineRun) string { + return fmt.Sprintf("%s/#/namespaces/%s/pipelineruns", t.BaseURL, pr.GetNamespace()) +} + func (t *TektonDashboard) TaskLogURL(pr *tektonv1.PipelineRun, taskRunStatus *tektonv1.PipelineRunTaskRunStatus) string { return fmt.Sprintf("%s?pipelineTask=%s", t.DetailURL(pr), taskRunStatus.PipelineTaskName) } diff --git a/pkg/formatting/starting.go b/pkg/formatting/starting.go index a3181d988..1db37b346 100644 --- a/pkg/formatting/starting.go +++ b/pkg/formatting/starting.go @@ -12,18 +12,24 @@ var StartingPipelineRunText string //go:embed templates/queuing.go.tmpl var QueuingPipelineRunText string +//go:embed templates/failures.tmpl +var FailurePipelineRunText string + type MessageTemplate struct { PipelineRunName string Namespace string + NamespaceURL string ConsoleName string ConsoleURL string TknBinary string TknBinaryURL string + TaskStatus string + FailureSnippet string } -func (mt MessageTemplate) MakeTemplate(msg string) (string, error) { +func (mt MessageTemplate) MakeTemplate(tmpl string) (string, error) { outputBuffer := bytes.Buffer{} - t := template.Must(template.New("Message").Parse(msg)) + t := template.Must(template.New("Message").Parse(tmpl)) data := struct{ Mt MessageTemplate }{Mt: mt} if err := t.Execute(&outputBuffer, data); err != nil { return "", err diff --git a/pkg/formatting/starting_test.go b/pkg/formatting/starting_test.go index 923f78ef2..1ec36582c 100644 --- a/pkg/formatting/starting_test.go +++ b/pkg/formatting/starting_test.go @@ -12,6 +12,7 @@ func TestMessageTemplate_MakeTemplate(t *testing.T) { ConsoleURL: "https://test-console-url.com", TknBinary: "test-tkn", TknBinaryURL: "https://test-tkn-url.com", + FailureSnippet: "such a failure", } tests := []struct { @@ -33,6 +34,12 @@ func TestMessageTemplate_MakeTemplate(t *testing.T) { msg: "Starting Pipelinerun {{.Mt.PipelineRunName}} in namespace {{.FOOOBAR }}", wantErr: true, }, + { + name: "Failure template", + mt: mt, + msg: "I am {{ .Mt.FailureSnippet }}", + want: "I am such a failure", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/formatting/templates/failures.tmpl b/pkg/formatting/templates/failures.tmpl new file mode 100644 index 000000000..0519f6e2b --- /dev/null +++ b/pkg/formatting/templates/failures.tmpl @@ -0,0 +1,10 @@ +
{{ .Mt.TknBinary }} pr logs -n {{ .Mt.Namespace }} {{ .Mt.PipelineRunName }} -f
diff --git a/pkg/params/settings/config.go b/pkg/params/settings/config.go
index b42603d6b..df2e97c48 100644
--- a/pkg/params/settings/config.go
+++ b/pkg/params/settings/config.go
@@ -24,10 +24,11 @@ const (
AutoConfigureNewGitHubRepoKey = "auto-configure-new-github-repo"
AutoConfigureRepoNamespaceTemplateKey = "auto-configure-repo-namespace-template"
- CustomConsoleNameKey = "custom-console-name"
- CustomConsoleURLKey = "custom-console-url"
- CustomConsolePRDetailKey = "custom-console-url-pr-details"
- CustomConsolePRTaskLogKey = "custom-console-url-pr-tasklog"
+ CustomConsoleNameKey = "custom-console-name"
+ CustomConsoleURLKey = "custom-console-url"
+ CustomConsolePRDetailKey = "custom-console-url-pr-details"
+ CustomConsolePRTaskLogKey = "custom-console-url-pr-tasklog"
+ CustomConsoleNamespaceURLKey = "custom-console-url-namespace"
SecretAutoCreateKey = "secret-auto-create"
secretAutoCreateDefaultValue = "true"
@@ -94,10 +95,11 @@ type Settings struct {
ErrorDetectionNumberOfLines int
ErrorDetectionSimpleRegexp string
- CustomConsoleName string
- CustomConsoleURL string
- CustomConsolePRdetail string
- CustomConsolePRTaskLog string
+ CustomConsoleName string
+ CustomConsoleURL string
+ CustomConsolePRdetail string
+ CustomConsolePRTaskLog string
+ CustomConsoleNamespaceURL string
RememberOKToTest bool
}
@@ -227,6 +229,11 @@ func ConfigToSettings(logger *zap.SugaredLogger, setting *Settings, config map[s
setting.CustomConsolePRdetail = config[CustomConsolePRDetailKey]
}
+ if setting.CustomConsoleNamespaceURL != config[CustomConsoleNamespaceURLKey] {
+ logger.Infof("CONFIG: setting custom console namespace URL to %v", config[CustomConsoleNamespaceURLKey])
+ setting.CustomConsoleNamespaceURL = config[CustomConsoleNamespaceURLKey]
+ }
+
if setting.CustomConsolePRTaskLog != config[CustomConsolePRTaskLogKey] {
logger.Infof("CONFIG: setting custom console pr task log URL to %v", config[CustomConsolePRTaskLogKey])
setting.CustomConsolePRTaskLog = config[CustomConsolePRTaskLogKey]
diff --git a/pkg/reconciler/status.go b/pkg/reconciler/status.go
index 034467973..2470df328 100644
--- a/pkg/reconciler/status.go
+++ b/pkg/reconciler/status.go
@@ -13,6 +13,7 @@ import (
"github.com/openshift-pipelines/pipelines-as-code/pkg/kubeinteraction"
kstatus "github.com/openshift-pipelines/pipelines-as-code/pkg/kubeinteraction/status"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+ "github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
"github.com/openshift-pipelines/pipelines-as-code/pkg/secrets"
"github.com/openshift-pipelines/pipelines-as-code/pkg/sort"
@@ -26,7 +27,6 @@ import (
const (
maxPipelineRunStatusRun = 5
logSnippetNumLines = 3
- failureReasonText = "%s