Versioning of Web Apps With Git Describe and a View Helper

The Value of Versioning

If you are involved in developing web applications in any role, from business sponsor, to project manager, to programmer, you will almost certainly have some appreciation for the value of versioning the project. Giving the application a version number makes sense, because it helps all the members of the team coordinate the planning, development, testing, and issue reporting. Without a version number, it can be difficult to be sure that everyone is talking about the same thing.

In the past, good versioning practices tended to vary in their implementation details, putting more responsibility on the project team to develop a solid, consistent, and meaningful versioning system. Fortunately, the open source community has settled on a standard called semantic versioning, which is both flexible and widely adopted.

Git tags are specific points in the Git history that are designated as being important. This is a great way to mark the semantic versions on a project.

Taken together, semantic versioning and git tags have been terrific tools for developers, but are not always of immediate value to the rest of a project team and the users, making issue tracking more cumbersome and imprecise. We’ll take a look at some simple steps that can be added to any build process, which automate the sharing of the semantic version in every environment.

To implement this, let’s review three important ingredients:

  • semantic versioning
  • ‘git tag’
  • ‘git describe’

Semantic Versioning

Semantic versioning is a simple set of rules and requirements that dictate how version numbers are assigned and incremented.

This standard emerged to support the growing popularity of dependency management systems, such as Composer, which require a consistent way of handling version dependencies. The official spec for semantic versioning is published at http://semver.org/

Git Tags

Git has a feature called Tags, which is compatible with semantic versioning. Git Tags provide an excellent, direct, and simple way to mark the code when a specific version gets released during the development life cycle.

Git tags in concert with semantic versioning are the critical ingredients for modern dependency management tools such as Composer, but they also can be used for team communication about more than just library code. End user applications can also benefit from semantic version tags.

See https://git-scm.com/book/en/v2/Git-Basics-Tagging

Git Describe

A project that is using tags isn’t always going to be on a tagged commit. This is why the `git describe` command exists.

The `git describe` command finds the most recent tag that is reachable from a commit. If the tag is on the current commit, then only the tag is shown. Otherwise, it shows the tag name appended with the number of additional commits and the abbreviated SHA of the current commit.

For example, if the environment is on a commit tagged 1.0.4, `git describe` will return that exact tag:

$ git describe
1.0.4

On the other hand, if the environment is on a branch that is 14 commits ahead of the last tag, `git describe` will return something like this:

$ git describe
1.0.4-14-g2414721


In the second example, the current head of the branch is based on 1.0.4, but since it has a few commits on top of that, `git describe` has appended the number of additional commits (“14”) and an abbreviated SHA for the current commit (“2414721”).

Note that the SHA part of the suffix starts with “g” followed by the first 7-characters of the SHA (which in this example was 2414721b194453f058079d897d13c4e377f92dc6).

For more details, see https://git-scm.com/docs/git-describe

This is extremely specific, but also completely flexible. It means that whether an environment is always kept on a specific tag (for example, in production), or is tracking a branch such as develop (for example, an integration environment), `git describe` can give everyone involved in that environment the exact version that it is on, even when it is new work which hasn’t been tagged yet.

This is all terrific, but the problem is, this valuable information is normally only available to developers or ops staff with access to the command line. How can we share this valuable information with everyone on the team?

Using A Version View Helper

The solution we present here, is to modify the build script for your environments so it updates a config automatically with the value returned from `git describe`.

Example

Imagine you are using a framework that supports view helpers, and you have a view script with a helper in it like this:

<html>
<head>
     <meta charset="utf-8">
     <?php echo $this-&gt;versionMetaTag(); ?>
<!-- snip -->

The rendered output in this example would look something like this:

<html>
<head>
    <meta charset="utf-8">
    <meta name="version" content="1.0.4-14-g2414721">
<!-- snip -->

[su_spacer]
As you can see, there is a versionMetaTag view helper which renders out, well…unsurprisingly, the version in a meta tag. Now QA testers and/or automation tooling can report the exact version of the application by reading the content of the version meta tag. The same technique could also be employed to render the version into a user-visible location on the page, such as in the footer text.

Implementing A Version View Helper

The pieces needed to implement a view helper like this will be very similar, regardless of language or framework.

  • A configuration file
  • A view helper with a factory that can inject the config value
  • A build script that can update the config value with `git describe`

Example Environment Config

<?php
return [
    'application_version' => '1.0.4-14-g2414721',
];

Example View Helper

<?php
return [
    'view_helpers' => [
        'factories' => [
            'versionMetaTag' => ApplicationViewHelperFactoryVersionMetaTagFactory::class,
        ],
    ],
];
<?php
namespace ApplicationViewHelperFactory;
 
use ApplicationViewHelperVersionMetaTag;
use InteropContainerContainerInterface;
 
class VersionMetaTagFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $config = $container->has('config') ? $container->get('config') : [];
        $version = isset($config['application_version']) ? $config['application_version'] : null;
        return new VersionMetaTag($version);
    }
}
<?php
namespace ApplicationViewHelper;
 
use ZendViewHelperAbstractHelper;
 
class VersionMetaTag extends AbstractHelper
{
    /**
     * @var string
     */
    protected $version;
 
    /**
     * @param null|string $version
     */
    public function __construct($version = null)
    {
        $this-&gt;version = $version;
    }
 
    /**
     * @return string
     */
    public function __invoke()
    {
        if ($this->version) {
            return '<meta name="version" content="' . $this->version . '">';
        }
        return '';
    }
}

Example Build Script

# Refresh the local version config file using the template and `git describe`. This is the neat part!
if [ -f ./config/autoload/version.local.php.dist ]
then
    # You must already have at least one tag set on the repo, or `git describe` will not work for this.
    version=&quot;$(git describe)&quot;
    rm -f ./config/autoload/version.local.php
    sed &quot;s/'application_version'.*/'application_version' =&gt; '$version',/g&quot; &lt;config/autoload/version.local.php.dist &gt;config/autoload/version.local.php
    printf &quot;nconfig/autoload/version.local.php created with $version.n&quot;
else
    printf &quot;nERROR: config/autoload/version.local.php.dist is missing. Cannot continue.n&quot;
    exit 1
fi

Production Friendly

With a config dist file in your project called ‘config/autoload/version.local.php.dist’, adding the above logic to your build script will use ‘sed’ to replace the value of ‘application_version’ in your special ‘config/autoload/version.local.php’ file. This will allow that environment to display the built version string with all the specificity of ‘git describe’, even if the environment it’s being deployed on is locked down, with no access to shell commands nor git. For local development environments, the view helper can return nothing, as in the example above, or you could have it return a default value such as ‘develop’ if the version config doesn’t exist.

The use of ‘git describe’ and a view helper is a simple addition to any project. Once implemented, it adds zero extra steps for maintenance and deployment, and provides the entire project team with much better versioning information for smooth, efficient communication.

Example Files

If you’re interested in a more full-featured version of the build script, and the other code snips above, you can check it out on GitHub.


Watch our videos for more Web tips and techniques:

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top