From 1d52ce4ce866b5537569bdc2f02a6dfaded7768f Mon Sep 17 00:00:00 2001 From: Johnny Winn Date: Mon, 22 Sep 2025 20:08:52 -0600 Subject: [PATCH] feat: enhance pipeline coupling errors for mixed generations - Add contextual error messages when coupling apps from different generations - Include app name and generation in error output for better UX - Update pipeline documentation with generation compatibility requirements Addresses mixed-generation pipeline error handling work item. --- docs/resources/pipeline.md | 5 +++++ heroku/resource_heroku_pipeline_coupling.go | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/resources/pipeline.md b/docs/resources/pipeline.md index cc9f5e13..1ebceddc 100644 --- a/docs/resources/pipeline.md +++ b/docs/resources/pipeline.md @@ -17,6 +17,11 @@ pipeline is created, and apps are added to different stages using [`heroku_pipeline_coupling`](./pipeline_coupling.html), you can promote app slugs to the next stage. +## Generation Compatibility + +All apps in a pipeline must use the same Heroku platform generation (Cedar or Fir). +Attempting to add apps from different generations will result in an error. + ## Ownership & Access Pipelines may be created as Personal or Team resources. Access to a pipeline diff --git a/heroku/resource_heroku_pipeline_coupling.go b/heroku/resource_heroku_pipeline_coupling.go index 11c42217..ac46b8fb 100644 --- a/heroku/resource_heroku_pipeline_coupling.go +++ b/heroku/resource_heroku_pipeline_coupling.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -67,7 +68,15 @@ func resourceHerokuPipelineCouplingCreate(d *schema.ResourceData, meta interface p, err := client.PipelineCouplingCreate(context.TODO(), opts) if err != nil { - return fmt.Errorf("Error creating pipeline: %s", err) + // Enhance generation-related errors with app context + errMsg := err.Error() + if strings.Contains(errMsg, "same generation") { + if app, appErr := client.AppInfo(context.TODO(), d.Get("app_id").(string)); appErr == nil { + return fmt.Errorf("%s\n\nYour app '%s' is %s generation. Ensure all apps in the pipeline use the same generation (Cedar or Fir)", + errMsg, app.Name, app.Generation.Name) + } + } + return fmt.Errorf("error creating pipeline: %s", err) } d.SetId(p.ID) @@ -84,7 +93,7 @@ func resourceHerokuPipelineCouplingDelete(d *schema.ResourceData, meta interface _, err := client.PipelineCouplingDelete(context.TODO(), d.Id()) if err != nil { - return fmt.Errorf("Error deleting pipeline: %s", err) + return fmt.Errorf("error deleting pipeline: %s", err) } return nil @@ -95,7 +104,7 @@ func resourceHerokuPipelineCouplingRead(d *schema.ResourceData, meta interface{} p, err := client.PipelineCouplingInfo(context.TODO(), d.Id()) if err != nil { - return fmt.Errorf("Error retrieving pipeline: %s", err) + return fmt.Errorf("error retrieving pipeline: %s", err) } d.Set("app_id", p.App.ID)