Can the runtime of a Heroku app know it's commit id?
Asked Answered
E

2

8

I'd like the runtime of my Heroku app (Play/Scala, running on Heroku Cedar) to be able to report to me which git commit it was built from. Heroku apps are generally built by the slug compiler on Heroku's infrastructure - unfortunately, the slug compiler does this as an early part of this build process:

Remove unused files, including .git directories, .gitmodules files, anything in log and tmp, and anything specified in a top-level .slugignore file.

...so the Git information is no longer available to the sbt-buildinfo plugin I'm using to record the Git commit.

How to record the HEAD commit in the slug? Is there an environment variable available with this information?

Euphroe answered 31/10, 2014 at 9:16 Comment(6)
You could put a post-checkout hook in the repo that logs the id somewhere it won't get erased. To get that automatically when you clone/init, put it in your template repo.Krimmer
@Krimmer I'm not sure I understand - client-side hooks are not copied when you clone a repository, so how would they get on to the slug compiler? git-scm.com/book/en/v2/… ...do you mean something particular by 'template repo', beyond it being the place where the app code resides?Euphroe
templates are a git feature, when you do git init or git clone git copies the initial content from some template directory. The default template has sample hooks in it, for instance. So whatever process is creating those repos the slug compiler is cleaning out, it's also doing a checkout for the contents. Make the repo template that process uses have the checkout hook you want.Krimmer
Heroku always runs the tip of master. If you git pull and then find the top entry in git reflog you will have the commit id.Deflective
Untested but I think you could use the platform-api (devcenter.heroku.com/articles/platform-api-reference) to first get the most recent release from which you can get a slug id. Then get info on the slug from which you can pull the commit-id.Devonadevondra
When I asked this question, sbt-heroku was an (sbt-specific) reasonable answer to my question, but since the introduction of SOURCE_VERSION, the best answer is no longer SBT-specific, and so an existing question applies just as well: https://mcmap.net/q/372025/-access-current-git-commit-number-from-within-heroku-appEuphroe
E
8

Three different options, best first...

SOURCE_VERSION environment variable (build-time)

From 1st April 2015, there's a SOURCE_VERSION environment variable available to builds running on Heroku. For git-push builds, this is the git commit SHA-1 of the source being built:

https://devcenter.heroku.com/changelog-items/630

(thanks to @srtech for pointing that out!)

/etc/heroku/dyno metadata file (run-time)

Heroku have beta functionality to write out a /etc/heroku/dyno metadata file onto your running dyno. If you email support you can probably get added to the beta. Here's a place where Heroku themselves are using it:

https://github.com/heroku/fix/blob/6c8ab7a/lib/heroku_dyno_metadata.rb

The contents look like this:

{
   "dyno":{
      "physical_id":"161bfad9-9e83-40b7-b385-78305db2f168",
      "size":1,
      "name":"run.7145"
   },
   "app":{
      "id":null
   },
   "release":{
      "id":50,
      "commit":"2c3a0b24069af49b3de35b8e8c26765c1dba9ff0",
      "description":null
   }
}

..so release.commit is the field you're after.

SBT-specific: use sbt-heroku to build slug locally

My initial solution was to use the sbt-heroku plugin published by Heroku themselves. This means no longer doing deploys by git push (having the slug compiled on Heroku's own infrastructure), but instead compiling the slug locally and uploading that directly to Heroku. Because the slug is compiled locally, in my work repo, the Git information is all there and the build process can easily identify the commit id and embed it into the app's code.

The slug is substantially larger in size that a Git diff (90MB vs 0.5KB), but apart from that the solution works reasonably well. I'm actually using Travis to do continuous deployment, and so Travis was doing the sbt stage deployHeroku for me (the Git commit id is available in that environment while building), meaning I could git-push from my laptop on the move, and Travis will do the large slug upload to Heroku.

Euphroe answered 8/11, 2014 at 15:43 Comment(2)
For now, that /etc/heroku/dyno file (while still in alpha) can be enabled with heroku labs:enable runtime-dyno-metadata command.Wonderstricken
Also (just noticed), when you enable that parameter then you will also get several pre-filled environment variables, including HEROKU_SLUG_COMMIT which holds full SHA value. As for me, it looks much easier to access than json file.Wonderstricken
I
0

Run a checkout filter (also known as a "smudge") on your code, and embed the HEAD SHA in a configuration file for your app.

Imhoff answered 31/10, 2014 at 9:16 Comment(1)
Similar to @jthill's solution, I think this requires overriding the slug compiler run by Heroku in order to ensure that the 'filter' is present in the cloned repo - from the link in your answer: "You have to be careful, though, because the .gitattributes file is committed and passed around with the project, but the driver (in this case, dater) isn’t, so it won’t work everywhere."Euphroe

© 2022 - 2024 — McMap. All rights reserved.