Deployment: adding git tag as HTML meta tag

I'd like to be able to see from generated pages which version of the app has generated it. As we're using git and always deploy a specific tag, having that tag in the HTML head as a meta tag would be suitable.

My current idea goes like this. The layout includes a partial that looks like this

  <meta name="version"    content="<%= `git describe --tags --always --dirty`.chomp %>">

When deployed, this file is overwritten with a static one referring to the deployed git tag

  <meta name="version" content="v1.1.42">

Then, in the capistrano recipe,

  after "deploy:update_code", "deploy:freeze_version_partial"

  namespace :deploy do     task :freeze_version_partial do       put %{<meta name="version" content="#{tag}" />\n},         File.join(current_release,          'app/views/layouts/_version.html.erb'),        :roles => :web     end   end

Deployment then requires a tag to be given

  $ cap -S tag=v1.1.42 deploy

Are there reasons not to do this or not to do it this way? I don't think there is a security problem of exposing to many details about the app as it is only for internal use.

Michael

Michael Schuerig wrote:

I'd like to be able to see from generated pages which version of the app has generated it. As we're using git and always deploy a specific tag, having that tag in the HTML head as a meta tag would be suitable.

My current idea goes like this. The layout includes a partial that looks like this

  <meta name="version"    content="<%= `git describe --tags --always --dirty`.chomp %>">

When deployed, this file is overwritten with a static one referring to the deployed git tag

  <meta name="version" content="v1.1.42">

Then, in the capistrano recipe,

  after "deploy:update_code", "deploy:freeze_version_partial"

  namespace :deploy do     task :freeze_version_partial do       put %{<meta name="version" content="#{tag}" />\n},         File.join(current_release,          'app/views/layouts/_version.html.erb'),        :roles => :web     end   end

Deployment then requires a tag to be given

  $ cap -S tag=v1.1.42 deploy

Are there reasons not to do this or not to do it this way? I don't think there is a security problem of exposing to many details about the app as it is only for internal use.

Michael

-- Michael Schuerig mailto:michael@schuerig.de Michael Schürig | Sentenced to making sense

I don't see where security would be an issue here, but reusability may be. A more generic "VERSION" file that can be loaded and read from would be available anywhere in your application, and could be simpler to maintain. You could do it as a plaintext file that just reads '1.1.42', or namespace it as MyApp::VERSION etc.

You could add a post-commit hook that would write to the VERSION file, make sure that you bump the version when you tag, or put your git call right into the file. Automating this would prevent your deploy from failing if you forget to state the tag as well.

Of course you don't have to do any of these things, just some ways I see to remove human error and streamline things for you guys.

Michael Schuerig wrote: > I'd like to be able to see from generated pages which version of > the app has generated it. As we're using git and always deploy a > specific tag, having that tag in the HTML head as a meta tag would > be suitable. > > My current idea goes like this. The layout includes a partial that > looks like this > > <meta name="version" >
> content="<%= `git describe --tags --always --dirty`.chomp %>"> > > When deployed, this file is overwritten with a static one referring > to the deployed git tag > > <meta name="version" content="v1.1.42"> >

[capistrano recipe for writing the version snipped]

I don't see where security would be an issue here, but reusability may be. A more generic "VERSION" file that can be loaded and read from would be available anywhere in your application, and could be simpler to maintain. You could do it as a plaintext file that just reads '1.1.42', or namespace it as MyApp::VERSION etc.

I didn't explain why I want this version number to begin with. I don't need the version anywhere in the app. The whole point is to identify the version of the app that has generated a page. So, if I get a bug report from a tester or user, I can tell them to attach the offending page to the bug report and from that I can find out what version they were using.

Michael

Michael Schuerig wrote: [...]

I didn't explain why I want this version number to begin with. I don't need the version anywhere in the app. The whole point is to identify the version of the app that has generated a page. So, if I get a bug report from a tester or user, I can tell them to attach the offending page to the bug report and from that I can find out what version they were using.

Then, instead of a meta tag, why not just put it in a hidden (or smallish) div in the HTML?

And I think Parker may have the right idea. It seems reasonable to read this from a VERSION file that's updated by Git or Cap.

Michael

Best,

Michael Schuerig wrote:

I don't see where security would be an issue here, but reusability may be. A more generic "VERSION" file that can be loaded and read from would be available anywhere in your application, and could be simpler to maintain. You could do it as a plaintext file that just reads '1.1.42', or namespace it as MyApp::VERSION etc.

I didn't explain why I want this version number to begin with. I don't need the version anywhere in the app. The whole point is to identify the version of the app that has generated a page. So, if I get a bug report from a tester or user, I can tell them to attach the offending page to the bug report and from that I can find out what version they were using.

Michael

Really the idea was that you would remove writing markup as part of your deploy recipe, and more importantly than that you'd automate syncing the VERSION with git.

With this method:

1. You have less to remember 2. A more orthogonal use of your deploy and layout 3. Can't ever have the incorrect tag in your layout

Michael Schuerig wrote: [...]

> I didn't explain why I want this version number to begin with. I > don't need the version anywhere in the app. The whole point is to > identify the version of the app that has generated a page. So, if > I get a bug report from a tester or user, I can tell them to > attach the offending page to the bug report and from that I can > find out what version they were using.

Then, instead of a meta tag, why not just put it in a hidden (or smallish) div in the HTML?

Why? I don't see what I would gain. I may need to mention that I'm not actually overwriting a file. The partial containing the explicit call to git is contained in an engine common to several applications. The partial I write that's containing the deployed version is in the app itself and therefore earlier in the path.

And I think Parker may have the right idea. It seems reasonable to read this from a VERSION file that's updated by Git or Cap.

That doesn't explain why that approach is better than what I'm currently doing. Yes, it does seem reasonable, but is my current approach unreasonable?

Michael

Michael Schuerig wrote: >> I don't see where security would be an issue here, but reusability >> may be. A more generic "VERSION" file that can be loaded and read >> from would be available anywhere in your application, and could be >> simpler to maintain. You could do it as a plaintext file that just >> reads '1.1.42', or namespace it as MyApp::VERSION etc. > > I didn't explain why I want this version number to begin with. I > don't need the version anywhere in the app. The whole point is to > identify the version of the app that has generated a page. So, if > I get a bug report from a tester or user, I can tell them to > attach the offending page to the bug report and from that I can > find out what version they were using. > > Michael

Really the idea was that you would remove writing markup as part of your deploy recipe, and more importantly than that you'd automate syncing the VERSION with git.

With this method:

1. You have less to remember

I don't follow. What do I have to remember with my current method?

2. A more orthogonal use of your deploy and layout

There I don't feel any guilt.

3. Can't ever have the incorrect tag in your layout

That's the same for both approaches, isn't it? When I deploy a tag, that tag is used to access the git repo and it is written to the partial.

Michael

Michael Schuerig wrote:

Then, instead of a meta tag, why not just put it in a hidden (or smallish) div in the HTML?

Why? I don't see what I would gain.

If it's not hidden, the user can actually *see* the build number rather than having to send you the HTML source. (This is the approach we use here at work.)

Besides, <meta name="version"> is meant for the version of the *document*, not the version of the *application* that built it, isn't it?

I may need to mention that I'm not actually overwriting a file. The partial containing the explicit call to git is contained in an engine common to several applications. The partial I write that's containing the deployed version is in the app itself and therefore earlier in the path.

But you *are* overwriting a file. Your initial post with your Cap recipe says that you're doing just that.

And I think Parker may have the right idea. It seems reasonable to read this from a VERSION file that's updated by Git or Cap.

That doesn't explain why that approach is better than what I'm currently doing. Yes, it does seem reasonable, but is my current approach unreasonable?

I think it is. It seems extremely hackish. The build number is an application-wide constant, so it should be defined as a Ruby constant (so that the app can be aware of it) instead of just hacked into an ERb partial.

In other words, the same code that now writes <meta name="version" content="#{tag}"> in your partial should probably be changed to write VERSION=#{tag} in some initializer file. Then the partial can just read VERSION -- and so can anything else that needs to know the build number.

Michael

-- Michael Schuerig mailto:michael@schuerig.de Michael Schürig | Sentenced to making sense

Best,

Parker Selbert wrote: [...]

Really the idea was that you would remove writing markup as part of your deploy recipe,

I agree with this too. If your deploy recipe is writing markup, something is very, very wrong. If you just set a constant VERSION with your deploy recipe, then you won't have your deploy recipe reaching so far into your app code.

In other words: a properly written deploy recipe can set configuration values, but should not otherwise change your app. That implies that it can touch initializers and config files, but should not touch anything in Rails.root/app . Otherwise, you're setting yourself up for weird maintenance problems, I think.

Best,

One more thing...

Michael Schuerig wrote: [...]

3. Can't ever have the incorrect tag in your layout

That's the same for both approaches, isn't it? When I deploy a tag, that tag is used to access the git repo and it is written to the partial.

I think Parker was referring to the fact that you can't ever have the wrong *HTML* tag, not Git tag, if you don't have your recipe messing with your layout.

Michael

-- Michael Schuerig mailto:michael@schuerig.de Michael Schürig | Sentenced to making sense

Best,

Michael Schuerig wrote: >> Then, instead of a meta tag, why not just put it in a hidden (or >> smallish) div in the HTML? > > Why? I don't see what I would gain.

If it's not hidden, the user can actually *see* the build number rather than having to send you the HTML source. (This is the approach we use here at work.)

No way, I'm constrained by the visual design people.

Besides, <meta name="version"> is meant for the version of the *document*, not the version of the *application* that built it, isn't it?

It's no big deal changing "version" to "app-version".

> I may need to mention that I'm not > actually overwriting a file. The partial containing the explicit > call to git is contained in an engine common to several > applications. The partial I write that's containing the deployed > version is in the app itself and therefore earlier in the path.

But you *are* overwriting a file. Your initial post with your Cap recipe says that you're doing just that.

Trust me, I'm not overwriting anything. Yes, I wrote so originally, but that was only for easier explanation. When I had to go into the details, I clarified that I'm not overwriting, but rather overriding.

>> And I think Parker may have the right idea. It seems reasonable >> to read this from a VERSION file that's updated by Git or Cap. > > That doesn't explain why that approach is better than what I'm > currently doing. Yes, it does seem reasonable, but is my current > approach unreasonable?

I think it is. It seems extremely hackish. The build number is an application-wide constant, so it should be defined as a Ruby constant (so that the app can be aware of it) instead of just hacked into an ERb partial.

In other words, the same code that now writes <meta name="version" content="#{tag}"> in your partial should probably be changed to write VERSION=#{tag} in some initializer file. Then the partial can just read VERSION -- and so can anything else that needs to know the build number.

I don't like that. I need to write that file in my development environment, possibly using a git post-commit hook. When there are uncomitted changes, the version I get is outdated. Using

  `git describe --tags --always --dirty`

in a partial, I get an indication that I'm looking at a page generated from an uncommitted version.

Here are the desiderata:

* The shown version has to be current, not just the last commit. * In production, no VERSION file is re-read for each request.

During deployment * The version is frozen to the deployed tag. * No markup is written. * No file is overwritten.

Capistrano already writes a REVISION file containing the commit sha1. Let's assume there's a TAG file, too. Then an initializer like this would do the job

if Rails.env.production?   version = File.read('TAG').strip else   version = `git describe --tags --always --dirty`.chomp end Rails.application.config.version = version

Michael

Michael Schuerig wrote: [...]

If it's not hidden, the user can actually *see* the build number rather than having to send you the HTML source. (This is the approach we use here at work.)

No way, I'm constrained by the visual design people.

They won't let you put it somewhere inconspicuous? Oy.

Besides, <meta name="version"> is meant for the version of the *document*, not the version of the *application* that built it, isn't it?

It's no big deal changing "version" to "app-version".

True.

> I may need to mention that I'm not > actually overwriting a file. The partial containing the explicit > call to git is contained in an engine common to several > applications. The partial I write that's containing the deployed > version is in the app itself and therefore earlier in the path.

But you *are* overwriting a file. Your initial post with your Cap recipe says that you're doing just that.

Trust me, I'm not overwriting anything. Yes, I wrote so originally, but that was only for easier explanation. When I had to go into the details, I clarified that I'm not overwriting, but rather overriding.

What's the difference? What are you *actually* doing? Your Cap recipe that you posted pretty clearly overwrites a file. Is that not your actual recipe?

In other words, the same code that now writes <meta name="version" content="#{tag}"> in your partial should probably be changed to write VERSION=#{tag} in some initializer file. Then the partial can just read VERSION -- and so can anything else that needs to know the build number.

I don't like that.

Why not?

I need to write that file in my development environment, possibly using a git post-commit hook.

Why? It should probably be written in the production environment as part of the post-deploy process.

[...]

Here are the desiderata:

* The shown version has to be current, not just the last commit.

What do you mean? The version *is* the last commit, unless I totally misunderstand.

* In production, no VERSION file is re-read for each request.

Right now, you're potentially rereading your partial for each request. A VERSION initializer such as I have suggested would load the constant in memory once at app startup and never read it again.

During deployment * The version is frozen to the deployed tag. * No markup is written. * No file is overwritten.

Capistrano already writes a REVISION file containing the commit sha1. Let's assume there's a TAG file, too. Then an initializer like this would do the job

if Rails.env.production?   version = File.read('TAG').strip else   version = `git describe --tags --always --dirty`.chomp end Rails.application.config.version = version

This looks to me like just about exactly what I have been suggesting. Why do you like this and not my suggestions? What are the differences as you see them?

Michael

-- Michael Schuerig mailto:michael@schuerig.de Michael Schürig | Sentenced to making sense

Best,

Michael Schuerig wrote:

Capistrano already writes a REVISION file containing the commit sha1. Let's assume there's a TAG file, too. Then an initializer like this would do the job

if Rails.env.production?   version = File.read('TAG').strip else   version = `git describe --tags --always --dirty`.chomp end Rails.application.config.version = version

That achieves precisely what I was saying, except uses 'TAG' instead of 'VERSION'. The version is simple to locate, and can be used anywhere it is needed.

Michael Schuerig wrote: [...]

> Trust me, I'm not overwriting anything. Yes, I wrote so originally, > but that was only for easier explanation. When I had to go into > the details, I clarified that I'm not overwriting, but rather > overriding.

What's the difference? What are you *actually* doing? Your Cap recipe that you posted pretty clearly overwrites a file. Is that not your actual recipe?

I would be overwriting a file if there was one to begin with. There isn't one.

> Here are the desiderata: > > * The shown version has to be current, not just the last commit.

What do you mean? The version *is* the last commit, unless I totally misunderstand.

> * In production, no VERSION file is re-read for each request.

No, in development the version is *not* the last commit, but what happens to be in my directory. I want that to be reflected in the version.

> During deployment > * The version is frozen to the deployed tag. > * No markup is written. > * No file is overwritten. > > Capistrano already writes a REVISION file containing the commit > sha1. Let's assume there's a TAG file, too. Then an initializer > like this would do the job > > if Rails.env.production? > > version = File.read('TAG').strip > > else > > version = `git describe --tags --always --dirty`.chomp > > end > Rails.application.config.version = version

This looks to me like just about exactly what I have been suggesting. Why do you like this and not my suggestions? What are the differences as you see them?

I don't need a commit hook and I get a dirty indication in development. Something like "60a5c37-dirty".

Michael

Despite my advanced age I may still be able to learn -- and accept advice.

Michael

This works well for me in a multi-stage environment so users can take a screenshot of the bug and then post it to the bug tracker and I can see straight away what version they are testing on. First four characters of the commit is enough in all probability.

OP: http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/53be9640c1a16faa/aa0c607502b3a059?hl=en&lnk=gst&q=owain#aa0c607502b3a059

but in summary:

/app/config/initializers/revision.rb filename = File.expand_path('REVISION', RAILS_ROOT) REVISION = File.exist?(filename) ? File.read(filename) : `cd #{RAILS_ROOT} && git rev-parse HEAD`.strip

/app/views/layout/application.html.erb <%- unless production? %>   <p id='revision'><%= "#{REVISION[0..3]} #{Time.now.to_s(:db)} "%></

<%- end -%>

/app/helpers/application_helper.rb   def production?       @is_production ||=(ENV['RAILS_ENV']=='production')   end

/public/stylesheets/content.css         #revision {                 color: gray;                 position: absolute;                 z-index: 9;                 top: 10px;                 left: 0px;         }