diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 9cc5f82a4..b1346fbf8 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -30,15 +30,28 @@ jobs: - name: Install Terraform run: | set -eu - curl -s -L "https://releases.hashicorp.com/terraform/1.3.6/terraform_1.3.6_linux_amd64.zip" > "terraform-bin.zip" + terraform_version="1.6.6" - # overwrite existing Terraform binary + set +e terraform_bin="$(which terraform)" + set -e + if [ -z "$terraform_bin" ] + then + terraform_bin="/usr/local/bin/terraform" + echo "Installing Terraform ($terraform_bin)" + else + echo "Replacing Terraform ($terraform_bin)" + fi + echo "Downloading version $terraform_version" + curl -s -L "https://releases.hashicorp.com/terraform/${terraform_version}/terraform_${terraform_version}_linux_amd64.zip" > "terraform-bin.zip" + echo "Unzipping archive" unzip -p terraform-bin.zip > terraform-bin + echo "Moving into place" sudo mv terraform-bin "$terraform_bin" + echo "Making executable" sudo chmod +x "$terraform_bin" + echo "Cleaning-up" rm terraform-bin.zip - echo "Installed: $(eval "$terraform_bin version") ($terraform_bin)" - name: Run make fmt diff --git a/.go-version b/.go-version index e6dbb7c23..6521720b4 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.11.5 +1.24.5 diff --git a/docs/resources/cert.md b/docs/resources/cert.md deleted file mode 100644 index d7cea4c06..000000000 --- a/docs/resources/cert.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -layout: "heroku" -page_title: "Heroku: heroku_cert" -sidebar_current: "docs-heroku-resource-cert" -description: |- - Provides a Heroku SSL certificate resource to manage a certificate for a Heroku app. ---- - -# heroku\_cert - -This resource manages an SSL certificate for a Heroku app. - -!> **WARNING:** This resource is deprecated in favor of `heroku_ssl`. - -## Example Usage - -```hcl-terraform -# Create a new Heroku app -resource "heroku_app" "default" { - name = "test-app" - region = "us" -} - -# Add-on SSL to application -resource "heroku_addon" "ssl" { - app_id = heroku_app.default.id - plan = "ssl" -} - -# Establish certificate for a given application -resource "heroku_cert" "ssl_certificate" { - app = heroku_app.default.id - certificate_chain = file("server.crt") - private_key = file("server.key") - depends_on = ["heroku_addon.ssl"] -} -``` - -## Argument Reference - -The following arguments are supported: - -* `app` - (Required) Heroku app ID (do not use app name) -* `certificate_chain` - (Required) The certificate chain to add -* `private_key` - (Required) The private key for a given certificate chain - -## Attributes Reference - -The following attributes are exported: - -* `id` - The ID of the add-on -* `cname` - The CNAME for the SSL endpoint -* `name` - The name of the SSL certificate - -## Importing - -When importing a Heroku cert resource, the ID must be built using the app name colon the unique ID from the Heroku API. For an app named `production-api` with a certificate ID of `b85d9224-310b-409b-891e-c903f5a40568`, you would import it as: - -``` -$ terraform import heroku_cert.production_api production-api:b85d9224-310b-409b-891e-c903f5a40568 -``` diff --git a/go.mod b/go.mod index 9825fb1c2..fbbe36a08 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,11 @@ module github.com/heroku/terraform-provider-heroku/v5 require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 - github.com/heroku/heroku-go/v5 v5.4.1 + github.com/heroku/heroku-go/v6 v6.0.0 github.com/mitchellh/go-homedir v1.1.0 github.com/verybluebot/tarinator-go v0.0.0-20190613183509-5ab4e1193986 ) @@ -61,4 +61,4 @@ require ( google.golang.org/protobuf v1.28.1 // indirect ) -go 1.19 +go 1.24 diff --git a/go.sum b/go.sum index f41863b4a..062156604 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,7 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYU github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= @@ -21,7 +22,6 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -47,6 +47,7 @@ github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6 github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -72,12 +73,11 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= @@ -123,14 +123,15 @@ github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKL github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/heroku/heroku-go/v5 v5.4.1 h1:J1nNnR3/571b2iUDHl+y1B3VkhKm6YOXIq9GGzQUv5s= -github.com/heroku/heroku-go/v5 v5.4.1/go.mod h1:Uo3XhGPwaTpniR4X1e50BDjg4SzdFk2Bd2mgYZVkfHo= +github.com/heroku/heroku-go/v6 v6.0.0 h1:uKZOlgu2iv8rwDkemxnEzogPbMHHhvpSAA8ZKS+Xmfs= +github.com/heroku/heroku-go/v6 v6.0.0/go.mod h1:TOVibkAD3yVSHzG0hIJc9KkyxuXiDNcr3zalcdjyeRc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -143,6 +144,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= @@ -164,9 +166,9 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -177,6 +179,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/heroku/config.go b/heroku/config.go index 60ba2064a..c6a73b9d5 100644 --- a/heroku/config.go +++ b/heroku/config.go @@ -13,7 +13,7 @@ import ( "github.com/bgentry/go-netrc/netrc" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" "github.com/heroku/terraform-provider-heroku/v5/version" homedir "github.com/mitchellh/go-homedir" ) diff --git a/heroku/data_source_heroku_app.go b/heroku/data_source_heroku_app.go index 99527782e..ed430336f 100644 --- a/heroku/data_source_heroku_app.go +++ b/heroku/data_source_heroku_app.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func dataSourceHerokuApp() *schema.Resource { diff --git a/heroku/data_source_heroku_team_members.go b/heroku/data_source_heroku_team_members.go index 5ab49cc7b..984555ab8 100644 --- a/heroku/data_source_heroku_team_members.go +++ b/heroku/data_source_heroku_team_members.go @@ -3,10 +3,11 @@ package heroku import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) var ( diff --git a/heroku/helper.go b/heroku/helper.go index b5ef28da7..3f2aec1be 100644 --- a/heroku/helper.go +++ b/heroku/helper.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" "github.com/heroku/terraform-provider-heroku/v5/version" ) diff --git a/heroku/import_heroku_cert_test.go b/heroku/import_heroku_cert_test.go deleted file mode 100644 index 842ca06f3..000000000 --- a/heroku/import_heroku_cert_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package heroku - -import ( - "fmt" - "os" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccHerokuCert_importBasic(t *testing.T) { - t.Skip("SSL Endpoint shutdown: https://devcenter.heroku.com/changelog-items/2280") - - appName := fmt.Sprintf("tftest-%s", acctest.RandString(10)) - - wd, _ := os.Getwd() - certFile := wd + "/test-fixtures/terraform.cert" - keyFile := wd + "/test-fixtures/terraform.key" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckHerokuCertDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckHerokuCertUSConfig(appName, certFile, keyFile), - }, - { - ResourceName: "heroku_cert.ssl_certificate", - ImportStateIdPrefix: appName + ":", - ImportState: true, - }, - }, - }) -} diff --git a/heroku/import_heroku_pipeline_coupling_test.go b/heroku/import_heroku_pipeline_coupling_test.go index 8404d613e..41b81f915 100644 --- a/heroku/import_heroku_pipeline_coupling_test.go +++ b/heroku/import_heroku_pipeline_coupling_test.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuPipelineCoupling_importBasic(t *testing.T) { diff --git a/heroku/provider.go b/heroku/provider.go index 4d368c35d..dcf50c5c2 100644 --- a/heroku/provider.go +++ b/heroku/provider.go @@ -5,7 +5,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) // Provider returns a terraform.ResourceProvider. @@ -111,7 +111,6 @@ func Provider() *schema.Provider { "heroku_app_release": resourceHerokuAppRelease(), "heroku_app_webhook": resourceHerokuAppWebhook(), "heroku_build": resourceHerokuBuild(), - "heroku_cert": resourceHerokuCert(), "heroku_collaborator": resourceHerokuCollaborator(), "heroku_config": resourceHerokuConfig(), "heroku_domain": resourceHerokuDomain(), diff --git a/heroku/resource_heroku_account_feature.go b/heroku/resource_heroku_account_feature.go index 73d225dcb..708516590 100644 --- a/heroku/resource_heroku_account_feature.go +++ b/heroku/resource_heroku_account_feature.go @@ -6,7 +6,7 @@ import ( "log" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAccountFeature() *schema.Resource { diff --git a/heroku/resource_heroku_account_feature_test.go b/heroku/resource_heroku_account_feature_test.go index a3f185c05..b211dc620 100644 --- a/heroku/resource_heroku_account_feature_test.go +++ b/heroku/resource_heroku_account_feature_test.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuAccountFeature_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_addon.go b/heroku/resource_heroku_addon.go index 5c9ae2505..706f6d16b 100644 --- a/heroku/resource_heroku_addon.go +++ b/heroku/resource_heroku_addon.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) // Global lock to prevent parallelism for heroku_addon since diff --git a/heroku/resource_heroku_addon_attachment.go b/heroku/resource_heroku_addon_attachment.go index 553eddd99..de9a2027f 100644 --- a/heroku/resource_heroku_addon_attachment.go +++ b/heroku/resource_heroku_addon_attachment.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAddonAttachment() *schema.Resource { diff --git a/heroku/resource_heroku_addon_attachment_migrate.go b/heroku/resource_heroku_addon_attachment_migrate.go index 9a59123f6..d7ee8deda 100644 --- a/heroku/resource_heroku_addon_attachment_migrate.go +++ b/heroku/resource_heroku_addon_attachment_migrate.go @@ -3,9 +3,10 @@ package heroku import ( "context" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAddonAttachmentMigrateState(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { diff --git a/heroku/resource_heroku_addon_migrate.go b/heroku/resource_heroku_addon_migrate.go index 3be5e0a64..e510ed7c1 100644 --- a/heroku/resource_heroku_addon_migrate.go +++ b/heroku/resource_heroku_addon_migrate.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAddonMigrate(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { diff --git a/heroku/resource_heroku_addon_test.go b/heroku/resource_heroku_addon_test.go index bc898b2db..6d437eadd 100644 --- a/heroku/resource_heroku_addon_test.go +++ b/heroku/resource_heroku_addon_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuAddon_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_app.go b/heroku/resource_heroku_app.go index 4c63419ca..1b18baf7c 100644 --- a/heroku/resource_heroku_app.go +++ b/heroku/resource_heroku_app.go @@ -15,7 +15,7 @@ import ( multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) // herokuApplication is a value type used to hold the details of an @@ -616,7 +616,9 @@ func (a *application) Update() error { a.App.Region = app.Region.Name a.App.Stack = app.BuildStack.Name a.App.GitURL = app.GitURL - a.App.WebURL = app.WebURL + if app.WebURL != nil { + a.App.WebURL = *app.WebURL + } a.App.Acm = app.Acm a.App.ID = app.ID diff --git a/heroku/resource_heroku_app_config_association.go b/heroku/resource_heroku_app_config_association.go index 59dd169b2..a2b868273 100644 --- a/heroku/resource_heroku_app_config_association.go +++ b/heroku/resource_heroku_app_config_association.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAppConfigAssociation() *schema.Resource { diff --git a/heroku/resource_heroku_app_feature.go b/heroku/resource_heroku_app_feature.go index 74bbb44ce..3b25458cb 100644 --- a/heroku/resource_heroku_app_feature.go +++ b/heroku/resource_heroku_app_feature.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAppFeature() *schema.Resource { diff --git a/heroku/resource_heroku_app_feature_test.go b/heroku/resource_heroku_app_feature_test.go index 3452f7e88..512fb9b82 100644 --- a/heroku/resource_heroku_app_feature_test.go +++ b/heroku/resource_heroku_app_feature_test.go @@ -12,7 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuAppFeature(t *testing.T) { diff --git a/heroku/resource_heroku_app_release.go b/heroku/resource_heroku_app_release.go index 47e554260..c8da61a54 100644 --- a/heroku/resource_heroku_app_release.go +++ b/heroku/resource_heroku_app_release.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAppRelease() *schema.Resource { diff --git a/heroku/resource_heroku_app_release_test.go b/heroku/resource_heroku_app_release_test.go index 6b4640425..9e6b0e143 100644 --- a/heroku/resource_heroku_app_release_test.go +++ b/heroku/resource_heroku_app_release_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuAppRelease_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_app_test.go b/heroku/resource_heroku_app_test.go index 017e7f306..20fa295cb 100644 --- a/heroku/resource_heroku_app_test.go +++ b/heroku/resource_heroku_app_test.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuApp_Basic(t *testing.T) { @@ -44,10 +44,10 @@ func TestAccHerokuApp_Basic(t *testing.T) { resource.TestCheckResourceAttrWith( "heroku_app.foobar", "heroku_hostname", func(value string) error { if !strings.HasSuffix(value, "herokuapp.com") { - return fmt.Errorf(fmt.Sprintf("'%s' should end with 'herokuapp.com'", value)) + return fmt.Errorf("'%s' should end with 'herokuapp.com'", value) } if !strings.HasPrefix(value, appName) { - return fmt.Errorf(fmt.Sprintf("'%s' should start with '%s'", value, appName)) + return fmt.Errorf("'%s' should start with '%s'", value, appName) } return nil }), diff --git a/heroku/resource_heroku_app_webhook.go b/heroku/resource_heroku_app_webhook.go index a4a6850a6..13df0275f 100644 --- a/heroku/resource_heroku_app_webhook.go +++ b/heroku/resource_heroku_app_webhook.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" validation "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuAppWebhook() *schema.Resource { diff --git a/heroku/resource_heroku_app_webhook_test.go b/heroku/resource_heroku_app_webhook_test.go index a307746df..09bd7a736 100644 --- a/heroku/resource_heroku_app_webhook_test.go +++ b/heroku/resource_heroku_app_webhook_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuAppWebhook_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_build.go b/heroku/resource_heroku_build.go index 1065800d1..c7519827e 100644 --- a/heroku/resource_heroku_build.go +++ b/heroku/resource_heroku_build.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" tarinator "github.com/verybluebot/tarinator-go" ) diff --git a/heroku/resource_heroku_build_test.go b/heroku/resource_heroku_build_test.go index 8829cf097..2aa32dbc3 100644 --- a/heroku/resource_heroku_build_test.go +++ b/heroku/resource_heroku_build_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuBuild_Basic(t *testing.T) { @@ -111,10 +111,11 @@ func TestAccHerokuBuild_LocalSourceTarball(t *testing.T) { var build, build2 heroku.Build randString := acctest.RandString(10) appName := fmt.Sprintf("tftest-%s", randString) - // Manually generated using `shasum --algorithm 256 slug.tgz` + // Manually generated using `shasum --algorithm 256 app.tgz` + // Manually generated using `shasum --algorithm 256 app-2.tgz` // per Heroku docs https://devcenter.heroku.com/articles/slug-checksums - sourceChecksum := "SHA256:14671a3dcf1ba3f4976438bfd4654da5d2b18ccefa59d10187ecc1286f08ee29" - sourceChecksum2 := "SHA256:a60dabd2ab4253e85a1a13734dcc444e830f61995247cd307655219c2504738a" + sourceChecksum := "SHA256:da57c23d767c971b383de3bf1a680e5ea0f3991f4738552cb383127e60864b20" + sourceChecksum2 := "SHA256:483332872ad9112337b5790da1406c8b3cdcf07d53d04c953d9e17d3e63fb522" defer resetSourceFiles() @@ -267,7 +268,7 @@ func testAccCheckHerokuBuildConfig_basic(appName string) string { resource "heroku_build" "foobar" { app_id = heroku_app.foobar.id source { - url = "https://github.com/heroku/terraform-provider-heroku/raw/master/heroku/test-fixtures/app.tgz" + url = "https://github.com/heroku/terraform-provider-heroku/raw/update-heroku-api-client/heroku/test-fixtures/app.tgz" } }`, appName) } @@ -281,7 +282,7 @@ func testAccCheckHerokuBuildConfig_fails(appName string) string { resource "heroku_build" "foobar" { app_id = heroku_app.foobar.id source { - url = "https://github.com/heroku/terraform-provider-heroku/raw/display-build-error-inline/heroku/test-fixtures/app-broken-build.tgz" + url = "https://github.com/heroku/terraform-provider-heroku/raw/update-heroku-api-client/heroku/test-fixtures/app-broken-build.tgz" } }`, appName) } @@ -295,7 +296,7 @@ func testAccCheckHerokuBuildConfig_insecureUrl(appName string) string { resource "heroku_build" "foobar" { app_id = heroku_app.foobar.id source { - url = "http://github.com/mars/terraform-provider-heroku/raw/build-resource/heroku/test-fixtures/app.tgz" + url = "http://github.com/mars/terraform-provider-heroku/raw/update-heroku-api-client/heroku/test-fixtures/app.tgz" } }`, appName) } @@ -315,7 +316,7 @@ resource "heroku_build" "foobar" { } func testAccCheckHerokuBuildConfig_allOpts(appName string) string { - // Manually generated `checksum` using `shasum --algorithm 256 v2.1.1.tar.gz` + // Manually generated `checksum` using `shasum --algorithm 256 app.tar.gz` // per Heroku docs https://devcenter.heroku.com/articles/slug-checksums return fmt.Sprintf(`resource "heroku_app" "foobar" { @@ -330,8 +331,8 @@ resource "heroku_build" "foobar" { "https://github.com/heroku/heroku-buildpack-ruby", ] source { - checksum = "SHA256:14671a3dcf1ba3f4976438bfd4654da5d2b18ccefa59d10187ecc1286f08ee29" - url = "https://github.com/heroku/terraform-provider-heroku/raw/master/heroku/test-fixtures/app.tgz" + checksum = "SHA256:da57c23d767c971b383de3bf1a680e5ea0f3991f4738552cb383127e60864b20" + url = "https://github.com/heroku/terraform-provider-heroku/raw/update-heroku-api-client/heroku/test-fixtures/app.tgz" version = "v0" } }`, appName) diff --git a/heroku/resource_heroku_cert.go b/heroku/resource_heroku_cert.go deleted file mode 100644 index a12347b89..000000000 --- a/heroku/resource_heroku_cert.go +++ /dev/null @@ -1,161 +0,0 @@ -package heroku - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" -) - -func resourceHerokuCert() *schema.Resource { - return &schema.Resource{ - DeprecationMessage: "This resource is deprecated in favor of `heroku_ssl`.", - - Create: resourceHerokuCertCreate, - Read: resourceHerokuCertRead, - Update: resourceHerokuCertUpdate, - Delete: resourceHerokuCertDelete, - - Importer: &schema.ResourceImporter{ - State: resourceHerokuCertImport, - }, - - Schema: map[string]*schema.Schema{ - "app": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "certificate_chain": { - Type: schema.TypeString, - Required: true, - }, - - "private_key": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - }, - - "cname": { - Type: schema.TypeString, - Computed: true, - }, - - "name": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceHerokuCertImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - client := meta.(*Config).Api - - app, id, err := parseCompositeID(d.Id()) - if err != nil { - return nil, err - } - - ep, err := client.SSLEndpointInfo(context.Background(), app, id) - if err != nil { - return nil, err - } - - d.SetId(ep.ID) - setErr := d.Set("app", app) - if setErr != nil { - return nil, setErr - } - - return []*schema.ResourceData{d}, nil -} - -func resourceHerokuCertCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*Config).Api - - app := d.Get("app").(string) - preprocess := true - opts := heroku.SSLEndpointCreateOpts{ - CertificateChain: d.Get("certificate_chain").(string), - Preprocess: &preprocess, - PrivateKey: d.Get("private_key").(string)} - - log.Printf("[DEBUG] SSL Certificate create configuration: %#v, %#v", app, opts) - a, err := client.SSLEndpointCreate(context.TODO(), app, opts) - if err != nil { - return fmt.Errorf("Error creating SSL endpoint: %s", err) - } - - d.SetId(a.ID) - log.Printf("[INFO] SSL Certificate ID: %s", d.Id()) - - return resourceHerokuCertRead(d, meta) -} - -func resourceHerokuCertRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*Config).Api - - cert, err := resourceHerokuSSLCertRetrieve( - d.Get("app").(string), d.Id(), client) - if err != nil { - return err - } - - d.Set("certificate_chain", cert.CertificateChain) - d.Set("name", cert.Name) - d.Set("cname", cert.CName) - - return nil -} - -func resourceHerokuCertUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*Config).Api - - app := d.Get("app").(string) - preprocess := true - opts := heroku.SSLEndpointUpdateOpts{ - CertificateChain: heroku.String(d.Get("certificate_chain").(string)), - Preprocess: &preprocess, - PrivateKey: heroku.String(d.Get("private_key").(string)), - } - - if d.HasChange("certificate_chain") || d.HasChange("private_key") { - log.Printf("[DEBUG] SSL Certificate update configuration: %#v, %#v", app, opts) - _, err := client.SSLEndpointUpdate(context.TODO(), app, d.Id(), opts) - if err != nil { - return fmt.Errorf("Error updating SSL endpoint: %s", err) - } - } - - return resourceHerokuCertRead(d, meta) -} - -func resourceHerokuCertDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*Config).Api - - log.Printf("[INFO] Deleting SSL Cert: %s", d.Id()) - - // Destroy the app - _, err := client.SSLEndpointDelete(context.TODO(), d.Get("app").(string), d.Id()) - if err != nil { - return fmt.Errorf("Error deleting SSL Cert: %s", err) - } - - d.SetId("") - return nil -} - -func resourceHerokuSSLCertRetrieve(app string, id string, client *heroku.Service) (*heroku.SSLEndpoint, error) { - addon, err := client.SSLEndpointInfo(context.TODO(), app, id) - - if err != nil { - return nil, fmt.Errorf("Error retrieving SSL Cert: %s", err) - } - - return addon, nil -} diff --git a/heroku/resource_heroku_cert_test.go b/heroku/resource_heroku_cert_test.go deleted file mode 100644 index 274d6f33c..000000000 --- a/heroku/resource_heroku_cert_test.go +++ /dev/null @@ -1,222 +0,0 @@ -package heroku - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "regexp" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" - "github.com/heroku/terraform-provider-heroku/v5/helper/test" -) - -// We break apart testing for EU and US because at present, Heroku deals with -// each a bit differently and the setup/teardown of separate tests seems to -// help them to perform more consistently. -// https://devcenter.heroku.com/articles/ssl-endpoint#add-certificate-and-intermediaries -// -// We also have a time.Sleep() set for the update step (step 2 of 2) in each -// region's tests. This is somewhat kludgy, but the Heroku API SSL Endpoint -// handles parts of the create and update requests asynchronously, and if you -// add a cert+key then immediately update it, and then delete it (end of test), -// there are scenarios where the operations get out of order. For now, sleeping -// on update seems to allow the test to run smoothly; in real life, this test -// case is definitely an extreme edge case. -func TestAccHerokuCert_EU(t *testing.T) { - t.Skip("SSL Endpoint shutdown: https://devcenter.heroku.com/changelog-items/2280") - - var endpoint heroku.SSLEndpoint - appName := fmt.Sprintf("tftest-%s", acctest.RandString(10)) - - wd, _ := os.Getwd() - certFile := wd + "/test-fixtures/terraform.cert" - certFile2 := wd + "/test-fixtures/terraform2.cert" - keyFile := wd + "/test-fixtures/terraform.key" - keyFile2 := wd + "/test-fixtures/terraform2.key" - - certificateChainBytes, _ := ioutil.ReadFile(certFile) - certificateChain := string(certificateChainBytes) - certificateChain2Bytes, _ := ioutil.ReadFile(certFile2) - certificateChain2 := string(certificateChain2Bytes) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckHerokuCertDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckHerokuCertEUConfig(appName, certFile, keyFile), - Check: resource.ComposeTestCheckFunc( - testAccCheckHerokuCertExists("heroku_cert.ssl_certificate", &endpoint), - testAccCheckHerokuCertificateChain(&endpoint, certificateChain), - resource.TestMatchResourceAttr( - "heroku_cert.ssl_certificate", - "cname", regexp.MustCompile(`^[^\.]+.ssl.herokudns.com$`)), - ), - }, - { - PreConfig: test.Sleep(t, 15), - Config: testAccCheckHerokuCertEUConfig(appName, certFile2, keyFile2), - Check: resource.ComposeTestCheckFunc( - testAccCheckHerokuCertExists("heroku_cert.ssl_certificate", &endpoint), - testAccCheckHerokuCertificateChain(&endpoint, certificateChain2), - resource.TestMatchResourceAttr( - "heroku_cert.ssl_certificate", - "cname", regexp.MustCompile(`^[^\.]+.ssl.herokudns.com$`)), - ), - }, - }, - }) -} - -func TestAccHerokuCert_US(t *testing.T) { - t.Skip("SSL Endpoint shutdown: https://devcenter.heroku.com/changelog-items/2280") - - var endpoint heroku.SSLEndpoint - appName := fmt.Sprintf("tftest-%s", acctest.RandString(10)) - - wd, _ := os.Getwd() - certFile := wd + "/test-fixtures/terraform.cert" - certFile2 := wd + "/test-fixtures/terraform2.cert" - keyFile := wd + "/test-fixtures/terraform.key" - keyFile2 := wd + "/test-fixtures/terraform2.key" - - certificateChainBytes, _ := ioutil.ReadFile(certFile) - certificateChain := string(certificateChainBytes) - certificateChain2Bytes, _ := ioutil.ReadFile(certFile2) - certificateChain2 := string(certificateChain2Bytes) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckHerokuCertDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckHerokuCertUSConfig(appName, certFile2, keyFile2), - Check: resource.ComposeTestCheckFunc( - testAccCheckHerokuCertExists("heroku_cert.ssl_certificate", &endpoint), - testAccCheckHerokuCertificateChain(&endpoint, certificateChain2), - resource.TestMatchResourceAttr( - "heroku_cert.ssl_certificate", - "cname", regexp.MustCompile(`^[^\.]+.ssl.herokudns.com$`)), - ), - }, - { - PreConfig: test.Sleep(t, 15), - Config: testAccCheckHerokuCertUSConfig(appName, certFile, keyFile), - Check: resource.ComposeTestCheckFunc( - testAccCheckHerokuCertExists("heroku_cert.ssl_certificate", &endpoint), - testAccCheckHerokuCertificateChain(&endpoint, certificateChain), - resource.TestMatchResourceAttr( - "heroku_cert.ssl_certificate", - "cname", regexp.MustCompile(`^[^\.]+.ssl.herokudns.com$`)), - ), - }, - }, - }) -} - -func testAccCheckHerokuCertEUConfig(appName, certFile, keyFile string) string { - return strings.TrimSpace(fmt.Sprintf(` -resource "heroku_app" "foobar" { - name = "%s" - region = "eu" -} - -resource "heroku_addon" "ssl" { - app_id = heroku_app.foobar.id - plan = "ssl:endpoint" -} - -resource "heroku_cert" "ssl_certificate" { - app = "${heroku_app.foobar.name}" - depends_on = ["heroku_addon.ssl"] - certificate_chain="${file("%s")}" - private_key="${file("%s")}" -}`, appName, certFile, keyFile)) -} - -func testAccCheckHerokuCertUSConfig(appName, certFile, keyFile string) string { - return strings.TrimSpace(fmt.Sprintf(` -resource "heroku_app" "foobar" { - name = "%s" - region = "us" -} - -resource "heroku_addon" "ssl" { - app_id = heroku_app.foobar.id - plan = "ssl:endpoint" -} - -resource "heroku_cert" "ssl_certificate" { - app = "${heroku_app.foobar.name}" - depends_on = ["heroku_addon.ssl"] - certificate_chain="${file("%s")}" - private_key="${file("%s")}" -}`, appName, certFile, keyFile)) -} - -func testAccCheckHerokuCertDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*Config).Api - - for _, rs := range s.RootModule().Resources { - if rs.Type != "heroku_cert" { - continue - } - - _, err := client.SSLEndpointInfo(context.TODO(), rs.Primary.Attributes["app"], rs.Primary.ID) - - if err == nil { - return fmt.Errorf("Cerfificate still exists") - } - } - - return nil -} - -func testAccCheckHerokuCertificateChain(endpoint *heroku.SSLEndpoint, chain string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - if endpoint.CertificateChain != chain { - return fmt.Errorf("Bad certificate chain: %s", endpoint.CertificateChain) - } - - return nil - } -} - -func testAccCheckHerokuCertExists(n string, endpoint *heroku.SSLEndpoint) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No SSL endpoint ID is set") - } - - client := testAccProvider.Meta().(*Config).Api - - foundEndpoint, err := client.SSLEndpointInfo(context.TODO(), rs.Primary.Attributes["app"], rs.Primary.ID) - - if err != nil { - return err - } - - if foundEndpoint.ID != rs.Primary.ID { - return fmt.Errorf("SSL endpoint not found") - } - - *endpoint = *foundEndpoint - - return nil - } -} diff --git a/heroku/resource_heroku_collaborator.go b/heroku/resource_heroku_collaborator.go index 24b4ab0f2..ffe7afd08 100644 --- a/heroku/resource_heroku_collaborator.go +++ b/heroku/resource_heroku_collaborator.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) /* diff --git a/heroku/resource_heroku_collaborator_test.go b/heroku/resource_heroku_collaborator_test.go index b5b866496..85b8aae5a 100644 --- a/heroku/resource_heroku_collaborator_test.go +++ b/heroku/resource_heroku_collaborator_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuCollaborator_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_domain.go b/heroku/resource_heroku_domain.go index d8c7af53d..260d6b111 100644 --- a/heroku/resource_heroku_domain.go +++ b/heroku/resource_heroku_domain.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuDomain() *schema.Resource { diff --git a/heroku/resource_heroku_domain_test.go b/heroku/resource_heroku_domain_test.go index 7c2417c12..82886bfe3 100644 --- a/heroku/resource_heroku_domain_test.go +++ b/heroku/resource_heroku_domain_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" "github.com/heroku/terraform-provider-heroku/v5/helper/test" ) diff --git a/heroku/resource_heroku_drain.go b/heroku/resource_heroku_drain.go index e6b02f808..a5d84ba1d 100644 --- a/heroku/resource_heroku_drain.go +++ b/heroku/resource_heroku_drain.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuDrain() *schema.Resource { diff --git a/heroku/resource_heroku_drain_test.go b/heroku/resource_heroku_drain_test.go index 3845afc0e..16f18e64b 100644 --- a/heroku/resource_heroku_drain_test.go +++ b/heroku/resource_heroku_drain_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuDrain_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_formation.go b/heroku/resource_heroku_formation.go index 5f9c78749..2ae1ff71f 100644 --- a/heroku/resource_heroku_formation.go +++ b/heroku/resource_heroku_formation.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) // herokuFormation is a value type used to hold the details of a formation @@ -110,14 +110,19 @@ func resourceHerokuFormationCreate(d *schema.ResourceData, meta interface{}) err if v, ok := d.GetOk("size"); ok { vs := v.(string) log.Printf("[DEBUG] Size: %s", vs) - opts.Size = &vs + opts.DynoSize = &struct { + ID *string `json:"id,omitempty" url:"id,omitempty,key"` // unique identifier of the dyno size + Name *string `json:"name,omitempty" url:"name,omitempty,key"` // name of the dyno size + }{ + Name: &vs, + } } quantity := d.Get("quantity").(int) log.Printf("[DEBUG] Quantity: %v", quantity) opts.Quantity = &quantity - log.Printf(fmt.Sprintf("[DEBUG] Updating %s formation...", appID)) + log.Printf("[DEBUG] Updating %s formation...", appID) f, err := client.FormationUpdate(context.TODO(), appID, getFormationType(d), opts) if err != nil { return err @@ -139,7 +144,12 @@ func resourceHerokuFormationUpdate(d *schema.ResourceData, meta interface{}) err if d.HasChange("size") { v := d.Get("size").(string) log.Printf("[DEBUG] New Size: %s", v) - opts.Size = &v + opts.DynoSize = &struct { + ID *string `json:"id,omitempty" url:"id,omitempty,key"` // unique identifier of the dyno size + Name *string `json:"name,omitempty" url:"name,omitempty,key"` // name of the dyno size + }{ + Name: &v, + } } if d.HasChange("quantity") { diff --git a/heroku/resource_heroku_formation_test.go b/heroku/resource_heroku_formation_test.go index bf3665abb..3ccd90e1c 100644 --- a/heroku/resource_heroku_formation_test.go +++ b/heroku/resource_heroku_formation_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuFormationSingleUpdate_WithOrg(t *testing.T) { diff --git a/heroku/resource_heroku_pipeline.go b/heroku/resource_heroku_pipeline.go index d33980010..3a92323e9 100644 --- a/heroku/resource_heroku_pipeline.go +++ b/heroku/resource_heroku_pipeline.go @@ -3,12 +3,13 @@ package heroku import ( "context" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "log" "regexp" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuPipeline() *schema.Resource { diff --git a/heroku/resource_heroku_pipeline_config_var.go b/heroku/resource_heroku_pipeline_config_var.go index aaf01a3fe..c644ed583 100644 --- a/heroku/resource_heroku_pipeline_config_var.go +++ b/heroku/resource_heroku_pipeline_config_var.go @@ -3,10 +3,11 @@ package heroku import ( "context" "fmt" + "log" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" - "log" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuPipelineConfigVar() *schema.Resource { diff --git a/heroku/resource_heroku_pipeline_coupling.go b/heroku/resource_heroku_pipeline_coupling.go index 59a01b2f0..11c422171 100644 --- a/heroku/resource_heroku_pipeline_coupling.go +++ b/heroku/resource_heroku_pipeline_coupling.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuPipelineCoupling() *schema.Resource { diff --git a/heroku/resource_heroku_pipeline_coupling_test.go b/heroku/resource_heroku_pipeline_coupling_test.go index ae619e140..3ef6700f6 100644 --- a/heroku/resource_heroku_pipeline_coupling_test.go +++ b/heroku/resource_heroku_pipeline_coupling_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuPipelineCoupling_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_pipeline_test.go b/heroku/resource_heroku_pipeline_test.go index 4229b3528..6f97df2a6 100644 --- a/heroku/resource_heroku_pipeline_test.go +++ b/heroku/resource_heroku_pipeline_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuPipeline_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_review_app_config.go b/heroku/resource_heroku_review_app_config.go index 5781ec061..af14194b0 100644 --- a/heroku/resource_heroku_review_app_config.go +++ b/heroku/resource_heroku_review_app_config.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) const ( diff --git a/heroku/resource_heroku_slug.go b/heroku/resource_heroku_slug.go index c247a7994..9e6ff7422 100644 --- a/heroku/resource_heroku_slug.go +++ b/heroku/resource_heroku_slug.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuSlug() *schema.Resource { diff --git a/heroku/resource_heroku_slug_test.go b/heroku/resource_heroku_slug_test.go index 640c93210..ab11e6a2a 100644 --- a/heroku/resource_heroku_slug_test.go +++ b/heroku/resource_heroku_slug_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuSlug_Basic(t *testing.T) { diff --git a/heroku/resource_heroku_space.go b/heroku/resource_heroku_space.go index 359e0885a..6c9cf6b5a 100644 --- a/heroku/resource_heroku_space.go +++ b/heroku/resource_heroku_space.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) type spaceWithNAT struct { diff --git a/heroku/resource_heroku_space_app_access.go b/heroku/resource_heroku_space_app_access.go index 427437a45..c479ce458 100644 --- a/heroku/resource_heroku_space_app_access.go +++ b/heroku/resource_heroku_space_app_access.go @@ -4,7 +4,7 @@ import ( "context" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuSpaceAppAccess() *schema.Resource { diff --git a/heroku/resource_heroku_space_inbound_ruleset.go b/heroku/resource_heroku_space_inbound_ruleset.go index 96052a381..bc335d8b2 100644 --- a/heroku/resource_heroku_space_inbound_ruleset.go +++ b/heroku/resource_heroku_space_inbound_ruleset.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuSpaceInboundRuleset() *schema.Resource { diff --git a/heroku/resource_heroku_space_peering_connection_accepter.go b/heroku/resource_heroku_space_peering_connection_accepter.go index aab775798..6400babd4 100644 --- a/heroku/resource_heroku_space_peering_connection_accepter.go +++ b/heroku/resource_heroku_space_peering_connection_accepter.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) type spacePeerInfo struct { diff --git a/heroku/resource_heroku_space_vpn_connection.go b/heroku/resource_heroku_space_vpn_connection.go index 1bc1c28aa..afbe45674 100644 --- a/heroku/resource_heroku_space_vpn_connection.go +++ b/heroku/resource_heroku_space_vpn_connection.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuSpaceVPNConnection() *schema.Resource { diff --git a/heroku/resource_heroku_space_vpn_connection_test.go b/heroku/resource_heroku_space_vpn_connection_test.go index 00b851876..de8e15e51 100644 --- a/heroku/resource_heroku_space_vpn_connection_test.go +++ b/heroku/resource_heroku_space_vpn_connection_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) // Generates a "test step" not a whole test, so that it can reuse the space. diff --git a/heroku/resource_heroku_ssl.go b/heroku/resource_heroku_ssl.go index 7ee6452a7..da47a6485 100644 --- a/heroku/resource_heroku_ssl.go +++ b/heroku/resource_heroku_ssl.go @@ -2,12 +2,13 @@ package heroku import ( "context" + "log" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuSSL() *schema.Resource { diff --git a/heroku/resource_heroku_ssl_test.go b/heroku/resource_heroku_ssl_test.go index fcf250078..416e11597 100644 --- a/heroku/resource_heroku_ssl_test.go +++ b/heroku/resource_heroku_ssl_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" "github.com/heroku/terraform-provider-heroku/v5/helper/test" ) diff --git a/heroku/resource_heroku_team_collaborator.go b/heroku/resource_heroku_team_collaborator.go index e39c01b3f..8c21f1ebd 100644 --- a/heroku/resource_heroku_team_collaborator.go +++ b/heroku/resource_heroku_team_collaborator.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) /** diff --git a/heroku/resource_heroku_team_collaborator_test.go b/heroku/resource_heroku_team_collaborator_test.go index 0303fb2e3..c22f86946 100644 --- a/heroku/resource_heroku_team_collaborator_test.go +++ b/heroku/resource_heroku_team_collaborator_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuTeamCollaborator_Org(t *testing.T) { diff --git a/heroku/resource_heroku_team_member.go b/heroku/resource_heroku_team_member.go index bd69a493e..42f0e086d 100644 --- a/heroku/resource_heroku_team_member.go +++ b/heroku/resource_heroku_team_member.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func resourceHerokuTeamMember() *schema.Resource { diff --git a/heroku/resource_heroku_team_member_test.go b/heroku/resource_heroku_team_member_test.go index bc39baf49..08ed4eda0 100644 --- a/heroku/resource_heroku_team_member_test.go +++ b/heroku/resource_heroku_team_member_test.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - heroku "github.com/heroku/heroku-go/v5" + heroku "github.com/heroku/heroku-go/v6" ) func TestAccHerokuTeamMember_Org(t *testing.T) { diff --git a/heroku/test-fixtures/README.md b/heroku/test-fixtures/README.md new file mode 100644 index 000000000..aff2b7385 --- /dev/null +++ b/heroku/test-fixtures/README.md @@ -0,0 +1,17 @@ +# Test Fixtures + +These files & directories are referenced in the `*_test.go` files. + +## App sources + +In `heroku/test-fixtures/`, directories like `app/`, `app-2/`, & `app-broken-build/` can be updated for continued functionality, such as updating the Bundler version in use. + +When the app dirs are changed, their associated `*.tgz` archives should be remade with: +``` +cd heroku/test-fixtures/ +tar -czf app.tgz app/* +tar -czf app-2.tgz app-2/* +tar -czf app-broken-build.tgz app-broken-build/* +``` + +Then, the **checksums** of these tarballs must be manually computed and updated throughout `heroku/resource_heroku_build_test.go`. diff --git a/heroku/test-fixtures/app-2.tgz b/heroku/test-fixtures/app-2.tgz index 9c8e19a3f..74cc82b4f 100644 Binary files a/heroku/test-fixtures/app-2.tgz and b/heroku/test-fixtures/app-2.tgz differ diff --git a/heroku/test-fixtures/app-2/Gemfile b/heroku/test-fixtures/app-2/Gemfile index 1afd2cce6..2ea79082c 100644 --- a/heroku/test-fixtures/app-2/Gemfile +++ b/heroku/test-fixtures/app-2/Gemfile @@ -1,7 +1,6 @@ # frozen_string_literal: true source "https://rubygems.org" +ruby "3.4.4" -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -# gem "rails" +gem "webrick", "~> 1.9" diff --git a/heroku/test-fixtures/app-2/Gemfile.lock b/heroku/test-fixtures/app-2/Gemfile.lock index 61268f8fa..6bcc4fb41 100644 --- a/heroku/test-fixtures/app-2/Gemfile.lock +++ b/heroku/test-fixtures/app-2/Gemfile.lock @@ -1,11 +1,16 @@ GEM remote: https://rubygems.org/ specs: + webrick (1.9.1) PLATFORMS ruby DEPENDENCIES + webrick (~> 1.9) + +RUBY VERSION + ruby 3.4.4 BUNDLED WITH - 1.16.2 + 2.6.9 diff --git a/heroku/test-fixtures/app-2/Procfile b/heroku/test-fixtures/app-2/Procfile new file mode 100644 index 000000000..6d1c3cb1e --- /dev/null +++ b/heroku/test-fixtures/app-2/Procfile @@ -0,0 +1 @@ +web: bundle exec ruby server.rb diff --git a/heroku/test-fixtures/app-broken-build.tgz b/heroku/test-fixtures/app-broken-build.tgz index 4f0fff90f..56106cff8 100644 Binary files a/heroku/test-fixtures/app-broken-build.tgz and b/heroku/test-fixtures/app-broken-build.tgz differ diff --git a/heroku/test-fixtures/app-broken-build/Gemfile b/heroku/test-fixtures/app-broken-build/Gemfile index aacfc7224..406525ac1 100644 --- a/heroku/test-fixtures/app-broken-build/Gemfile +++ b/heroku/test-fixtures/app-broken-build/Gemfile @@ -4,6 +4,4 @@ source "https://non-existent-rubygems.example.org" -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - # gem "rails" diff --git a/heroku/test-fixtures/app-broken-build/Gemfile.lock b/heroku/test-fixtures/app-broken-build/Gemfile.lock index 61268f8fa..373fe8e8f 100644 --- a/heroku/test-fixtures/app-broken-build/Gemfile.lock +++ b/heroku/test-fixtures/app-broken-build/Gemfile.lock @@ -2,10 +2,13 @@ GEM remote: https://rubygems.org/ specs: +RUBY VERSION + ruby 3.4.4 + PLATFORMS ruby DEPENDENCIES BUNDLED WITH - 1.16.2 + 2.6.9 diff --git a/heroku/test-fixtures/app-broken-build/Procfile b/heroku/test-fixtures/app-broken-build/Procfile new file mode 100644 index 000000000..6d1c3cb1e --- /dev/null +++ b/heroku/test-fixtures/app-broken-build/Procfile @@ -0,0 +1 @@ +web: bundle exec ruby server.rb diff --git a/heroku/test-fixtures/app-new.tgz b/heroku/test-fixtures/app-new.tgz new file mode 100644 index 000000000..4ab25bc54 Binary files /dev/null and b/heroku/test-fixtures/app-new.tgz differ diff --git a/heroku/test-fixtures/app.tgz b/heroku/test-fixtures/app.tgz index ab4a149a1..e2605685c 100644 Binary files a/heroku/test-fixtures/app.tgz and b/heroku/test-fixtures/app.tgz differ diff --git a/heroku/test-fixtures/app/Gemfile b/heroku/test-fixtures/app/Gemfile index 1afd2cce6..2ea79082c 100644 --- a/heroku/test-fixtures/app/Gemfile +++ b/heroku/test-fixtures/app/Gemfile @@ -1,7 +1,6 @@ # frozen_string_literal: true source "https://rubygems.org" +ruby "3.4.4" -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -# gem "rails" +gem "webrick", "~> 1.9" diff --git a/heroku/test-fixtures/app/Gemfile.lock b/heroku/test-fixtures/app/Gemfile.lock index 61268f8fa..6bcc4fb41 100644 --- a/heroku/test-fixtures/app/Gemfile.lock +++ b/heroku/test-fixtures/app/Gemfile.lock @@ -1,11 +1,16 @@ GEM remote: https://rubygems.org/ specs: + webrick (1.9.1) PLATFORMS ruby DEPENDENCIES + webrick (~> 1.9) + +RUBY VERSION + ruby 3.4.4 BUNDLED WITH - 1.16.2 + 2.6.9 diff --git a/heroku/test-fixtures/app/Procfile b/heroku/test-fixtures/app/Procfile new file mode 100644 index 000000000..6d1c3cb1e --- /dev/null +++ b/heroku/test-fixtures/app/Procfile @@ -0,0 +1 @@ +web: bundle exec ruby server.rb diff --git a/heroku/test-fixtures/stub.go b/heroku/test-fixtures/stub.go new file mode 100644 index 000000000..f688b79f7 --- /dev/null +++ b/heroku/test-fixtures/stub.go @@ -0,0 +1,2 @@ +// Empty file to avoid `go vet` error "no Go files" +package testfixtures diff --git a/vendor/github.com/google/uuid/.travis.yml b/vendor/github.com/google/uuid/.travis.yml deleted file mode 100644 index d8156a60b..000000000 --- a/vendor/github.com/google/uuid/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.4.3 - - 1.5.3 - - tip - -script: - - go test -v ./... diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md new file mode 100644 index 000000000..7ec5ac7ea --- /dev/null +++ b/vendor/github.com/google/uuid/CHANGELOG.md @@ -0,0 +1,41 @@ +# Changelog + +## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) + + +### Features + +* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) + + +### Bug Fixes + +* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) +* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) + +## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) + + +### Features + +* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) + +## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) + + +### Features + +* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) + +### Fixes + +* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) + +## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) + + +### Bug Fixes + +* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) + +## Changelog diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md index 04fdf09f1..a502fdc51 100644 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -2,6 +2,22 @@ We definitely welcome patches and contribution to this project! +### Tips + +Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). + +Always try to include a test case! If it is not possible or not necessary, +please explain why in the pull request description. + +### Releasing + +Commits that would precipitate a SemVer change, as described in the Conventional +Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) +to create a release candidate pull request. Once submitted, `release-please` +will create a release. + +For tips on how to work with `release-please`, see its documentation. + ### Legal requirements In order to protect both you and ourselves, you will need to sign the diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md index f765a46f9..3e9a61889 100644 --- a/vendor/github.com/google/uuid/README.md +++ b/vendor/github.com/google/uuid/README.md @@ -1,6 +1,6 @@ -# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master) +# uuid The uuid package generates and inspects UUIDs based on -[RFC 4122](http://tools.ietf.org/html/rfc4122) +[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) and DCE 1.1: Authentication and Security Services. This package is based on the github.com/pborman/uuid package (previously named @@ -9,10 +9,12 @@ a UUID is a 16 byte array rather than a byte slice. One loss due to this change is the ability to represent an invalid UUID (vs a NIL UUID). ###### Install -`go get github.com/google/uuid` +```sh +go get github.com/google/uuid +``` ###### Documentation -[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid) +[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here: diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go index b404f4bec..dc60082d3 100644 --- a/vendor/github.com/google/uuid/hash.go +++ b/vendor/github.com/google/uuid/hash.go @@ -17,6 +17,12 @@ var ( NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) Nil UUID // empty UUID, all zeros + + // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. + Max = UUID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + } ) // NewHash returns a new UUID derived from the hash of space concatenated with diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go index 24b78edc9..b2a0bc871 100644 --- a/vendor/github.com/google/uuid/node_js.go +++ b/vendor/github.com/google/uuid/node_js.go @@ -7,6 +7,6 @@ package uuid // getHardwareInterface returns nil values for the JS version of the code. -// This remvoves the "net" dependency, because it is not used in the browser. +// This removes the "net" dependency, because it is not used in the browser. // Using the "net" library inflates the size of the transpiled JS code by 673k bytes. func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go index e6ef06cdc..c35112927 100644 --- a/vendor/github.com/google/uuid/time.go +++ b/vendor/github.com/google/uuid/time.go @@ -108,12 +108,23 @@ func setClockSequence(seq int) { } // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1 and 2 UUIDs. +// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. func (uuid UUID) Time() Time { - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - return Time(time) + var t Time + switch uuid.Version() { + case 6: + time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 + t = Time(time) + case 7: + time := binary.BigEndian.Uint64(uuid[:8]) + t = Time((time>>16)*10000 + g1582ns100) + default: // forward compatible + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + t = Time(time) + } + return t } // ClockSequence returns the clock sequence encoded in uuid. diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index a57207aeb..5232b4867 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -56,11 +56,15 @@ func IsInvalidLengthError(err error) bool { return ok } -// Parse decodes s into a UUID or returns an error. Both the standard UUID -// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the -// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex -// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both +// the standard UUID forms defined in RFC 4122 +// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, +// Parse accepts non-standard strings such as the raw hex encoding +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, +// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are +// examined in the latter case. Parse should not be used to validate strings as +// it parses non-standard encodings as indicated above. func Parse(s string) (UUID, error) { var uuid UUID switch len(s) { @@ -69,7 +73,7 @@ func Parse(s string) (UUID, error) { // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: - if strings.ToLower(s[:9]) != "urn:uuid:" { + if !strings.EqualFold(s[:9], "urn:uuid:") { return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) } s = s[9:] @@ -101,7 +105,8 @@ func Parse(s string) (UUID, error) { 9, 11, 14, 16, 19, 21, - 24, 26, 28, 30, 32, 34} { + 24, 26, 28, 30, 32, 34, + } { v, ok := xtob(s[x], s[x+1]) if !ok { return uuid, errors.New("invalid UUID format") @@ -117,7 +122,7 @@ func ParseBytes(b []byte) (UUID, error) { switch len(b) { case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { + if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) } b = b[9:] @@ -145,7 +150,8 @@ func ParseBytes(b []byte) (UUID, error) { 9, 11, 14, 16, 19, 21, - 24, 26, 28, 30, 32, 34} { + 24, 26, 28, 30, 32, 34, + } { v, ok := xtob(b[x], b[x+1]) if !ok { return uuid, errors.New("invalid UUID format") @@ -180,6 +186,59 @@ func Must(uuid UUID, err error) UUID { return uuid } +// Validate returns an error if s is not a properly formatted UUID in one of the following formats: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// It returns an error if the format is invalid, otherwise nil. +func Validate(s string) error { + switch len(s) { + // Standard UUID format + case 36: + + // UUID with "urn:uuid:" prefix + case 36 + 9: + if !strings.EqualFold(s[:9], "urn:uuid:") { + return fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // UUID enclosed in braces + case 36 + 2: + if s[0] != '{' || s[len(s)-1] != '}' { + return fmt.Errorf("invalid bracketed UUID format") + } + s = s[1 : len(s)-1] + + // UUID without hyphens + case 32: + for i := 0; i < len(s); i += 2 { + _, ok := xtob(s[i], s[i+1]) + if !ok { + return errors.New("invalid UUID format") + } + } + + default: + return invalidLengthError{len(s)} + } + + // Check for standard UUID format + if len(s) == 36 { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return errors.New("invalid UUID format") + } + for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { + if _, ok := xtob(s[x], s[x+1]); !ok { + return errors.New("invalid UUID format") + } + } + } + + return nil +} + // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // , or "" if uuid is invalid. func (uuid UUID) String() string { @@ -292,3 +351,15 @@ func DisableRandPool() { poolMu.Lock() poolPos = randPoolSize } + +// UUIDs is a slice of UUID types. +type UUIDs []UUID + +// Strings returns a string slice containing the string form of each UUID in uuids. +func (uuids UUIDs) Strings() []string { + var uuidStrs = make([]string, len(uuids)) + for i, uuid := range uuids { + uuidStrs[i] = uuid.String() + } + return uuidStrs +} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go new file mode 100644 index 000000000..339a959a7 --- /dev/null +++ b/vendor/github.com/google/uuid/version6.go @@ -0,0 +1,56 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "encoding/binary" + +// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. +// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. +// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 +// +// NewV6 returns a Version 6 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewV6 returns Nil and an error. +func NewV6() (UUID, error) { + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_high | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_mid | time_low_and_version | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |clk_seq_hi_res | clk_seq_low | node (0-1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | node (2-5) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + binary.BigEndian.PutUint64(uuid[0:], uint64(now)) + binary.BigEndian.PutUint16(uuid[8:], seq) + + uuid[6] = 0x60 | (uuid[6] & 0x0F) + uuid[8] = 0x80 | (uuid[8] & 0x3F) + + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + copy(uuid[10:], nodeID[:]) + nodeMu.Unlock() + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go new file mode 100644 index 000000000..3167b643d --- /dev/null +++ b/vendor/github.com/google/uuid/version7.go @@ -0,0 +1,104 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// UUID version 7 features a time-ordered value field derived from the widely +// implemented and well known Unix Epoch timestamp source, +// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. +// As well as improved entropy characteristics over versions 1 or 6. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 +// +// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. +// +// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). +// Uses the randomness pool if it was enabled with EnableRandPool. +// On error, NewV7 returns Nil and an error +func NewV7() (UUID, error) { + uuid, err := NewRandom() + if err != nil { + return uuid, err + } + makeV7(uuid[:]) + return uuid, nil +} + +// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). +// it use NewRandomFromReader fill random bits. +// On error, NewV7FromReader returns Nil and an error. +func NewV7FromReader(r io.Reader) (UUID, error) { + uuid, err := NewRandomFromReader(r) + if err != nil { + return uuid, err + } + + makeV7(uuid[:]) + return uuid, nil +} + +// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) +// uuid[8] already has the right version number (Variant is 10) +// see function NewV7 and NewV7FromReader +func makeV7(uuid []byte) { + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | ver | rand_a (12 bit seq) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |var| rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + _ = uuid[15] // bounds check + + t, s := getV7Time() + + uuid[0] = byte(t >> 40) + uuid[1] = byte(t >> 32) + uuid[2] = byte(t >> 24) + uuid[3] = byte(t >> 16) + uuid[4] = byte(t >> 8) + uuid[5] = byte(t) + + uuid[6] = 0x70 | (0x0F & byte(s>>8)) + uuid[7] = byte(s) +} + +// lastV7time is the last time we returned stored as: +// +// 52 bits of time in milliseconds since epoch +// 12 bits of (fractional nanoseconds) >> 8 +var lastV7time int64 + +const nanoPerMilli = 1000000 + +// getV7Time returns the time in milliseconds and nanoseconds / 256. +// The returned (milli << 12 + seq) is guarenteed to be greater than +// (milli << 12 + seq) returned by any previous call to getV7Time. +func getV7Time() (milli, seq int64) { + timeMu.Lock() + defer timeMu.Unlock() + + nano := timeNow().UnixNano() + milli = nano / nanoPerMilli + // Sequence number is between 0 and 3906 (nanoPerMilli>>8) + seq = (nano - milli*nanoPerMilli) >> 8 + now := milli<<12 + seq + if now <= lastV7time { + now = lastV7time + 1 + milli = now >> 12 + seq = now & 0xfff + } + lastV7time = now + return milli, seq +} diff --git a/vendor/github.com/heroku/heroku-go/v5/LICENSE b/vendor/github.com/heroku/heroku-go/v6/LICENSE similarity index 100% rename from vendor/github.com/heroku/heroku-go/v5/LICENSE rename to vendor/github.com/heroku/heroku-go/v6/LICENSE diff --git a/vendor/github.com/heroku/heroku-go/v5/heroku.go b/vendor/github.com/heroku/heroku-go/v6/heroku.go similarity index 87% rename from vendor/github.com/heroku/heroku-go/v5/heroku.go rename to vendor/github.com/heroku/heroku-go/v6/heroku.go index 82b7b31e9..ebcf6eb8b 100644 --- a/vendor/github.com/heroku/heroku-go/v5/heroku.go +++ b/vendor/github.com/heroku/heroku-go/v6/heroku.go @@ -3,32 +3,30 @@ // To be able to interact with this API, you have to // create a new service: // -// s := heroku.NewService(nil) +// s := heroku.NewService(nil) // // The Service struct has all the methods you need // to interact with heroku API. -// -package v5 +package v6 import ( "bytes" "context" "encoding/json" "fmt" + "github.com/google/go-querystring/query" "io" "net/http" "reflect" "runtime" "strings" "time" - - "github.com/google/go-querystring/query" ) var _ = time.Second const ( - Version = "v5" + Version = "v6" DefaultUserAgent = "heroku/" + Version + " (" + runtime.GOOS + "; " + runtime.GOARCH + ")" DefaultURL = "https://api.heroku.com" ) @@ -271,7 +269,10 @@ func (s *Service) AccountUpdate(ctx context.Context, o AccountUpdateOpts) (*Acco return &account, s.Patch(ctx, &account, fmt.Sprintf("/account"), o) } -// Delete account. Note that this action cannot be undone. +// Delete account. Note that this action cannot be undone. Note: This +// endpoint requires the HTTP_HEROKU_PASSWORD or +// HTTP_HEROKU_PASSWORD_BASE64 header be set correctly for the user +// account. func (s *Service) AccountDelete(ctx context.Context) (*Account, error) { var account Account return &account, s.Delete(ctx, &account, fmt.Sprintf("/account")) @@ -295,12 +296,32 @@ func (s *Service) AccountUpdateByUser(ctx context.Context, accountIdentity strin return &account, s.Patch(ctx, &account, fmt.Sprintf("/users/%v", accountIdentity), o) } -// Delete account. Note that this action cannot be undone. +// Delete account. Note that this action cannot be undone. Note: This +// endpoint requires the HTTP_HEROKU_PASSWORD or +// HTTP_HEROKU_PASSWORD_BASE64 header be set correctly for the user +// account. func (s *Service) AccountDeleteByUser(ctx context.Context, accountIdentity string) (*Account, error) { var account Account return &account, s.Delete(ctx, &account, fmt.Sprintf("/users/%v", accountIdentity)) } +// A Heroku account becomes delinquent due to non-payment. We [suspend +// and +// delete](https://help.heroku.com/EREVRILX/what-happens-if-i-have-unpaid +// -heroku-invoices) delinquent accounts if their invoices remain +// unpaid. +type AccountDelinquency struct { + ScheduledDeletionTime *time.Time `json:"scheduled_deletion_time" url:"scheduled_deletion_time,key"` // scheduled time of when we will delete your account due to delinquency + ScheduledSuspensionTime *time.Time `json:"scheduled_suspension_time" url:"scheduled_suspension_time,key"` // scheduled time of when we will suspend your account due to + // delinquency +} + +// Account delinquency information. +func (s *Service) AccountDelinquencyInfo(ctx context.Context) (*AccountDelinquency, error) { + var accountDelinquency AccountDelinquency + return &accountDelinquency, s.Get(ctx, &accountDelinquency, fmt.Sprintf("/account/delinquency"), nil, nil) +} + // An account feature represents a Heroku labs capability that can be // enabled or disabled for an account on Heroku. type AccountFeature struct { @@ -370,10 +391,11 @@ type AddOn struct { ID string `json:"id" url:"id,key"` // unique identifier of this plan Name string `json:"name" url:"name,key"` // unique name of this plan } `json:"plan" url:"plan,key"` // identity of add-on plan - ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider - State string `json:"state" url:"state,key"` // state in the add-on's lifecycle - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated - WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) + ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider + ProvisionMessage string `json:"provision_message" url:"provision_message,key"` // A provision message + State string `json:"state" url:"state,key"` // state in the add-on's lifecycle + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated + WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) } type AddOnListResult []AddOn @@ -501,10 +523,11 @@ type AddOnActionProvisionResult struct { ID string `json:"id" url:"id,key"` // unique identifier of this plan Name string `json:"name" url:"name,key"` // unique name of this plan } `json:"plan" url:"plan,key"` // identity of add-on plan - ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider - State string `json:"state" url:"state,key"` // state in the add-on's lifecycle - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated - WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) + ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider + ProvisionMessage string `json:"provision_message" url:"provision_message,key"` // A provision message + State string `json:"state" url:"state,key"` // state in the add-on's lifecycle + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated + WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) } // Mark an add-on as provisioned for use. @@ -541,10 +564,11 @@ type AddOnActionDeprovisionResult struct { ID string `json:"id" url:"id,key"` // unique identifier of this plan Name string `json:"name" url:"name,key"` // unique name of this plan } `json:"plan" url:"plan,key"` // identity of add-on plan - ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider - State string `json:"state" url:"state,key"` // state in the add-on's lifecycle - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated - WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) + ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider + ProvisionMessage string `json:"provision_message" url:"provision_message,key"` // A provision message + State string `json:"state" url:"state,key"` // state in the add-on's lifecycle + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated + WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) } // Mark an add-on as deprovisioned. @@ -691,13 +715,17 @@ type AddOnPlanAction struct { // returned by these endpoints. type AddOnRegionCapability struct { AddonService struct { - CliPluginName *string `json:"cli_plugin_name" url:"cli_plugin_name,key"` // npm package name of the add-on service's Heroku CLI plugin - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when add-on-service was created - HumanName string `json:"human_name" url:"human_name,key"` // human-readable name of the add-on service provider - ID string `json:"id" url:"id,key"` // unique identifier of this add-on-service - Name string `json:"name" url:"name,key"` // unique name of this add-on-service - State string `json:"state" url:"state,key"` // release status for add-on service - SupportsMultipleInstallations bool `json:"supports_multiple_installations" url:"supports_multiple_installations,key"` // whether or not apps can have access to more than one instance of this + CliPluginName *string `json:"cli_plugin_name" url:"cli_plugin_name,key"` // npm package name of the add-on service's Heroku CLI plugin + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when add-on-service was created + HumanName string `json:"human_name" url:"human_name,key"` // human-readable name of the add-on service provider + ID string `json:"id" url:"id,key"` // unique identifier of this add-on-service + Name string `json:"name" url:"name,key"` // unique name of this add-on-service + State string `json:"state" url:"state,key"` // release status for add-on service + SupportedGenerations []struct { + ID string `json:"id" url:"id,key"` // unique identifier of generation + Name string `json:"name" url:"name,key"` // unique name of generation + } `json:"supported_generations" url:"supported_generations,key"` // generations supported by this add-on + SupportsMultipleInstallations bool `json:"supports_multiple_installations" url:"supports_multiple_installations,key"` // whether or not apps can have access to more than one instance of this // add-on at the same time SupportsSharing bool `json:"supports_sharing" url:"supports_sharing,key"` // whether or not apps can have access to add-ons billed to a different // app @@ -751,13 +779,17 @@ func (s *Service) AddOnRegionCapabilityListByRegion(ctx context.Context, regionI // Endpoints under add-on services can be accessed without // authentication. type AddOnService struct { - CliPluginName *string `json:"cli_plugin_name" url:"cli_plugin_name,key"` // npm package name of the add-on service's Heroku CLI plugin - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when add-on-service was created - HumanName string `json:"human_name" url:"human_name,key"` // human-readable name of the add-on service provider - ID string `json:"id" url:"id,key"` // unique identifier of this add-on-service - Name string `json:"name" url:"name,key"` // unique name of this add-on-service - State string `json:"state" url:"state,key"` // release status for add-on service - SupportsMultipleInstallations bool `json:"supports_multiple_installations" url:"supports_multiple_installations,key"` // whether or not apps can have access to more than one instance of this + CliPluginName *string `json:"cli_plugin_name" url:"cli_plugin_name,key"` // npm package name of the add-on service's Heroku CLI plugin + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when add-on-service was created + HumanName string `json:"human_name" url:"human_name,key"` // human-readable name of the add-on service provider + ID string `json:"id" url:"id,key"` // unique identifier of this add-on-service + Name string `json:"name" url:"name,key"` // unique name of this add-on-service + State string `json:"state" url:"state,key"` // release status for add-on service + SupportedGenerations []struct { + ID string `json:"id" url:"id,key"` // unique identifier of generation + Name string `json:"name" url:"name,key"` // unique name of generation + } `json:"supported_generations" url:"supported_generations,key"` // generations supported by this add-on + SupportsMultipleInstallations bool `json:"supports_multiple_installations" url:"supports_multiple_installations,key"` // whether or not apps can have access to more than one instance of this // add-on at the same time SupportsSharing bool `json:"supports_sharing" url:"supports_sharing,key"` // whether or not apps can have access to add-ons billed to a different // app @@ -1096,12 +1128,17 @@ type App struct { } `json:"build_stack" url:"build_stack,key"` // identity of the stack that will be used for new builds BuildpackProvidedDescription *string `json:"buildpack_provided_description" url:"buildpack_provided_description,key"` // description from buildpack of app CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when app was created - GitURL string `json:"git_url" url:"git_url,key"` // git repo URL of app - ID string `json:"id" url:"id,key"` // unique identifier of app - InternalRouting *bool `json:"internal_routing" url:"internal_routing,key"` // describes whether a Private Spaces app is externally routable or not - Maintenance bool `json:"maintenance" url:"maintenance,key"` // maintenance status of app - Name string `json:"name" url:"name,key"` // unique name of app - Organization *struct { + Generation struct { + ID string `json:"id" url:"id,key"` // unique identifier of the generation of the Heroku platform for this + // app + Name string `json:"name" url:"name,key"` // unique name of the generation of the Heroku platform for this app + } `json:"generation" url:"generation,key"` // Generation of the Heroku platform for this app + GitURL string `json:"git_url" url:"git_url,key"` // git repo URL of app + ID string `json:"id" url:"id,key"` // unique identifier of app + InternalRouting *bool `json:"internal_routing" url:"internal_routing,key"` // describes whether a Private Spaces app is externally routable or not + Maintenance bool `json:"maintenance" url:"maintenance,key"` // maintenance status of app + Name string `json:"name" url:"name,key"` // unique name of app + Organization *struct { ID string `json:"id" url:"id,key"` // unique identifier of team Name string `json:"name" url:"name,key"` // unique name of team } `json:"organization" url:"organization,key"` // identity of team @@ -1130,12 +1167,13 @@ type App struct { Name string `json:"name" url:"name,key"` // unique name of team } `json:"team" url:"team,key"` // identity of team UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when app was updated - WebURL string `json:"web_url" url:"web_url,key"` // web URL of app + WebURL *string `json:"web_url" url:"web_url,key"` // web URL of app } type AppCreateOpts struct { - Name *string `json:"name,omitempty" url:"name,omitempty,key"` // unique name of app - Region *string `json:"region,omitempty" url:"region,omitempty,key"` // unique identifier of region - Stack *string `json:"stack,omitempty" url:"stack,omitempty,key"` // unique name of stack + FeatureFlags []*string `json:"feature_flags,omitempty" url:"feature_flags,omitempty,key"` // unique name of app feature + Name *string `json:"name,omitempty" url:"name,omitempty,key"` // unique name of app + Region *string `json:"region,omitempty" url:"region,omitempty,key"` // unique identifier of region + Stack *string `json:"stack,omitempty" url:"stack,omitempty,key"` // unique name of stack } // Create a new app. @@ -1241,18 +1279,6 @@ func (s *Service) AppFeatureUpdate(ctx context.Context, appIdentity string, appF return &appFeature, s.Patch(ctx, &appFeature, fmt.Sprintf("/apps/%v/features/%v", appIdentity, appFeatureIdentity), o) } -// App formation set describes the combination of process types with -// their quantities and sizes as well as application process tier -type AppFormationSet struct { - App struct { - ID string `json:"id" url:"id,key"` // unique identifier of app - Name string `json:"name" url:"name,key"` // unique name of app - } `json:"app" url:"app,key"` // app being described by the formation-set - Description string `json:"description" url:"description,key"` // a string representation of the formation set - ProcessTier string `json:"process_tier" url:"process_tier,key"` // application process tier - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // last time fomation-set was updated -} - // An app setup represents an app on Heroku that is setup using an // environment, addons, and scripts described in an app.json manifest // file. @@ -1657,8 +1683,8 @@ func (s *Service) AuditTrailEventList(ctx context.Context, enterpriseAccountIden return &auditTrailEvent, s.Get(ctx, &auditTrailEvent, fmt.Sprintf("/enterprise-accounts/%v/events", enterpriseAccountIdentity), nil, lr) } -// A build represents the process of transforming a code tarball into a -// slug +// A build represents the process of transforming a code tarball into +// build artifacts type Build struct { App struct { ID string `json:"id" url:"id,key"` // unique identifier of app @@ -1666,7 +1692,8 @@ type Build struct { Buildpacks []struct { Name string `json:"name" url:"name,key"` // Buildpack Registry name of the buildpack for the app URL string `json:"url" url:"url,key"` // the URL of the buildpack for the app - } `json:"buildpacks" url:"buildpacks,key"` // buildpacks executed for this build, in order + } `json:"buildpacks" url:"buildpacks,key"` // buildpacks executed for this build, in order (only applicable to + // Cedar-generation apps) CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when build was created ID string `json:"id" url:"id,key"` // unique identifier of build OutputStreamURL string `json:"output_stream_url" url:"output_stream_url,key"` // Build process output will be available from this URL as a stream. The @@ -1679,13 +1706,15 @@ type Build struct { } `json:"release" url:"release,key"` // release resulting from the build Slug *struct { ID string `json:"id" url:"id,key"` // unique identifier of slug - } `json:"slug" url:"slug,key"` // slug created by this build + } `json:"slug" url:"slug,key"` // slug created by this build (only applicable for Cedar-generation + // apps) SourceBlob struct { Checksum *string `json:"checksum" url:"checksum,key"` // an optional checksum of the gzipped tarball for verifying its // integrity URL string `json:"url" url:"url,key"` // URL where gzipped tar archive of source code for build was // downloaded. - Version *string `json:"version" url:"version,key"` // Version of the gzipped tarball. + Version *string `json:"version" url:"version,key"` // Version of the gzipped tarball. + VersionDescription *string `json:"version_description" url:"version_description,key"` // Version description of the gzipped tarball. } `json:"source_blob" url:"source_blob,key"` // location of gzipped tarball of source code used to create build Stack string `json:"stack" url:"stack,key"` // stack of build Status string `json:"status" url:"status,key"` // status of build @@ -1699,13 +1728,15 @@ type BuildCreateOpts struct { Buildpacks []*struct { Name *string `json:"name,omitempty" url:"name,omitempty,key"` // Buildpack Registry name of the buildpack for the app URL *string `json:"url,omitempty" url:"url,omitempty,key"` // the URL of the buildpack for the app - } `json:"buildpacks,omitempty" url:"buildpacks,omitempty,key"` // buildpacks executed for this build, in order + } `json:"buildpacks,omitempty" url:"buildpacks,omitempty,key"` // buildpacks executed for this build, in order (only applicable to + // Cedar-generation apps) SourceBlob struct { Checksum *string `json:"checksum,omitempty" url:"checksum,omitempty,key"` // an optional checksum of the gzipped tarball for verifying its // integrity URL *string `json:"url,omitempty" url:"url,omitempty,key"` // URL where gzipped tar archive of source code for build was // downloaded. - Version *string `json:"version,omitempty" url:"version,omitempty,key"` // Version of the gzipped tarball. + Version *string `json:"version,omitempty" url:"version,omitempty,key"` // Version of the gzipped tarball. + VersionDescription *string `json:"version_description,omitempty" url:"version_description,omitempty,key"` // Version description of the gzipped tarball. } `json:"source_blob" url:"source_blob,key"` // location of gzipped tarball of source code used to create build } @@ -1735,6 +1766,12 @@ func (s *Service) BuildDeleteCache(ctx context.Context, appIdentity string) (*Bu return &build, s.Delete(ctx, &build, fmt.Sprintf("/apps/%v/build-cache", appIdentity)) } +// Cancel running build. +func (s *Service) BuildCancel(ctx context.Context, appIdentity string, buildIdentity string) (*Build, error) { + var build Build + return &build, s.Delete(ctx, &build, fmt.Sprintf("/apps/%v/builds/%v", appIdentity, buildIdentity)) +} + // A buildpack installation represents a buildpack that will be run // against an app. type BuildpackInstallation struct { @@ -1964,7 +2001,7 @@ type Dyno struct { ID string `json:"id" url:"id,key"` // unique identifier of release Version int `json:"version" url:"version,key"` // unique version assigned to the release } `json:"release" url:"release,key"` // app release of the dyno - Size string `json:"size" url:"size,key"` // dyno size (default: "standard-1X") + Size string `json:"size" url:"size,key"` // dyno size State string `json:"state" url:"state,key"` // current status of process (either: crashed, down, idle, starting, or // up) Type string `json:"type" url:"type,key"` // type of process @@ -1975,7 +2012,7 @@ type DynoCreateOpts struct { Command string `json:"command" url:"command,key"` // command used to start this process Env map[string]string `json:"env,omitempty" url:"env,omitempty,key"` // custom environment to add to the dyno config vars ForceNoTty *bool `json:"force_no_tty,omitempty" url:"force_no_tty,omitempty,key"` // force an attached one-off dyno to not run in a tty - Size *string `json:"size,omitempty" url:"size,omitempty,key"` // dyno size (default: "standard-1X") + Size *string `json:"size,omitempty" url:"size,omitempty,key"` // dyno size TimeToLive *int `json:"time_to_live,omitempty" url:"time_to_live,omitempty,key"` // seconds until dyno expires, after which it will soon be killed, max // 86400 seconds (24 hours) Type *string `json:"type,omitempty" url:"type,omitempty,key"` // type of process @@ -1995,6 +2032,14 @@ func (s *Service) DynoRestart(ctx context.Context, appIdentity string, dynoIdent return dyno, s.Delete(ctx, &dyno, fmt.Sprintf("/apps/%v/dynos/%v", appIdentity, dynoIdentity)) } +type DynoRestartFormationResult struct{} + +// Restart dynos of a given formation type. +func (s *Service) DynoRestartFormation(ctx context.Context, appIdentity string, dynoFormationType string) (DynoRestartFormationResult, error) { + var dyno DynoRestartFormationResult + return dyno, s.Delete(ctx, &dyno, fmt.Sprintf("/apps/%v/formations/%v", appIdentity, dynoFormationType)) +} + type DynoRestartAllResult struct{} // Restart all dynos. @@ -2011,6 +2056,14 @@ func (s *Service) DynoStop(ctx context.Context, appIdentity string, dynoIdentity return dyno, s.Post(ctx, &dyno, fmt.Sprintf("/apps/%v/dynos/%v/actions/stop", appIdentity, dynoIdentity), nil) } +type DynoStopFormationResult struct{} + +// Stop dynos of a given formation type. +func (s *Service) DynoStopFormation(ctx context.Context, appIdentity string, dynoFormationType string) (DynoStopFormationResult, error) { + var dyno DynoStopFormationResult + return dyno, s.Post(ctx, &dyno, fmt.Sprintf("/apps/%v/formations/%v/actions/stop", appIdentity, dynoFormationType), nil) +} + // Info for existing dyno. func (s *Service) DynoInfo(ctx context.Context, appIdentity string, dynoIdentity string) (*Dyno, error) { var dyno Dyno @@ -2030,14 +2083,22 @@ func (s *Service) DynoList(ctx context.Context, appIdentity string, lr *ListRang // [https://devcenter.heroku.com/articles/dyno-types](https://devcenter.h // eroku.com/articles/dyno-types). type DynoSize struct { - Compute int `json:"compute" url:"compute,key"` // minimum vCPUs, non-dedicated may get more depending on load - Cost *struct{} `json:"cost" url:"cost,key"` // price information for this dyno size - Dedicated bool `json:"dedicated" url:"dedicated,key"` // whether this dyno will be dedicated to one user - DynoUnits int `json:"dyno_units" url:"dyno_units,key"` // unit of consumption for Heroku Enterprise customers - ID string `json:"id" url:"id,key"` // unique identifier of this dyno size - Memory float64 `json:"memory" url:"memory,key"` // amount of RAM in GB - Name string `json:"name" url:"name,key"` // the name of this dyno-size - PrivateSpaceOnly bool `json:"private_space_only" url:"private_space_only,key"` // whether this dyno can only be provisioned in a private space + Architecture string `json:"architecture" url:"architecture,key"` // CPU architecture of this dyno size + Compute int `json:"compute" url:"compute,key"` // minimum vCPUs, non-dedicated may get more depending on load + Cost *struct{} `json:"cost" url:"cost,key"` // price information for this dyno size + Dedicated bool `json:"dedicated" url:"dedicated,key"` // whether this dyno will be dedicated to one user + Generation struct { + ID string `json:"id" url:"id,key"` // unique identifier of the generation of the Heroku platform for this + // dyno size + Name string `json:"name" url:"name,key"` // unique name of the generation of the Heroku platform for this dyno + // size + } `json:"generation" url:"generation,key"` // Generation of the Heroku platform for this dyno size + ID string `json:"id" url:"id,key"` // unique identifier of the dyno size + Memory float64 `json:"memory" url:"memory,key"` // amount of RAM in GB + Name string `json:"name" url:"name,key"` // name of the dyno size + PreciseDynoUnits float64 `json:"precise_dyno_units" url:"precise_dyno_units,key"` // unit of consumption for Heroku Enterprise customers to 2 decimal + // places + PrivateSpaceOnly bool `json:"private_space_only" url:"private_space_only,key"` // whether this dyno can only be provisioned in a private space } // Info for existing dyno size. @@ -2054,6 +2115,13 @@ func (s *Service) DynoSizeList(ctx context.Context, lr *ListRange) (DynoSizeList return dynoSize, s.Get(ctx, &dynoSize, fmt.Sprintf("/dyno-sizes"), nil, lr) } +type DynoSizeListAppDynoSizesResult []DynoSize + +// List available dyno sizes for an app +func (s *Service) DynoSizeListAppDynoSizes(ctx context.Context, appIdentity string) error { + return s.Get(ctx, nil, fmt.Sprintf("/apps/%v/available-dyno-sizes", appIdentity), nil, nil) +} + // Enterprise accounts allow companies to manage their development teams // and billing. type EnterpriseAccount struct { @@ -2068,7 +2136,9 @@ type EnterpriseAccount struct { Type string `json:"type" url:"type,key"` // type of the owner } `json:"owner" url:"owner,key"` // entity that owns this identity provider } `json:"identity_provider" url:"identity_provider,key"` // Identity Provider associated with the Enterprise Account - Name string `json:"name" url:"name,key"` // unique name of the enterprise account + Name string `json:"name" url:"name,key"` // unique name of the enterprise account + PartnerBenefits bool `json:"partner_benefits" url:"partner_benefits,key"` // whether the enterprise account is part of the Salesforce Partner + // Program Permissions []string `json:"permissions" url:"permissions,key"` // the current user's permissions for this enterprise account Trial bool `json:"trial" url:"trial,key"` // whether the enterprise account is a trial or not UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when the enterprise account was updated @@ -2132,12 +2202,10 @@ type EnterpriseAccountDailyUsageInfoResult []EnterpriseAccountDailyUsage // Retrieves usage for an enterprise account for a range of days. Start // and end dates can be specified as query parameters using the date -// format YYYY-MM-DD. -// The enterprise account identifier can be found +// format YYYY-MM-DD. The enterprise account identifier can be found // from the [enterprise account // list](https://devcenter.heroku.com/articles/platform-api-reference#ent // erprise-account-list). -// func (s *Service) EnterpriseAccountDailyUsageInfo(ctx context.Context, enterpriseAccountID string, o EnterpriseAccountDailyUsageInfoOpts, lr *ListRange) (EnterpriseAccountDailyUsageInfoResult, error) { var enterpriseAccountDailyUsage EnterpriseAccountDailyUsageInfoResult return enterpriseAccountDailyUsage, s.Get(ctx, &enterpriseAccountDailyUsage, fmt.Sprintf("/enterprise-accounts/%v/usage/daily", enterpriseAccountID), o, lr) @@ -2211,7 +2279,7 @@ func (s *Service) EnterpriseAccountMemberDelete(ctx context.Context, enterpriseA // Usage for an enterprise account at a monthly resolution. type EnterpriseAccountMonthlyUsage struct { Addons float64 `json:"addons" url:"addons,key"` // total add-on credits used - Connect float64 `json:"connect" url:"connect,key"` // average connect rows synced + Connect float64 `json:"connect" url:"connect,key"` // max connect rows synced Data float64 `json:"data" url:"data,key"` // total add-on credits used for first party add-ons Dynos float64 `json:"dynos" url:"dynos,key"` // dynos used ID string `json:"id" url:"id,key"` // enterprise account identifier @@ -2228,7 +2296,7 @@ type EnterpriseAccountMonthlyUsage struct { Dynos float64 `json:"dynos" url:"dynos,key"` // dynos used Partner float64 `json:"partner" url:"partner,key"` // total add-on credits used for third party add-ons } `json:"apps" url:"apps,key"` // app usage in the team - Connect float64 `json:"connect" url:"connect,key"` // average connect rows synced + Connect float64 `json:"connect" url:"connect,key"` // max connect rows synced Data float64 `json:"data" url:"data,key"` // total add-on credits used for first party add-ons Dynos float64 `json:"dynos" url:"dynos,key"` // dynos used ID string `json:"id" url:"id,key"` // team identifier @@ -2246,12 +2314,10 @@ type EnterpriseAccountMonthlyUsageInfoResult []EnterpriseAccountMonthlyUsage // Retrieves usage for an enterprise account for a range of months. // Start and end dates can be specified as query parameters using the // date format YYYY-MM. If no end date is specified, one month of usage -// is returned. -// The enterprise account identifier can be found from the +// is returned. The enterprise account identifier can be found from the // [enterprise account // list](https://devcenter.heroku.com/articles/platform-api-reference#ent // erprise-account-list). -// func (s *Service) EnterpriseAccountMonthlyUsageInfo(ctx context.Context, enterpriseAccountID string, o EnterpriseAccountMonthlyUsageInfoOpts, lr *ListRange) (EnterpriseAccountMonthlyUsageInfoResult, error) { var enterpriseAccountMonthlyUsage EnterpriseAccountMonthlyUsageInfoResult return enterpriseAccountMonthlyUsage, s.Get(ctx, &enterpriseAccountMonthlyUsage, fmt.Sprintf("/enterprise-accounts/%v/usage/monthly", enterpriseAccountID), o, lr) @@ -2308,7 +2374,7 @@ type FilterAppsAppsResult []struct { Name string `json:"name" url:"name,key"` // unique name of team } `json:"team" url:"team,key"` // team that owns this app UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when app was updated - WebURL string `json:"web_url" url:"web_url,key"` // web URL of app + WebURL *string `json:"web_url" url:"web_url,key"` // web URL of app } // Request an apps list filtered by app id. @@ -2329,9 +2395,13 @@ type Formation struct { } `json:"app" url:"app,key"` // app formation belongs to Command string `json:"command" url:"command,key"` // command to use to launch this process CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when process type was created + DynoSize struct { + ID string `json:"id" url:"id,key"` // unique identifier of the dyno size + Name string `json:"name" url:"name,key"` // name of the dyno size + } `json:"dyno_size" url:"dyno_size,key"` // dyno size ID string `json:"id" url:"id,key"` // unique identifier of this process type Quantity int `json:"quantity" url:"quantity,key"` // number of processes to maintain - Size string `json:"size" url:"size,key"` // dyno size (default: "standard-1X") + Size string `json:"size" url:"size,key"` // deprecated, refer to 'dyno_size' instead Type string `json:"type" url:"type,key"` // type of process to maintain UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when dyno type was updated } @@ -2352,12 +2422,15 @@ func (s *Service) FormationList(ctx context.Context, appIdentity string, lr *Lis type FormationBatchUpdateOpts struct { Updates []struct { - Quantity *int `json:"quantity,omitempty" url:"quantity,omitempty,key"` // number of processes to maintain - Size *string `json:"size,omitempty" url:"size,omitempty,key"` // dyno size (default: "standard-1X") - Type string `json:"type" url:"type,key"` // type of process to maintain + DynoSize *struct { + ID *string `json:"id,omitempty" url:"id,omitempty,key"` // unique identifier of the dyno size + Name *string `json:"name,omitempty" url:"name,omitempty,key"` // name of the dyno size + } `json:"dyno_size,omitempty" url:"dyno_size,omitempty,key"` // dyno size + Quantity *int `json:"quantity,omitempty" url:"quantity,omitempty,key"` // number of processes to maintain + Type string `json:"type" url:"type,key"` // type of process to maintain } `json:"updates" url:"updates,key"` // Array with formation updates. Each element must have "type", the id // or name of the process type to be updated, and can optionally update - // its "quantity" or "size". + // its "quantity" or "dyno_size". } type FormationBatchUpdateResult []Formation @@ -2368,8 +2441,11 @@ func (s *Service) FormationBatchUpdate(ctx context.Context, appIdentity string, } type FormationUpdateOpts struct { - Quantity *int `json:"quantity,omitempty" url:"quantity,omitempty,key"` // number of processes to maintain - Size *string `json:"size,omitempty" url:"size,omitempty,key"` // dyno size (default: "standard-1X") + DynoSize *struct { + ID *string `json:"id,omitempty" url:"id,omitempty,key"` // unique identifier of the dyno size + Name *string `json:"name,omitempty" url:"name,omitempty,key"` // name of the dyno size + } `json:"dyno_size,omitempty" url:"dyno_size,omitempty,key"` // dyno size + Quantity *int `json:"quantity,omitempty" url:"quantity,omitempty,key"` // number of processes to maintain } // Update process type @@ -2378,8 +2454,40 @@ func (s *Service) FormationUpdate(ctx context.Context, appIdentity string, forma return &formation, s.Patch(ctx, &formation, fmt.Sprintf("/apps/%v/formation/%v", appIdentity, formationIdentity), o) } -// Identity Providers represent the SAML configuration of an Enterprise -// Account or Team. +// A generation represents a version of the Heroku platform that +// includes the app execution environment, routing, telemetry, and build +// systems. +type Generation struct { + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when generation was created + ID string `json:"id" url:"id,key"` // unique identifier of generation + Name string `json:"name" url:"name,key"` // unique name of generation + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when generation was updated +} + +// Info for generation. +func (s *Service) GenerationInfo(ctx context.Context, stackIdentity string) (*Generation, error) { + var generation Generation + return &generation, s.Get(ctx, &generation, fmt.Sprintf("/generations/%v", stackIdentity), nil, nil) +} + +type GenerationListResult []Generation + +// List available generations. +func (s *Service) GenerationList(ctx context.Context, lr *ListRange) (GenerationListResult, error) { + var generation GenerationListResult + return generation, s.Get(ctx, &generation, fmt.Sprintf("/generations"), nil, lr) +} + +type GenerationListByTeamResult []Generation + +// List available generations for a team. +func (s *Service) GenerationListByTeam(ctx context.Context, teamIdentity string, lr *ListRange) (GenerationListByTeamResult, error) { + var generation GenerationListByTeamResult + return generation, s.Get(ctx, &generation, fmt.Sprintf("/teams/%v/available-generations", teamIdentity), nil, lr) +} + +// Identity Providers represent the SAML configuration of teams or an +// Enterprise account type IdentityProvider struct { Certificate string `json:"certificate" url:"certificate,key"` // raw contents of the public certificate (eg: .crt or .pem file) CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when provider record was created @@ -2587,9 +2695,17 @@ func (s *Service) KeyList(ctx context.Context, lr *ListRange) (KeyListResult, er // removed by removing the add-on. type LogDrain struct { Addon *struct { + App struct { + ID string `json:"id" url:"id,key"` // unique identifier of app + Name string `json:"name" url:"name,key"` // unique name of app + } `json:"app" url:"app,key"` // billing application associated with this add-on ID string `json:"id" url:"id,key"` // unique identifier of add-on Name string `json:"name" url:"name,key"` // globally unique name of the add-on } `json:"addon" url:"addon,key"` // add-on that created the drain + App *struct { + ID string `json:"id" url:"id,key"` // unique identifier of app + Name string `json:"name" url:"name,key"` // unique name of app + } `json:"app" url:"app,key"` // application that is attached to this drain CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when log drain was created ID string `json:"id" url:"id,key"` // unique identifier of this log drain Token string `json:"token" url:"token,key"` // token associated with the log drain @@ -2653,10 +2769,11 @@ type LogSession struct { UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when log session was updated } type LogSessionCreateOpts struct { - Dyno *string `json:"dyno,omitempty" url:"dyno,omitempty,key"` // dyno to limit results to - Lines *int `json:"lines,omitempty" url:"lines,omitempty,key"` // number of log lines to stream at once - Source *string `json:"source,omitempty" url:"source,omitempty,key"` // log source to limit results to - Tail *bool `json:"tail,omitempty" url:"tail,omitempty,key"` // whether to stream ongoing logs + DynoName *string `json:"dyno_name,omitempty" url:"dyno_name,omitempty,key"` // dyno name to limit results to + Lines *int `json:"lines,omitempty" url:"lines,omitempty,key"` // number of log lines to stream at once + Source *string `json:"source,omitempty" url:"source,omitempty,key"` // log source to limit results to + Tail *bool `json:"tail,omitempty" url:"tail,omitempty,key"` // whether to stream ongoing logs + Type *string `json:"type,omitempty" url:"type,omitempty,key"` // process type to limit results to } // Create a new log session. @@ -2681,8 +2798,9 @@ type OAuthAuthorization struct { Name string `json:"name" url:"name,key"` // OAuth client name RedirectURI string `json:"redirect_uri" url:"redirect_uri,key"` // endpoint for redirection after authorization with OAuth client } `json:"client" url:"client,key"` // identifier of the client that obtained this authorization, if any - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when OAuth authorization was created - Grant *struct { + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when OAuth authorization was created + Description string `json:"description" url:"description,key"` // human-friendly description of this OAuth authorization + Grant *struct { Code string `json:"code" url:"code,key"` // grant code received from OAuth web application authorization ExpiresIn int `json:"expires_in" url:"expires_in,key"` // seconds until OAuth grant expires ID string `json:"id" url:"id,key"` // unique identifier of OAuth grant @@ -2694,7 +2812,10 @@ type OAuthAuthorization struct { ID string `json:"id" url:"id,key"` // unique identifier of OAuth token Token string `json:"token" url:"token,key"` // contents of the token to be used for authorization } `json:"refresh_token" url:"refresh_token,key"` // refresh token for this authorization - Scope []string `json:"scope" url:"scope,key"` // The scope of access OAuth authorization allows + Scope []string `json:"scope" url:"scope,key"` // The scope of access OAuth authorization allows + Session *struct { + ID string `json:"id" url:"id,key"` // unique identifier of OAuth token + } `json:"session" url:"session,key"` // this authorization's session UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when OAuth authorization was updated User struct { Email string `json:"email" url:"email,key"` // unique email address of account @@ -2728,6 +2849,20 @@ func (s *Service) OAuthAuthorizationInfo(ctx context.Context, oauthAuthorization return &oauthAuthorization, s.Get(ctx, &oauthAuthorization, fmt.Sprintf("/oauth/authorizations/%v", oauthAuthorizationIdentity), nil, nil) } +type OAuthAuthorizationUpdateOpts struct { + Client struct { + ID *string `json:"id,omitempty" url:"id,omitempty,key"` // unique identifier of this OAuth client + Secret *string `json:"secret,omitempty" url:"secret,omitempty,key"` // secret used to obtain OAuth authorizations under this client + } `json:"client" url:"client,key"` // identifier of the client that obtained this authorization + Description *string `json:"description,omitempty" url:"description,omitempty,key"` // human-friendly description of this OAuth authorization +} + +// Update an existing OAuth authorization. +func (s *Service) OAuthAuthorizationUpdate(ctx context.Context, oauthAuthorizationIdentity string, o OAuthAuthorizationUpdateOpts) (*OAuthAuthorization, error) { + var oauthAuthorization OAuthAuthorization + return &oauthAuthorization, s.Patch(ctx, &oauthAuthorization, fmt.Sprintf("/oauth/authorizations/%v", oauthAuthorizationIdentity), o) +} + type OAuthAuthorizationListResult []OAuthAuthorization // List OAuth authorizations. @@ -2773,7 +2908,8 @@ func (s *Service) OAuthClientDelete(ctx context.Context, oauthClientIdentity str return &oauthClient, s.Delete(ctx, &oauthClient, fmt.Sprintf("/oauth/clients/%v", oauthClientIdentity)) } -// Info for an OAuth client +// Info for an OAuth client. The output for unauthenticated requests +// excludes the `secret` parameter. func (s *Service) OAuthClientInfo(ctx context.Context, oauthClientIdentity string) (*OAuthClient, error) { var oauthClient OAuthClient return &oauthClient, s.Get(ctx, &oauthClient, fmt.Sprintf("/oauth/clients/%v", oauthClientIdentity), nil, nil) @@ -2873,61 +3009,74 @@ func (s *Service) OAuthTokenDelete(ctx context.Context, oauthTokenIdentity strin return &oauthToken, s.Delete(ctx, &oauthToken, fmt.Sprintf("/oauth/tokens/%v", oauthTokenIdentity)) } -// An outbound-ruleset is a collection of rules that specify what hosts -// Dynos are allowed to communicate with. -type OutboundRuleset struct { - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when outbound-ruleset was created - CreatedBy string `json:"created_by" url:"created_by,key"` // unique email address of account - ID string `json:"id" url:"id,key"` // unique identifier of an outbound-ruleset - Rules []struct { - FromPort int `json:"from_port" url:"from_port,key"` // an endpoint of communication in an operating system. - Protocol string `json:"protocol" url:"protocol,key"` // formal standards and policies comprised of rules, procedures and - // formats that define communication between two or more devices over a - // network - Target string `json:"target" url:"target,key"` // is the target destination in CIDR notation - ToPort int `json:"to_port" url:"to_port,key"` // an endpoint of communication in an operating system. - } `json:"rules" url:"rules,key"` - Space struct { - ID string `json:"id" url:"id,key"` // unique identifier of space - Name string `json:"name" url:"name,key"` // unique name of space - } `json:"space" url:"space,key"` // identity of space -} - -// Current outbound ruleset for a space -func (s *Service) OutboundRulesetCurrent(ctx context.Context, spaceIdentity string) (*OutboundRuleset, error) { - var outboundRuleset OutboundRuleset - return &outboundRuleset, s.Get(ctx, &outboundRuleset, fmt.Sprintf("/spaces/%v/outbound-ruleset", spaceIdentity), nil, nil) -} - -// Info on an existing Outbound Ruleset -func (s *Service) OutboundRulesetInfo(ctx context.Context, spaceIdentity string, outboundRulesetIdentity string) (*OutboundRuleset, error) { - var outboundRuleset OutboundRuleset - return &outboundRuleset, s.Get(ctx, &outboundRuleset, fmt.Sprintf("/spaces/%v/outbound-rulesets/%v", spaceIdentity, outboundRulesetIdentity), nil, nil) -} - -type OutboundRulesetListResult []OutboundRuleset - -// List all Outbound Rulesets for a space -func (s *Service) OutboundRulesetList(ctx context.Context, spaceIdentity string, lr *ListRange) (OutboundRulesetListResult, error) { - var outboundRuleset OutboundRulesetListResult - return outboundRuleset, s.Get(ctx, &outboundRuleset, fmt.Sprintf("/spaces/%v/outbound-rulesets", spaceIdentity), nil, lr) -} - -type OutboundRulesetCreateOpts struct { - Rules []*struct { - FromPort int `json:"from_port" url:"from_port,key"` // an endpoint of communication in an operating system. - Protocol string `json:"protocol" url:"protocol,key"` // formal standards and policies comprised of rules, procedures and - // formats that define communication between two or more devices over a - // network - Target string `json:"target" url:"target,key"` // is the target destination in CIDR notation - ToPort int `json:"to_port" url:"to_port,key"` // an endpoint of communication in an operating system. - } `json:"rules,omitempty" url:"rules,omitempty,key"` -} - -// Create a new outbound ruleset -func (s *Service) OutboundRulesetCreate(ctx context.Context, spaceIdentity string, o OutboundRulesetCreateOpts) (*OutboundRuleset, error) { - var outboundRuleset OutboundRuleset - return &outboundRuleset, s.Put(ctx, &outboundRuleset, fmt.Sprintf("/spaces/%v/outbound-ruleset", spaceIdentity), o) +// An OCI (Open Container Initiative) image is a standardized format for +// packaging and distributing containerized applications, ready to run +// on the platform. +type OciImage struct { + Architecture *string `json:"architecture" url:"architecture,key"` // build architecture for OCI image + BaseImageName string `json:"base_image_name" url:"base_image_name,key"` // name of the image used for the base layers of the OCI image + BaseTopLayer string `json:"base_top_layer" url:"base_top_layer,key"` // the digest of the top most layer of the base image. + Buildpacks []struct { + Homepage string `json:"homepage" url:"homepage,key"` // homepage of the buildpack + ID string `json:"id" url:"id,key"` // identifier of the buildpack + Version string `json:"version" url:"version,key"` // version of the buildpack + } `json:"buildpacks" url:"buildpacks,key"` // buildpacks of the OCI image + Commit string `json:"commit" url:"commit,key"` // identification of the code in your version control system (eg: SHA of + // the git HEAD) + CommitDescription string `json:"commit_description" url:"commit_description,key"` // an optional description of the provided commit + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when the OCI image was created + Digest string `json:"digest" url:"digest,key"` // unique identifier representing the content of the OCI image + ID string `json:"id" url:"id,key"` // unique identifier of the OCI image + ImageRepo string `json:"image_repo" url:"image_repo,key"` // name of the image registry repository used for storage + ProcessTypes map[string]struct { + Command string `json:"command" url:"command,key"` // the command that will be executed + Default *bool `json:"default" url:"default,key"` // true if it is the default process type + DisplayCmd string `json:"display_cmd" url:"display_cmd,key"` // the detailed command used for display purposes + Name string `json:"name" url:"name,key"` // name of the process type + WorkingDir string `json:"working_dir" url:"working_dir,key"` // working directory + } `json:"process_types" url:"process_types,key"` // process types of the OCI image + Stack struct { + ID string `json:"id" url:"id,key"` // unique identifier of stack + Name string `json:"name" url:"name,key"` // unique name of stack + } `json:"stack" url:"stack,key"` // stack associated to the OCI image + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when the OCI image was updated +} +type OciImageInfoResult []OciImage + +// Info for the OCI images of an app, filtered by identifier. +func (s *Service) OciImageInfo(ctx context.Context, appIdentity string, ociImageIdentity string) (OciImageInfoResult, error) { + var ociImage OciImageInfoResult + return ociImage, s.Get(ctx, &ociImage, fmt.Sprintf("/apps/%v/oci-images/%v", appIdentity, ociImageIdentity), nil, nil) +} + +type OciImageCreateOpts struct { + Architecture *string `json:"architecture,omitempty" url:"architecture,omitempty,key"` // build architecture for OCI image + BaseImageName *string `json:"base_image_name,omitempty" url:"base_image_name,omitempty,key"` // name of the image used for the base layers of the OCI image + BaseTopLayer *string `json:"base_top_layer,omitempty" url:"base_top_layer,omitempty,key"` // the digest of the top most layer of the base image. + Buildpacks []*struct { + Homepage *string `json:"homepage,omitempty" url:"homepage,omitempty,key"` // homepage of the buildpack + ID *string `json:"id,omitempty" url:"id,omitempty,key"` // identifier of the buildpack + Version *string `json:"version,omitempty" url:"version,omitempty,key"` // version of the buildpack + } `json:"buildpacks,omitempty" url:"buildpacks,omitempty,key"` // buildpacks of the OCI image + Commit *string `json:"commit,omitempty" url:"commit,omitempty,key"` // identification of the code in your version control system (eg: SHA of + // the git HEAD) + CommitDescription *string `json:"commit_description,omitempty" url:"commit_description,omitempty,key"` // an optional description of the provided commit + Digest *string `json:"digest,omitempty" url:"digest,omitempty,key"` // unique identifier representing the content of the OCI image + ImageRepo *string `json:"image_repo,omitempty" url:"image_repo,omitempty,key"` // name of the image registry repository used for storage + ProcessTypes map[string]struct { + Command string `json:"command" url:"command,key"` // the command that will be executed + Default *bool `json:"default" url:"default,key"` // true if it is the default process type + DisplayCmd string `json:"display_cmd" url:"display_cmd,key"` // the detailed command used for display purposes + Name string `json:"name" url:"name,key"` // name of the process type + WorkingDir string `json:"working_dir" url:"working_dir,key"` // working directory + } `json:"process_types,omitempty" url:"process_types,omitempty,key"` // process types of the OCI image + Stack *string `json:"stack,omitempty" url:"stack,omitempty,key"` // unique name of stack +} + +// Create an new OCI image of an app +func (s *Service) OciImageCreate(ctx context.Context, appIdentity string, o OciImageCreateOpts) (*OciImage, error) { + var ociImage OciImage + return &ociImage, s.Post(ctx, &ociImage, fmt.Sprintf("/apps/%v/oci-images", appIdentity), o) } // A password reset represents a in-process password reset attempt. @@ -2939,7 +3088,7 @@ type PasswordReset struct { } `json:"user" url:"user,key"` } type PasswordResetResetPasswordOpts struct { - Email *string `json:"email,omitempty" url:"email,omitempty,key"` // unique email address of account + Email string `json:"email" url:"email,key"` // unique email address of account } // Reset account's password. This will send a reset password link to the @@ -2950,8 +3099,8 @@ func (s *Service) PasswordResetResetPassword(ctx context.Context, o PasswordRese } type PasswordResetCompleteResetPasswordOpts struct { - Password *string `json:"password,omitempty" url:"password,omitempty,key"` // current password on the account - PasswordConfirmation *string `json:"password_confirmation,omitempty" url:"password_confirmation,omitempty,key"` // confirmation of the new password + Password string `json:"password" url:"password,key"` // current password on the account + PasswordConfirmation string `json:"password_confirmation" url:"password_confirmation,key"` // confirmation of the new password } // Complete password reset. @@ -2961,7 +3110,8 @@ func (s *Service) PasswordResetCompleteResetPassword(ctx context.Context, passwo } // [Peering](https://devcenter.heroku.com/articles/private-space-peering) -// provides a way to peer your Private Space VPC to another AWS VPC. +// +// provides a way to peer your Private Space VPC to another AWS VPC. type Peering struct { AwsAccountID string `json:"aws_account_id" url:"aws_account_id,key"` // The AWS account ID of your Private Space. AwsRegion string `json:"aws_region" url:"aws_region,key"` // The AWS region of the peer connection. @@ -3042,10 +3192,16 @@ func (s *Service) PermissionEntityList(ctx context.Context, teamIdentity string, // A pipeline allows grouping of apps into different stages. type Pipeline struct { - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when pipeline was created - ID string `json:"id" url:"id,key"` // unique identifier of pipeline - Name string `json:"name" url:"name,key"` // name of pipeline - Owner *struct { + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when pipeline was created + Generation struct { + ID string `json:"id" url:"id,key"` // unique identifier of the generation of the Heroku platform for this + // pipeline + Name string `json:"name" url:"name,key"` // unique name of the generation of the Heroku platform for this + // pipeline + } `json:"generation" url:"generation,key"` // the generation of the Heroku platform for this pipeline + ID string `json:"id" url:"id,key"` // unique identifier of pipeline + Name string `json:"name" url:"name,key"` // name of pipeline + Owner *struct { ID string `json:"id" url:"id,key"` // unique identifier of a pipeline owner Type string `json:"type" url:"type,key"` // type of pipeline owner } `json:"owner" url:"owner,key"` // Owner of a pipeline. @@ -3095,16 +3251,17 @@ func (s *Service) PipelineList(ctx context.Context, lr *ListRange) (PipelineList return pipeline, s.Get(ctx, &pipeline, fmt.Sprintf("/pipelines"), nil, lr) } -// Information about latest builds of apps in a pipeline. -type PipelineBuild struct{} -type PipelineBuildListResult []struct { +// Information about the latest builds of apps in a pipeline. A build +// represents the process of transforming code into build artifacts. +type PipelineBuild struct { App struct { ID string `json:"id" url:"id,key"` // unique identifier of app } `json:"app" url:"app,key"` // app that the build belongs to Buildpacks []struct { Name string `json:"name" url:"name,key"` // Buildpack Registry name of the buildpack for the app URL string `json:"url" url:"url,key"` // the URL of the buildpack for the app - } `json:"buildpacks" url:"buildpacks,key"` // buildpacks executed for this build, in order + } `json:"buildpacks" url:"buildpacks,key"` // buildpacks executed for this build, in order (only applicable to + // Cedar-generation apps) CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when build was created ID string `json:"id" url:"id,key"` // unique identifier of build OutputStreamURL string `json:"output_stream_url" url:"output_stream_url,key"` // Build process output will be available from this URL as a stream. The @@ -3123,7 +3280,8 @@ type PipelineBuildListResult []struct { // integrity URL string `json:"url" url:"url,key"` // URL where gzipped tar archive of source code for build was // downloaded. - Version *string `json:"version" url:"version,key"` // Version of the gzipped tarball. + Version *string `json:"version" url:"version,key"` // version of the gzipped tarball + VersionDescription *string `json:"version_description" url:"version_description,key"` // version description of the gzipped tarball } `json:"source_blob" url:"source_blob,key"` // location of gzipped tarball of source code used to create build Stack string `json:"stack" url:"stack,key"` // stack of build Status string `json:"status" url:"status,key"` // status of build @@ -3133,6 +3291,7 @@ type PipelineBuildListResult []struct { ID string `json:"id" url:"id,key"` // unique identifier of an account } `json:"user" url:"user,key"` // user that started the build } +type PipelineBuildListResult []PipelineBuild // List latest builds for each app in a pipeline func (s *Service) PipelineBuildList(ctx context.Context, pipelineID string, lr *ListRange) (PipelineBuildListResult, error) { @@ -3140,8 +3299,8 @@ func (s *Service) PipelineBuildList(ctx context.Context, pipelineID string, lr * return pipelineBuild, s.Get(ctx, &pipelineBuild, fmt.Sprintf("/pipelines/%v/latest-builds", pipelineID), nil, lr) } -// Pipeline Config Vars allow you to manage the configuration -// information provided to a pipeline. +// Pipeline config vars in Heroku CI and review apps used to manage the +// configuration information for a pipeline. type PipelineConfigVar map[string]string type PipelineConfigVarInfoForAppResult map[string]*string @@ -3246,19 +3405,24 @@ func (s *Service) PipelineCouplingInfoByApp(ctx context.Context, appIdentity str return &pipelineCoupling, s.Get(ctx, &pipelineCoupling, fmt.Sprintf("/apps/%v/pipeline-couplings", appIdentity), nil, nil) } -// Information about latest deployments of apps in a pipeline. -type PipelineDeployment struct{} -type PipelineDeploymentListResult []struct { +// A release represents a combination of code, config vars and add-ons +// for an app on Heroku. +type PipelineDeployment struct { AddonPlanNames []string `json:"addon_plan_names" url:"addon_plan_names,key"` // add-on plans installed on the app for this release App struct { ID string `json:"id" url:"id,key"` // unique identifier of app Name string `json:"name" url:"name,key"` // unique name of app } `json:"app" url:"app,key"` // app involved in the release - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created - Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app - Description string `json:"description" url:"description,key"` // description of changes in this release - ID string `json:"id" url:"id,key"` // unique identifier of release - OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. + Artifacts []struct { + ID string `json:"id" url:"id,key"` // unique identifier of slug + Type string `json:"type" url:"type,key"` // type of artifact + } `json:"artifacts" url:"artifacts,key"` // build artifacts for the release + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created + Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app + Description string `json:"description" url:"description,key"` // description of changes in this release + EligibleForRollback bool `json:"eligible_for_rollback" url:"eligible_for_rollback,key"` // indicates if this release is eligible for rollback + ID string `json:"id" url:"id,key"` // unique identifier of release + OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. // The stream is available as either `text/plain` or // `text/event-stream`. Clients should be prepared to handle disconnects // and can resume the stream by sending a `Range` header (for @@ -3275,10 +3439,40 @@ type PipelineDeploymentListResult []struct { Version int `json:"version" url:"version,key"` // unique version assigned to the release } -// List latest slug releases for each app in a pipeline -func (s *Service) PipelineDeploymentList(ctx context.Context, pipelineID string, lr *ListRange) (PipelineDeploymentListResult, error) { +// Info for existing release. +func (s *Service) PipelineDeploymentInfo(ctx context.Context, appIdentity string, releaseIdentity string) (*PipelineDeployment, error) { + var pipelineDeployment PipelineDeployment + return &pipelineDeployment, s.Get(ctx, &pipelineDeployment, fmt.Sprintf("/apps/%v/releases/%v", appIdentity, releaseIdentity), nil, nil) +} + +type PipelineDeploymentListResult []PipelineDeployment + +// List existing releases. +func (s *Service) PipelineDeploymentList(ctx context.Context, appIdentity string, lr *ListRange) (PipelineDeploymentListResult, error) { var pipelineDeployment PipelineDeploymentListResult - return pipelineDeployment, s.Get(ctx, &pipelineDeployment, fmt.Sprintf("/pipelines/%v/latest-deployments", pipelineID), nil, lr) + return pipelineDeployment, s.Get(ctx, &pipelineDeployment, fmt.Sprintf("/apps/%v/releases", appIdentity), nil, lr) +} + +type PipelineDeploymentCreateOpts struct { + Description *string `json:"description,omitempty" url:"description,omitempty,key"` // description of changes in this release + OciImage *string `json:"oci_image,omitempty" url:"oci_image,omitempty,key"` // unique identifier of the OCI image + Slug string `json:"slug" url:"slug,key"` // unique identifier of slug +} + +// Create new release. +func (s *Service) PipelineDeploymentCreate(ctx context.Context, appIdentity string, o PipelineDeploymentCreateOpts) (*PipelineDeployment, error) { + var pipelineDeployment PipelineDeployment + return &pipelineDeployment, s.Post(ctx, &pipelineDeployment, fmt.Sprintf("/apps/%v/releases", appIdentity), o) +} + +type PipelineDeploymentRollbackOpts struct { + Release string `json:"release" url:"release,key"` // unique identifier of release +} + +// Rollback to an existing release. +func (s *Service) PipelineDeploymentRollback(ctx context.Context, appIdentity string, o PipelineDeploymentRollbackOpts) (*PipelineDeployment, error) { + var pipelineDeployment PipelineDeployment + return &pipelineDeployment, s.Post(ctx, &pipelineDeployment, fmt.Sprintf("/apps/%v/releases", appIdentity), o) } // Promotions allow you to move code from an app in a pipeline to all @@ -3351,19 +3545,55 @@ func (s *Service) PipelinePromotionTargetList(ctx context.Context, pipelinePromo return pipelinePromotionTarget, s.Get(ctx, &pipelinePromotionTarget, fmt.Sprintf("/pipeline-promotions/%v/promotion-targets", pipelinePromotionID), nil, lr) } -// Information about latest releases of apps in a pipeline. -type PipelineRelease struct{} +// Information about the latest release of each app in a pipeline. A +// release makes a deployment available to end-users. +type PipelineRelease struct { + AddonPlanNames []string `json:"addon_plan_names" url:"addon_plan_names,key"` // add-on plans installed on the app for this release + App struct { + ID string `json:"id" url:"id,key"` // unique identifier of app + Name string `json:"name" url:"name,key"` // unique name of app + } `json:"app" url:"app,key"` // app involved in the release + Artifacts struct { + ID string `json:"id" url:"id,key"` // unique identifier of slug + Type string `json:"type" url:"type,key"` // type of artifact + } `json:"artifacts" url:"artifacts,key"` // a build artifact for the release + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created + Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app + Description string `json:"description" url:"description,key"` // description of changes in this release + EligibleForRollback bool `json:"eligible_for_rollback" url:"eligible_for_rollback,key"` // indicates if this release is eligible for rollback + ID string `json:"id" url:"id,key"` // unique identifier of release + OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. + // The stream is available as either `text/plain` or + // `text/event-stream`. Clients should be prepared to handle disconnects + // and can resume the stream by sending a `Range` header (for + // `text/plain`) or a `Last-Event-Id` header (for `text/event-stream`). + Slug *struct { + ID string `json:"id" url:"id,key"` // unique identifier of slug + } `json:"slug" url:"slug,key"` // slug running in the release + Status string `json:"status" url:"status,key"` // current status of the release + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when release was updated + User struct { + Email string `json:"email" url:"email,key"` // unique email address of account + ID string `json:"id" url:"id,key"` // unique identifier of an account + } `json:"user" url:"user,key"` // user that created the release + Version int `json:"version" url:"version,key"` // unique version assigned to the release +} type PipelineReleaseListResult []struct { AddonPlanNames []string `json:"addon_plan_names" url:"addon_plan_names,key"` // add-on plans installed on the app for this release App struct { ID string `json:"id" url:"id,key"` // unique identifier of app Name string `json:"name" url:"name,key"` // unique name of app } `json:"app" url:"app,key"` // app involved in the release - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created - Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app - Description string `json:"description" url:"description,key"` // description of changes in this release - ID string `json:"id" url:"id,key"` // unique identifier of release - OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. + Artifacts []struct { + ID string `json:"id" url:"id,key"` // unique identifier of slug + Type string `json:"type" url:"type,key"` // type of artifact + } `json:"artifacts" url:"artifacts,key"` // build artifacts for the release + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created + Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app + Description string `json:"description" url:"description,key"` // description of changes in this release + EligibleForRollback bool `json:"eligible_for_rollback" url:"eligible_for_rollback,key"` // indicates if this release is eligible for rollback + ID string `json:"id" url:"id,key"` // unique identifier of release + OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. // The stream is available as either `text/plain` or // `text/event-stream`. Clients should be prepared to handle disconnects // and can resume the stream by sending a `Range` header (for @@ -3534,11 +3764,16 @@ type Release struct { ID string `json:"id" url:"id,key"` // unique identifier of app Name string `json:"name" url:"name,key"` // unique name of app } `json:"app" url:"app,key"` // app involved in the release - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created - Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app - Description string `json:"description" url:"description,key"` // description of changes in this release - ID string `json:"id" url:"id,key"` // unique identifier of release - OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. + Artifacts []struct { + ID string `json:"id" url:"id,key"` // unique identifier of slug + Type string `json:"type" url:"type,key"` // type of artifact + } `json:"artifacts" url:"artifacts,key"` // build artifacts for the release + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when release was created + Current bool `json:"current" url:"current,key"` // indicates this release as being the current one for the app + Description string `json:"description" url:"description,key"` // description of changes in this release + EligibleForRollback bool `json:"eligible_for_rollback" url:"eligible_for_rollback,key"` // indicates if this release is eligible for rollback + ID string `json:"id" url:"id,key"` // unique identifier of release + OutputStreamURL *string `json:"output_stream_url" url:"output_stream_url,key"` // Release command output will be available from this URL as a stream. // The stream is available as either `text/plain` or // `text/event-stream`. Clients should be prepared to handle disconnects // and can resume the stream by sending a `Range` header (for @@ -3571,6 +3806,7 @@ func (s *Service) ReleaseList(ctx context.Context, appIdentity string, lr *ListR type ReleaseCreateOpts struct { Description *string `json:"description,omitempty" url:"description,omitempty,key"` // description of changes in this release + OciImage *string `json:"oci_image,omitempty" url:"oci_image,omitempty,key"` // unique identifier of the OCI image Slug string `json:"slug" url:"slug,key"` // unique identifier of slug } @@ -3902,6 +4138,11 @@ type Space struct { DataCIDR string `json:"data_cidr" url:"data_cidr,key"` // The RFC-1918 CIDR that the Private Space will use for the // Heroku-managed peering connection that's automatically created when // using Heroku Data add-ons. It must be between a /16 and a /20 + Generation struct { + ID string `json:"id" url:"id,key"` // unique identifier of the generation of the Heroku platform for this + // space + Name string `json:"name" url:"name,key"` // unique name of the generation of the Heroku platform for this space + } `json:"generation" url:"generation,key"` // Generation of the Heroku platform for this space ID string `json:"id" url:"id,key"` // unique identifier of space Name string `json:"name" url:"name,key"` // unique name of space Organization struct { @@ -3955,6 +4196,7 @@ type SpaceCreateOpts struct { DataCIDR *string `json:"data_cidr,omitempty" url:"data_cidr,omitempty,key"` // The RFC-1918 CIDR that the Private Space will use for the // Heroku-managed peering connection that's automatically created when // using Heroku Data add-ons. It must be between a /16 and a /20 + Generation *string `json:"generation,omitempty" url:"generation,omitempty,key"` // unique name of the generation of the Heroku platform for this space LogDrainURL *string `json:"log_drain_url,omitempty" url:"log_drain_url,omitempty,key"` // URL to which all apps will drain logs. Only settable during space // creation and enables direct logging. Must use HTTPS. Name string `json:"name" url:"name,key"` // unique name of space @@ -4070,6 +4312,11 @@ type SpaceTransferTransferResult struct { DataCIDR string `json:"data_cidr" url:"data_cidr,key"` // The RFC-1918 CIDR that the Private Space will use for the // Heroku-managed peering connection that's automatically created when // using Heroku Data add-ons. It must be between a /16 and a /20 + Generation struct { + ID string `json:"id" url:"id,key"` // unique identifier of the generation of the Heroku platform for this + // space + Name string `json:"name" url:"name,key"` // unique name of the generation of the Heroku platform for this space + } `json:"generation" url:"generation,key"` // Generation of the Heroku platform for this space ID string `json:"id" url:"id,key"` // unique identifier of space Name string `json:"name" url:"name,key"` // unique name of space Organization struct { @@ -4094,82 +4341,6 @@ func (s *Service) SpaceTransferTransfer(ctx context.Context, spaceIdentity strin return &spaceTransfer, s.Post(ctx, &spaceTransfer, fmt.Sprintf("/spaces/%v/transfer", spaceIdentity), o) } -// [SSL Endpoint](https://devcenter.heroku.com/articles/ssl-endpoint) is -// a public address serving custom SSL cert for HTTPS traffic to a -// Heroku app. Note that an app must have the `ssl:endpoint` add-on -// installed before it can provision an SSL Endpoint using these APIs. -type SSLEndpoint struct { - App struct { - ID string `json:"id" url:"id,key"` // unique identifier of app - Name string `json:"name" url:"name,key"` // unique name of app - } `json:"app" url:"app,key"` // application associated with this ssl-endpoint - CertificateChain string `json:"certificate_chain" url:"certificate_chain,key"` // raw contents of the public certificate chain (eg: .crt or .pem file) - CName string `json:"cname" url:"cname,key"` // canonical name record, the address to point a domain at - CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when endpoint was created - DisplayName *string `json:"display_name" url:"display_name,key"` // unique name for SSL endpoint - Domains []string `json:"domains" url:"domains,key"` // domains associated with this endpoint - ID string `json:"id" url:"id,key"` // unique identifier of this SSL endpoint - Name string `json:"name" url:"name,key"` // unique name for SSL endpoint - SSLCert struct { - IsCaSigned bool `json:"ca_signed?" url:"ca_signed?,key"` - CertDomains []interface{} `json:"cert_domains" url:"cert_domains,key"` - ExpiresAt time.Time `json:"expires_at" url:"expires_at,key"` - ID string `json:"id" url:"id,key"` // unique identifier of this SSL certificate - Issuer string `json:"issuer" url:"issuer,key"` - IsSelfSigned bool `json:"self_signed?" url:"self_signed?,key"` - StartsAt time.Time `json:"starts_at" url:"starts_at,key"` - Subject string `json:"subject" url:"subject,key"` - } `json:"ssl_cert" url:"ssl_cert,key"` // certificate provided by this endpoint - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when endpoint was updated -} -type SSLEndpointCreateOpts struct { - CertificateChain string `json:"certificate_chain" url:"certificate_chain,key"` // raw contents of the public certificate chain (eg: .crt or .pem file) - Preprocess *bool `json:"preprocess,omitempty" url:"preprocess,omitempty,key"` // allow Heroku to modify an uploaded public certificate chain if deemed - // advantageous by adding missing intermediaries, stripping unnecessary - // ones, etc. - PrivateKey string `json:"private_key" url:"private_key,key"` // contents of the private key (eg .key file) -} - -// Create a new SSL endpoint. -func (s *Service) SSLEndpointCreate(ctx context.Context, appIdentity string, o SSLEndpointCreateOpts) (*SSLEndpoint, error) { - var sslEndpoint SSLEndpoint - return &sslEndpoint, s.Post(ctx, &sslEndpoint, fmt.Sprintf("/apps/%v/ssl-endpoints", appIdentity), o) -} - -// Delete existing SSL endpoint. -func (s *Service) SSLEndpointDelete(ctx context.Context, appIdentity string, sslEndpointIdentity string) (*SSLEndpoint, error) { - var sslEndpoint SSLEndpoint - return &sslEndpoint, s.Delete(ctx, &sslEndpoint, fmt.Sprintf("/apps/%v/ssl-endpoints/%v", appIdentity, sslEndpointIdentity)) -} - -// Info for existing SSL endpoint. -func (s *Service) SSLEndpointInfo(ctx context.Context, appIdentity string, sslEndpointIdentity string) (*SSLEndpoint, error) { - var sslEndpoint SSLEndpoint - return &sslEndpoint, s.Get(ctx, &sslEndpoint, fmt.Sprintf("/apps/%v/ssl-endpoints/%v", appIdentity, sslEndpointIdentity), nil, nil) -} - -type SSLEndpointListResult []SSLEndpoint - -// List existing SSL endpoints. -func (s *Service) SSLEndpointList(ctx context.Context, appIdentity string, lr *ListRange) (SSLEndpointListResult, error) { - var sslEndpoint SSLEndpointListResult - return sslEndpoint, s.Get(ctx, &sslEndpoint, fmt.Sprintf("/apps/%v/ssl-endpoints", appIdentity), nil, lr) -} - -type SSLEndpointUpdateOpts struct { - CertificateChain *string `json:"certificate_chain,omitempty" url:"certificate_chain,omitempty,key"` // raw contents of the public certificate chain (eg: .crt or .pem file) - Preprocess *bool `json:"preprocess,omitempty" url:"preprocess,omitempty,key"` // allow Heroku to modify an uploaded public certificate chain if deemed - // advantageous by adding missing intermediaries, stripping unnecessary - // ones, etc. - PrivateKey *string `json:"private_key,omitempty" url:"private_key,omitempty,key"` // contents of the private key (eg .key file) -} - -// Update an existing SSL endpoint. -func (s *Service) SSLEndpointUpdate(ctx context.Context, appIdentity string, sslEndpointIdentity string, o SSLEndpointUpdateOpts) (*SSLEndpoint, error) { - var sslEndpoint SSLEndpoint - return &sslEndpoint, s.Patch(ctx, &sslEndpoint, fmt.Sprintf("/apps/%v/ssl-endpoints/%v", appIdentity, sslEndpointIdentity), o) -} - // Stacks are the different application execution environments available // in the Heroku platform. type Stack struct { @@ -4195,6 +4366,14 @@ func (s *Service) StackList(ctx context.Context, lr *ListRange) (StackListResult return stack, s.Get(ctx, &stack, fmt.Sprintf("/stacks"), nil, lr) } +type StackListByAppResult []Stack + +// List available app stacks for an app. +func (s *Service) StackListByApp(ctx context.Context, appIdentity string, lr *ListRange) (StackListByAppResult, error) { + var stack StackListByAppResult + return stack, s.Get(ctx, &stack, fmt.Sprintf("/apps/%v/available-stacks", appIdentity), nil, lr) +} + // Teams allow you to manage access to a shared group of applications // and other resources. type Team struct { @@ -4325,10 +4504,11 @@ type TeamAddOnListForTeamResult []struct { ID string `json:"id" url:"id,key"` // unique identifier of this plan Name string `json:"name" url:"name,key"` // unique name of this plan } `json:"plan" url:"plan,key"` // identity of add-on plan - ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider - State string `json:"state" url:"state,key"` // state in the add-on's lifecycle - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated - WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) + ProviderID string `json:"provider_id" url:"provider_id,key"` // id of this add-on with its provider + ProvisionMessage string `json:"provision_message" url:"provision_message,key"` // A provision message + State string `json:"state" url:"state,key"` // state in the add-on's lifecycle + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when add-on was updated + WebURL *string `json:"web_url" url:"web_url,key"` // URL for logging into web interface of add-on (e.g. a dashboard) } // List add-ons used across all Team apps @@ -4377,7 +4557,7 @@ type TeamApp struct { Name string `json:"name" url:"name,key"` // unique name of team } `json:"team" url:"team,key"` // team that owns this app UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when app was updated - WebURL string `json:"web_url" url:"web_url,key"` // web URL of app + WebURL *string `json:"web_url" url:"web_url,key"` // web URL of app } type TeamAppCreateOpts struct { InternalRouting *bool `json:"internal_routing,omitempty" url:"internal_routing,omitempty,key"` // describes whether a Private Spaces app is externally routable or not @@ -4550,16 +4730,28 @@ type TeamDailyUsageInfoResult []TeamDailyUsage // Retrieves usage for an enterprise team for a range of days. Start and // end dates can be specified as query parameters using the date format -// YYYY-MM-DD. -// The team identifier can be found from the [team list +// YYYY-MM-DD. The team identifier can be found from the [team list // endpoint](https://devcenter.heroku.com/articles/platform-api-reference // #team-list). -// func (s *Service) TeamDailyUsageInfo(ctx context.Context, teamID string, o TeamDailyUsageInfoOpts, lr *ListRange) (TeamDailyUsageInfoResult, error) { var teamDailyUsage TeamDailyUsageInfoResult return teamDailyUsage, s.Get(ctx, &teamDailyUsage, fmt.Sprintf("/teams/%v/usage/daily", teamID), o, lr) } +// A Heroku team becomes delinquent due to non-payment. We [suspend and +// delete](https://help.heroku.com/EREVRILX/what-happens-if-i-have-unpaid +// -heroku-invoices) delinquent teams if their invoices remain unpaid. +type TeamDelinquency struct { + ScheduledDeletionTime *time.Time `json:"scheduled_deletion_time" url:"scheduled_deletion_time,key"` // scheduled time of when we will delete your team due to delinquency + ScheduledSuspensionTime *time.Time `json:"scheduled_suspension_time" url:"scheduled_suspension_time,key"` // scheduled time of when we will suspend your team due to delinquency +} + +// Team delinquency information. +func (s *Service) TeamDelinquencyInfo(ctx context.Context, teamIdentity string) (*TeamDelinquency, error) { + var teamDelinquency TeamDelinquency + return &teamDelinquency, s.Get(ctx, &teamDelinquency, fmt.Sprintf("/teams/%v/delinquency", teamIdentity), nil, nil) +} + // A team feature represents a feature enabled on a team account. type TeamFeature struct { CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when team feature was created @@ -4655,11 +4847,10 @@ type TeamInvitationAcceptResult struct { } `json:"owner" url:"owner,key"` // entity that owns this identity provider Redacted bool `json:"redacted" url:"redacted,key"` // whether the identity_provider information is redacted or not } `json:"identity_provider" url:"identity_provider,key"` // Identity Provider information the member is federated with - Role *string `json:"role" url:"role,key"` // role in the team - TwoFactorAuthentication bool `json:"two_factor_authentication" url:"two_factor_authentication,key"` // whether the Enterprise team member has two factor authentication - // enabled - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when the membership record was updated - User struct { + Role *string `json:"role" url:"role,key"` // role in the team + TwoFactorAuthentication bool `json:"two_factor_authentication" url:"two_factor_authentication,key"` // whether the team member has two factor authentication enabled + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when the membership record was updated + User struct { Email string `json:"email" url:"email,key"` // unique email address of account ID string `json:"id" url:"id,key"` // unique identifier of an account Name *string `json:"name" url:"name,key"` // full name of the account owner @@ -4723,11 +4914,10 @@ type TeamMember struct { } `json:"owner" url:"owner,key"` // entity that owns this identity provider Redacted bool `json:"redacted" url:"redacted,key"` // whether the identity_provider information is redacted or not } `json:"identity_provider" url:"identity_provider,key"` // Identity Provider information the member is federated with - Role *string `json:"role" url:"role,key"` // role in the team - TwoFactorAuthentication bool `json:"two_factor_authentication" url:"two_factor_authentication,key"` // whether the Enterprise team member has two factor authentication - // enabled - UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when the membership record was updated - User struct { + Role *string `json:"role" url:"role,key"` // role in the team + TwoFactorAuthentication bool `json:"two_factor_authentication" url:"two_factor_authentication,key"` // whether the team member has two factor authentication enabled + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when the membership record was updated + User struct { Email string `json:"email" url:"email,key"` // unique email address of account ID string `json:"id" url:"id,key"` // unique identifier of an account Name *string `json:"name" url:"name,key"` // full name of the account owner @@ -4821,7 +5011,7 @@ type TeamMemberListByMemberResult []struct { Name string `json:"name" url:"name,key"` // unique name of team } `json:"team" url:"team,key"` // team that owns this app UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when app was updated - WebURL string `json:"web_url" url:"web_url,key"` // web URL of app + WebURL *string `json:"web_url" url:"web_url,key"` // web URL of app } // List the apps of a team member. @@ -4840,7 +5030,7 @@ type TeamMonthlyUsage struct { Dynos float64 `json:"dynos" url:"dynos,key"` // dynos used Partner float64 `json:"partner" url:"partner,key"` // total add-on credits used for third party add-ons } `json:"apps" url:"apps,key"` // app usage in the team - Connect float64 `json:"connect" url:"connect,key"` // average connect rows synced + Connect float64 `json:"connect" url:"connect,key"` // max connect rows synced Data float64 `json:"data" url:"data,key"` // total add-on credits used for first party add-ons Dynos float64 `json:"dynos" url:"dynos,key"` // dynos used ID string `json:"id" url:"id,key"` // team identifier @@ -4861,7 +5051,6 @@ type TeamMonthlyUsageInfoResult []TeamMonthlyUsage // The team identifier can be found from the [team list // endpoint](https://devcenter.heroku.com/articles/platform-api-reference // #team-list). -// func (s *Service) TeamMonthlyUsageInfo(ctx context.Context, teamID string, o TeamMonthlyUsageInfoOpts, lr *ListRange) (TeamMonthlyUsageInfoResult, error) { var teamMonthlyUsage TeamMonthlyUsageInfoResult return teamMonthlyUsage, s.Get(ctx, &teamMonthlyUsage, fmt.Sprintf("/teams/%v/usage/monthly", teamID), o, lr) @@ -4901,6 +5090,11 @@ type TeamSpaceListResult []struct { DataCIDR string `json:"data_cidr" url:"data_cidr,key"` // The RFC-1918 CIDR that the Private Space will use for the // Heroku-managed peering connection that's automatically created when // using Heroku Data add-ons. It must be between a /16 and a /20 + Generation struct { + ID string `json:"id" url:"id,key"` // unique identifier of the generation of the Heroku platform for this + // space + Name string `json:"name" url:"name,key"` // unique name of the generation of the Heroku platform for this space + } `json:"generation" url:"generation,key"` // Generation of the Heroku platform for this space ID string `json:"id" url:"id,key"` // unique identifier of space Name string `json:"name" url:"name,key"` // unique name of space Organization struct { @@ -4925,6 +5119,85 @@ func (s *Service) TeamSpaceList(ctx context.Context, teamIdentity string, lr *Li return teamSpace, s.Get(ctx, &teamSpace, fmt.Sprintf("/teams/%v/spaces", teamIdentity), nil, lr) } +// A telemetry drain forwards OpenTelemetry traces, metrics, and logs to +// your own consumer. For Fir-generation apps only. +type TelemetryDrain struct { + CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when the telemetry drain was created + Exporter struct { + Endpoint string `json:"endpoint" url:"endpoint,key"` // URI of your OpenTelemetry consumer + Headers map[string]string `json:"headers" url:"headers,key"` // JSON headers to send to your OpenTelemetry consumer + Type string `json:"type" url:"type,key"` // the transport type to be used for your OpenTelemetry consumer + } `json:"exporter" url:"exporter,key"` // OpenTelemetry exporter configuration + ID string `json:"id" url:"id,key"` // unique identifier of telemetry drain + Owner struct { + ID string `json:"id" url:"id,key"` // unique identifier of owner + Type string `json:"type" url:"type,key"` // type of owner + } `json:"owner" url:"owner,key"` // entity that owns this telemetry drain + Signals []string `json:"signals" url:"signals,key"` // OpenTelemetry signals to send to telemetry drain + UpdatedAt time.Time `json:"updated_at" url:"updated_at,key"` // when telemetry drain was last updated +} +type TelemetryDrainCreateOpts struct { + Exporter struct { + Endpoint string `json:"endpoint" url:"endpoint,key"` // URI of your OpenTelemetry consumer + Headers map[string]string `json:"headers,omitempty" url:"headers,omitempty,key"` // JSON headers to send to your OpenTelemetry consumer + Type string `json:"type" url:"type,key"` // the transport type to be used for your OpenTelemetry consumer + } `json:"exporter" url:"exporter,key"` // OpenTelemetry exporter configuration + Owner struct { + ID string `json:"id" url:"id,key"` // unique identifier of owner + Type string `json:"type" url:"type,key"` // type of owner + } `json:"owner" url:"owner,key"` // entity that owns this telemetry drain + Signals []string `json:"signals" url:"signals,key"` // OpenTelemetry signals to send to telemetry drain +} + +// Create a telemetry drain. +func (s *Service) TelemetryDrainCreate(ctx context.Context, o TelemetryDrainCreateOpts) (*TelemetryDrain, error) { + var telemetryDrain TelemetryDrain + return &telemetryDrain, s.Post(ctx, &telemetryDrain, fmt.Sprintf("/telemetry-drains"), o) +} + +type TelemetryDrainListByAppResult []TelemetryDrain + +// List telemetry drains for an app. +func (s *Service) TelemetryDrainListByApp(ctx context.Context, appIdentity string, lr *ListRange) (TelemetryDrainListByAppResult, error) { + var telemetryDrain TelemetryDrainListByAppResult + return telemetryDrain, s.Get(ctx, &telemetryDrain, fmt.Sprintf("/apps/%v/telemetry-drains", appIdentity), nil, lr) +} + +type TelemetryDrainListBySpaceResult []TelemetryDrain + +// List telemetry drains for a space. +func (s *Service) TelemetryDrainListBySpace(ctx context.Context, spaceIdentity string, lr *ListRange) (TelemetryDrainListBySpaceResult, error) { + var telemetryDrain TelemetryDrainListBySpaceResult + return telemetryDrain, s.Get(ctx, &telemetryDrain, fmt.Sprintf("/spaces/%v/telemetry-drains", spaceIdentity), nil, lr) +} + +type TelemetryDrainUpdateOpts struct { + Exporter *struct { + Endpoint string `json:"endpoint" url:"endpoint,key"` // URI of your OpenTelemetry consumer + Headers map[string]string `json:"headers,omitempty" url:"headers,omitempty,key"` // JSON headers to send to your OpenTelemetry consumer + Type string `json:"type" url:"type,key"` // the transport type to be used for your OpenTelemetry consumer + } `json:"exporter,omitempty" url:"exporter,omitempty,key"` // OpenTelemetry exporter configuration + Signals []*string `json:"signals,omitempty" url:"signals,omitempty,key"` // OpenTelemetry signals to send to telemetry drain +} + +// Update a telemetry drain. +func (s *Service) TelemetryDrainUpdate(ctx context.Context, telemetryDrainIdentity string, o TelemetryDrainUpdateOpts) (*TelemetryDrain, error) { + var telemetryDrain TelemetryDrain + return &telemetryDrain, s.Patch(ctx, &telemetryDrain, fmt.Sprintf("/telemetry-drains/%v", telemetryDrainIdentity), o) +} + +// Delete a telemetry drain. +func (s *Service) TelemetryDrainDelete(ctx context.Context, telemetryDrainIdentity string) (*TelemetryDrain, error) { + var telemetryDrain TelemetryDrain + return &telemetryDrain, s.Delete(ctx, &telemetryDrain, fmt.Sprintf("/telemetry-drains/%v", telemetryDrainIdentity)) +} + +// Info for a telemetry drain. +func (s *Service) TelemetryDrainInfo(ctx context.Context, telemetryDrainIdentity string) (*TelemetryDrain, error) { + var telemetryDrain TelemetryDrain + return &telemetryDrain, s.Get(ctx, &telemetryDrain, fmt.Sprintf("/telemetry-drains/%v", telemetryDrainIdentity), nil, nil) +} + // A single test case belonging to a test run type TestCase struct { CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when test case was created @@ -4990,7 +5263,7 @@ type TestRun struct { CreatedAt time.Time `json:"created_at" url:"created_at,key"` // when test run was created Debug bool `json:"debug" url:"debug,key"` // whether the test run was started for interactive debugging Dyno *struct { - Size string `json:"size" url:"size,key"` // dyno size (default: "standard-1X") + Size string `json:"size" url:"size,key"` // dyno size } `json:"dyno" url:"dyno,key"` // the type of dynos used for this test-run ID string `json:"id" url:"id,key"` // unique identifier of a test run Message *string `json:"message" url:"message,key"` // human friendly message indicating reason for an error diff --git a/vendor/github.com/heroku/heroku-go/v5/round_trip_with_retry_backoff.go b/vendor/github.com/heroku/heroku-go/v6/round_trip_with_retry_backoff.go similarity index 99% rename from vendor/github.com/heroku/heroku-go/v5/round_trip_with_retry_backoff.go rename to vendor/github.com/heroku/heroku-go/v6/round_trip_with_retry_backoff.go index 3fa5b554b..102f146f5 100644 --- a/vendor/github.com/heroku/heroku-go/v5/round_trip_with_retry_backoff.go +++ b/vendor/github.com/heroku/heroku-go/v6/round_trip_with_retry_backoff.go @@ -1,4 +1,4 @@ -package v5 +package v6 import ( "fmt" diff --git a/vendor/github.com/heroku/heroku-go/v5/schema.json b/vendor/github.com/heroku/heroku-go/v6/schema.json similarity index 90% rename from vendor/github.com/heroku/heroku-go/v5/schema.json rename to vendor/github.com/heroku/heroku-go/v6/schema.json index 8c71b4d02..2293a601b 100644 --- a/vendor/github.com/heroku/heroku-go/v5/schema.json +++ b/vendor/github.com/heroku/heroku-go/v6/schema.json @@ -4,6 +4,58 @@ "object" ], "definitions": { + "account-delinquency": { + "description": "A Heroku account becomes delinquent due to non-payment. We [suspend and delete](https://help.heroku.com/EREVRILX/what-happens-if-i-have-unpaid-heroku-invoices) delinquent accounts if their invoices remain unpaid.", + "$schema": "http://json-schema.org/draft-04/hyper-schema", + "stability": "development", + "strictProperties": true, + "title": "Heroku Platform API - Account Delinquency", + "type": [ + "object" + ], + "definitions": { + "scheduled_suspension_time": { + "description": "scheduled time of when we will suspend your account due to delinquency", + "example": "2024-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string", + "null" + ] + }, + "scheduled_deletion_time": { + "description": "scheduled time of when we will delete your account due to delinquency", + "example": "2024-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string", + "null" + ] + } + }, + "links": [ + { + "description": "Account delinquency information.", + "href": "/account/delinquency", + "method": "GET", + "rel": "self", + "targetSchema": { + "$ref": "#/definitions/account-delinquency" + }, + "title": "Info" + } + ], + "properties": { + "scheduled_suspension_time": { + "$ref": "#/definitions/account-delinquency/definitions/scheduled_suspension_time" + }, + "scheduled_deletion_time": { + "$ref": "#/definitions/account-delinquency/definitions/scheduled_deletion_time" + } + } + }, "account-feature": { "description": "An account feature represents a Heroku labs capability that can be enabled or disabled for an account on Heroku.", "$schema": "http://json-schema.org/draft-04/hyper-schema", @@ -408,7 +460,7 @@ "title": "Update" }, { - "description": "Delete account. Note that this action cannot be undone.", + "description": "Delete account. Note that this action cannot be undone. Note: This endpoint requires the HTTP_HEROKU_PASSWORD or HTTP_HEROKU_PASSWORD_BASE64 header be set correctly for the user account.", "href": "/account", "method": "DELETE", "rel": "destroy", @@ -454,7 +506,7 @@ "title": "Update By User" }, { - "description": "Delete account. Note that this action cannot be undone.", + "description": "Delete account. Note that this action cannot be undone. Note: This endpoint requires the HTTP_HEROKU_PASSWORD or HTTP_HEROKU_PASSWORD_BASE64 header be set correctly for the user account.", "href": "/users/{(%23%2Fdefinitions%2Faccount%2Fdefinitions%2Fidentity)}", "method": "DELETE", "rel": "destroy", @@ -592,14 +644,13 @@ "type": [ "object" ], - "definitions": { - }, + "definitions": {}, "links": [ { "description": "Mark an add-on as provisioned for use.", "href": "/addons/{(%23%2Fdefinitions%2Fadd-on%2Fdefinitions%2Fidentity)}/actions/provision", "method": "POST", - "rel": "create", + "rel": "update", "targetSchema": { "$ref": "#/definitions/add-on" }, @@ -609,15 +660,14 @@ "description": "Mark an add-on as deprovisioned.", "href": "/addons/{(%23%2Fdefinitions%2Fadd-on%2Fdefinitions%2Fidentity)}/actions/deprovision", "method": "POST", - "rel": "create", + "rel": "update", "targetSchema": { "$ref": "#/definitions/add-on" }, "title": "Deprovision" } ], - "properties": { - } + "properties": {} }, "add-on-attachment": { "description": "An add-on attachment represents a connection between an app and an add-on that it has been given access to.", @@ -1295,6 +1345,27 @@ "type": [ "string" ] + }, + "supported_generations": { + "description": "generations supported by this add-on", + "readonly": true, + "type": [ + "array" + ], + "items": { + "type": [ + "object" + ], + "properties": { + "name": { + "$ref": "#/definitions/generation/definitions/name", + "example": "cedar" + }, + "id": { + "$ref": "#/definitions/generation/definitions/id" + } + } + } } }, "links": [ @@ -1351,6 +1422,9 @@ }, "updated_at": { "$ref": "#/definitions/add-on-service/definitions/updated_at" + }, + "supported_generations": { + "$ref": "#/definitions/add-on-service/definitions/supported_generations" } } }, @@ -1622,8 +1696,24 @@ "description": "Add-ons represent add-ons that have been provisioned and attached to one or more apps.", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "production", - "strictProperties": true, "title": "Heroku Platform API - Add-on", + "additionalProperties": false, + "required": [ + "actions", + "addon_service", + "billing_entity", + "app", + "billed_price", + "config_vars", + "created_at", + "id", + "name", + "plan", + "provider_id", + "state", + "updated_at", + "web_url" + ], "type": [ "object" ], @@ -1788,6 +1878,63 @@ "null", "string" ] + }, + "addon_service": { + "description": "identity of add-on service", + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/add-on-service/definitions/id" + }, + { + "$ref": "#/definitions/add-on-service/definitions/name" + } + ] + }, + "properties": { + "id": { + "$ref": "#/definitions/add-on-service/definitions/id" + }, + "name": { + "$ref": "#/definitions/add-on-service/definitions/name" + } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "plan": { + "description": "identity of add-on plan", + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/plan/definitions/id" + }, + { + "$ref": "#/definitions/plan/definitions/name" + } + ] + }, + "properties": { + "id": { + "$ref": "#/definitions/plan/definitions/id" + }, + "name": { + "$ref": "#/definitions/plan/definitions/name" + } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "provision_message": { + "description": "A provision message", + "readOnly": true, + "type": [ + "string" + ] } }, "links": [ @@ -1918,6 +2065,9 @@ "object" ] }, + "targetSchema": { + "$ref": "#/definitions/add-on" + }, "title": "Update" }, { @@ -1990,19 +2140,7 @@ "$ref": "#/definitions/add-on/definitions/actions" }, "addon_service": { - "description": "identity of add-on service", - "properties": { - "id": { - "$ref": "#/definitions/add-on-service/definitions/id" - }, - "name": { - "$ref": "#/definitions/add-on-service/definitions/name" - } - }, - "strictProperties": true, - "type": [ - "object" - ] + "$ref": "#/definitions/add-on/definitions/addon_service" }, "billing_entity": { "description": "billing entity associated with this add-on", @@ -2089,23 +2227,14 @@ "$ref": "#/definitions/add-on/definitions/name" }, "plan": { - "description": "identity of add-on plan", - "properties": { - "id": { - "$ref": "#/definitions/plan/definitions/id" - }, - "name": { - "$ref": "#/definitions/plan/definitions/name" - } - }, - "strictProperties": true, - "type": [ - "object" - ] + "$ref": "#/definitions/add-on/definitions/plan" }, "provider_id": { "$ref": "#/definitions/add-on/definitions/provider_id" }, + "provision_message": { + "$ref": "#/definitions/add-on/definitions/provision_message" + }, "state": { "$ref": "#/definitions/add-on/definitions/state" }, @@ -2455,63 +2584,6 @@ } } }, - "app-formation-set": { - "description": "App formation set describes the combination of process types with their quantities and sizes as well as application process tier", - "$schema": "http://json-schema.org/draft-04/hyper-schema", - "stability": "development", - "strictProperties": true, - "title": "Heroku Platform API - Application Formation Set", - "type": [ - "object" - ], - "properties": { - "description": { - "description": "a string representation of the formation set", - "example": "web@2:Standard-2X worker@3:Performance-M", - "readOnly": true, - "type": [ - "string" - ] - }, - "process_tier": { - "description": "application process tier", - "enum": [ - "production", - "free", - "hobby", - "private" - ], - "example": "production", - "readOnly": true, - "type": [ - "string" - ] - }, - "app": { - "description": "app being described by the formation-set", - "properties": { - "name": { - "$ref": "#/definitions/app/definitions/name" - }, - "id": { - "$ref": "#/definitions/app/definitions/id" - } - }, - "type": [ - "object" - ] - }, - "updated_at": { - "description": "last time fomation-set was updated", - "example": "2012-01-01T12:00:00Z", - "format": "date-time", - "readOnly": true, - "type": [ - "string" - ] - } - } - }, "app-setup": { "description": "An app setup represents an app on Heroku that is setup using an environment, addons, and scripts described in an app.json manifest file.", "$schema": "http://json-schema.org/draft-04/hyper-schema", @@ -3749,6 +3821,32 @@ "string" ] }, + "generation": { + "description": "Generation of the Heroku platform for this app", + "readOnly": true, + "type": [ + "object" + ], + "properties": { + "id": { + "description": "unique identifier of the generation of the Heroku platform for this app", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "name": { + "description": "unique name of the generation of the Heroku platform for this app", + "example": "cedar", + "readOnly": true, + "type": [ + "string" + ] + } + } + }, "git_url": { "description": "git repo URL of app", "example": "https://git.heroku.com/example.git", @@ -3839,9 +3937,10 @@ "description": "web URL of app", "example": "https://example.herokuapp.com/", "format": "uri", - "pattern": "^https?://[a-z][a-z0-9-]{3,30}\\.herokuapp\\.com/$", + "pattern": "^https?://[a-z][a-z0-9-]{3,43}\\.herokuapp\\.com/$", "readOnly": true, "type": [ + "null", "string" ] }, @@ -3871,6 +3970,15 @@ }, "stack": { "$ref": "#/definitions/stack/definitions/identity" + }, + "feature_flags": { + "description": "unique name of app feature", + "type": [ + "array" + ], + "items": { + "$ref": "#/definitions/app-feature/definitions/name" + } } }, "type": [ @@ -4027,6 +4135,9 @@ "created_at": { "$ref": "#/definitions/app/definitions/created_at" }, + "generation": { + "$ref": "#/definitions/app/definitions/generation" + }, "git_url": { "$ref": "#/definitions/app/definitions/git_url" }, @@ -4482,16 +4593,24 @@ }, "build": { "$schema": "http://json-schema.org/draft-04/hyper-schema", - "description": "A build represents the process of transforming a code tarball into a slug", + "description": "A build represents the process of transforming a code tarball into build artifacts", "title": "Heroku Build API - Build", "stability": "production", - "strictProperties": true, + "strictProperties": false, + "required": [ + "created_at", + "id", + "source_blob", + "status", + "updated_at", + "user" + ], "type": [ "object" ], "definitions": { "buildpacks": { - "description": "buildpacks executed for this build, in order", + "description": "buildpacks executed for this build, in order (only applicable to Cedar-generation apps)", "type": [ "array", "null" @@ -4608,6 +4727,15 @@ "string", "null" ] + }, + "version_description": { + "description": "Version description of the gzipped tarball.", + "example": "* Fake User: Change session key", + "readOnly": true, + "type": [ + "string", + "null" + ] } }, "strictProperties": true, @@ -4617,7 +4745,7 @@ }, "stack": { "description": "stack of build", - "example": "heroku-16", + "example": "heroku-22", "readOnly": true, "type": [ "string" @@ -4708,6 +4836,16 @@ "method": "DELETE", "rel": "empty", "title": "Delete cache" + }, + { + "description": "Cancel running build.", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/builds/{(%23%2Fdefinitions%2Fbuild%2Fdefinitions%2Fidentity)}", + "method": "DELETE", + "rel": "self", + "targetSchema": { + "$ref": "#/definitions/build" + }, + "title": "Cancel" } ], "properties": { @@ -4742,7 +4880,7 @@ "$ref": "#/definitions/build/definitions/release" }, "slug": { - "description": "slug created by this build", + "description": "slug created by this build (only applicable for Cedar-generation apps)", "properties": { "id": { "$ref": "#/definitions/slug/definitions/id" @@ -5607,6 +5745,14 @@ "object" ], "definitions": { + "architecture": { + "description": "CPU architecture of this dyno size", + "example": "amd64", + "readOnly": true, + "type": [ + "string" + ] + }, "compute": { "description": "minimum vCPUs, non-dedicated may get more depending on load", "example": 1, @@ -5623,18 +5769,44 @@ "boolean" ] }, - "id": { - "description": "unique identifier of this dyno size", - "example": "01234567-89ab-cdef-0123-456789abcdef", - "format": "uuid", + "generation": { + "description": "Generation of the Heroku platform for this dyno size", "readOnly": true, "type": [ - "string" - ] - }, - "identity": { - "anyOf": [ - { + "object" + ], + "properties": { + "id": { + "description": "unique identifier of the generation of the Heroku platform for this dyno size", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "name": { + "description": "unique name of the generation of the Heroku platform for this dyno size", + "example": "cedar", + "readOnly": true, + "type": [ + "string" + ] + } + } + }, + "id": { + "description": "unique identifier of the dyno size", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "identity": { + "anyOf": [ + { "$ref": "#/definitions/dyno-size/definitions/id" }, { @@ -5651,8 +5823,8 @@ ] }, "name": { - "description": "the name of this dyno-size", - "example": "free", + "description": "name of the dyno size", + "example": "eco", "readOnly": true, "type": [ "string" @@ -5684,12 +5856,12 @@ } } }, - "dyno_units": { - "description": "unit of consumption for Heroku Enterprise customers", - "example": 0, + "precise_dyno_units": { + "description": "unit of consumption for Heroku Enterprise customers to 2 decimal places", + "example": 0.28, "readOnly": true, "type": [ - "integer" + "number" ] }, "private_space_only": { @@ -5726,9 +5898,24 @@ ] }, "title": "List" + }, + { + "description": "List available dyno sizes for an app", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/available-dyno-sizes", + "method": "GET", + "rel": "available-app-dynos", + "targetSchema": { + "items": { + "$ref": "#/definitions/dyno-size" + } + }, + "title": "List App Dyno Sizes" } ], "properties": { + "architecture": { + "$ref": "#/definitions/dyno-size/definitions/architecture" + }, "compute": { "$ref": "#/definitions/dyno-size/definitions/compute" }, @@ -5738,8 +5925,11 @@ "dedicated": { "$ref": "#/definitions/dyno-size/definitions/dedicated" }, - "dyno_units": { - "$ref": "#/definitions/dyno-size/definitions/dyno_units" + "precise_dyno_units": { + "$ref": "#/definitions/dyno-size/definitions/precise_dyno_units" + }, + "generation": { + "$ref": "#/definitions/dyno-size/definitions/generation" }, "id": { "$ref": "#/definitions/dyno-size/definitions/id" @@ -5846,6 +6036,14 @@ "string" ] }, + "formation_type": { + "description": "the formation type of this process on this dyno", + "example": "run", + "readOnly": true, + "type": [ + "string" + ] + }, "force_no_tty": { "description": "force an attached one-off dyno to not run in a tty", "example": null, @@ -5856,7 +6054,7 @@ ] }, "size": { - "description": "dyno size (default: \"standard-1X\")", + "description": "dyno size", "example": "standard-1X", "readOnly": false, "type": [ @@ -5952,6 +6150,19 @@ }, "title": "Restart" }, + { + "description": "Restart dynos of a given formation type.", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/formations/{(%23%2Fdefinitions%2Fdyno%2Fdefinitions%2Fformation_type)}", + "method": "DELETE", + "rel": "empty", + "targetSchema": { + "additionalProperties": false, + "type": [ + "object" + ] + }, + "title": "Restart formation" + }, { "description": "Restart all dynos.", "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/dynos", @@ -5978,6 +6189,19 @@ }, "title": "Stop" }, + { + "description": "Stop dynos of a given formation type.", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/formations/{(%23%2Fdefinitions%2Fdyno%2Fdefinitions%2Fformation_type)}/actions/stop", + "method": "POST", + "rel": "empty", + "targetSchema": { + "additionalProperties": false, + "type": [ + "object" + ] + }, + "title": "Stop formation" + }, { "description": "Info for existing dyno.", "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/dynos/{(%23%2Fdefinitions%2Fdyno%2Fdefinitions%2Fidentity)}", @@ -6160,7 +6384,7 @@ }, "links": [ { - "description": "Retrieves usage for an enterprise account for a range of days. Start and end dates can be specified as query parameters using the date format YYYY-MM-DD.\nThe enterprise account identifier can be found from the [enterprise account list](https://devcenter.heroku.com/articles/platform-api-reference#enterprise-account-list).\n", + "description": "Retrieves usage for an enterprise account for a range of days. Start and end dates can be specified as query parameters using the date format YYYY-MM-DD. The enterprise account identifier can be found from the [enterprise account list](https://devcenter.heroku.com/articles/platform-api-reference#enterprise-account-list).\n", "href": "/enterprise-accounts/{(%23%2Fdefinitions%2Fenterprise-account%2Fdefinitions%2Fid)}/usage/daily", "method": "GET", "rel": "instances", @@ -6533,7 +6757,7 @@ ] }, "connect": { - "description": "average connect rows synced", + "description": "max connect rows synced", "example": 15000, "readOnly": true, "type": [ @@ -6619,7 +6843,7 @@ }, "links": [ { - "description": "Retrieves usage for an enterprise account for a range of months. Start and end dates can be specified as query parameters using the date format YYYY-MM. If no end date is specified, one month of usage is returned.\nThe enterprise account identifier can be found from the [enterprise account list](https://devcenter.heroku.com/articles/platform-api-reference#enterprise-account-list).\n", + "description": "Retrieves usage for an enterprise account for a range of months. Start and end dates can be specified as query parameters using the date format YYYY-MM. If no end date is specified, one month of usage is returned. The enterprise account identifier can be found from the [enterprise account list](https://devcenter.heroku.com/articles/platform-api-reference#enterprise-account-list).\n", "href": "/enterprise-accounts/{(%23%2Fdefinitions%2Fenterprise-account%2Fdefinitions%2Fid)}/usage/monthly", "method": "GET", "rel": "instances", @@ -6758,6 +6982,9 @@ "anyOf": [ { "$ref": "#/definitions/enterprise-account/definitions/id" + }, + { + "$ref": "#/definitions/enterprise-account/definitions/name" } ] }, @@ -6817,6 +7044,14 @@ "type": [ "boolean" ] + }, + "partner_benefits": { + "description": "whether the enterprise account is part of the Salesforce Partner Program", + "example": false, + "readOnly": true, + "type": [ + "boolean" + ] } }, "links": [ @@ -6840,6 +7075,9 @@ "href": "/enterprise-accounts/{(%23%2Fdefinitions%2Fenterprise-account%2Fdefinitions%2Fidentity)}", "method": "GET", "rel": "self", + "targetSchema": { + "$ref": "#/definitions/enterprise-account" + }, "title": "Info" }, { @@ -6881,6 +7119,9 @@ "trial": { "$ref": "#/definitions/enterprise-account/definitions/trial" }, + "partner_benefits": { + "$ref": "#/definitions/enterprise-account/definitions/partner_benefits" + }, "identity_provider": { "$ref": "#/definitions/enterprise-account/definitions/identity_provider" } @@ -6977,6 +7218,45 @@ "string" ] }, + "dyno_size": { + "description": "dyno size", + "example": { + "id": "01234567-89ab-cdef-0123-456789abcdef" + }, + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/dyno_size/definitions/id" + }, + { + "$ref": "#/definitions/dyno_size/definitions/name" + } + ] + }, + "properties": { + "id": { + "description": "unique identifier of the dyno size", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "name": { + "description": "name of the dyno size", + "example": "Standard-1X", + "readOnly": true, + "type": [ + "string" + ] + } + }, + "readOnly": false, + "type": [ + "object" + ] + }, "id": { "description": "unique identifier of this process type", "example": "01234567-89ab-cdef-0123-456789abcdef", @@ -7005,7 +7285,8 @@ ] }, "size": { - "description": "dyno size (default: \"standard-1X\")", + "deprecated": true, + "description": "deprecated, refer to 'dyno_size' instead", "example": "standard-1X", "readOnly": false, "type": [ @@ -7034,12 +7315,12 @@ "additionalProperties": false, "description": "Properties to update a process type", "properties": { + "dyno_size": { + "$ref": "#/definitions/formation/definitions/dyno_size" + }, "quantity": { "$ref": "#/definitions/formation/definitions/quantity" }, - "size": { - "$ref": "#/definitions/formation/definitions/size" - }, "type": { "$ref": "#/definitions/formation/definitions/type" } @@ -7093,7 +7374,7 @@ "items": { "$ref": "#/definitions/formation/definitions/update" }, - "description": "Array with formation updates. Each element must have \"type\", the id or name of the process type to be updated, and can optionally update its \"quantity\" or \"size\"." + "description": "Array with formation updates. Each element must have \"type\", the id or name of the process type to be updated, and can optionally update its \"quantity\" or \"dyno_size\"." } }, "required": [ @@ -7120,11 +7401,11 @@ "rel": "update", "schema": { "properties": { + "dyno_size": { + "$ref": "#/definitions/formation/definitions/dyno_size" + }, "quantity": { "$ref": "#/definitions/formation/definitions/quantity" - }, - "size": { - "$ref": "#/definitions/formation/definitions/size" } }, "type": [ @@ -7161,6 +7442,20 @@ "created_at": { "$ref": "#/definitions/formation/definitions/created_at" }, + "dyno_size": { + "description": "dyno size", + "properties": { + "id": { + "$ref": "#/definitions/dyno-size/definitions/id" + }, + "name": { + "$ref": "#/definitions/dyno-size/definitions/name" + } + }, + "type": [ + "object" + ] + }, "id": { "$ref": "#/definitions/formation/definitions/id" }, @@ -7178,8 +7473,121 @@ } } }, + "generation": { + "description": "A generation represents a version of the Heroku platform that includes the app execution environment, routing, telemetry, and build systems.", + "$schema": "http://json-schema.org/draft-04/hyper-schema", + "stability": "prototype", + "strictProperties": true, + "title": "Heroku Platform API - Generation", + "type": [ + "object" + ], + "definitions": { + "created_at": { + "description": "when generation was created", + "example": "2024-12-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" + ] + }, + "id": { + "description": "unique identifier of generation", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/generation/definitions/name" + }, + { + "$ref": "#/definitions/generation/definitions/id" + } + ] + }, + "name": { + "description": "unique name of generation", + "example": "fir", + "readOnly": true, + "type": [ + "string" + ] + }, + "updated_at": { + "description": "when generation was updated", + "example": "2024-12-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" + ] + } + }, + "links": [ + { + "description": "Info for generation.", + "href": "/generations/{(%23%2Fdefinitions%2Fstack%2Fdefinitions%2Fidentity)}", + "method": "GET", + "rel": "self", + "targetSchema": { + "$ref": "#/definitions/generation" + }, + "title": "Info" + }, + { + "description": "List available generations.", + "href": "/generations", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/generation" + }, + "type": [ + "array" + ] + }, + "title": "List" + }, + { + "description": "List available generations for a team.", + "href": "/teams/{(%23%2Fdefinitions%2Fteam%2Fdefinitions%2Fidentity)}/available-generations", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/generation" + }, + "type": [ + "array" + ] + }, + "title": "List by Team" + } + ], + "properties": { + "created_at": { + "$ref": "#/definitions/generation/definitions/created_at" + }, + "id": { + "$ref": "#/definitions/generation/definitions/id" + }, + "name": { + "$ref": "#/definitions/generation/definitions/name" + }, + "updated_at": { + "$ref": "#/definitions/generation/definitions/updated_at" + } + } + }, "identity-provider": { - "description": "Identity Providers represent the SAML configuration of an Enterprise Account or Team.", + "description": "Identity Providers represent the SAML configuration of teams or an Enterprise account", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "production", "strictProperties": true, @@ -7542,6 +7950,9 @@ "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/inbound-ruleset", "method": "PUT", "rel": "create", + "targetSchema": { + "$ref": "#/definitions/inbound-ruleset" + }, "schema": { "type": [ "object" @@ -7682,6 +8093,9 @@ "href": "/account/invoice-address", "method": "GET", "rel": "self", + "targetSchema": { + "$ref": "#/definitions/invoice-address" + }, "title": "info" }, { @@ -7720,6 +8134,9 @@ "type": [ "object" ] + }, + "targetSchema": { + "$ref": "#/definitions/invoice-address" } } ], @@ -8060,7 +8477,11 @@ "description": "add-on that created the drain", "example": { "id": "01234567-89ab-cdef-0123-456789abcdef", - "name": "singing-swiftly-1242" + "name": "singing-swiftly-1242", + "app": { + "id": "01234567-89ab-cdef-0123-456789abcdef", + "name": "example" + } }, "properties": { "id": { @@ -8068,6 +8489,21 @@ }, "name": { "$ref": "#/definitions/add-on/definitions/name" + }, + "app": { + "description": "billing application associated with this add-on", + "type": [ + "object" + ], + "properties": { + "id": { + "$ref": "#/definitions/app/definitions/id" + }, + "name": { + "$ref": "#/definitions/app/definitions/name" + } + }, + "strictProperties": true } }, "readOnly": true, @@ -8076,17 +8512,38 @@ "null" ] }, - "created_at": { - "description": "when log drain was created", - "example": "2012-01-01T12:00:00Z", - "format": "date-time", - "readOnly": true, - "type": [ - "string" - ] - }, - "id": { - "description": "unique identifier of this log drain", + "app": { + "description": "application that is attached to this drain", + "example": { + "id": "01234567-89ab-cdef-0123-456789abcdef", + "name": "example" + }, + "properties": { + "id": { + "$ref": "#/definitions/app/definitions/id" + }, + "name": { + "$ref": "#/definitions/app/definitions/name" + } + }, + "strictProperties": true, + "readOnly": true, + "type": [ + "object", + "null" + ] + }, + "created_at": { + "description": "when log drain was created", + "example": "2012-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" + ] + }, + "id": { + "description": "unique identifier of this log drain", "example": "01234567-89ab-cdef-0123-456789abcdef", "format": "uuid", "readOnly": true, @@ -8242,6 +8699,9 @@ "addon": { "$ref": "#/definitions/log-drain/definitions/addon" }, + "app": { + "$ref": "#/definitions/log-drain/definitions/app" + }, "created_at": { "$ref": "#/definitions/log-drain/definitions/created_at" }, @@ -8278,9 +8738,17 @@ "string" ] }, - "dyno": { - "description": "dyno to limit results to", - "example": "web.1", + "dyno_name": { + "description": "dyno name to limit results to", + "example": "'web.1' (Cedar-generation) or 'web-1234abcde-123ab' (Fir-generation)", + "readOnly": false, + "type": [ + "string" + ] + }, + "type": { + "description": "process type to limit results to", + "example": "web", "readOnly": false, "type": [ "string" @@ -8352,8 +8820,11 @@ "rel": "create", "schema": { "properties": { - "dyno": { - "$ref": "#/definitions/log-session/definitions/dyno" + "dyno_name": { + "$ref": "#/definitions/log-session/definitions/dyno_name" + }, + "type": { + "$ref": "#/definitions/log-session/definitions/type" }, "lines": { "$ref": "#/definitions/log-session/definitions/lines" @@ -8511,6 +8982,43 @@ }, "title": "Info" }, + { + "description": "Update an existing OAuth authorization.", + "href": "/oauth/authorizations/{(%23%2Fdefinitions%2Foauth-authorization%2Fdefinitions%2Fidentity)}", + "method": "PATCH", + "rel": "update", + "targetSchema": { + "$ref": "#/definitions/oauth-authorization" + }, + "schema": { + "properties": { + "description": { + "$ref": "#/definitions/oauth-authorization/definitions/description" + }, + "client": { + "type": [ + "object" + ], + "description": "identifier of the client that obtained this authorization", + "properties": { + "id": { + "$ref": "#/definitions/oauth-client/definitions/id" + }, + "secret": { + "$ref": "#/definitions/oauth-client/definitions/secret" + } + } + } + }, + "required": [ + "client" + ], + "type": [ + "object" + ] + }, + "title": "Update" + }, { "description": "List OAuth authorizations.", "href": "/oauth/authorizations", @@ -8577,6 +9085,9 @@ "created_at": { "$ref": "#/definitions/oauth-authorization/definitions/created_at" }, + "description": { + "$ref": "#/definitions/oauth-authorization/definitions/description" + }, "grant": { "description": "this authorization's grant", "properties": { @@ -8621,6 +9132,19 @@ "scope": { "$ref": "#/definitions/oauth-authorization/definitions/scope" }, + "session": { + "description": "this authorization's session", + "properties": { + "id": { + "$ref": "#/definitions/oauth-token/definitions/id" + } + }, + "strictProperties": true, + "type": [ + "null", + "object" + ] + }, "updated_at": { "$ref": "#/definitions/oauth-authorization/definitions/updated_at" }, @@ -8761,7 +9285,7 @@ "title": "Delete" }, { - "description": "Info for an OAuth client", + "description": "Info for an OAuth client. The output for unauthenticated requests excludes the `secret` parameter.", "href": "/oauth/clients/{(%23%2Fdefinitions%2Foauth-client%2Fdefinitions%2Fidentity)}", "method": "GET", "rel": "self", @@ -8891,10 +9415,8 @@ ] } }, - "links": [ - ], - "properties": { - } + "links": [], + "properties": {} }, "oauth-token": { "description": "OAuth tokens provide access for authorized clients to act on behalf of a Heroku user to automate, customize or extend their usage of the platform. For more information please refer to the [Heroku OAuth documentation](https://devcenter.heroku.com/articles/oauth)", @@ -8942,7 +9464,7 @@ }, "token": { "description": "contents of the token to be used for authorization", - "example": "01234567-89ab-cdef-0123-456789abcdef", + "example": "HRKU-01234567-89ab-cdef-0123-456789abcdef", "readOnly": true, "type": [ "string" @@ -9137,183 +9659,355 @@ } } }, - "outbound-ruleset": { - "description": "An outbound-ruleset is a collection of rules that specify what hosts Dynos are allowed to communicate with. ", + "oci-image": { + "description": "An OCI (Open Container Initiative) image is a standardized format for packaging and distributing containerized applications, ready to run on the platform.", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "prototype", "strictProperties": true, - "title": "Heroku Platform API - Outbound Ruleset", + "title": "Heroku Platform API - OCI Image", "type": [ "object" ], "definitions": { - "target": { - "description": "is the target destination in CIDR notation", - "example": "1.1.1.1/1", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$", + "id": { + "description": "unique identifier of the OCI image", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "digest": { + "description": "unique identifier representing the content of the OCI image", + "example": "sha256:dc14ae5fbc1e7230e0a782bf216fb46500e210631703bcc6bab8acf2c6a23f42", "readOnly": false, "type": [ "string" ] }, - "created_at": { - "description": "when outbound-ruleset was created", - "example": "2012-01-01T12:00:00Z", - "format": "date-time", - "readOnly": true, + "architecture": { + "description": "build architecture for OCI image", + "example": "arm64", + "readOnly": false, + "type": [ + "string", + "null" + ] + }, + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/oci-image/definitions/id" + }, + { + "$ref": "#/definitions/oci-image/definitions/digest" + } + ] + }, + "base_image_name": { + "description": "name of the image used for the base layers of the OCI image", + "example": "heroku/heroku:22-cnb", + "readOnly": false, "type": [ "string" ] }, - "id": { - "description": "unique identifier of an outbound-ruleset", - "example": "01234567-89ab-cdef-0123-456789abcdef", - "format": "uuid", - "readOnly": true, + "base_top_layer": { + "description": "the digest of the top most layer of the base image.", + "example": "sha256:ea36ae5fbc1e7230e0a782bf216fb46500e210382703baa6bab8acf2c6a23f78", + "readOnly": false, "type": [ "string" ] }, - "port": { - "description": "an endpoint of communication in an operating system.", - "example": 80, + "commit": { + "description": "identification of the code in your version control system (eg: SHA of the git HEAD)", + "example": "60883d9e8947a57e04dc9124f25df004866a2051", "readOnly": false, "type": [ - "integer" + "string" ] }, - "protocol": { - "description": "formal standards and policies comprised of rules, procedures and formats that define communication between two or more devices over a network", - "example": "tcp", + "commit_description": { + "description": "an optional description of the provided commit", + "example": "fixed a bug with API documentation", "readOnly": false, "type": [ "string" ] }, - "identity": { - "anyOf": [ - { - "$ref": "#/definitions/outbound-ruleset/definitions/id" + "image_repo": { + "description": "name of the image registry repository used for storage", + "example": "d7ba1ace-b396-4691-968c-37ae53153426/builds", + "readOnly": false, + "type": [ + "string" + ] + }, + "process_type": { + "description": "process type information such as names and commands", + "readOnly": false, + "properties": { + "name": { + "description": "name of the process type", + "example": "web", + "type": [ + "string" + ] + }, + "display_cmd": { + "description": "the detailed command used for display purposes", + "example": "bundle exec puma -p $PORT", + "type": [ + "string" + ] + }, + "command": { + "description": "the command that will be executed", + "example": "/cnb/process/web", + "type": [ + "string" + ] + }, + "working_dir": { + "description": "working directory", + "example": "/worspace/webapp", + "type": [ + "string" + ] + }, + "default": { + "description": "true if it is the default process type", + "example": true, + "type": [ + "boolean", + "null" + ] } + }, + "example": { + "name": "web", + "display_cmd": "bundle exec puma -p $PORT", + "command": "/cnb/process/web", + "working_dir": "/workspace/webapp", + "default": true + }, + "type": [ + "object" ] }, - "rule": { - "description": "the combination of an IP address in CIDR notation, a from_port, to_port and protocol.", + "process_types": { + "description": "process types of the OCI image", + "patternProperties": { + "^[-\\w]{1,128}$": { + "$ref": "#/definitions/oci-image/definitions/process_type" + } + }, + "example": { + "web": { + "name": "web", + "display_cmd": "bundle exec puma -p $PORT", + "command": "/cnb/process/web", + "working_dir": "/workspace/webapp", + "default": true + } + }, "type": [ "object" - ], + ] + }, + "buildpack": { + "description": "set of executables that inspects app source code and creates a plan to build and run your image", + "readOnly": false, "properties": { - "target": { - "$ref": "#/definitions/outbound-ruleset/definitions/target" + "id": { + "description": "identifier of the buildpack", + "example": "heroku/ruby", + "type": [ + "string" + ] }, - "from_port": { - "$ref": "#/definitions/outbound-ruleset/definitions/port" + "version": { + "description": "version of the buildpack", + "example": "2.0.0", + "type": [ + "string" + ] }, - "to_port": { - "$ref": "#/definitions/outbound-ruleset/definitions/port" + "homepage": { + "description": "homepage of the buildpack", + "example": "https://github.com/heroku/buildpacks-ruby", + "type": [ + "string" + ] + } + }, + "example": { + "id": "heroku/ruby", + "version": "2.0.0", + "homepage": "https://github.com/heroku/buildpacks-ruby" + }, + "type": [ + "object" + ] + }, + "buildpacks": { + "description": "buildpacks of the OCI image", + "items": { + "$ref": "#/definitions/oci-image/definitions/buildpack" + }, + "type": [ + "array" + ] + }, + "stack": { + "description": "stack associated to the OCI image", + "readOnly": false, + "properties": { + "id": { + "$ref": "#/definitions/stack/definitions/id", + "example": "ba46bf09-7bd1-42fd-90df-a1a9a93eb4a2" }, - "protocol": { - "$ref": "#/definitions/outbound-ruleset/definitions/protocol" + "name": { + "$ref": "#/definitions/stack/definitions/name", + "example": "cnb" } }, - "required": [ - "target", - "from_port", - "to_port", - "protocol" + "type": [ + "object" + ] + }, + "created_at": { + "description": "when the OCI image was created", + "example": "2012-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" + ] + }, + "updated_at": { + "description": "when the OCI image was updated", + "example": "2012-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" ] } }, "links": [ { - "description": "Current outbound ruleset for a space", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/outbound-ruleset", - "method": "GET", - "rel": "self", - "targetSchema": { - "$ref": "#/definitions/outbound-ruleset" - }, - "title": "Current" - }, - { - "description": "Info on an existing Outbound Ruleset", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/outbound-rulesets/{(%23%2Fdefinitions%2Foutbound-ruleset%2Fdefinitions%2Fidentity)}", + "description": "Info for the OCI images of an app, filtered by identifier.", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/oci-images/{(%23%2Fdefinitions%2Foci-image%2Fdefinitions%2Fidentity)}", "method": "GET", "rel": "self", - "targetSchema": { - "$ref": "#/definitions/outbound-ruleset" - }, - "title": "Info" - }, - { - "description": "List all Outbound Rulesets for a space", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/outbound-rulesets", - "method": "GET", - "rel": "instances", "targetSchema": { "items": { - "$ref": "#/definitions/outbound-ruleset" + "$ref": "#/definitions/oci-image" }, "type": [ "array" ] }, - "title": "List" + "title": "Info" }, { - "description": "Create a new outbound ruleset", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/outbound-ruleset", - "method": "PUT", + "description": "Create an new OCI image of an app", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/oci-images", + "method": "POST", "rel": "create", "schema": { - "type": [ - "object" - ], "properties": { - "rules": { - "type": [ - "array" - ], - "items": { - "$ref": "#/definitions/outbound-ruleset/definitions/rule" - } + "architecture": { + "$ref": "#/definitions/oci-image/definitions/architecture" + }, + "base_image_name": { + "$ref": "#/definitions/oci-image/definitions/base_image_name" + }, + "base_top_layer": { + "$ref": "#/definitions/oci-image/definitions/base_top_layer" + }, + "commit": { + "$ref": "#/definitions/oci-image/definitions/commit" + }, + "commit_description": { + "$ref": "#/definitions/oci-image/definitions/commit_description" + }, + "image_repo": { + "$ref": "#/definitions/oci-image/definitions/image_repo" + }, + "digest": { + "$ref": "#/definitions/oci-image/definitions/digest" + }, + "stack": { + "anyOf": [ + { + "$ref": "#/definitions/stack/definitions/name", + "example": "cnb" + }, + { + "$ref": "#/definitions/stack/definitions/id" + } + ] + }, + "process_types": { + "$ref": "#/definitions/oci-image/definitions/process_types" + }, + "buildpacks": { + "$ref": "#/definitions/oci-image/definitions/buildpacks" } - } + }, + "type": [ + "object" + ] + }, + "targetSchema": { + "$ref": "#/definitions/oci-image" }, "title": "Create" } ], "properties": { "id": { - "$ref": "#/definitions/outbound-ruleset/definitions/id" + "$ref": "#/definitions/oci-image/definitions/id" }, - "space": { - "description": "identity of space", - "properties": { - "id": { - "$ref": "#/definitions/space/definitions/id" - }, - "name": { - "$ref": "#/definitions/space/definitions/name" - } - }, - "type": [ - "object" - ] + "base_image_name": { + "$ref": "#/definitions/oci-image/definitions/base_image_name" + }, + "base_top_layer": { + "$ref": "#/definitions/oci-image/definitions/base_top_layer" + }, + "commit": { + "$ref": "#/definitions/oci-image/definitions/commit" + }, + "commit_description": { + "$ref": "#/definitions/oci-image/definitions/commit_description" + }, + "image_repo": { + "$ref": "#/definitions/oci-image/definitions/image_repo" + }, + "digest": { + "$ref": "#/definitions/oci-image/definitions/digest" + }, + "stack": { + "$ref": "#/definitions/oci-image/definitions/stack" + }, + "process_types": { + "$ref": "#/definitions/oci-image/definitions/process_types" + }, + "buildpacks": { + "$ref": "#/definitions/oci-image/definitions/buildpacks" }, "created_at": { - "$ref": "#/definitions/outbound-ruleset/definitions/created_at" + "$ref": "#/definitions/oci-image/definitions/created_at" }, - "rules": { - "type": [ - "array" - ], - "items": { - "$ref": "#/definitions/outbound-ruleset/definitions/rule" - } + "updated_at": { + "$ref": "#/definitions/oci-image/definitions/updated_at" }, - "created_by": { - "$ref": "#/definitions/account/definitions/email" + "architecture": { + "$ref": "#/definitions/oci-image/definitions/architecture" } } }, @@ -9373,10 +10067,16 @@ "$ref": "#/definitions/account/definitions/email" } }, + "required": [ + "email" + ], "type": [ "object" ] }, + "targetSchema": { + "$ref": "#/definitions/password-reset" + }, "title": "Reset Password" }, { @@ -9393,10 +10093,17 @@ "$ref": "#/definitions/password-reset/definitions/password_confirmation" } }, + "required": [ + "password", + "password_confirmation" + ], "type": [ "object" ] }, + "targetSchema": { + "$ref": "#/definitions/password-reset" + }, "title": "Complete Reset Password" } ], @@ -9626,14 +10333,20 @@ "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/peerings/{(%23%2Fdefinitions%2Fpeering%2Fdefinitions%2Fpcx_id)}/actions/accept", "method": "POST", "rel": "empty", - "title": "Accept" + "title": "Accept", + "targetSchema": { + "$ref": "#/definitions/peering" + } }, { "description": "Destroy an active peering connection with a private space.", "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/peerings/{(%23%2Fdefinitions%2Fpeering%2Fdefinitions%2Fpcx_id)}", "rel": "empty", "method": "DELETE", - "title": "Destroy" + "title": "Destroy", + "targetSchema": { + "$ref": "#/definitions/peering" + } }, { "description": "Fetch information for existing peering connection", @@ -9758,7 +10471,7 @@ } }, "pipeline-build": { - "description": "Information about latest builds of apps in a pipeline.", + "description": "Information about the latest builds of apps in a pipeline. A build represents the process of transforming code into build artifacts.", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "production", "strictProperties": true, @@ -9766,7 +10479,131 @@ "type": [ "object" ], - "definitions": { + "definitions": {}, + "properties": { + "app": { + "description": "app that the build belongs to", + "properties": { + "id": { + "description": "unique identifier of the app", + "$ref": "#/definitions/app/definitions/id" + } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "buildpacks": { + "$ref": "#/definitions/build/definitions/buildpacks" + }, + "created_at": { + "description": "when the build was created", + "$ref": "#/definitions/build/definitions/created_at" + }, + "id": { + "description": "unique identifier of the build", + "$ref": "#/definitions/build/definitions/id" + }, + "output_stream_url": { + "description": "streaming URL of the build process output", + "$ref": "#/definitions/build/definitions/output_stream_url" + }, + "source_blob": { + "description": "location of gzipped tarball of source code used to create build", + "properties": { + "checksum": { + "description": "an optional checksum of the gzipped tarball for verifying its integrity", + "example": "SHA256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "readOnly": true, + "type": [ + "null", + "string" + ] + }, + "url": { + "description": "URL where gzipped tar archive of source code for build was downloaded.", + "example": "https://example.com/source.tgz?token=xyz", + "readOnly": true, + "type": [ + "string" + ] + }, + "version": { + "description": "version of the gzipped tarball", + "example": "v1.3.0", + "readOnly": true, + "type": [ + "string", + "null" + ] + }, + "version_description": { + "description": "version description of the gzipped tarball", + "example": "* Fake User: Change session key", + "readOnly": true, + "type": [ + "string", + "null" + ] + } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "release": { + "properties": { + "id": { + "description": "unique identifier of the release", + "$ref": "#/definitions/release/definitions/id" + } + }, + "$ref": "#/definitions/build/definitions/release" + }, + "slug": { + "description": "slug created by this build", + "properties": { + "id": { + "description": "unique identifier of the slug", + "$ref": "#/definitions/slug/definitions/id" + } + }, + "strictProperties": true, + "type": [ + "object", + "null" + ] + }, + "stack": { + "description": "stack of the build", + "example": "heroku-24", + "$ref": "#/definitions/build/definitions/stack" + }, + "status": { + "description": "status of the build", + "$ref": "#/definitions/build/definitions/status" + }, + "updated_at": { + "description": "when the build was updated", + "$ref": "#/definitions/build/definitions/updated_at" + }, + "user": { + "description": "user that started the build", + "properties": { + "id": { + "$ref": "#/definitions/account/definitions/id" + }, + "email": { + "$ref": "#/definitions/account/definitions/email" + } + }, + "strictProperties": true, + "type": [ + "object" + ] + } }, "links": [ { @@ -9776,7 +10613,7 @@ "rel": "instances", "targetSchema": { "items": { - "$ref": "#/definitions/build" + "$ref": "#/definitions/pipeline-build" }, "type": [ "array" @@ -9787,7 +10624,7 @@ ] }, "pipeline-config-var": { - "description": "Pipeline Config Vars allow you to manage the configuration information provided to a pipeline.", + "description": "Pipeline config vars in Heroku CI and review apps used to manage the configuration information for a pipeline.", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "production", "strictProperties": true, @@ -9816,6 +10653,17 @@ ] } }, + "properties": { + "[\"NAME\"]: [\"value\"]": { + "type": [ + "object" + ], + "description": "user-defined config var name and value", + "example": { + "FOO": "bar" + } + } + }, "links": [ { "description": "Get config-vars for a pipeline stage.", @@ -10108,7 +10956,7 @@ } }, "pipeline-deployment": { - "description": "Information about latest deployments of apps in a pipeline.", + "description": "Information about the latest deployment of each app in a pipeline. A deployment is the process of moving the build artifacts to a target environment.", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "production", "strictProperties": true, @@ -10116,49 +10964,143 @@ "type": [ "object" ], - "definitions": { - }, - "links": [ - { - "description": "List latest slug releases for each app in a pipeline", - "href": "/pipelines/{(%23%2Fdefinitions%2Fpipeline%2Fdefinitions%2Fid)}/latest-deployments", - "method": "GET", - "rel": "instances", - "targetSchema": { - "items": { - "$ref": "#/definitions/release" + "$ref": "#/definitions/release", + "properties": { + "addon_plan_names": { + "description": "add-on plans installed on the app for this deployment", + "type": [ + "array" + ], + "items": { + "$ref": "#/definitions/plan/definitions/name" + } + }, + "artifacts": { + "$ref": "#/definitions/release/definitions/artifact" + }, + "app": { + "description": "app involved in the deployment", + "properties": { + "name": { + "description": "unique name of the app", + "$ref": "#/definitions/app/definitions/name" }, - "type": [ - "array" - ] + "id": { + "description": "unique identifier of the app", + "$ref": "#/definitions/app/definitions/id" + } }, - "title": "List" - } - ] - }, - "pipeline-promotion-target": { - "description": "Promotion targets represent an individual app being promoted to", - "$schema": "http://json-schema.org/draft-04/hyper-schema", - "stability": "production", - "strictProperties": true, - "title": "Heroku Platform API - Pipeline Promotion Target", - "type": [ - "object" - ], - "definitions": { - "error_message": { - "description": "an error message for why the promotion failed", - "example": "User does not have access to that app", "type": [ - "null", - "string" + "object" ] }, - "id": { - "description": "unique identifier of promotion target", - "example": "01234567-89ab-cdef-0123-456789abcdef", - "readOnly": true, - "format": "uuid", + "created_at": { + "description": "when the deployment was created", + "$ref": "#/definitions/release/definitions/created_at" + }, + "description": { + "description": "description of changes in this deployment", + "$ref": "#/definitions/release/definitions/description" + }, + "id": { + "description": "unique identifier of the deployment", + "$ref": "#/definitions/release/definitions/id" + }, + "updated_at": { + "description": "when the deployment was updated", + "$ref": "#/definitions/release/definitions/updated_at" + }, + "slug": { + "description": "slug running in this deployment", + "properties": { + "id": { + "description": "unique identifier of the slug", + "$ref": "#/definitions/slug/definitions/id" + } + }, + "strictProperties": true, + "type": [ + "object", + "null" + ] + }, + "status": { + "description": "current status of the deployment", + "$ref": "#/definitions/release/definitions/status" + }, + "user": { + "description": "user that created the deployment", + "properties": { + "id": { + "$ref": "#/definitions/account/definitions/id" + }, + "email": { + "$ref": "#/definitions/account/definitions/email" + } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "version": { + "description": "unique version assigned to the deployment", + "$ref": "#/definitions/release/definitions/version" + }, + "current": { + "description": "indicates if this deployment is the current one for the app", + "$ref": "#/definitions/release/definitions/current" + }, + "output_stream_url": { + "description": "streaming URL for the release command output", + "$ref": "#/definitions/release/definitions/output_stream_url" + }, + "eligible_for_rollback": { + "description": "indicates if this deployment is eligible for rollback", + "$ref": "#/definitions/release/definitions/eligible_for_rollback" + } + }, + "links": [ + { + "description": "List latest deployments for each app in a pipeline. A deployment is a release that changed your source slug, container image, or Heroku processes.", + "href": "/pipelines/{(%23%2Fdefinitions%2Fpipeline%2Fdefinitions%2Fid)}/latest-deployments", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/release" + }, + "type": [ + "array" + ] + }, + "title": "List" + } + ] + }, + "pipeline-promotion-target": { + "description": "Promotion targets represent an individual app being promoted to", + "$schema": "http://json-schema.org/draft-04/hyper-schema", + "stability": "production", + "strictProperties": true, + "title": "Heroku Platform API - Pipeline Promotion Target", + "type": [ + "object" + ], + "definitions": { + "error_message": { + "description": "an error message for why the promotion failed", + "example": "User does not have access to that app", + "type": [ + "null", + "string" + ] + }, + "id": { + "description": "unique identifier of promotion target", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "readOnly": true, + "format": "uuid", "type": [ "string" ] @@ -10457,7 +11399,7 @@ } }, "pipeline-release": { - "description": "Information about latest releases of apps in a pipeline.", + "description": "Information about the latest release of each app in a pipeline. A release makes a deployment available to end-users.", "$schema": "http://json-schema.org/draft-04/hyper-schema", "stability": "production", "strictProperties": true, @@ -10465,7 +11407,96 @@ "type": [ "object" ], - "definitions": { + "properties": { + "addon_plan_names": { + "description": "add-on plans installed on the app for this release", + "type": [ + "array" + ], + "items": { + "$ref": "#/definitions/plan/definitions/name" + } + }, + "artifacts": { + "$ref": "#/definitions/release/definitions/artifact" + }, + "app": { + "description": "app involved in the release", + "properties": { + "name": { + "description": "unique name of the app", + "$ref": "#/definitions/app/definitions/name" + }, + "id": { + "description": "unique identifier of the app", + "$ref": "#/definitions/app/definitions/id" + } + }, + "type": [ + "object" + ] + }, + "created_at": { + "description": "when the release was created", + "$ref": "#/definitions/release/definitions/created_at" + }, + "description": { + "$ref": "#/definitions/release/definitions/description" + }, + "id": { + "description": "unique identifier of the release", + "$ref": "#/definitions/release/definitions/id" + }, + "updated_at": { + "description": "when the release was updated", + "$ref": "#/definitions/release/definitions/updated_at" + }, + "slug": { + "description": "slug running in the release", + "properties": { + "id": { + "description": "unique identifier of the slug", + "$ref": "#/definitions/slug/definitions/id" + } + }, + "strictProperties": true, + "type": [ + "object", + "null" + ] + }, + "status": { + "$ref": "#/definitions/release/definitions/status" + }, + "user": { + "description": "user that created the release", + "properties": { + "id": { + "$ref": "#/definitions/account/definitions/id" + }, + "email": { + "$ref": "#/definitions/account/definitions/email" + } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "version": { + "$ref": "#/definitions/release/definitions/version" + }, + "current": { + "description": "indicates if this release is the current one for the app", + "$ref": "#/definitions/release/definitions/current" + }, + "output_stream_url": { + "description": "streaming URL of the build process output", + "$ref": "#/definitions/release/definitions/output_stream_url" + }, + "eligible_for_rollback": { + "$ref": "#/definitions/release/definitions/eligible_for_rollback" + } }, "links": [ { @@ -10697,8 +11728,7 @@ ] } }, - "links": [ - ], + "links": [], "properties": { "id": { "$ref": "#/definitions/pipeline/definitions/owner/definitions/id" @@ -10724,6 +11754,49 @@ "type": [ "string" ] + }, + "generation": { + "description": "the generation of the Heroku platform for this pipeline", + "definitions": { + "id": { + "description": "unique identifier of the generation of the Heroku platform for this pipeline", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/pipeline/definitions/generation/definitions/id" + }, + { + "$ref": "#/definitions/pipeline/definitions/generation/definitions/name" + } + ] + }, + "name": { + "description": "unique name of the generation of the Heroku platform for this pipeline", + "example": "cedar", + "readOnly": true, + "type": [ + "string" + ] + } + }, + "properties": { + "id": { + "$ref": "#/definitions/pipeline/definitions/generation/definitions/id" + }, + "name": { + "$ref": "#/definitions/pipeline/definitions/generation/definitions/name" + } + }, + "type": [ + "object" + ] } }, "links": [ @@ -10829,6 +11902,9 @@ }, "updated_at": { "$ref": "#/definitions/pipeline/definitions/updated_at" + }, + "generation": { + "$ref": "#/definitions/pipeline/definitions/generation" } } }, @@ -11124,8 +12200,7 @@ "object" ], "definitions": { - "identity": { - }, + "identity": {}, "remaining": { "description": "allowed requests remaining in current interval", "example": 2399, @@ -11258,12 +12333,14 @@ "ap-southeast-1", "ap-southeast-2", "eu-central-1", + "eu-west-2", "ap-northeast-2", "ap-northeast-1", "us-east-1", "sa-east-1", "us-west-1", - "us-west-2" + "us-west-2", + "ca-central-1" ] } }, @@ -11346,6 +12423,32 @@ "object" ], "definitions": { + "artifact": { + "description": "a build artifact for the release", + "properties": { + "type": { + "description": "type of artifact", + "example": "slug", + "type": [ + "string" + ] + }, + "id": { + "anyOf": [ + { + "$ref": "#/definitions/slug/definitions/id" + }, + { + "$ref": "#/definitions/oci-image/definitions/id" + } + ] + } + }, + "readOnly": true, + "type": [ + "object" + ] + }, "created_at": { "description": "when release was created", "example": "2012-01-01T12:00:00Z", @@ -11428,6 +12531,14 @@ "string", "null" ] + }, + "eligible_for_rollback": { + "description": "indicates if this release is eligible for rollback", + "example": true, + "readOnly": true, + "type": [ + "boolean" + ] } }, "links": [ @@ -11466,6 +12577,9 @@ "description": { "$ref": "#/definitions/release/definitions/description" }, + "oci_image": { + "$ref": "#/definitions/oci-image/definitions/identity" + }, "slug": { "$ref": "#/definitions/slug/definitions/identity" } @@ -11516,6 +12630,15 @@ "$ref": "#/definitions/plan/definitions/name" } }, + "artifacts": { + "description": "build artifacts for the release", + "type": [ + "array" + ], + "items": { + "$ref": "#/definitions/release/definitions/artifact" + } + }, "app": { "description": "app involved in the release", "properties": { @@ -11581,6 +12704,9 @@ }, "output_stream_url": { "$ref": "#/definitions/release/definitions/output_stream_url" + }, + "eligible_for_rollback": { + "$ref": "#/definitions/release/definitions/eligible_for_rollback" } } }, @@ -12024,8 +13150,7 @@ ] } }, - "links": [ - ], + "links": [], "properties": { "id": { "$ref": "#/definitions/review-app-config/definitions/deploy_target/definitions/id" @@ -12508,6 +13633,18 @@ "object" ], "definitions": { + "ca_signed?": { + "readOnly": true, + "type": [ + "boolean" + ] + }, + "cert_domains": { + "readOnly": true, + "type": [ + "array" + ] + }, "certificate_chain": { "description": "raw contents of the public certificate chain (eg: .crt or .pem file)", "example": "-----BEGIN CERTIFICATE----- ...", @@ -12525,10 +13662,37 @@ "string" ] }, - "id": { - "description": "unique identifier of this SNI endpoint", - "example": "01234567-89ab-cdef-0123-456789abcdef", - "format": "uuid", + "domains": { + "description": "domains associated with this SSL certificate", + "type": [ + "array" + ], + "readOnly": true, + "items": { + "$ref": "#/definitions/domain/definitions/id" + } + }, + "display_name": { + "description": "unique name for SSL certificate", + "example": "example", + "pattern": "^[a-z][a-z0-9-]{2,29}$", + "readOnly": false, + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "readOnly": true, + "format": "date-time", + "type": [ + "string" + ] + }, + "id": { + "description": "unique identifier of this SNI endpoint", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", "readOnly": true, "type": [ "string" @@ -12544,6 +13708,12 @@ } ] }, + "issuer": { + "readOnly": true, + "type": [ + "string" + ] + }, "name": { "description": "unique name for SNI endpoint", "example": "example", @@ -12561,33 +13731,32 @@ "string" ] }, - "updated_at": { - "description": "when SNI endpoint was updated", - "example": "2012-01-01T12:00:00Z", - "format": "date-time", + "self_signed?": { "readOnly": true, "type": [ - "string" + "boolean" ] }, - "domains": { - "description": "domains associated with this SSL certificate", + "starts_at": { + "readOnly": true, + "format": "date-time", "type": [ - "array" - ], + "string" + ] + }, + "subject": { "readOnly": true, - "items": { - "$ref": "#/definitions/domain/definitions/id" - } + "type": [ + "string" + ] }, - "display_name": { - "description": "unique name for SSL certificate", - "example": "example", - "pattern": "^[a-z][a-z0-9-]{2,29}$", - "readOnly": false, + "updated_at": { + "description": "when SNI endpoint was updated", + "example": "2012-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, "type": [ - "string", - "null" + "string" ] } }, @@ -12726,25 +13895,25 @@ ], "properties": { "ca_signed?": { - "$ref": "#/definitions/ssl-endpoint/definitions/ca_signed?" + "$ref": "#/definitions/sni-endpoint/definitions/ca_signed?" }, "cert_domains": { - "$ref": "#/definitions/ssl-endpoint/definitions/cert_domains" + "$ref": "#/definitions/sni-endpoint/definitions/cert_domains" }, "expires_at": { - "$ref": "#/definitions/ssl-endpoint/definitions/expires_at" + "$ref": "#/definitions/sni-endpoint/definitions/expires_at" }, "issuer": { - "$ref": "#/definitions/ssl-endpoint/definitions/issuer" + "$ref": "#/definitions/sni-endpoint/definitions/issuer" }, "self_signed?": { - "$ref": "#/definitions/ssl-endpoint/definitions/self_signed?" + "$ref": "#/definitions/sni-endpoint/definitions/self_signed?" }, "starts_at": { - "$ref": "#/definitions/ssl-endpoint/definitions/starts_at" + "$ref": "#/definitions/sni-endpoint/definitions/starts_at" }, "subject": { - "$ref": "#/definitions/ssl-endpoint/definitions/subject" + "$ref": "#/definitions/sni-endpoint/definitions/subject" }, "id": { "description": "unique identifier of this SSL certificate", @@ -13241,7 +14410,7 @@ "space": { "description": "A space is an isolated, highly available, secure app execution environment.", "$schema": "http://json-schema.org/draft-04/hyper-schema", - "stability": "prototype", + "stability": "production", "strictProperties": true, "title": "Heroku Platform API - Space", "type": [ @@ -13339,500 +14508,208 @@ "type": [ "string" ] - } - }, - "links": [ - { - "description": "List existing spaces.", - "href": "/spaces", - "method": "GET", - "rel": "instances", - "targetSchema": { - "items": { - "$ref": "#/definitions/space" - }, - "type": [ - "array" - ] - }, - "title": "List" - }, - { - "description": "Info for existing space.", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}", - "method": "GET", - "rel": "self", - "targetSchema": { - "$ref": "#/definitions/space" - }, - "title": "Info" - }, - { - "description": "Update an existing space.", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}", - "method": "PATCH", - "rel": "update", - "schema": { - "properties": { - "name": { - "$ref": "#/definitions/space/definitions/name" - } - }, - "type": [ - "object" - ] - }, - "targetSchema": { - "$ref": "#/definitions/space" - }, - "title": "Update" - }, - { - "description": "Delete an existing space.", - "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}", - "method": "DELETE", - "rel": "destroy", - "targetSchema": { - "$ref": "#/definitions/space" - }, - "title": "Delete" - }, - { - "description": "Create a new space.", - "href": "/spaces", - "method": "POST", - "rel": "create", - "schema": { - "properties": { - "name": { - "$ref": "#/definitions/space/definitions/name" - }, - "team": { - "$ref": "#/definitions/team/definitions/name" - }, - "region": { - "$ref": "#/definitions/region/definitions/identity" - }, - "shield": { - "$ref": "#/definitions/space/definitions/shield" - }, - "cidr": { - "$ref": "#/definitions/space/definitions/cidr" - }, - "data_cidr": { - "$ref": "#/definitions/space/definitions/data_cidr" - }, - "log_drain_url": { - "$ref": "#/definitions/space/definitions/log_drain_url" - } - }, - "required": [ - "name", - "team" - ], - "type": [ - "object" - ] - }, - "targetSchema": { - "$ref": "#/definitions/space" - }, - "title": "Create" - } - ], - "properties": { - "created_at": { - "$ref": "#/definitions/space/definitions/created_at" - }, - "id": { - "$ref": "#/definitions/space/definitions/id" - }, - "name": { - "$ref": "#/definitions/space/definitions/name" - }, - "organization": { - "description": "organization that owns this space", - "properties": { - "name": { - "$ref": "#/definitions/team/definitions/name" - } - }, - "type": [ - "object" - ] }, - "team": { - "description": "team that owns this space", - "properties": { - "id": { - "$ref": "#/definitions/team/definitions/id" - }, - "name": { - "$ref": "#/definitions/team/definitions/name" - } - }, + "generation": { + "description": "Generation of the Heroku platform for this space", + "readOnly": true, "type": [ "object" - ] - }, - "region": { - "description": "identity of space region", + ], "properties": { "id": { - "$ref": "#/definitions/region/definitions/id" - }, - "name": { - "$ref": "#/definitions/region/definitions/name" - } - }, - "strictProperties": true, - "type": [ - "object" - ] - }, - "shield": { - "$ref": "#/definitions/space/definitions/shield" - }, - "state": { - "$ref": "#/definitions/space/definitions/state" - }, - "updated_at": { - "$ref": "#/definitions/space/definitions/updated_at" - }, - "cidr": { - "$ref": "#/definitions/space/definitions/cidr" - }, - "data_cidr": { - "$ref": "#/definitions/space/definitions/data_cidr" - } - } - }, - "ssl-endpoint": { - "description": "[SSL Endpoint](https://devcenter.heroku.com/articles/ssl-endpoint) is a public address serving custom SSL cert for HTTPS traffic to a Heroku app. Note that an app must have the `ssl:endpoint` add-on installed before it can provision an SSL Endpoint using these APIs.", - "$schema": "http://json-schema.org/draft-04/hyper-schema", - "title": "Heroku Platform API - SSL Endpoint", - "stability": "production", - "strictProperties": true, - "type": [ - "object" - ], - "definitions": { - "acm": { - "readOnly": true, - "type": [ - "boolean" - ] - }, - "ca_signed?": { - "readOnly": true, - "type": [ - "boolean" - ] - }, - "cert_domains": { - "readOnly": true, - "type": [ - "array" - ] - }, - "certificate_chain": { - "description": "raw contents of the public certificate chain (eg: .crt or .pem file)", - "example": "-----BEGIN CERTIFICATE----- ...", - "readOnly": false, - "type": [ - "string" - ] - }, - "cname": { - "description": "canonical name record, the address to point a domain at", - "example": "example.herokussl.com", - "readOnly": false, - "type": [ - "string" - ] - }, - "created_at": { - "description": "when endpoint was created", - "example": "2012-01-01T12:00:00Z", - "format": "date-time", - "readOnly": true, - "type": [ - "string" - ] - }, - "display_name": { - "description": "unique name for SSL endpoint", - "example": "example", - "pattern": "^[a-z][a-z0-9-]{2,29}$", - "readOnly": false, - "type": [ - "string", - "null" - ] - }, - "expires_at": { - "readOnly": true, - "format": "date-time", - "type": [ - "string" - ] - }, - "id": { - "description": "unique identifier of this SSL endpoint", - "example": "01234567-89ab-cdef-0123-456789abcdef", - "format": "uuid", - "readOnly": true, - "type": [ - "string" - ] - }, - "identity": { - "anyOf": [ - { - "$ref": "#/definitions/ssl-endpoint/definitions/id" + "description": "unique identifier of the generation of the Heroku platform for this space", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] }, - { - "$ref": "#/definitions/ssl-endpoint/definitions/name" - } - ] - }, - "issuer": { - "readOnly": true, - "type": [ - "string" - ] - }, - "name": { - "description": "unique name for SSL endpoint", - "example": "example", - "pattern": "^[a-z][a-z0-9-]{2,29}$", - "readOnly": true, - "type": [ - "string" - ] - }, - "preprocess": { - "default": true, - "description": "allow Heroku to modify an uploaded public certificate chain if deemed advantageous by adding missing intermediaries, stripping unnecessary ones, etc.", - "example": true, - "readOnly": false, - "type": [ - "boolean" - ] - }, - "private_key": { - "description": "contents of the private key (eg .key file)", - "example": "-----BEGIN RSA PRIVATE KEY----- ...", - "readOnly": false, - "type": [ - "string" - ] - }, - "self_signed?": { - "readOnly": true, - "type": [ - "boolean" - ] - }, - "starts_at": { - "readOnly": true, - "format": "date-time", - "type": [ - "string" - ] - }, - "subject": { - "readOnly": true, - "type": [ - "string" - ] - }, - "updated_at": { - "description": "when endpoint was updated", - "example": "2012-01-01T12:00:00Z", - "format": "date-time", - "readOnly": true, - "type": [ - "string" - ] + "name": { + "description": "unique name of the generation of the Heroku platform for this space", + "example": "cedar", + "readOnly": true, + "type": [ + "string" + ] + } + } } }, "links": [ { - "description": "Create a new SSL endpoint.", - "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/ssl-endpoints", - "method": "POST", - "rel": "create", - "schema": { - "properties": { - "certificate_chain": { - "$ref": "#/definitions/ssl-endpoint/definitions/certificate_chain" - }, - "preprocess": { - "$ref": "#/definitions/ssl-endpoint/definitions/preprocess" - }, - "private_key": { - "$ref": "#/definitions/ssl-endpoint/definitions/private_key" - } + "description": "List existing spaces.", + "href": "/spaces", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/space" }, - "required": [ - "certificate_chain", - "private_key" - ], "type": [ - "object" + "array" ] }, - "targetSchema": { - "$ref": "#/definitions/ssl-endpoint" - }, - "title": "Create" - }, - { - "description": "Delete existing SSL endpoint.", - "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/ssl-endpoints/{(%23%2Fdefinitions%2Fssl-endpoint%2Fdefinitions%2Fidentity)}", - "method": "DELETE", - "rel": "destroy", - "targetSchema": { - "$ref": "#/definitions/ssl-endpoint" - }, - "title": "Delete" + "title": "List" }, { - "description": "Info for existing SSL endpoint.", - "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/ssl-endpoints/{(%23%2Fdefinitions%2Fssl-endpoint%2Fdefinitions%2Fidentity)}", + "description": "Info for existing space.", + "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}", "method": "GET", "rel": "self", "targetSchema": { - "$ref": "#/definitions/ssl-endpoint" + "$ref": "#/definitions/space" }, "title": "Info" }, { - "description": "List existing SSL endpoints.", - "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/ssl-endpoints", - "method": "GET", - "rel": "instances", - "targetSchema": { - "items": { - "$ref": "#/definitions/ssl-endpoint" + "description": "Update an existing space.", + "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}", + "method": "PATCH", + "rel": "update", + "schema": { + "properties": { + "name": { + "$ref": "#/definitions/space/definitions/name" + } }, "type": [ - "array" + "object" ] }, - "title": "List" + "targetSchema": { + "$ref": "#/definitions/space" + }, + "title": "Update" }, { - "description": "Update an existing SSL endpoint.", - "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/ssl-endpoints/{(%23%2Fdefinitions%2Fssl-endpoint%2Fdefinitions%2Fidentity)}", - "method": "PATCH", - "rel": "update", + "description": "Delete an existing space.", + "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}", + "method": "DELETE", + "rel": "destroy", + "targetSchema": { + "$ref": "#/definitions/space" + }, + "title": "Delete" + }, + { + "description": "Create a new space.", + "href": "/spaces", + "method": "POST", + "rel": "create", "schema": { "properties": { - "certificate_chain": { - "$ref": "#/definitions/ssl-endpoint/definitions/certificate_chain" + "name": { + "$ref": "#/definitions/space/definitions/name" + }, + "team": { + "$ref": "#/definitions/team/definitions/name" }, - "preprocess": { - "$ref": "#/definitions/ssl-endpoint/definitions/preprocess" + "region": { + "$ref": "#/definitions/region/definitions/identity" }, - "private_key": { - "$ref": "#/definitions/ssl-endpoint/definitions/private_key" + "shield": { + "$ref": "#/definitions/space/definitions/shield" + }, + "cidr": { + "$ref": "#/definitions/space/definitions/cidr" + }, + "data_cidr": { + "$ref": "#/definitions/space/definitions/data_cidr" + }, + "log_drain_url": { + "$ref": "#/definitions/space/definitions/log_drain_url" + }, + "generation": { + "description": "unique name of the generation of the Heroku platform for this space", + "example": "cedar", + "readOnly": true, + "type": [ + "string" + ] } }, + "required": [ + "name", + "team" + ], "type": [ "object" ] }, "targetSchema": { - "$ref": "#/definitions/ssl-endpoint" + "$ref": "#/definitions/space" }, - "title": "Update" + "title": "Create" } ], "properties": { - "app": { - "description": "application associated with this ssl-endpoint", + "created_at": { + "$ref": "#/definitions/space/definitions/created_at" + }, + "id": { + "$ref": "#/definitions/space/definitions/id" + }, + "name": { + "$ref": "#/definitions/space/definitions/name" + }, + "organization": { + "description": "organization that owns this space", + "properties": { + "name": { + "$ref": "#/definitions/team/definitions/name" + } + }, "type": [ "object" - ], + ] + }, + "team": { + "description": "team that owns this space", "properties": { "id": { - "$ref": "#/definitions/app/definitions/id" + "$ref": "#/definitions/team/definitions/id" }, "name": { - "$ref": "#/definitions/app/definitions/name" + "$ref": "#/definitions/team/definitions/name" } }, - "strictProperties": true - }, - "certificate_chain": { - "$ref": "#/definitions/ssl-endpoint/definitions/certificate_chain" - }, - "cname": { - "$ref": "#/definitions/ssl-endpoint/definitions/cname" - }, - "created_at": { - "$ref": "#/definitions/ssl-endpoint/definitions/created_at" - }, - "display_name": { - "$ref": "#/definitions/ssl-endpoint/definitions/display_name" - }, - "domains": { - "description": "domains associated with this endpoint", - "type": [ - "array" - ], - "items": { - "$ref": "#/definitions/domain/definitions/id" - } - }, - "id": { - "$ref": "#/definitions/ssl-endpoint/definitions/id" - }, - "name": { - "$ref": "#/definitions/ssl-endpoint/definitions/name" - }, - "ssl_cert": { - "description": "certificate provided by this endpoint", "type": [ "object" - ], + ] + }, + "region": { + "description": "identity of space region", "properties": { - "ca_signed?": { - "$ref": "#/definitions/ssl-endpoint/definitions/ca_signed?" - }, - "cert_domains": { - "$ref": "#/definitions/ssl-endpoint/definitions/cert_domains" - }, - "expires_at": { - "$ref": "#/definitions/ssl-endpoint/definitions/expires_at" - }, - "issuer": { - "$ref": "#/definitions/ssl-endpoint/definitions/issuer" - }, - "self_signed?": { - "$ref": "#/definitions/ssl-endpoint/definitions/self_signed?" - }, - "starts_at": { - "$ref": "#/definitions/ssl-endpoint/definitions/starts_at" - }, - "subject": { - "$ref": "#/definitions/ssl-endpoint/definitions/subject" - }, "id": { - "description": "unique identifier of this SSL certificate", - "example": "01234567-89ab-cdef-0123-456789abcdef", - "format": "uuid", - "readOnly": true, - "type": [ - "string" - ] + "$ref": "#/definitions/region/definitions/id" + }, + "name": { + "$ref": "#/definitions/region/definitions/name" } - } + }, + "strictProperties": true, + "type": [ + "object" + ] + }, + "shield": { + "$ref": "#/definitions/space/definitions/shield" + }, + "state": { + "$ref": "#/definitions/space/definitions/state" }, "updated_at": { - "$ref": "#/definitions/ssl-endpoint/definitions/updated_at" + "$ref": "#/definitions/space/definitions/updated_at" + }, + "cidr": { + "$ref": "#/definitions/space/definitions/cidr" + }, + "data_cidr": { + "$ref": "#/definitions/space/definitions/data_cidr" + }, + "generation": { + "$ref": "#/definitions/space/definitions/generation" } } }, @@ -13933,6 +14810,21 @@ ] }, "title": "List" + }, + { + "description": "List available app stacks for an app.", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/available-stacks", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/stack" + }, + "type": [ + "array" + ] + }, + "title": "List by App" } ], "properties": { @@ -14233,11 +15125,7 @@ ] }, "identity": { - "anyOf": [ - { - "$ref": "#/definitions/app/definitions/name" - } - ] + "$ref": "#/definitions/app/definitions/name" }, "internal_routing": { "default": false, @@ -14303,6 +15191,9 @@ "object" ] }, + "targetSchema": { + "$ref": "#/definitions/team-app" + }, "title": "Create" }, { @@ -14310,6 +15201,9 @@ "href": "/teams/apps/{(%23%2Fdefinitions%2Fteam-app%2Fdefinitions%2Fidentity)}", "method": "GET", "rel": "self", + "targetSchema": { + "$ref": "#/definitions/team-app" + }, "title": "Info" }, { @@ -14646,7 +15540,7 @@ }, "links": [ { - "description": "Retrieves usage for an enterprise team for a range of days. Start and end dates can be specified as query parameters using the date format YYYY-MM-DD.\nThe team identifier can be found from the [team list endpoint](https://devcenter.heroku.com/articles/platform-api-reference#team-list).\n", + "description": "Retrieves usage for an enterprise team for a range of days. Start and end dates can be specified as query parameters using the date format YYYY-MM-DD. The team identifier can be found from the [team list endpoint](https://devcenter.heroku.com/articles/platform-api-reference#team-list).\n", "href": "/teams/{(%23%2Fdefinitions%2Fteam%2Fdefinitions%2Fid)}/usage/daily", "method": "GET", "title": "Info", @@ -14705,11 +15599,63 @@ "name": { "$ref": "#/definitions/team-daily-usage/definitions/name" }, - "partner": { - "$ref": "#/definitions/team-daily-usage/definitions/partner" + "partner": { + "$ref": "#/definitions/team-daily-usage/definitions/partner" + }, + "space": { + "$ref": "#/definitions/team-daily-usage/definitions/space" + } + } + }, + "team-delinquency": { + "description": "A Heroku team becomes delinquent due to non-payment. We [suspend and delete](https://help.heroku.com/EREVRILX/what-happens-if-i-have-unpaid-heroku-invoices) delinquent teams if their invoices remain unpaid.", + "$schema": "http://json-schema.org/draft-04/hyper-schema", + "stability": "development", + "strictProperties": true, + "title": "Heroku Platform API - Team Delinquency", + "type": [ + "object" + ], + "definitions": { + "scheduled_suspension_time": { + "description": "scheduled time of when we will suspend your team due to delinquency", + "example": "2024-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string", + "null" + ] + }, + "scheduled_deletion_time": { + "description": "scheduled time of when we will delete your team due to delinquency", + "example": "2024-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string", + "null" + ] + } + }, + "links": [ + { + "description": "Team delinquency information.", + "href": "/teams/{(%23%2Fdefinitions%2Fteam%2Fdefinitions%2Fidentity)}/delinquency", + "method": "GET", + "rel": "self", + "targetSchema": { + "$ref": "#/definitions/team-delinquency" + }, + "title": "Info" + } + ], + "properties": { + "scheduled_suspension_time": { + "$ref": "#/definitions/team-delinquency/definitions/scheduled_suspension_time" }, - "space": { - "$ref": "#/definitions/team-daily-usage/definitions/space" + "scheduled_deletion_time": { + "$ref": "#/definitions/team-delinquency/definitions/scheduled_deletion_time" } } }, @@ -14968,6 +15914,9 @@ "type": [ "object" ] + }, + "targetSchema": { + "$ref": "#/definitions/team-invitation" } }, { @@ -14975,7 +15924,10 @@ "title": "Revoke", "href": "/teams/{(%23%2Fdefinitions%2Fteam%2Fdefinitions%2Fidentity)}/invitations/{(%23%2Fdefinitions%2Fteam-invitation%2Fdefinitions%2Fidentity)}", "method": "DELETE", - "rel": "self" + "rel": "self", + "targetSchema": { + "$ref": "#/definitions/team-invitation" + } }, { "description": "Get an invitation by its token", @@ -15370,7 +16322,7 @@ ] }, "two_factor_authentication": { - "description": "whether the Enterprise team member has two factor authentication enabled", + "description": "whether the team member has two factor authentication enabled", "example": true, "readOnly": true, "type": [ @@ -15637,7 +16589,7 @@ } }, "connect": { - "description": "average connect rows synced", + "description": "max connect rows synced", "example": 15000, "readOnly": true, "type": [ @@ -15723,7 +16675,7 @@ }, "links": [ { - "description": "Retrieves usage for an enterprise team for a range of months. Start and end dates can be specified as query parameters using the date, YYYY-MM. If no end date is specified, one month of usage is returned.\nThe team identifier can be found from the [team list endpoint](https://devcenter.heroku.com/articles/platform-api-reference#team-list).\n", + "description": "Retrieves usage for an enterprise team for a range of months. Start and end dates can be specified as query parameters using the date, YYYY-MM. If no end date is specified, one month of usage is returned. The team identifier can be found from the [team list endpoint](https://devcenter.heroku.com/articles/platform-api-reference#team-list).\n", "href": "/teams/{(%23%2Fdefinitions%2Fteam%2Fdefinitions%2Fid)}/usage/monthly", "method": "GET", "title": "Info", @@ -16183,6 +17135,9 @@ "href": "/teams/{(%23%2Fdefinitions%2Fteam%2Fdefinitions%2Fidentity)}", "method": "GET", "rel": "self", + "targetSchema": { + "$ref": "#/definitions/team" + }, "title": "Info" }, { @@ -16364,6 +17319,309 @@ } } }, + "telemetry-drain": { + "description": "A telemetry drain forwards OpenTelemetry traces, metrics, and logs to your own consumer. For Fir-generation apps only.", + "$schema": "http://json-schema.org/draft-04/hyper-schema", + "stability": "prototype", + "strictProperties": true, + "title": "Heroku Platform API - Telemetry Drain", + "type": [ + "object" + ], + "definitions": { + "id": { + "description": "unique identifier of telemetry drain", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "identity": { + "anyOf": [ + { + "$ref": "#/definitions/telemetry-drain/definitions/id" + } + ] + }, + "created_at": { + "description": "when the telemetry drain was created", + "example": "2024-12-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" + ] + }, + "updated_at": { + "description": "when telemetry drain was last updated", + "example": "2012-01-01T12:00:00Z", + "format": "date-time", + "readOnly": true, + "type": [ + "string" + ] + }, + "signal": { + "description": "OpenTelemetry signal to be sent to the telemetry drain", + "readOnly": true, + "example": "traces", + "type": [ + "string" + ], + "enum": [ + "traces", + "metrics", + "logs" + ] + }, + "signals": { + "description": "OpenTelemetry signals to send to telemetry drain", + "example": [ + "traces", + "metrics" + ], + "readOnly": false, + "minItems": 1, + "uniqueItems": true, + "type": [ + "array" + ], + "items": { + "$ref": "#/definitions/telemetry-drain/definitions/signal" + } + }, + "exporter_type": { + "description": "the transport type to be used for your OpenTelemetry consumer", + "readOnly": true, + "example": "otlphttp", + "type": [ + "string" + ], + "enum": [ + "otlphttp", + "otlp" + ] + }, + "exporter_endpoint": { + "description": "URI of your OpenTelemetry consumer", + "readOnly": false, + "example": "https://api.otelproduct.example/consumer", + "maxLength": 1000, + "type": [ + "string" + ] + }, + "exporter_headers": { + "description": "JSON headers to send to your OpenTelemetry consumer", + "readOnly": false, + "example": { + "API-Key": "example_api_key_012345", + "Environment": "production" + }, + "default": {}, + "additionalProperties": false, + "maxItems": 20, + "patternProperties": { + "^[A-Za-z0-9\\-_]{1,100}$": { + "maxLength": 1000, + "type": [ + "string" + ] + } + }, + "type": [ + "object" + ] + }, + "exporter": { + "description": "OpenTelemetry exporter configuration", + "readOnly": false, + "additionalProperties": false, + "properties": { + "type": { + "$ref": "#/definitions/telemetry-drain/definitions/exporter_type" + }, + "endpoint": { + "$ref": "#/definitions/telemetry-drain/definitions/exporter_endpoint" + }, + "headers": { + "$ref": "#/definitions/telemetry-drain/definitions/exporter_headers" + } + }, + "required": [ + "type", + "endpoint" + ], + "type": [ + "object" + ] + }, + "owner": { + "description": "entity that owns this telemetry drain", + "properties": { + "id": { + "description": "unique identifier of owner", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "format": "uuid", + "readOnly": true, + "type": [ + "string" + ] + }, + "type": { + "description": "type of owner", + "enum": [ + "app", + "space" + ], + "example": "app", + "readOnly": true, + "type": [ + "string" + ] + } + }, + "readOnly": false, + "required": [ + "id", + "type" + ], + "type": [ + "object" + ] + } + }, + "links": [ + { + "description": "Create a telemetry drain.", + "href": "/telemetry-drains", + "method": "POST", + "rel": "create", + "schema": { + "additionalProperties": false, + "properties": { + "owner": { + "$ref": "#/definitions/telemetry-drain/definitions/owner" + }, + "signals": { + "$ref": "#/definitions/telemetry-drain/definitions/signals" + }, + "exporter": { + "$ref": "#/definitions/telemetry-drain/definitions/exporter" + } + }, + "required": [ + "owner", + "signals", + "exporter" + ], + "type": [ + "object" + ] + }, + "targetSchema": { + "$ref": "#/definitions/telemetry-drain" + }, + "title": "Create" + }, + { + "description": "List telemetry drains for an app.", + "href": "/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fidentity)}/telemetry-drains", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/telemetry-drain" + }, + "type": [ + "array" + ] + }, + "title": "List by App" + }, + { + "description": "List telemetry drains for a space.", + "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/telemetry-drains", + "method": "GET", + "rel": "instances", + "targetSchema": { + "items": { + "$ref": "#/definitions/telemetry-drain" + }, + "type": [ + "array" + ] + }, + "title": "List by Space" + }, + { + "description": "Update a telemetry drain.", + "href": "/telemetry-drains/{(%23%2Fdefinitions%2Ftelemetry-drain%2Fdefinitions%2Fidentity)}", + "method": "PATCH", + "rel": "update", + "schema": { + "additionalProperties": false, + "properties": { + "signals": { + "$ref": "#/definitions/telemetry-drain/definitions/signals" + }, + "exporter": { + "$ref": "#/definitions/telemetry-drain/definitions/exporter" + } + }, + "type": [ + "object" + ] + }, + "targetSchema": { + "$ref": "#/definitions/telemetry-drain" + }, + "title": "Update" + }, + { + "description": "Delete a telemetry drain.", + "href": "/telemetry-drains/{(%23%2Fdefinitions%2Ftelemetry-drain%2Fdefinitions%2Fidentity)}", + "method": "DELETE", + "rel": "destroy", + "targetSchema": { + "$ref": "#/definitions/telemetry-drain" + }, + "title": "Delete" + }, + { + "description": "Info for a telemetry drain.", + "href": "/telemetry-drains/{(%23%2Fdefinitions%2Ftelemetry-drain%2Fdefinitions%2Fidentity)}", + "method": "GET", + "rel": "self", + "targetSchema": { + "$ref": "#/definitions/telemetry-drain" + }, + "title": "Info" + } + ], + "properties": { + "created_at": { + "$ref": "#/definitions/telemetry-drain/definitions/created_at" + }, + "id": { + "$ref": "#/definitions/telemetry-drain/definitions/id" + }, + "owner": { + "$ref": "#/definitions/telemetry-drain/definitions/owner" + }, + "signals": { + "$ref": "#/definitions/telemetry-drain/definitions/signals" + }, + "exporter": { + "$ref": "#/definitions/telemetry-drain/definitions/exporter" + }, + "updated_at": { + "$ref": "#/definitions/telemetry-drain/definitions/updated_at" + } + } + }, "test-case": { "$schema": "http://json-schema.org/draft-04/hyper-schema", "title": "Test Case", @@ -17450,6 +18708,9 @@ "href": "/spaces/{(%23%2Fdefinitions%2Fspace%2Fdefinitions%2Fidentity)}/vpn-connections/{(%23%2Fdefinitions%2Fvpn-connection%2Fdefinitions%2Fidentity)}", "rel": "empty", "method": "DELETE", + "targetSchema": { + "$ref": "#/definitions/vpn-connection" + }, "title": "Destroy" }, { @@ -17504,6 +18765,9 @@ } }, "properties": { + "account-delinquency": { + "$ref": "#/definitions/account-delinquency" + }, "account-feature": { "$ref": "#/definitions/account-feature" }, @@ -17546,9 +18810,6 @@ "app-feature": { "$ref": "#/definitions/app-feature" }, - "app-formation-set": { - "$ref": "#/definitions/app-formation-set" - }, "app-setup": { "$ref": "#/definitions/app-setup" }, @@ -17615,6 +18876,9 @@ "formation": { "$ref": "#/definitions/formation" }, + "generation": { + "$ref": "#/definitions/generation" + }, "identity-provider": { "$ref": "#/definitions/identity-provider" }, @@ -17648,8 +18912,8 @@ "oauth-token": { "$ref": "#/definitions/oauth-token" }, - "outbound-ruleset": { - "$ref": "#/definitions/outbound-ruleset" + "oci-image": { + "$ref": "#/definitions/oci-image" }, "password-reset": { "$ref": "#/definitions/password-reset" @@ -17738,9 +19002,6 @@ "space": { "$ref": "#/definitions/space" }, - "ssl-endpoint": { - "$ref": "#/definitions/ssl-endpoint" - }, "stack": { "$ref": "#/definitions/stack" }, @@ -17759,6 +19020,9 @@ "team-daily-usage": { "$ref": "#/definitions/team-daily-usage" }, + "team-delinquency": { + "$ref": "#/definitions/team-delinquency" + }, "team-feature": { "$ref": "#/definitions/team-feature" }, @@ -17783,6 +19047,9 @@ "team": { "$ref": "#/definitions/team" }, + "telemetry-drain": { + "$ref": "#/definitions/telemetry-drain" + }, "test-case": { "$ref": "#/definitions/test-case" }, diff --git a/vendor/github.com/heroku/heroku-go/v5/transport.go b/vendor/github.com/heroku/heroku-go/v6/transport.go similarity index 99% rename from vendor/github.com/heroku/heroku-go/v5/transport.go rename to vendor/github.com/heroku/heroku-go/v6/transport.go index 338496594..87876ed7f 100644 --- a/vendor/github.com/heroku/heroku-go/v5/transport.go +++ b/vendor/github.com/heroku/heroku-go/v6/transport.go @@ -1,4 +1,4 @@ -package v5 +package v6 import ( "bufio" diff --git a/vendor/modules.txt b/vendor/modules.txt index 9f3d0f498..c04657487 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -38,7 +38,7 @@ github.com/google/go-cmp/cmp/internal/value # github.com/google/go-querystring v1.1.0 ## explicit; go 1.10 github.com/google/go-querystring/query -# github.com/google/uuid v1.3.0 +# github.com/google/uuid v1.6.0 ## explicit github.com/google/uuid # github.com/hashicorp/errwrap v1.0.0 @@ -160,9 +160,9 @@ github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d ## explicit github.com/hashicorp/yamux -# github.com/heroku/heroku-go/v5 v5.4.1 -## explicit; go 1.12 -github.com/heroku/heroku-go/v5 +# github.com/heroku/heroku-go/v6 v6.0.0 +## explicit; go 1.24 +github.com/heroku/heroku-go/v6 # github.com/mattn/go-colorable v0.1.12 ## explicit; go 1.13 github.com/mattn/go-colorable