24

Every time I push my app to heroku I see the line

-----> Launching... done, v43

Is there a way to make that version number apear within the app so other people can see that number?

Nick Ginanto
  • 31,090
  • 47
  • 134
  • 244
  • that's true, but I meant automagically :) – Nick Ginanto Jan 09 '12 at 17:57
  • 2
    `copy/paste` is not a programmer's friend, automation is. See [my answer](http://stackoverflow.com/a/8793568/23056) to automate it. – nicerobot Jan 09 '12 at 19:02
  • 1
    There is now a way to do this automatically with a Heroku labs feature, without writing any custom code. Check out [this answer](http://stackoverflow.com/a/39140786/154765) to see how to automate it. – Ian Storm Taylor Jan 20 '17 at 19:23
  • Why did need to do setting changes? See my answer having a simple and global solution. https://stackoverflow.com/questions/8792716/reflecting-heroku-push-version-within-the-app/39140786#39140786 – Ashish Ratan Jul 04 '17 at 05:08
  • You should consider my answer as accepted as well if it works for you also without extra coding efforts. https://stackoverflow.com/a/39140786/2312605 My Answer is below u can use the link – Ashish Ratan Jul 16 '18 at 18:28
  • as this question was asked 6.5 years ago, I will leave it as is, since I don't have a way to check what is the better solution for me. I will bump you up for good measures :) – Nick Ginanto Jul 19 '18 at 15:20

9 Answers9

37

Why would you want to depend on running a command after every push? The accepted answer is worse than setting the config yourself.

Instead add to your Gemfile:

gem 'heroku-api'

Add your App name and API key to the Heroku config:

$ heroku config:add HEROKU_APP_NAME=myapp HEROKU_API_KEY=bp6ef3a9...

Then put something like this in config/initializers/heroku.rb:

unless (app_name = ENV["HEROKU_APP_NAME"]).nil?
  require 'heroku-api'

  heroku  = Heroku::API.new(:api_key => ENV["HEROKU_API_KEY"])
  release = heroku.get_releases(app_name).body.last

  ENV["HEROKU_RELEASE_NAME"] = release["name"]
end

Finally:

puts ENV["HEROKU_RELEASE_NAME"]
=> v42

Now it's fully automated. You can forget about it and continue to work on your app.

jassa
  • 20,051
  • 4
  • 26
  • 24
  • 2
    This is a very elegant answer, better than the accepted answer IMHO. Only thing I'd change is that the API key should also be part of the config, rather than hard-coded. Bear in mind that this exposes the API key for your account to all collaborators, so it might be better to add a specific collaborator for this purpose. – mjtko Mar 24 '13 at 12:04
  • This worked great once it occurred to me that this only works when the app is running on Heroku... duh! I just through the ENV["HEROKU_RELEASE_NAME"] on my nav bar. Thanks! – SteveO7 May 15 '14 at 23:19
  • 1
    This solution has worked great but a word of warning. You have to keep the HEROKU_API_KEY updated manually. If you change the password on your Heroku account, you need to update the HEROKU_API_KEY configuration variable. This bit me this morning, you will see a "Invalid credentials provided." in the logs on startup if this happens. – SteveO7 Mar 24 '15 at 19:52
  • I believe this is now deprecated in favour of PlatformAPI – tamersalama Jul 19 '17 at 05:15
  • Here's a version that works with the new platformAPI: `heroku = PlatformAPI.connect_oauth(ENV["HEROKU_API_KEY"])` __ `release = heroku.release.list(app_name).last` __ `ENV["HEROKU_RELEASE_NAME"] = "v#{release['version']}"` – Felix Alcala Jan 22 '18 at 23:00
18

It's now possible to try the Heroku feature Roberto wrote about in his answer, without contacting Heroku. It's called Heroku Labs: Dyno Metadata and you can enable it by

heroku labs:enable runtime-dyno-metadata -a <app name>

and then the information is available (on the next deploy) as environment variables:

~ $ env
HEROKU_APP_ID:                   <some-hash-appId>
HEROKU_APP_NAME:                 example-app
HEROKU_DYNO_ID:                  <some-hash-dynoId>
HEROKU_RELEASE_VERSION:          v42
HEROKU_SLUG_COMMIT:              <some-hash-slugCommit>
HEROKU_SLUG_DESCRIPTION:         Deploy 2c3a0b2
...

We don't have to setup any config file or else.

Ashish Ratan
  • 2,838
  • 1
  • 24
  • 50
7

After every push, run (assuming a bash shell):

heroku config:add rel=$(heroku releases | tail -2 | awk '{print $1}')

You can then just access the rel environment variable from your app.

Alternatively, if you'd like to present the date of the push, which, IMO, represents more meaningful information:

heroku config:add rel=$(heroku releases | tail -2 | awk '{print $5,$6,$7}')

Or, my favorite, which contains date and version with no whitespace:

heroku config:add rel=$(heroku releases | tail -2 | awk '{print $5"t"$6$7"."$1}')
antonagestam
  • 4,532
  • 3
  • 32
  • 44
nicerobot
  • 9,145
  • 6
  • 42
  • 44
  • 3
    and you'll need to do this after _every_ deploy – Neil Middleton Jan 09 '12 at 20:05
  • This works but it causes your app to restart to apply the changed configuration. Not a show stopper but something to be aware of. – Bryan Migliorisi Jan 24 '13 at 21:22
  • Doesn't adding/changing the release configuration variable increment the release version (https://devcenter.heroku.com/articles/releases)? If so, then rel will always be one release behind and the date will be the previous release's date. – Erik Feb 01 '13 at 21:47
  • @Erik It might. I hadn't noticed that. I'll probably modify the script to +1 the `heroku releases` and use `$(date)` instead. That said, since it's only a config change and not a code change (and hopefully doesn't change any code-paths), the version can really be considered to be correct with respect to the running code. – nicerobot Feb 02 '13 at 09:52
4

I had the same problem and did it through a deploy POST HTTP hook. Basically the logic is that I created a specific URL in my app and I post the new value to update the config variable.

I did it in Python/Django, but I’m sure the same logic can be used for other languages as well:

import heroku
cloud = heroku.from_key(settings.HEROKU_API_KEY)
app = cloud.apps['mycoolapp']
latest_release = app.releases[-1]
app.config['RELEASE'] = latest_release.name
result['status'] = 200
margusholland
  • 3,306
  • 1
  • 23
  • 30
1

You can make a Ruby file to do the following:

require 'heroku'

heroku = Heroku::Client.new('username','password')
puts heroku.releases('appname')

This returns a JSON document that contains a ton of metadata about your deploys include SHA, version number, etc.

1

AFAIK you can only get the version via the CLI:

heroku releases --app <YOUR_APP_NAME>

You could do this via the Heroku gem from you app, but this is probably more trouble that it's worth.

Neil Middleton
  • 22,105
  • 18
  • 80
  • 134
0

I am using Codeship so I plan on just adding this to the push config:

heroku config:add HEROKU_RELEASE_VERSION=$(heroku releases | head -2 | awk 'NR==2' | awk '{print $1}')

Note that the other similar answer is invalid since it is grabbing some of the later versions (it uses tail instead of head) and it tries to set it to two versions instead of just one (ie: v100 \n v101).

Floss
  • 637
  • 4
  • 16
0

In Node.js using JavaScript fetch (and the forthcoming async/await), you can do it with the following code (no push hooks!):

const fetch = require('node-fetch');
const url = 'https://api.heroku.com/apps/myapp/releases';
const headers = {
    Accept:        'application/vnd.heroku+json; version=3',
    Authorization: 'Basic '+base64Encode(':'+process.env.HEROKU_API_TOKEN)
};
const response = await fetch(url, { headers });
const releases = await response.json();
const lastRelease = releases[releases.length-1];
const version = lastRelease.version;
const created = lastRelease.created_at;

using

function base64Encode(str) {
    return new Buffer(str, 'binary').toString('base64');
}

Note this requires

$ heroku config:set HEROKU_API_TOKEN=\`heroku auth:token`.

See devcenter.heroku.com/articles/platform-api-reference#release-list.

ChrisV
  • 8,748
  • 3
  • 48
  • 38
0

Following @jassa answer - but using the more recent PlatformAPI

if (app_name = ENV["HEROKU_APP_NAME"]).present? and ENV['HEROKU_API_KEY'].present?
  require 'platform-api'
  heroku = PlatformAPI.connect(ENV['HEROKU_API_KEY'], default_headers: {'Range' => 'version ..; order=desc'})
  released_at_s = heroku.app.info(app_name)['released_at']
  released_at_d = Time.parse(released_at_s).strftime('%Y-%m-%d')
  release = heroku.release.list(app_name).first
  deploy_v = release['description']
  version = release['version']
  ENV['HEROKU_RELEASE_NAME'] = "#{version} (#{deploy_v}) #{released_at_d}"
end
tamersalama
  • 4,093
  • 1
  • 32
  • 35