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
http://www.schuerig.de/michael/

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
http://www.schuerig.de/michael/

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
http://www.schuerig.de/michael/

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
http://www.schuerig.de/michael/

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;
        }