From db6966c78d05351134d8dc5a6eafc61dced2c261 Mon Sep 17 00:00:00 2001 From: t-kikuc Date: Thu, 21 Aug 2025 18:21:19 +0900 Subject: [PATCH 1/6] impl for pipedv1 Signed-off-by: t-kikuc --- tool/actions-plan-preview/go.mod | 16 ++- tool/actions-plan-preview/go.sum | 46 +++---- tool/actions-plan-preview/planpreview.go | 156 ++++++++++++++++------- 3 files changed, 141 insertions(+), 77 deletions(-) diff --git a/tool/actions-plan-preview/go.mod b/tool/actions-plan-preview/go.mod index 32ed34782a..48b1dd3a4c 100644 --- a/tool/actions-plan-preview/go.mod +++ b/tool/actions-plan-preview/go.mod @@ -4,20 +4,22 @@ go 1.24.1 require ( github.com/google/go-github/v36 v36.0.0 + github.com/pipe-cd/pipecd v0.53.0 github.com/shurcooL/githubv4 v0.0.0-20220115235240-a14260e6f8a2 - github.com/stretchr/testify v1.7.0 - golang.org/x/oauth2 v0.5.0 + github.com/stretchr/testify v1.10.0 + golang.org/x/oauth2 v0.27.0 ) require ( - github.com/davecgh/go-spew v1.1.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/coreos/go-oidc/v3 v3.11.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/google/go-querystring v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/net v0.38.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/tool/actions-plan-preview/go.sum b/tool/actions-plan-preview/go.sum index ced3e6dd41..3ea7a329a0 100644 --- a/tool/actions-plan-preview/go.sum +++ b/tool/actions-plan-preview/go.sum @@ -1,51 +1,45 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v36 v36.0.0 h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs= github.com/google/go-github/v36 v36.0.0/go.mod h1:LFlKC047IOqiglRGNqNb9s/iAPTnnjtlshm+bxp+kwk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/pipe-cd/pipecd v0.53.0 h1:q6AiDhPFsS0enAehvn2UTVJMKfdnLDPB1BNo6Pr+FgQ= +github.com/pipe-cd/pipecd v0.53.0/go.mod h1:BI0uxrpeuxcjFykL5+tnLc5DRd8v24Hm/it7fBOth6Y= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shurcooL/githubv4 v0.0.0-20220115235240-a14260e6f8a2 h1:82EIpiGB79OIPgSGa63Oj4Ipf+YAX1c6A9qjmEYoRXc= github.com/shurcooL/githubv4 v0.0.0-20220115235240-a14260e6f8a2/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a h1:KikTa6HtAK8cS1qjvUvvq4QO21QnwC+EfvB+OAuZ/ZU= github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tool/actions-plan-preview/planpreview.go b/tool/actions-plan-preview/planpreview.go index 7c9564718a..5a059a7c6c 100644 --- a/tool/actions-plan-preview/planpreview.go +++ b/tool/actions-plan-preview/planpreview.go @@ -27,6 +27,7 @@ import ( "time" "unicode/utf8" + "github.com/pipe-cd/pipecd/pkg/model" "github.com/shurcooL/githubv4" ) @@ -47,9 +48,13 @@ func (r *PlanPreviewResult) NoChange() bool { type ApplicationResult struct { ApplicationInfo SyncStrategy string // QUICK_SYNC, PIPELINE - PlanSummary string - PlanDetails string - NoChange bool + // Deprecated: Use PluginPlanResults in pipedv1 + PlanSummary string + // Deprecated: Use PluginPlanResults in pipedv1 + PlanDetails string + NoChange bool + + PluginPlanResults []*model.PluginPlanPreviewResult } type FailurePiped struct { @@ -59,8 +64,11 @@ type FailurePiped struct { type FailureApplication struct { ApplicationInfo - Reason string + Reason string + // Deprecated: Use PluginPlanResults in pipedv1 PlanDetails string + + PluginPlanResults []*model.PluginPlanPreviewResult } type PipedInfo struct { @@ -69,12 +77,16 @@ type PipedInfo struct { } type ApplicationInfo struct { - ApplicationID string - ApplicationName string - ApplicationURL string - Env string + ApplicationID string + ApplicationName string + ApplicationURL string + Env string + // Deprecated: Use PluginNames in pipedv1 ApplicationKind string // KUBERNETES, TERRAFORM, CLOUDRUN, LAMBDA, ECS ApplicationDirectory string + + PlannedPluginNames string + AllPluginNames string } func retrievePlanPreview( @@ -133,12 +145,14 @@ const ( failureBadgeURL = `[![PLAN_PREVIEW](https://img.shields.io/static/v1?label=PipeCD&message=Plan_Preview&color=orange&style=flat)](https://pipecd.dev/docs/user-guide/plan-preview/)` actionBadgeURLFormat = "[![ACTIONS](https://img.shields.io/static/v1?label=PipeCD&message=Action_Log&style=flat)](%s)" - noChangeTitleFormat = "Ran plan-preview against head commit %s of this pull request. PipeCD detected `0` updated application. It means no deployment will be triggered once this pull request got merged.\n" - hasChangeTitleFormat = "Ran plan-preview against head commit %s of this pull request. PipeCD detected `%d` updated applications and here are their plan results. Once this pull request got merged their deployments will be triggered to run as these estimations.\n" - detailsFormat = "
\nDetails (Click me)\n

\n\n``` %s\n%s\n```\n

\n
\n\n" - detailsOmittedMessage = "The details are too long to display. Please check the actions log to see full details." - appInfoWithEnvFormat = "app: [%s](%s), env: %s, kind: %s" - appInfoWithoutEnvFormat = "app: [%s](%s), kind: %s" + noChangeTitleFormat = "Ran plan-preview against head commit %s of this pull request. PipeCD detected `0` updated application. It means no deployment will be triggered once this pull request got merged.\n" + hasChangeTitleFormat = "Ran plan-preview against head commit %s of this pull request. PipeCD detected `%d` updated applications and here are their plan results. Once this pull request got merged their deployments will be triggered to run as these estimations.\n" + detailsFormat = "
\nDetails (Click me)\n

\n\n``` %s\n%s\n```\n

\n
\n\n" + detailsOmittedMessage = "The details are too long to display. Please check the actions log to see full details." + appInfoWithEnvFormat = "app: [%s](%s), env: %s, kind: %s" + appInfoWithoutEnvFormat = "app: [%s](%s), kind: %s" + appInfoWithEnvFormatV1 = "app: [%s](%s), env: %s, planned plugin(s): %s" + appInfoWithoutEnvFormatV1 = "app: [%s](%s), planned plugin(s): %s" ghMessageLenLimit = 65536 @@ -196,30 +210,64 @@ func makeCommentBody(event *githubEvent, r *PlanPreviewResult, title string) str for _, app := range changedApps { fmt.Fprintf(&b, "### %s\n", makeTitleText(&app.ApplicationInfo)) fmt.Fprintf(&b, "Sync strategy: %s\n", app.SyncStrategy) - fmt.Fprintf(&b, "Summary: %s\n\n", app.PlanSummary) - - var ( - lang = "diff" - details = app.PlanDetails - ) - if app.ApplicationKind == "TERRAFORM" { - lang = "hcl" - if shortened, err := generateTerraformShortPlanDetails(details); err == nil { - details = shortened + + if app.AllPluginNames == "" { + // pipedv0 + fmt.Fprintf(&b, "Summary: %s\n\n", app.PlanSummary) + var ( + lang = "diff" + details = app.PlanDetails + ) + if app.ApplicationKind == "TERRAFORM" { + lang = "hcl" + if shortened, err := generateTerraformShortPlanDetails(details); err == nil { + details = shortened + } } - } - l := utf8.RuneCountInString(details) - if detailLen+l > detailsLenLimit { - fmt.Fprintf(&b, detailsFormat, lang, detailsOmittedMessage) - detailLen += utf8.RuneCountInString(detailsOmittedMessage) - continue - } + l := utf8.RuneCountInString(details) + if detailLen+l > detailsLenLimit { + fmt.Fprintf(&b, detailsFormat, lang, detailsOmittedMessage) + detailLen += utf8.RuneCountInString(detailsOmittedMessage) + continue + } - if l > 0 { - detailLen += l - fmt.Fprintf(&b, detailsFormat, lang, details) + if l > 0 { + detailLen += l + fmt.Fprintf(&b, detailsFormat, lang, details) + } + } else { + // pipedv1 + fmt.Fprintf(&b, " plugin(s): %s\n", app.AllPluginNames) + fmt.Fprintf(&b, " summary:\n") + for _, ppr := range app.PluginPlanResults { + fmt.Fprintf(&b, " - %s(%s): %s\n", ppr.PluginName, ppr.DeployTarget, ppr.PlanSummary) + } + fmt.Fprint(&b, " details:\n\n") + for _, ppr := range app.PluginPlanResults { + fmt.Fprintf(&b, " - %s(%s):\n", ppr.PluginName, ppr.DeployTarget) + + details := string(ppr.PlanDetails) + if ppr.DiffLanguage == "hcl" { + if shortened, err := generateTerraformShortPlanDetails(details); err == nil { + details = shortened + } + } + + l := utf8.RuneCountInString(details) + if detailLen+l > detailsLenLimit { + fmt.Fprintf(&b, detailsFormat, ppr.DiffLanguage, detailsOmittedMessage) + detailLen += utf8.RuneCountInString(detailsOmittedMessage) + continue + } + + if l > 0 { + detailLen += l + fmt.Fprintf(&b, detailsFormat, ppr.DiffLanguage, details) + } + } } + } if len(pipelineApps)+len(quickSyncApps) > 0 { @@ -253,13 +301,24 @@ func makeCommentBody(event *githubEvent, r *PlanPreviewResult, title string) str fmt.Fprintf(&b, "\n### %s\n", makeTitleText(&app.ApplicationInfo)) fmt.Fprintf(&b, "Reason: %s\n\n", app.Reason) - var lang = "diff" - if app.ApplicationKind == "TERRAFORM" { - lang = "hcl" - } - - if len(app.PlanDetails) > 0 { - fmt.Fprintf(&b, detailsFormat, lang, app.PlanDetails) + if app.AllPluginNames == "" { + // pipedv0 + var lang = "diff" + if app.ApplicationKind == "TERRAFORM" { + lang = "hcl" + } + + if len(app.PlanDetails) > 0 { + fmt.Fprintf(&b, detailsFormat, lang, app.PlanDetails) + } + } else { + // pipedv1 + for _, ppr := range app.PluginPlanResults { + fmt.Fprintf(&b, " - %s(%s):\n", ppr.PluginName, ppr.DeployTarget) + if len(ppr.PlanDetails) > 0 { + fmt.Fprintf(&b, detailsFormat, ppr.DiffLanguage, ppr.PlanDetails) + } + } } } } @@ -311,10 +370,19 @@ func makeActionLogURL() string { } func makeTitleText(app *ApplicationInfo) string { - if app.Env == "" { - return fmt.Sprintf(appInfoWithoutEnvFormat, app.ApplicationName, app.ApplicationURL, strings.ToLower(app.ApplicationKind)) + if app.AllPluginNames == "" { + // pipedv0 + if app.Env == "" { + return fmt.Sprintf(appInfoWithoutEnvFormat, app.ApplicationName, app.ApplicationURL, strings.ToLower(app.ApplicationKind)) + } + return fmt.Sprintf(appInfoWithEnvFormat, app.ApplicationName, app.ApplicationURL, app.Env, strings.ToLower(app.ApplicationKind)) + } else { + // pipedv1 + if app.Env == "" { + return fmt.Sprintf(appInfoWithoutEnvFormatV1, app.ApplicationName, app.ApplicationURL, app.PlannedPluginNames) + } + return fmt.Sprintf(appInfoWithEnvFormatV1, app.ApplicationName, app.ApplicationURL, app.Env, app.PlannedPluginNames) } - return fmt.Sprintf(appInfoWithEnvFormat, app.ApplicationName, app.ApplicationURL, app.Env, strings.ToLower(app.ApplicationKind)) } func generateTerraformShortPlanDetails(details string) (string, error) { From a12f5d905adf3482f0917972169363d8c090b84d Mon Sep 17 00:00:00 2001 From: t-kikuc Date: Thu, 21 Aug 2025 18:23:37 +0900 Subject: [PATCH 2/6] add test: makeTitleText Signed-off-by: t-kikuc --- tool/actions-plan-preview/planpreview_test.go | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tool/actions-plan-preview/planpreview_test.go b/tool/actions-plan-preview/planpreview_test.go index e1beb638ce..5530bc749d 100644 --- a/tool/actions-plan-preview/planpreview_test.go +++ b/tool/actions-plan-preview/planpreview_test.go @@ -724,3 +724,62 @@ guarantee to take exactly these actions if you run "terraform apply" now.`, }) } } + +func TestMakeTitleText(t *testing.T) { + t.Parallel() + + testcases := []struct { + name string + app *ApplicationInfo + want string + }{ + { + name: "pipedv0: without env", + app: &ApplicationInfo{ + ApplicationName: "test-app", + ApplicationURL: "https://pipecd.dev/apps/test-app", + ApplicationKind: "KUBERNETES", + }, + want: "app: [test-app](https://pipecd.dev/apps/test-app), kind: kubernetes", + }, + { + name: "pipedv0: with env", + app: &ApplicationInfo{ + ApplicationName: "test-app", + ApplicationURL: "https://pipecd.dev/apps/test-app", + ApplicationKind: "KUBERNETES", + Env: "dev", + }, + want: "app: [test-app](https://pipecd.dev/apps/test-app), env: dev, kind: kubernetes", + }, + { + name: "pipedv1: without env", + app: &ApplicationInfo{ + ApplicationName: "test-app", + ApplicationURL: "https://pipecd.dev/apps/test-app", + PlannedPluginNames: "kubernetes", + AllPluginNames: "kubernetes,analysis", + }, + want: "app: [test-app](https://pipecd.dev/apps/test-app), planned plugin(s): kubernetes", + }, + { + name: "pipedv1: with env", + app: &ApplicationInfo{ + ApplicationName: "test-app", + ApplicationURL: "https://pipecd.dev/apps/test-app", + PlannedPluginNames: "kubernetes,terraform", + AllPluginNames: "kubernetes,terraform,analysis", + Env: "dev", + }, + want: "app: [test-app](https://pipecd.dev/apps/test-app), env: dev, planned plugin(s): kubernetes,terraform", + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + got := makeTitleText(tc.app) + assert.Equal(t, tc.want, got) + }) + } +} From 274905e5d507951e0f956965d8cd5ec46e9b30f7 Mon Sep 17 00:00:00 2001 From: t-kikuc Date: Fri, 22 Aug 2025 17:12:20 +0900 Subject: [PATCH 3/6] update tests Signed-off-by: t-kikuc --- tool/actions-plan-preview/planpreview.go | 11 +- tool/actions-plan-preview/planpreview_test.go | 146 ++++++++++++++++++ .../comment-plugin-has-failed-app.txt | 32 ++++ ...-plugin-one-failure-app-unknown-plugin.txt | 12 ++ ...lugin-one-success-app-multiple-plugins.txt | 36 +++++ .../comment-plugin-one-success-app.txt | 24 +++ 6 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 tool/actions-plan-preview/testdata/comment-plugin-has-failed-app.txt create mode 100644 tool/actions-plan-preview/testdata/comment-plugin-one-failure-app-unknown-plugin.txt create mode 100644 tool/actions-plan-preview/testdata/comment-plugin-one-success-app-multiple-plugins.txt create mode 100644 tool/actions-plan-preview/testdata/comment-plugin-one-success-app.txt diff --git a/tool/actions-plan-preview/planpreview.go b/tool/actions-plan-preview/planpreview.go index 5a059a7c6c..3356553f6d 100644 --- a/tool/actions-plan-preview/planpreview.go +++ b/tool/actions-plan-preview/planpreview.go @@ -238,17 +238,20 @@ func makeCommentBody(event *githubEvent, r *PlanPreviewResult, title string) str } } else { // pipedv1 - fmt.Fprintf(&b, " plugin(s): %s\n", app.AllPluginNames) - fmt.Fprintf(&b, " summary:\n") + fmt.Fprintf(&b, " Plugin(s): %s\n", app.AllPluginNames) + fmt.Fprintf(&b, " Summary:\n") for _, ppr := range app.PluginPlanResults { fmt.Fprintf(&b, " - %s(%s): %s\n", ppr.PluginName, ppr.DeployTarget, ppr.PlanSummary) } - fmt.Fprint(&b, " details:\n\n") + fmt.Fprint(&b, " Details:\n") for _, ppr := range app.PluginPlanResults { fmt.Fprintf(&b, " - %s(%s):\n", ppr.PluginName, ppr.DeployTarget) details := string(ppr.PlanDetails) - if ppr.DiffLanguage == "hcl" { + switch ppr.DiffLanguage { + case "": + ppr.DiffLanguage = "diff" // Use diff by default + case "hcl": if shortened, err := generateTerraformShortPlanDetails(details); err == nil { details = shortened } diff --git a/tool/actions-plan-preview/planpreview_test.go b/tool/actions-plan-preview/planpreview_test.go index 5530bc749d..6f6105844c 100644 --- a/tool/actions-plan-preview/planpreview_test.go +++ b/tool/actions-plan-preview/planpreview_test.go @@ -18,6 +18,7 @@ import ( "os" "testing" + "github.com/pipe-cd/pipecd/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -233,6 +234,151 @@ func TestMakeCommentBody(t *testing.T) { }, expected: "testdata/comment-has-failed-piped.txt", }, + // pipedv1 + { + name: "plugin: one success app", + event: githubEvent{ + HeadCommit: "abc", + }, + title: "", + result: PlanPreviewResult{ + Applications: []ApplicationResult{ + { + ApplicationInfo: ApplicationInfo{ + ApplicationID: "app-1", + ApplicationName: "app-name-1", + ApplicationURL: "app-url-1", + Env: "env-1", + PlannedPluginNames: "kubernetes", + AllPluginNames: "kubernetes", + ApplicationDirectory: "app-dir-1", + }, + SyncStrategy: "QUICK_SYNC", + NoChange: false, + PluginPlanResults: []*model.PluginPlanPreviewResult{ + { + PluginName: "kubernetes", + DeployTarget: "dt-1", + PlanSummary: []byte("2 resources will be added, 1 resource will be deleted and 5 resources will be changed"), + PlanDetails: []byte("details-1"), + }, + }, + }, + }, + }, + expected: "testdata/comment-plugin-one-success-app.txt", + }, + { + name: "plugin: one success app with multiple plugins", + event: githubEvent{ + HeadCommit: "abc", + }, + title: "", + result: PlanPreviewResult{ + Applications: []ApplicationResult{ + { + ApplicationInfo: ApplicationInfo{ + ApplicationID: "app-1", + ApplicationName: "app-name-1", + ApplicationURL: "app-url-1", + Env: "env-1", + PlannedPluginNames: "kubernetes, terraform", + AllPluginNames: "kubernetes, terraform, analysis", + ApplicationDirectory: "app-dir-1", + }, + SyncStrategy: "PIPELINE", + NoChange: false, + PluginPlanResults: []*model.PluginPlanPreviewResult{ + { + PluginName: "kubernetes", + DeployTarget: "dt-1", + PlanSummary: []byte("2 resources will be added, 1 resource will be deleted and 5 resources will be changed"), + PlanDetails: []byte("details-1"), + }, + { + PluginName: "terraform", + DeployTarget: "dt-2", + PlanSummary: []byte("1 resource will be added, 2 resources will be deleted and 3 resources will be changed"), + PlanDetails: []byte("details-2"), + DiffLanguage: "hcl", + }, + }, + }, + }, + }, + expected: "testdata/comment-plugin-one-success-app-multiple-plugins.txt", + }, + { + name: "plugin: has failed app", + event: githubEvent{ + HeadCommit: "abc", + }, + title: "", + result: PlanPreviewResult{ + Applications: []ApplicationResult{ + { + ApplicationInfo: ApplicationInfo{ + ApplicationID: "app-1", + ApplicationName: "app-name-1", + ApplicationURL: "app-url-1", + Env: "env-1", + PlannedPluginNames: "kubernetes", + AllPluginNames: "kubernetes", + ApplicationDirectory: "app-dir-1", + }, + SyncStrategy: "PIPELINE", + NoChange: false, + PluginPlanResults: []*model.PluginPlanPreviewResult{ + { + PluginName: "kubernetes", + DeployTarget: "dt-1", + PlanSummary: []byte("2 resources will be added, 1 resource will be deleted and 5 resources will be changed"), + PlanDetails: []byte("details-1"), + }, + }, + }, + }, + FailureApplications: []FailureApplication{ + { + ApplicationInfo: ApplicationInfo{ + ApplicationID: "app-2", + ApplicationName: "app-name-2", + ApplicationURL: "app-url-2", + Env: "env-2", + PlannedPluginNames: "kubernetes-failed", + AllPluginNames: "kubernetes-failed", + ApplicationDirectory: "app-dir-2", + }, + Reason: "wrong application configuration", + }, + }, + }, + expected: "testdata/comment-plugin-has-failed-app.txt", + }, + { + name: "plugin: one failure app with unknown plugin", + event: githubEvent{ + HeadCommit: "abc", + }, + title: "", + result: PlanPreviewResult{ + FailureApplications: []FailureApplication{ + { + ApplicationInfo: ApplicationInfo{ + ApplicationID: "app-2", + ApplicationName: "app-name-2", + ApplicationURL: "app-url-2", + Env: "env-2", + PlannedPluginNames: "", + AllPluginNames: "", + ApplicationDirectory: "app-dir-2", + }, + Reason: "wrong application configuration", + }, + }, + }, + expected: "testdata/comment-plugin-one-failure-app-unknown-plugin.txt", + }, } for _, tc := range testcases { diff --git a/tool/actions-plan-preview/testdata/comment-plugin-has-failed-app.txt b/tool/actions-plan-preview/testdata/comment-plugin-has-failed-app.txt new file mode 100644 index 0000000000..75ad24583e --- /dev/null +++ b/tool/actions-plan-preview/testdata/comment-plugin-has-failed-app.txt @@ -0,0 +1,32 @@ + +[![PLAN_PREVIEW](https://img.shields.io/static/v1?label=PipeCD&message=Plan_Preview&color=orange&style=flat)](https://pipecd.dev/docs/user-guide/plan-preview/) + +Ran plan-preview against head commit abc of this pull request. PipeCD detected `1` updated applications and here are their plan results. Once this pull request got merged their deployments will be triggered to run as these estimations. + +## Plans + +### app: [app-name-1](app-url-1), env: env-1, planned plugin(s): kubernetes +Sync strategy: PIPELINE + Plugin(s): kubernetes + Summary: + - kubernetes(dt-1): 2 resources will be added, 1 resource will be deleted and 5 resources will be changed + Details: + - kubernetes(dt-1): +
+Details (Click me) +

+ +``` diff +details-1 +``` +

+
+ + +## NOTE + +**An error occurred while building plan-preview for the following applications** + +### app: [app-name-2](app-url-2), env: env-2, planned plugin(s): kubernetes-failed +Reason: wrong application configuration + diff --git a/tool/actions-plan-preview/testdata/comment-plugin-one-failure-app-unknown-plugin.txt b/tool/actions-plan-preview/testdata/comment-plugin-one-failure-app-unknown-plugin.txt new file mode 100644 index 0000000000..00bac32567 --- /dev/null +++ b/tool/actions-plan-preview/testdata/comment-plugin-one-failure-app-unknown-plugin.txt @@ -0,0 +1,12 @@ + +[![PLAN_PREVIEW](https://img.shields.io/static/v1?label=PipeCD&message=Plan_Preview&color=orange&style=flat)](https://pipecd.dev/docs/user-guide/plan-preview/) + +Ran plan-preview against head commit abc of this pull request. PipeCD detected `0` updated applications and here are their plan results. Once this pull request got merged their deployments will be triggered to run as these estimations. + +## NOTE + +**An error occurred while building plan-preview for the following applications** + +### app: [app-name-2](app-url-2), env: env-2, planned plugin(s): +Reason: wrong application configuration + diff --git a/tool/actions-plan-preview/testdata/comment-plugin-one-success-app-multiple-plugins.txt b/tool/actions-plan-preview/testdata/comment-plugin-one-success-app-multiple-plugins.txt new file mode 100644 index 0000000000..29848849d3 --- /dev/null +++ b/tool/actions-plan-preview/testdata/comment-plugin-one-success-app-multiple-plugins.txt @@ -0,0 +1,36 @@ + +[![PLAN_PREVIEW](https://img.shields.io/static/v1?label=PipeCD&message=Plan_Preview&color=success&style=flat)](https://pipecd.dev/docs/user-guide/plan-preview/) + +Ran plan-preview against head commit abc of this pull request. PipeCD detected `1` updated applications and here are their plan results. Once this pull request got merged their deployments will be triggered to run as these estimations. + +## Plans + +### app: [app-name-1](app-url-1), env: env-1, planned plugin(s): kubernetes, terraform +Sync strategy: PIPELINE + Plugin(s): kubernetes, terraform, analysis + Summary: + - kubernetes(dt-1): 2 resources will be added, 1 resource will be deleted and 5 resources will be changed + - terraform(dt-2): 1 resource will be added, 2 resources will be deleted and 3 resources will be changed + Details: + - kubernetes(dt-1): +
+Details (Click me) +

+ +``` diff +details-1 +``` +

+
+ + - terraform(dt-2): +
+Details (Click me) +

+ +``` hcl +details-2 +``` +

+
+ diff --git a/tool/actions-plan-preview/testdata/comment-plugin-one-success-app.txt b/tool/actions-plan-preview/testdata/comment-plugin-one-success-app.txt new file mode 100644 index 0000000000..46ce9aee76 --- /dev/null +++ b/tool/actions-plan-preview/testdata/comment-plugin-one-success-app.txt @@ -0,0 +1,24 @@ + +[![PLAN_PREVIEW](https://img.shields.io/static/v1?label=PipeCD&message=Plan_Preview&color=success&style=flat)](https://pipecd.dev/docs/user-guide/plan-preview/) + +Ran plan-preview against head commit abc of this pull request. PipeCD detected `1` updated applications and here are their plan results. Once this pull request got merged their deployments will be triggered to run as these estimations. + +## Plans + +### app: [app-name-1](app-url-1), env: env-1, planned plugin(s): kubernetes +Sync strategy: QUICK_SYNC + Plugin(s): kubernetes + Summary: + - kubernetes(dt-1): 2 resources will be added, 1 resource will be deleted and 5 resources will be changed + Details: + - kubernetes(dt-1): +
+Details (Click me) +

+ +``` diff +details-1 +``` +

+
+ From af6dc0a736b8786d79ae33fab90d93773c1a61f5 Mon Sep 17 00:00:00 2001 From: t-kikuc Date: Fri, 22 Aug 2025 17:12:27 +0900 Subject: [PATCH 4/6] update pipectl version Signed-off-by: t-kikuc --- tool/actions-plan-preview/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/actions-plan-preview/Dockerfile b/tool/actions-plan-preview/Dockerfile index 81e8520d98..c2e340e22c 100644 --- a/tool/actions-plan-preview/Dockerfile +++ b/tool/actions-plan-preview/Dockerfile @@ -5,7 +5,7 @@ RUN go mod download COPY . ./ RUN go build -o /plan-preview . -FROM ghcr.io/pipe-cd/pipectl:v0.43.1 +FROM ghcr.io/pipe-cd/pipectl:v0.53.0 COPY --from=builder /plan-preview / ENV PATH=$PATH:/app/cmd/pipectl RUN chmod +x /plan-preview From 7ee9aef68978bce1369292911958256c7cfa18e7 Mon Sep 17 00:00:00 2001 From: t-kikuc Date: Fri, 22 Aug 2025 17:19:53 +0900 Subject: [PATCH 5/6] go mod tidy Signed-off-by: t-kikuc --- tool/actions-plan-preview/go.mod | 10 +++++++--- tool/actions-plan-preview/go.sum | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tool/actions-plan-preview/go.mod b/tool/actions-plan-preview/go.mod index 6de80b542c..48b1dd3a4c 100644 --- a/tool/actions-plan-preview/go.mod +++ b/tool/actions-plan-preview/go.mod @@ -6,16 +6,20 @@ require ( github.com/google/go-github/v36 v36.0.0 github.com/pipe-cd/pipecd v0.53.0 github.com/shurcooL/githubv4 v0.0.0-20220115235240-a14260e6f8a2 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.10.0 golang.org/x/oauth2 v0.27.0 ) require ( - github.com/davecgh/go-spew v1.1.0 // indirect + github.com/coreos/go-oidc/v3 v3.11.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/google/go-querystring v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/net v0.38.0 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/tool/actions-plan-preview/go.sum b/tool/actions-plan-preview/go.sum index a400fffed9..3ea7a329a0 100644 --- a/tool/actions-plan-preview/go.sum +++ b/tool/actions-plan-preview/go.sum @@ -1,9 +1,15 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v36 v36.0.0 h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs= github.com/google/go-github/v36 v36.0.0/go.mod h1:LFlKC047IOqiglRGNqNb9s/iAPTnnjtlshm+bxp+kwk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= @@ -31,6 +37,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From f03649f43964aed7e5e630cf7ec78269b654eb69 Mon Sep 17 00:00:00 2001 From: t-kikuc Date: Fri, 22 Aug 2025 17:26:19 +0900 Subject: [PATCH 6/6] fix lint Signed-off-by: t-kikuc --- tool/actions-plan-preview/planpreview.go | 3 ++- tool/actions-plan-preview/planpreview_test.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tool/actions-plan-preview/planpreview.go b/tool/actions-plan-preview/planpreview.go index 3356553f6d..bb7583e74a 100644 --- a/tool/actions-plan-preview/planpreview.go +++ b/tool/actions-plan-preview/planpreview.go @@ -27,8 +27,9 @@ import ( "time" "unicode/utf8" - "github.com/pipe-cd/pipecd/pkg/model" "github.com/shurcooL/githubv4" + + "github.com/pipe-cd/pipecd/pkg/model" ) type PlanPreviewResult struct { diff --git a/tool/actions-plan-preview/planpreview_test.go b/tool/actions-plan-preview/planpreview_test.go index 6f6105844c..10f410ff41 100644 --- a/tool/actions-plan-preview/planpreview_test.go +++ b/tool/actions-plan-preview/planpreview_test.go @@ -18,9 +18,10 @@ import ( "os" "testing" - "github.com/pipe-cd/pipecd/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/pipe-cd/pipecd/pkg/model" ) func TestMakeCommentBody(t *testing.T) {