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

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

Then, in the capistrano recipe,

after “deploy:update_code”, “deploy:freeze_version_partial”

namespace :deploy do
task :freeze_version_partial do
put %{\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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Michael S. 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

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

Then, in the capistrano recipe,

after “deploy:update_code”, “deploy:freeze_version_partial”

namespace :deploy do
task :freeze_version_partial do
put %{\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 S.
mailto:[email protected]
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.

On Tuesday 10 August 2010, Parker S. wrote:

content="<%= git describe --tags --always --dirty.chomp %>">

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

[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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Michael S. 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,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Michael S. 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

On Tuesday 10 August 2010, Marnen Laibow-Koser 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. 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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Michael S. wrote:

On Tuesday 10 August 2010, Marnen Laibow-Koser 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, 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 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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Parker S. 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,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Tuesday 10 August 2010, Parker S. wrote:

I get a bug report from a tester or user, I can tell them to

  1. You have less to remember

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

  1. A more orthogonal use of your deploy and layout

There I don’t feel any guilt.

  1. 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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

One more thing…

Michael S. wrote:

On Tuesday 10 August 2010, Parker S. wrote:
[…]

  1. 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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Tuesday 10 August 2010, Marnen Laibow-Koser wrote:

Michael S. wrote:

On Tuesday 10 August 2010, Marnen Laibow-Koser 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, 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.

ERb partial.

In other words, the same code that now writes 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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Michael S. 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, 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 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 S.
mailto:[email protected]
http://www.schuerig.de/michael/

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Michael S. 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.

On Tuesday 10 August 2010, Marnen Laibow-Koser wrote:

Michael S. 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.

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


Michael S.
mailto:[email protected]
http://www.schuerig.de/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? %>

<%= "#{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;
}

On Tuesday 10 August 2010, Parker S. wrote:

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.

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

Michael


Michael S.
mailto:[email protected]
http://www.schuerig.de/michael/

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs