8

I have a development branch hosted on Heroku and we have a couple of people using this branch to look for bugs, it would be nice to show the SHA-1 Hash of the commit that's the latest deployed on Heroku so that we know which bugs belong to which commit.

But I cannot at all find any way to find this information. nothing in the ENV variable in heroku run console. Though "heroku releases" does show a list of deployment info, including the first few character of the SHA-1 hash, that leads me to think that Heroku must store it somehwere, but I just cannot find where. Does anyone know?

I realize that I haven't really put down the question as clear as I should: I meant to find the SHA-1 hash inside Rails on Heroku. Like I can do something like this:

<h1><%= ENV['REV']</h1>

Thank You!

Nik So
  • 16,683
  • 21
  • 74
  • 108
  • i have to ask why? You say ` we have a couple of people using this branch to look for bugs` I'm not trying to troll but wonder why you wouldn't branch the bug in dev, upload it for the others to look at and then merge once "approved" or whatever reason you have for them to look at a specific branch in heroku and not on their own dev machines. – pjammer Jun 11 '12 at 02:06
  • no problem at all, I don't think it's trolling -- Perhaps my method is not backed by the optimal thinking, but if they test out the app only on their local machine, I just simply can't sleep well thinking it will work exactly the same way on Heroku. – Nik So Jun 11 '12 at 13:49
  • but that's what a staging environment is for right? How many guys do you have mucking around in the code? I mean, if there is a bug, one guy branches from master, fixes it, updates staging. You approve it. You then merge into master and push to production. All letting you get some sleep. – pjammer Jun 11 '12 at 21:48
  • two, and they don't muck around in the code, only doing surface testing. – Nik So Jun 12 '12 at 02:36
  • related: http://stackoverflow.com/questions/26671073/can-the-runtime-of-a-heroku-app-know-its-commit-id – Roberto Tyley Nov 27 '14 at 09:47

3 Answers3

11

Treat Heroku just like any other remote Git repo - you can use git ls-remote:

git ls-remote heroku

(heroku here being the remote name)

UPDATE:

Since the OP is actually looking to acquire the SHA in the Ruby env, one possible way would be to use a custom buildpack.

To get started, head over to Heroku's Ruby Buildpack and fork it so you can make your own variations. Now clone your fork and take a look at lib/language_pack/ruby.rb. Add a new method, something like:

def get_SHA
    #get SHA
    #save SHA to ENV, ala: ENV['SHA'] = retrieved_sha
end

How you go about getting the SHA is up to you. You could execute a git command and use what's returned:

git log -1 --format="%H"

Or you could use @avaynshtok's advice and use the Heroku gem to use the releases method.

Then, once you have the SHA, set it as an ENV var.

Next, find the compile method in ruby.rb, and add the get_sha method to the end of it:

def compile
    Dir.chdir(build_path)
    install_ruby
    setup_language_pack_environment
    allow_git do
        install_language_pack_gems
        build_bundler
        create_database_yml
        install_binaries
        run_assets_precompile_rake_task
        get_sha #your additional method
    end
end

Push your changes back up to GitHub, and now head over to the command line. You'll need to add a new config var to your Heroku app:

heroku config:add BUILDPACK_URL=git@github.com:<your GitHub username>/heroku-buildpack-ruby.git

Note that you'll need to make sure you've replace <your GitHub username> with...well, your GitHub username, so you are pointing at your forked repo.

Finally, execute one last command that enables a Heroku labs feature that allows the slug compiler access to user vars:

heroku labs:enable user_env_compile

Now you should be all set. So what exactly happens now? Well, when you push to Heroku, Heroku will receive the changes, and then see that you have a custom buildpack url set. So it'll fetch your custom buildpack from GitHub, and then use that to create the slug. That means that once it runs through all of the default compile commands, it'll end with your get_sha method, which should set the ENV var SHA to the appropriate SHA. Now you should have access to that ENV var from within Ruby, to do with what you will.

redhotvengeance
  • 27,446
  • 10
  • 49
  • 54
  • Sorry about my unclear question. I am to find this information inside Rails – Nik So Jun 11 '12 at 00:19
  • Ah, well, that changes things a bit. I don't think there's any built in Heroku functionality for this, but if you are on Cedar then you could fork Ruby/Rails buildpack and set an ENV yourself. – redhotvengeance Jun 11 '12 at 00:42
  • I see. that's too bad, I was really hoping somewhere they would have stored the SHA. I mean, it's retrieved from the "heroku releases" command, that says they've got it *somewhere* ... – Nik So Jun 11 '12 at 00:47
  • Yes, but you're trying to access that info from within your Ruby server, which is running in an isolated slug, not from the repo. So unless Heroku is manually passing that info to the server itself (which I doubt), it wouldn't be there. You could do it yourself, though, by using a custom buildpack and setting an ENV var during the slug compilation. If you like, I can update my answer with more details. – redhotvengeance Jun 11 '12 at 01:04
  • Yes, if it's not too much trouble. From the log screen immediately after "git push heroku", I sense that there are lots going on, I wonder if it is realistic for a noob like me to start my own buildpack. But of course, I will read up on Heroku's dev docs anyway. Meanwhile, if you have a few words of advise, I am all ears – Nik So Jun 11 '12 at 04:19
  • Updated. There's also several links in my updates that point towards buildpack docs, among other things. Let me know if you have any questions. – redhotvengeance Jun 11 '12 at 06:02
  • Wow that's very detailed. Thank you! – Nik So Jun 11 '12 at 13:52
  • Hi ilollar, I have successfully set up the buildpack, but I am having problem getting the hash, because where that git command is run, it is not a git repository. I tried going to the heroku console to run `git log -1 --format="%H"` and it's the same, it just says that it's not a git repo, nor any of the parents. and when I do an `ls`, it lists the rails apps structure, meaning, app gemfile config and so on. any thoughts on how I may get the hash? Should I try the Heroku::Client approach? – Nik So Jun 12 '12 at 15:11
  • Hmm, yes. It looks like the repo is probably isolated from the buildpack environment. Heroku's docs are a bit minimal on this, so sometimes it takes a little guesswork. I'd say try to access the info with the `Heroku::Client` approach @avaynshtok suggested. The downside of that being that you need to store your credentials somewhere, which feels undesirable. I'd probably store them as config vars on the Heroku app to at least keep them out of the code. Or use an API key, which feels better to set as a var than your username/password. – redhotvengeance Jun 12 '12 at 16:02
  • 1
    Alternatively, @avaynstok mentioned deploy hooks - that could be creatively utilized as well. You could set up a simple web api route in your app to receive a POST, and then enable deploy hooks on your app: `heroku addons:add deployhooks:http url=http://yourapp.com/deployhookroute`. When that route receives the POST, it can set that information available for the rest of the app. The only downside here is that a mischievous person could spoof the information, so if this needs to be locked down and secure, this might not be the best option. If you like, I can update my answer with this too. – redhotvengeance Jun 12 '12 at 16:12
  • Yeah Iwas thinking that I really have to do the deploy hook – Nik So Jun 12 '12 at 22:09
  • Running `git ls-remote heroku` doesn't always give you the commit that the production instance is running. It breaks after running a rollback. After running `heroku releases:rollback v42`, the output of `git ls-remote heroku` remains the same as before the rollback, even though that is not the current commit in production on Heroku. – Flimm Mar 04 '22 at 08:12
3

You can get release info using the Heroku gem: https://github.com/heroku/heroku

c = Heroku::Client.new <LOGIN>, <PASSWORD>
c.releases(<APPNAME>).last['commit']

Alternatively, you can authenticate using your API key:

c = Heroku::Client.new '', <API_KEY>

The downside is that you'll need to store a login/password combo (or API key) somewhere (either in your app or Heroku env).

You can also use deploy hooks to get this info: https://devcenter.heroku.com/articles/deploy-hooks

avaynshtok
  • 2,519
  • 1
  • 16
  • 14
  • Both the hooks and the client look promising, I am going with the buildpack as it seems much less strenuous to build than I previously thought, and it seems like having the ENV variable avoids having to call up the Heroku client each time one wants to look at the SHA (which I intend to put on everypage like a stamp). Though the deployment hook will eliminate this by storing it in some database table. So if the buildpack doens't work, I might have to resort to this. Thank You Avaynshtok – Nik So Jun 11 '12 at 13:55
1

I ended up using the Heroku platform API gem for this. It's a big long winded, but is memoized, so you'll only need to do this once per deploy, and saves messing around with custom buildpacks (fiddly) and deploy hooks (insecure):

def current_sha
  @current_sha ||= begin
    heroku = PlatformAPI.connect_oauth(ENV['HEROKU_TOKEN'])
    slug_id = heroku.release.list(ENV['HEROKU_APP']).last["slug"]["id"]
    heroku.slug.info(ENV['HEROKU_APP'], slug_id)["commit"]
  end
end
Pezholio
  • 2,439
  • 5
  • 27
  • 41
  • That's a great suggestion indeed. I found Heroku's HTTP deployment hooks to be occasionally flakey. – Nik So Nov 28 '14 at 11:35
  • This is not giving me the correct commit. It returns a short sha, but I'm not sure what it is, and it does not update upon repeated calls. Where is the "last" method defined for the release list? – justingordon Dec 09 '14 at 03:33
  • The problem is that this only works if you have less than 200 git commits! https://discussion.heroku.com/t/can-a-custom-buildpack-put-the-current-git-commit-sha-into-apps-env/932. After 200, you get the same release every time! Must be some way ask for the last release more effectively. – justingordon Dec 09 '14 at 04:29