Search code examples
node.jsbashpostgresqlherokustrapi

how to automatically add the required strapi(postgres) config vars for a heroku pr review app


When deploying strapi on heroku using the postgres add-on, strapi requires individual config vars set for the db connection configuration and not just the DATABASE_URL. I have it setup and it all works fine. The problem is using the review app feature in a heroku pipeline. I cannot set static config vars for all review apps because Heroku provisions a new instance of the postgres add-on everytime a review app is created hence the review app gets a new DATABASE_URL. Im leaning towards using the root app.json file to specify a script that will read in the the auto generated DATABASE_URL config var and split it and set the strapi required config vars. Is that the best and/or only way to do it? what life cycle should the script be a part of? is it going to be a bash script? how would i go about reading and splitting the DATABASE_URL? thanks,


Solution

  • I managed to figure it out... I basically answered it in my actual question.

    -go to account settings and get your HEROKU_API_TOKEN. -add it as a config var to your pipeline. -create an app.json file in the root which inherits the HEROKU_API_TOKEN and HEROKU_APP_NAME config vars. You need it in the script. -set the script you wish to run in the postdeploy event.

    your app.json should have this basic structure:

    {
     "environments": {
        "review": {
          "scripts": {
            "postdeploy": "node ./postdeployReviewapp.js"
          },
          "addons": [
            "heroku-postgresql:hobby-dev"
          ]
        }
      },
      "env":{
        "HEROKU_APP_NAME": {
          "required": true
      },
        "HEROKU_API_TOKEN":{
          "required":true
        }
      }
    }
    

    -Then create the script... your script should read in the auto generated database_url and spilt it to get the individual dbconnection variables. -make a patch request to the heroku platform api config-vars endpoint passing your dbconnection variables in the body.

    your node script should look something like this:

    const https = require('https');
    const url = require('url');
    
    /**
    * eg. DATABASE_URL = postgres://ebitxebvixeeqd:dc59b16dedb3a1eef84d4999sb4baf@ec2-50-37-231-192.compute-2.amazonaws.com: 5432/d516fp1u21ph7b
    * It's read like so: postgres:// USERNAME : PASSWORD @ HOST : PORT : DATABASE_NAME
    */
    let settings = {
        client: 'postgres'
    };
    
    const parsed = url.parse(process.env.DATABASE_URL, true);
    const [username, password] = parsed.auth.split(':');
    
    settings.host = parsed.hostname;
    settings.port = Number(parsed.port);
    settings.database = parsed.pathname.substr(1);
    settings.username = username;
    settings.password = password;
    settings.ssl = (parsed.query.ssl === 'true');
    
    var options = {
        'method': 'PATCH',
        'hostname': 'api.heroku.com',
        'path': '/apps/' + process.env.HEROKU_APP_NAME + '/config-vars',
        'headers': {
            'Content-Type': 'application/json',
            'Accept': 'application/vnd.heroku+json; version=3',
            'Authorization': 'Bearer ' + process.env.HEROKU_API_TOKEN
        }
    };
    
    var req = https.request(options, function (res) {
        var chunks = [];
    
        res.on("data", function (chunk) {
            chunks.push(chunk);
        });
    
        res.on("end", function (chunk) {
            var body = Buffer.concat(chunks);
            console.log(body.toString());
        });
    
        res.on("error", function (error) {
            console.error(error);
        });
    });
    
    var postData = JSON.stringify(
        {
            "DATABASE_USERNAME": settings.username,
            "DATABASE_PASSWORD": settings.password,
            "DATABASE_HOST": settings.host,
            "DATABASE_PORT": settings.port,
            "DATABASE_NAME": settings.database
        });
    
    req.write(postData);
    
    req.end();
    

    your review app should now have new config vars that will be used by strapi to connect to postgres.