14

My team currently uses a fairly simple branching/deployment process that looks like this:

                ┌────────┐ ┌────┐ ┌──────┐
 Environments:  │  DEV   │ │ QA │ │ PROD │
                └────────┘ └────┘ └──────┘

                     ▲       ▲       ▲
                     │       │       │

                ┌────────┐ ┌────┐ ┌──────┐
 Builds:        │  DEV   │ │ QA │ │ PROD │
                └────────┘ └────┘ └──────┘

                     ▲       ▲       ▲
                     │       │       │

                ┌────────┐ ┌────┐ ┌──────┐
 Branches:      │ master │ │ qa │ │ prod │
                └────────┘ └────┘ └──────┘

Each environment has its own branch (we use git) and its own build that uses that branch. When we want to promote from one environment to another, for example, from DEV to QA, we merge the master branch into qa and kick off a new QA build (which is then automatically deployed to the QA environment).

We're considering moving to a new process that would do away with having a dedicated branch and build for each environment. Instead, a single release build would create a "deployment package" which could then be deployed to any environment. We're imagining a typical workflow would look something like this:

                ┌────────┐     ┌────┐     ┌──────┐
 Environments:  │  DEV   │ ──► │ QA │ ──► │ PROD │
                └────────┘     └────┘     └──────┘

                      ▲ 
                       \ 

                        ┌───────────────┐
 Builds:                │ release build │
                        └───────────────┘

                                ▲
                                │

                ┌────────┐ ┌─────────┐
 Branches:      │ master │ │ release │
                └────────┘ └─────────┘

Promoting from one environment to another would no longer be handled in source control; rather, we'd just take the already-built binaries (the "deployment package") and drop that on the new environment.

This new system would allow us to deploy any build to any environment, which has several advantages. For example, it's trivial to test PROD bug fixes in DEV and QA. Our current system doesn't provide an easy way to do this without rolling back a branch, which we'd obviously like to avoid.

The biggest drawback with this new system is that we no longer have an automatic way of tracking what code is in which environment. If we need to make a fix in PROD, we no longer have a dedicated branch in sync with the current production codebase. The same goes for QA - if we want to push a quick change to QA without dredging up in-progress work from master, we no longer have a branch that reflects the current state of the QA environment.

How can we keep track of what code is in each environment?

Some options we're considering:

  • utilizing git tags to keep track of which commit is in which environment
  • embedding the git commit used by the build into each deployment package
  • Do you have a CI system such as Hudson or Jenkins? Is it capable of pushing tags of what it built back to git? (I know there are plugins for Hudson and Jenkins that can... - not as sure about others). – user40980 Nov 6 '15 at 22:03
  • @MichaelT We use MSBuild for our builds and Octopus Deploy for our deployments. I'm pretty confident we could make Octopus manipulate our git repository with a custom Powershell deployment script. – Nathan Friend Nov 6 '15 at 22:11
14

Git tags are what you really want to use to designate releases. The reason is that they have meaning to you and can be used to quickly recognize the linkage between the state deployed code and any information that the build server may have (such as build number).

While that is the answer you are looking for, it only solves half the problem. The other is "hey, here's the deployed .[wje]ar on the server, what build did it come from?" We know that you'll never have different versions of the application deployed on dev and qa or prod. Right?

The solution to that part of the question is to have the build server put the information into the manifest. Coming from a maven and svn example that I have in front of me:

<manifestEntries>
    <Specification-Title>${project.name}</Specification-Title>
    <Specification-Version>${project.version}</Specification-Version>
    <Build-Number>${build.number}</Build-Number>
    <Build-Id>${build.id}</Build-Id>
    <Svn-Revison>${svn.revision}</Svn-Revison>
</manifestEntries>

That's in the maven-war-plugin archive configuration. But you can find it in other plugins too. Then in Hudson, part of the maven build invocation is:

-Dbuild.number=${BUILD_NUMBER}
-Dsvn.revision=${SVN_REVISION}
-Dbuild.id=${BUILD_ID}

which sets those defines that then maven picks up. And then its just a matter of looking in the MANIFEST.MF file that has been deployed on the server to see what version it is.

There's a git plugin, that offers a similar set of environment variables including:

  • GIT_COMMIT - SHA of the current
  • GIT_BRANCH - Name of the remote repository (defaults to origin), followed by name of the branch currently being used, e.g. "origin/master" or "origin/foo"

The combination of these two practices allows you to easily identify the build (because build numbers go forward, and have meaning, unlike sha checksums) and the specific git commit that it is built from.

3

A completely different approach would be to dismiss the idea of versions completely. You only have "one version" which has a different configurable behaviour. The only difference would be, that you have a common codebase - even in production you would deploy work in progress: but not activated.

The difference only boils down to different sets of features being enabled in your product.

The de-/activation is done via feature toggles.

Upside: the whole release process is simplified: You are always delivering an integrated version of your software. Every feature is always available in master. No additional branches are needed.

There is no pain with merging features together, because: no branches no need for merging. There is no confusion what feature is on which branch and maybe depend or clashes with features from other branches. Every part could be activated at will. Even a rollback is not necessary anymore: it's only a flip of a switch.

I do not know, if that works for your codebase: the prerequisites in terms of code quality and developer discipline are quite high - you have to deal with "cleanup" after a feature becomes a core functionality and you have to manage a bunch of toggles preventing a bigger mess.

Perhaps it works for you.

  • But what about having different repository states deployed to different servers? Is the code that is running on the QA box the same as the one running on production to be able to reproduce a bug? Has the code that the developers pushed to their developer box the same as the code that QA is running against? – user40980 Nov 7 '15 at 13:13
  • 1
    The question has to be asked different: is the bug with a special configuration reproducible "now" if yes, you can fix it. If no - does the bug matter? You always push working (and integrated code). – Thomas Junk Nov 7 '15 at 14:00
-1

We use maven to put the version into the manifest file. Then have the application display the version if its a web app, or have a /version endpoint for web services.

protected by user22815 Nov 11 '15 at 4:18

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.