Merge pull request #13910 from bernerdschaefer/bs-heroku-buildpacks
provider/heroku: set app buildpacks from config
This commit is contained in:
commit
c839a7b2ff
|
@ -30,6 +30,7 @@ type application struct {
|
|||
App *herokuApplication // The heroku application
|
||||
Client *heroku.Service // Client to interact with the heroku API
|
||||
Vars map[string]string // The vars on the application
|
||||
Buildpacks []string // The application's buildpack names or URLs
|
||||
Organization bool // is the application organization app
|
||||
}
|
||||
|
||||
|
@ -71,6 +72,11 @@ func (a *application) Update() error {
|
|||
}
|
||||
}
|
||||
|
||||
a.Buildpacks, err = retrieveBuildpacks(a.Id, a.Client)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
a.Vars, err = retrieveConfigVars(a.Id, a.Client)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
|
@ -109,6 +115,14 @@ func resourceHerokuApp() *schema.Resource {
|
|||
ForceNew: true,
|
||||
},
|
||||
|
||||
"buildpacks": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
"config_vars": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
|
@ -215,6 +229,10 @@ func resourceHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("buildpacks"); ok {
|
||||
err = updateBuildpacks(d.Id(), client, v.([]interface{}))
|
||||
}
|
||||
|
||||
return resourceHerokuAppRead(d, meta)
|
||||
}
|
||||
|
||||
|
@ -293,6 +311,9 @@ func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Only track buildpacks when set in the configuration.
|
||||
_, buildpacksConfigured := d.GetOk("buildpacks")
|
||||
|
||||
organizationApp := isOrganizationApp(d)
|
||||
|
||||
// Only set the config_vars that we have set in the configuration.
|
||||
|
@ -317,6 +338,9 @@ func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("region", app.App.Region)
|
||||
d.Set("git_url", app.App.GitURL)
|
||||
d.Set("web_url", app.App.WebURL)
|
||||
if buildpacksConfigured {
|
||||
d.Set("buildpacks", app.Buildpacks)
|
||||
}
|
||||
d.Set("config_vars", configVarsValue)
|
||||
d.Set("all_config_vars", app.Vars)
|
||||
if organizationApp {
|
||||
|
@ -374,6 +398,13 @@ func resourceHerokuAppUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
if d.HasChange("buildpacks") {
|
||||
err := updateBuildpacks(d.Id(), client, d.Get("buildpacks").([]interface{}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return resourceHerokuAppRead(d, meta)
|
||||
}
|
||||
|
||||
|
@ -402,6 +433,21 @@ func resourceHerokuAppRetrieve(id string, organization bool, client *heroku.Serv
|
|||
return &app, nil
|
||||
}
|
||||
|
||||
func retrieveBuildpacks(id string, client *heroku.Service) ([]string, error) {
|
||||
results, err := client.BuildpackInstallationList(context.TODO(), id, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buildpacks := []string{}
|
||||
for _, installation := range results {
|
||||
buildpacks = append(buildpacks, installation.Buildpack.Name)
|
||||
}
|
||||
|
||||
return buildpacks, nil
|
||||
}
|
||||
|
||||
func retrieveConfigVars(id string, client *heroku.Service) (map[string]string, error) {
|
||||
vars, err := client.ConfigVarInfoForApp(context.TODO(), id)
|
||||
|
||||
|
@ -450,3 +496,24 @@ func updateConfigVars(
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateBuildpacks(id string, client *heroku.Service, v []interface{}) error {
|
||||
opts := heroku.BuildpackInstallationUpdateOpts{
|
||||
Updates: []struct {
|
||||
Buildpack string `json:"buildpack" url:"buildpack,key"`
|
||||
}{}}
|
||||
|
||||
for _, buildpack := range v {
|
||||
opts.Updates = append(opts.Updates, struct {
|
||||
Buildpack string `json:"buildpack" url:"buildpack,key"`
|
||||
}{
|
||||
Buildpack: buildpack.(string),
|
||||
})
|
||||
}
|
||||
|
||||
if _, err := client.BuildpackInstallationUpdate(context.TODO(), id, opts); err != nil {
|
||||
return fmt.Errorf("Error updating buildpacks: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -109,6 +109,75 @@ func TestAccHerokuApp_NukeVars(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccHerokuApp_Buildpacks(t *testing.T) {
|
||||
var app heroku.AppInfoResult
|
||||
appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckHerokuAppDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckHerokuAppConfig_go(appName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckHerokuAppExists("heroku_app.foobar", &app),
|
||||
testAccCheckHerokuAppBuildpacks(appName, false),
|
||||
resource.TestCheckResourceAttr("heroku_app.foobar", "buildpacks.0", "heroku/go"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccCheckHerokuAppConfig_multi(appName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckHerokuAppExists("heroku_app.foobar", &app),
|
||||
testAccCheckHerokuAppBuildpacks(appName, true),
|
||||
resource.TestCheckResourceAttr(
|
||||
"heroku_app.foobar", "buildpacks.0", "https://github.com/heroku/heroku-buildpack-multi-procfile"),
|
||||
resource.TestCheckResourceAttr("heroku_app.foobar", "buildpacks.1", "heroku/go"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccCheckHerokuAppConfig_no_vars(appName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckHerokuAppExists("heroku_app.foobar", &app),
|
||||
testAccCheckHerokuAppNoBuildpacks(appName),
|
||||
resource.TestCheckNoResourceAttr("heroku_app.foobar", "buildpacks.0"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccHerokuApp_ExternallySetBuildpacks(t *testing.T) {
|
||||
var app heroku.AppInfoResult
|
||||
appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckHerokuAppDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckHerokuAppConfig_no_vars(appName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckHerokuAppExists("heroku_app.foobar", &app),
|
||||
testAccCheckHerokuAppNoBuildpacks(appName),
|
||||
resource.TestCheckNoResourceAttr("heroku_app.foobar", "buildpacks.0"),
|
||||
),
|
||||
},
|
||||
{
|
||||
PreConfig: testAccInstallUnconfiguredBuildpack(t, appName),
|
||||
Config: testAccCheckHerokuAppConfig_no_vars(appName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckHerokuAppExists("heroku_app.foobar", &app),
|
||||
testAccCheckHerokuAppBuildpacks(appName, false),
|
||||
resource.TestCheckNoResourceAttr("heroku_app.foobar", "buildpacks.0"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccHerokuApp_Organization(t *testing.T) {
|
||||
var app heroku.OrganizationApp
|
||||
appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
|
||||
|
@ -230,6 +299,59 @@ func testAccCheckHerokuAppAttributesNoVars(app *heroku.AppInfoResult, appName st
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppBuildpacks(appName string, multi bool) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
||||
results, err := client.BuildpackInstallationList(context.TODO(), appName, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buildpacks := []string{}
|
||||
for _, installation := range results {
|
||||
buildpacks = append(buildpacks, installation.Buildpack.Name)
|
||||
}
|
||||
|
||||
if multi {
|
||||
herokuMulti := "https://github.com/heroku/heroku-buildpack-multi-procfile"
|
||||
if len(buildpacks) != 2 || buildpacks[0] != herokuMulti || buildpacks[1] != "heroku/go" {
|
||||
return fmt.Errorf("Bad buildpacks: %v", buildpacks)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(buildpacks) != 1 || buildpacks[0] != "heroku/go" {
|
||||
return fmt.Errorf("Bad buildpacks: %v", buildpacks)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppNoBuildpacks(appName string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
||||
results, err := client.BuildpackInstallationList(context.TODO(), appName, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buildpacks := []string{}
|
||||
for _, installation := range results {
|
||||
buildpacks = append(buildpacks, installation.Buildpack.Name)
|
||||
}
|
||||
|
||||
if len(buildpacks) != 0 {
|
||||
return fmt.Errorf("Bad buildpacks: %v", buildpacks)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppAttributesOrg(app *heroku.OrganizationApp, appName string, org string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
@ -323,6 +445,25 @@ func testAccCheckHerokuAppExistsOrg(n string, app *heroku.OrganizationApp) resou
|
|||
}
|
||||
}
|
||||
|
||||
func testAccInstallUnconfiguredBuildpack(t *testing.T, appName string) func() {
|
||||
return func() {
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
||||
opts := heroku.BuildpackInstallationUpdateOpts{
|
||||
Updates: []struct {
|
||||
Buildpack string `json:"buildpack" url:"buildpack,key"`
|
||||
}{
|
||||
{Buildpack: "heroku/go"},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := client.BuildpackInstallationUpdate(context.TODO(), appName, opts)
|
||||
if err != nil {
|
||||
t.Fatalf("Error updating buildpacks: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppConfig_basic(appName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "heroku_app" "foobar" {
|
||||
|
@ -335,6 +476,29 @@ resource "heroku_app" "foobar" {
|
|||
}`, appName)
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppConfig_go(appName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "heroku_app" "foobar" {
|
||||
name = "%s"
|
||||
region = "us"
|
||||
|
||||
buildpacks = ["heroku/go"]
|
||||
}`, appName)
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppConfig_multi(appName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "heroku_app" "foobar" {
|
||||
name = "%s"
|
||||
region = "us"
|
||||
|
||||
buildpacks = [
|
||||
"https://github.com/heroku/heroku-buildpack-multi-procfile",
|
||||
"heroku/go"
|
||||
]
|
||||
}`, appName)
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppConfig_updated(appName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "heroku_app" "foobar" {
|
||||
|
|
|
@ -22,6 +22,10 @@ resource "heroku_app" "default" {
|
|||
config_vars {
|
||||
FOOBAR = "baz"
|
||||
}
|
||||
|
||||
buildpacks = [
|
||||
"heroku/go"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -34,6 +38,8 @@ The following arguments are supported:
|
|||
* `region` - (Required) The region that the app should be deployed in.
|
||||
* `stack` - (Optional) The application stack is what platform to run the application
|
||||
in.
|
||||
* `buildpacks` - (Optional) Buildpack names or URLs for the application.
|
||||
Buildpacks configured externally won't be altered if this is not present.
|
||||
* `config_vars` - (Optional) Configuration variables for the application.
|
||||
The config variables in this map are not the final set of configuration
|
||||
variables, but rather variables you want present. That is, other
|
||||
|
|
Loading…
Reference in New Issue