Heroku CI with Postgres postgis extension - heroku

I'm using a postgis extension to my database on Heroku. In production this works just fine; I'm mapping like a boss.
But, I can't get my app to build on HerokuCI because the database addon in the test environment doesn't have GDAL installed (part of the postgis extension):
django.core.exceptions.ImproperlyConfigured: Could not find the GDAL library (tried "gdal", "GDAL", "gdal2.3.0", "gdal2.2.0", "gdal2.1.0", "gdal2.0.0", "gdal1.11.0"). Is GDAL installed? If it is, try setting GDAL_LIBRARY_PATH in your settings.
-----> test command `python manage.py migrate --noinput && python manage.py test` failed with exit status 1
I can't find out how to create extensions in the heroku CI environment. Heroku's app json schema say nothing about how to create extensions on the test databases.
I know that I can't use in-dyno database for CI, as postgis is not an available extension for that, but I'm not using an in-dyno one, I'm using a plan...
Here's my app schema:
{
"name": "mymegaapp",
"scripts": {
"heroku-prebuild": "create extension postgis",
"heroku-postbuild": "echo heroku-postbuild script runs here."
},
"env": {
},
"formation": {
},
"addons": [
],
"buildpacks": [
{
"url": "heroku/python"
},
{
"url": "heroku/nodejs"
}
],
"environments": {
"test": {
"scripts": {
"test": "python manage.py migrate --noinput && python manage.py test"
},
"env": {
"DJANGO_DEBUG": "1"
},
"addons":[
{
"plan": "heroku-postgresql",
"options": {
"version": "11"
}
},
"heroku-redis:hobby-dev"
]
}
}
}
Note that I've tried to create the postgis extension in the prebuild script, which doesn't make a difference.
I've also tried invoking the creation before the test script:
"scripts": {
"test": "heroku create extension postgis && python manage.py migrate --noinput && python manage.py test"
},
which doesn't work because the heroku cli isn't installed in the dyno.
The key questions:
How can I create extensions in HerokuCI?
Is postgis an allowable extension at all in HerokuCI?

You've almost got it. There's no first class support for creating pg extensions directly from the CLI. However, you can pass a statement into psql.
Try this in your postdeploy or test setup script:
psql -c "create extension postgis" $DATABASE_URL As you're aware, you'll need to do this with a real database, not in-dyno. If you've attached the database as something other than DATABASE_URL, you will need to update that in the script.
[Edit by OP to add useful info] In this case, GDAL libraries will also be needed, which can be installed by setting the BUILD_WITH_GEO_LIBRARIES environment variable to 1. The final working solution in app.json will be:
"environments": {
"test": {
"scripts": {
"postdeploy": "psql -c \"create extension postgis\" $DATABASE_URL",
"test": "python manage.py migrate --noinput && python manage.py test"
},
"env": {
"DJANGO_DEBUG": "1",
"BUILD_WITH_GEO_LIBRARIES": "1"
},
"addons":[
{
"plan": "heroku-postgresql",
"options": {
"version": "11"
}
}
]
}
}

Here a 2021 update as the setting BUILD_WITH_GEO_LIBRARIES is now deprecated and unsupported by Heroku:
This app.json worked for my CI setup with Django / Heroku:
{
"buildpacks": [
{
"url": "https://github.com/heroku/heroku-geo-buildpack.git"
},
{
"url": "heroku/python"
}
],
"environments": {
"test": {
"scripts": {
"test": "python3 manage.py migrate --noinput && python3 manage.py test --keepdb"
},
"env": {
"DJANGO_DEBUG": "1"
}
}
}
}

Related

Does post-deploy run only on review apps in Heroku?

The documentation on Review Apps in Heroku says:
The app.json file has a scripts section that lets you specify a postdeploy command. Use this to run any one-time setup tasks that make the app, and any databases, ready and useful for testing
Does that mean it never runs on production? what about staging? Does it run on production if I create a new production app from scratch?
I'm trying to find out how to generate sample data for my review apps, a post-deploy hook that seems to apply to my whole pipeline, and not just review apps, feels like the wrong place.
It was as easy as specifying it in environments -> review, like this:
{
"env": {
"RAILS_MASTER_KEY": {
"description": "Rails master encryption key.",
"required": true,
"generator": "secret"
},
},
"formation": {
"web": {
"quantity": 1,
"size": "hobby"
},
"worker": {
"quantity": 1,
"size": "hobby"
}
},
"addons": [
{
"plan": "heroku-postgresql"
}
],
"environments": {
"review": {
"scripts": {
"postdeploy": "bundle exec rails db:seed"
}
}
}
}

Heroku Pipelines: You need to have the deploy or operate permission on this app

I've inherited an app hosted on Heroku which uses review apps. Right up until the day before I took over responsibility for the system, the review apps were working absolutely fine, pulling in the branch, building it, then using a postdeploy command to pull in a database backup from the staging server.
Then I started, and all of a sudden, it's not working. I don't know if this is related to something I've done (which at this point is very little), or maybe an actual permissions issue (I've been set-up as an admin on everything, although the other developers, who this was working for before, are also unable to complete it) but the final step of pulling in the database is failing:
I'm at a complete loss as to what's going wrong here.
Below is the app.json file being used, and the $HEROKU_DATABASE_RESTORE is set to clixifix-staging-eu::b530 (which is the staging server::backup file).
{
"buildpacks": [
{ "url": "heroku/nodejs" },
{ "url": "heroku/ruby" },
{ "url": "heroku-community/nginx" }
],
"environments": {
"review": {
"addons": [
{
"plan": "heroku-postgresql:hobby-basic",
"options": {
"version": "9.6"
}
},
{ "plan": "memcachedcloud:30" },
{ "plan": "mailtrap:unpaid" }
],
"buildpacks": [
{ "url": "heroku/nodejs" },
{ "url": "heroku/ruby" },
{ "url": "heroku-community/nginx" },
{ "url": "heroku-community/cli" }
],
"env": {
"SECRET_KEY_BASE": {
"generator": "secret"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "hobby"
},
"generalworker": {
"quantity": 1,
"size": "hobby"
},
"reportworker": {
"quantity": 1,
"size": "hobby"
}
},
"scripts": {
"postdeploy": "heroku pg:backups:restore $HEROKU_DATABASE_RESTORE DATABASE_URL -a $HEROKU_APP_NAME --confirm $HEROKU_APP_NAME"
}
}
}
}
I reached out to Heroku, who gave me the answer I needed:
What the issue is most likely for the error in the postdeploy, is that to run:
heroku pg:backups:restore $HEROKU_DATABASE_RESTORE DATABASE_URL -a $HEROKU_APP_NAME --confirm $HEROKU_APP_NAME
You will need a platform API key stored somewhere withing your pipeline review app config vars so the CLI can log in. The user who this API key belongs to has most likely lost access to your team and doesn't have permissions to access your review apps. You should generate a new API key using heroku authorizations:create and update it on your pipeline.
Basically, when the old guy left, his permissions were revoked, causing the error. I generated a new key using the command above, set the token as the HEROKU_API_KEY value within the envars in the review app settings, and it worked.

Specify Postgres database plan in Heroku review apps

I am trying to use Heroku review apps for testing and demonstrating my site to my colleagues. The site has a large database that will not function with Heroku's free hobby-dev databases.
I am trying to use the app.json manifest file to specify the platform of my app, as per the guide. The code I'm using is below:
app.json
{
"name": "SiteName",
"description": "The website for SiteName",
"keywords": [
"mezzanine",
"django"
],
"image": "heroku/python",
"env": {
"EMAIL_SYSTEM": {
"description": "The email system to use, either console or mailgun",
"value": "mailgun"
},
"ENVIRONMENT": {
"description": "The dev environment, either production or test",
"value": "production"
},
"ALLOWED_HOSTS": {
"description": "Comma-separated list of hosts",
"value": ".herokuapp.com"
},
"DEFAULT_FROM_EMAIL": "noreply#example.com",
"SECRET_KEY": {
"description": "A secret key for verifying the integrity of signed cookies.",
"generator": "secret"
},
"WEB_CONCURRENCY": {
"description": "The number of processes to run.",
"value": "5"
},
"NODE_ENV": "production",
"DEBUG": "False",
"NPM_CONFIG_PRODUCTION": "false",
"CELERY_REDIS_MAX_CONNECTIONS": 3,
"S3_BUCKET": "my-s3-bucket",
"USE_CELERY_TASKS": "True"
},
"formation": {
"web": {
"quantity": 1,
"size": "Standard-1X"
},
"worker": {
"quantity": 1,
"size": "Standard-1X"
}
},
"addons": [
"heroku-redis",
{
"plan": "heroku-postgresql:standard-0",
"as": "DATABASE"
}
],
"buildpacks": [
{
"url": "https://github.com/heroku/heroku-buildpack-python.git"
}
],
"scripts": {
"postdeploy": "python manage.py migrate && python manage.py populate_db"
},
"environments": {
"test": {
"addons": [
"heroku-postgresql:in-dyno",
"heroku-redis:in-dyno"
],
"env": {
"APP_SKIP_DB_TEARDOWN": "True",
"DB_REQUIRE_SSL": "False",
"DEBUG": "True",
"S3_BUCKET": "my-s3-bucket",
"USE_CELERY_TASKS": "False"
},
"scripts": {
"test-setup": "python manage.py collectstatic --noinput",
"test": "python manage.py test"
}
}
}
}
This will build OK, but how can I explicitly specify the database plan I wish to use?
In case anyone else runs into this.
According to heroku support they have changed how they provision addons for review and CI apps to mean that by default they'll only provision the free / cheapest plan, regardless of what is in your app.json Here are some details and explanation of their reasoning
They can override this at an account level if you open a ticket (at time of writing this doesn't seem to be built into their admin area)
You just need to specify the plan using the sintax:
heroku-postgresql:<plan_you_select>
"addons": [
{
"plan": "heroku-postgresql:<plan_you_select>",
"as": "DATABASE"
}
]
For a list of the available plans, checkout this link:
https://devcenter.heroku.com/articles/heroku-postgres-plans#hobby-tier
You can also use this link: https://elements.heroku.com/addons/heroku-postgresql
Select a plan on it, and you'll see the plan name on the CLI
If you don't/can't open a ticket like Pete's answer suggests, here's some bash code I just wrote to upgrade my Postgres DB. It's complicated since:
Heroku always starts review apps with a hobby db, ignoring app.json and other settings
heroku pg:upgrade only works on non-hobby dbs
after creating a new db there's no simple way to learn its ALL_CAPS name for use in later commands
# there's no easy way to grab the DATABASE_NAME so we have to grep the output here :-(
# see https://devcenter.heroku.com/articles/upgrading-heroku-postgres-databases
# and https://help.heroku.com/SY28FR6H/why-aren-t-i-seeing-the-add-on-plan-specified-in-my-app-json-in-my-review-or-ci-app
echo
echo "Upgrading Postgres."
heroku maintenance:on --app $app
addon_name=`heroku addons:create heroku-postgresql:standard-0 --app $app | grep "is being created" | awk '{print $1}'`
db_name=`heroku addons:info $addon_name --app $app | grep "Attachments" | awk -F :: '{print $2}'`_URL
echo $app $addon_name $db_name
heroku pg:wait --app $app
heroku pg:copy DATABASE_URL $db_name --app $app --confirm $app
heroku addons:destroy $addon_name --app $app --confirm $app
heroku pg:promote $db_name --app $app
heroku maintenance:off --app $app

Heroku Review App Cannot find Database

I have a Django app, which uses a postgres database hosted on heroku. I'm trying to create a review app based on this Django app. However, I can't seem to access my DB on the review app. I've added a postdeploy script as shown in the app.json below but it doesn't seem to solve it:
{
"name": "bookapp",
"scripts": {
"postdeploy": "pg_dump $DATABASE_URL | psql $DATABASE_URL && python
./manage.py migrate"
},
"env": {
"DATABASE_URL": {
"required": true
},
"QV_CLOUDINARY_API_KEY": {
"required": true
},
"QV_CLOUDINARY_API_SECRET": {
"required": true
},
"QV_CLOUDINARY_CLOUD_NAME": {
"required": true
},
"QV_DATABASE_NAME": {
"required": true
},
"QV_DATABASE_PASSWORD": {
"required": true
},
"QV_DATABASE_USER": {
"required": true
},
"QV_SECRET_KEY": {
"required": true
}
},
"formation": {
"web": {
"quantity": 1
}
},
"addons": [
"heroku-postgresql"
],
"buildpacks": [
{
"url": "heroku/python"
}
]
}
Found the solution!.
The app.json file above is correct. Apparently the post-deploy script only runs the first time the app is created. I had to close the Pull Request for the review app and re-open a new one so that a new review app is created. Doing that executed the post-deploy script and i was able to access my DB.

How to set a .rc file conditionally

I am using babel and have a .babelrc file for its configuration:
{
"stage": 0,
"ignore": [
"node_modules",
"bower_components",
"testing",
"test"
]
}
However, when I'm developing locally, having this .babelrc file disallows me from running Babel's CLI babel-node in the testing folder (see: babel-node no longer working in different directory )
That said, when I push to Heroku, I need this configuration because I need to make sure the testing folder isn't compiled.
How can I conditionally set a .babelrc file that doesn't involve me having to remember to switch it back to the production version everytime I want to push to Heroku?
You can set conditional things using the env option in your .babelrc
from their docs:
{
"stage": 0,
"env": {
"development": {
"ignore": [
"node_modules",
"bower_components",
"testing",
"test"
]
}
}
}
Then, in your package.json
"scripts": {
"start": "NODE_ENV=production node index.js",
"dev": "NODE_ENV=development node index.js"
}
it checks BABEL_ENV, then NODE_ENV

Resources