0

In a certain software project I'm involved with, (one or more) of the executables which get built to write logs, and it is customary/expected for those logs to include some sort of tag or version information regarding the running process. This is currently done both for release builds, which have release version numbers (e.g. 3.5.1), but also for development builds, where the tag can and is more involved than that. There is a bespoke mechanism which generates code for this tagging, and uses git (i.e. assumes the source code is also a git repository) to obtain commit hashes and such. During build (re)configuration, a source file with functions returning build tags is generated, by examining the git history and/or computing hashes of things.

I want to scrap this mechanism, for the following reasons:

  • Code should not rely on the existence of the revision control mechanism it may or may not be developed with. Specifically, one should be able to package a release tarball, unpack and build it with no revision control employed at all (e.g. no .git, .hg, .svn etc. subdirectories in the repository source).
  • I don't like bespoke build-related mechanisms or libraries for tasks which are not specific to our project or to our organization; I'd like to use something common, well-known/well-established, which we don't need to maintain and worry about.
  • I'd rather have build tags be intentional rather than extentional, i.e. the repository itself is not aware of, and cannot determine, what the build version is; and it is only the person (or program) configuring the build that says "your build tag is 'foo_experimental_2024_11_23+'", or whatever.

I would like to propose something different to the team, but I'm not sure what that would be, especially since I'm not familiar with build-tagging conventions in other projects. Any suggestions?

14
  • Instead of looking for what is out there, I would urge you to first write down what the result is that you want to achieve and then look at how your current tooling/processes are lacking in achieving that result. Then you could ask a focused question on how to overcome the shortcomings to get closer to your desired end result. Commented Nov 24 at 10:46
  • If something works fine then why would I change it? Just because it doesn't feel right? I would suggest you reconsider it.
    – freakish
    Commented Nov 24 at 11:50
  • why not just increment the build number part of the version string every (CI) build?
    – Ewan
    Commented Nov 24 at 11:55
  • 1
    @Ewan: That assumes a single centralized entity performing builds. In fact, builds are performed in parallel by multiple human and automatic entities. Also, not every build goes through CI.
    – einpoklum
    Commented Nov 24 at 12:11
  • @freakish: I actually explained how it's not fine, but I'll elaborate to clarify.
    – einpoklum
    Commented Nov 24 at 12:12

4 Answers 4

4

First, let me say there is nothing inherently wrong in having a build process which depends on specific tools, and Git may be one of theses tools. Source code requires always special tools like specific compilers, scripting languages, HTML or PDF generators, and though you may design a program to support a variety of tools, at the end there is a list of tool dependencies one cannot avoid. If your team has decided to put Git on the list of the dependencies of your project, than that is a valid decision.

However, there is just as little wrong with making a build process independent of Git. Generating a build version into the source code can be done (and is done!) differently in different environments, so searching for "the" standard is in vain. Still, lots of compilers / IDEs / build tools support such a mechanism, so you can use theirs instead of the SCCS's. For example, here on this older SO post you find some information about Visual Studio. Here is a post about a Maven plugin which accomplishes this. And if your compiler/build environment does not have a standard mechanism out of the box which suits your needs, just write your own little script which does what you want.

Let me add the idea of generating revision number from the used SCCS into the source itself is not new. SVN, for example, provides keyword expansion. Git does not support this directly, but it can be accomplished through customization (which bears a certain risk to work differently in different Git environments). CVS has such a mechanism. Other systems which I had to deal with in the past also had. So having sources or build process (loosely) dependend on the SCCS is not a very special or unusual idea.

11
  • "Specific tools" - certainly, if that's relevant. If I'm building a git visualization tool, or an IDE, then I can depend on git. If I'm building an app which, itself, does not use a revision control system or pieces of its code - then it is inherently wrong for there to be a dependence on that system for building it. But the fact that development of the app uses an RCS should not make the app depend on the RCS. That is inherently wrong. But I'd +1 this for the second paragraph.
    – einpoklum
    Commented Nov 24 at 14:14
  • You seem to think that project is just code. It is not. It is a lot more.
    – freakish
    Commented Nov 24 at 14:18
  • @freakish: what exactly are you trying to tell me? Or was your comment adressing the OP?
    – Doc Brown
    Commented Nov 24 at 14:30
  • @DocBrown sorry, I was addressing OP.
    – freakish
    Commented Nov 24 at 14:35
  • 1
    @einpoklum: not that I am a fan of putting Git commit numbers into the source code, but this is still a valid approach and I don't see any real, founded factual arguments against it. It seems more like a dogmatic believe of yours.
    – Doc Brown
    Commented Nov 24 at 14:42
1

Build versions / labelling is a tool, you need to decide what are your requirements, some common requirements are:

  1. To identify the specific commit that the build was produced from.
  2. To identify the branch in source control.
  3. To identify the relative order of two builds A was built before B.
  4. To indicate functional compatibility (Semantic Versioning)

If your system identifies the commit (#1) you can work out the branch (#2) and ordering of builds (#3) however it is sometimes useful to be able to look at a build without referring back to source control. You may be able to achieve that with additional metadata (build date and branch) hence it may not be necessary to include that information in the version number.

Git hashes, Perforce CL# etc are often used because it is very low effort for everyone involved - the DevOps team simply includes the info in the build and everyone else can simply refer to it identify which build they have / where it came from.

There are two primary issues with Semantic versioning:

  • It doesn't handle branches (concurrent development) very well because code being merged between branches doesn't really change its semantic meaning.
  • Ideally you include a manual step to indicate that important changes have been made, optionally having a concept of SNAPSHOT verses RELEASE builds. **

** - If you don't manage your numbers - you are not using the changes to indicate significant changes, it just becomes a build number so why bother?

Recommendations:

  • Use semantic version if you think your team will leverage/benefit from it.
  • But also include the other metadata (GitHash, Branch, Build date) into the build - in a way that is easy to query.
  • If your build tooling leverages semantic versioning use it for artifact repositories.
  • For binary images (VMs, Docker etc) its probably best to continue to use git hashes since there will likely be multiple builds before semantic versions are reved.
-1

Having a git commit/tag baked into the final artifact (package, executable, docker image, etc) is extremely useful. It helps debugging a lot. If you use anything else, then how will you know what code was actually deployed? You will need some mapping between versions and git commits. Which is an external dependency anyway. Which is just more complicated solution, and even less portable.

But that doesn't mean that code itself should depend on a revision system. It is enough if the appropriate build number is injected during build process. The code doesn't even have to use it, it is enough if it is present in the final artifact. But it can use it, for example a server that serves its own version, why not?

Side note: I'm saying it is useful, but not necessarily safe. Malicious users can do something with that information if it ever leaks. Just be aware of that. That being said the risk is (or should be) rather low.

So, all you need is a build process. Most compiled languages (including those compiled into bytecode like Java and C#) have mechanisms to run arbitrary code at compile time. You can use that. If not then you will need some build scripts. Just make sure that those work even when a revision system is not present. That's all.

So the bottom line here is: build process should be aware of the revision system. Code does not have to be. Separate those two, and it will be fine.

As a final note: I really love semantic versioning. And I think it is better than baked in random build numbers. But it has one major flaw which IMO makes it very inferior: it requires a dev attention. I will always chose things that can be easily automatized above those that require manual work. Even if such solution is technically inferior. Because ultimately there's always more trouble with people than with code. That being said nothing prevents you from having both at the same time.

10
  • 1
    1. I'm not asking about final artifacts, but about all builds. 2. "how will you know what code was actually deployed?" - Well, when releasing, one creates a linkage between a git commit hash or tag, and the released version number - e.g. by naming the git tag "release_3_5_1", or by the release process including this information. That's what all projects I know are doing basically... 3. " It is enough if the appropriate build number is injected during build process." - it is currently injected during build configuration.
    – einpoklum
    Commented Nov 24 at 14:08
  • @einpoklum (1) all builds should run the same single sequence of commands, perhaps grouped in a single shell file. It's a mess to do otherwise. Just don't. (2) So you do make git tags with version, which ultimately is the same thing, except you have more complicated solution to generate versions. I have no idea why would you prefer that.
    – freakish
    Commented Nov 24 at 14:10
  • "all builds should run the same single sequence of commands" - that contradicts the existence of build configuration. You configure your build so that it runs a different sequence of commands, based on the platform you're on, the available tools and libraries, and - arbitrary choices of build configuration parameters. Those can control whether debugging, logging, or profiling facilities are baked in or not, and they can determine a build tag and/or a version tag.
    – einpoklum
    Commented Nov 24 at 14:18
  • @einpoklum ideally it should not run different commands, even on different platforms. That's why we use compilers, and other tools that do that for us. We can even use same shell everywhere (I know that at least powershell is very portable). But ok, sometimes it has to. My point was that the injection of build number should be done on every build, the same way. Unless the revision system is not present of course (in which case it can default to say empty string).
    – freakish
    Commented Nov 24 at 14:21
  • " ideally it should not run different commands, even on different platforms." <- No, that's not an ideal. " That's why we use compilers, and other tools that do that for us." <- No, we don't use compilers for choosing what to compile. "Unless the revision system is not present of course" <- My question is about build tagging without depending on a revision control system.
    – einpoklum
    Commented Nov 24 at 14:36
-1

I think almost everyone uses:

  1. Single CI pipeline for all builds,human specified Major.Minor and an incremented build number

This wont pick up on local builds, but it works for all dev/test/prod builds because they are forced to go through the pipeline.

A key thing here is that you are versioning the built code. Not the aource

Alternatives.

  1. I think microsoft used to provide an option to use a date as the build number. This also provides an ever increasing version which is independent of a central system. But can get confusing if your local dev build from an old commit has a higher build number than the most recent version.

  2. git commit ids. I think its fairly common to tag builds with this info, but it fails as a version number. Simply speaking if you have two feature branches, asking which is the later version makes no sense. Also, what if you build the same commit twice with different options etc

  3. Don't use a build number at all, just manually update the version when you publish. This is problematic because you can end up with two different exes with the same version

7
  • With respect - you think wrong: A large fraction, if not most, of builds-of-code are people starting a build, manually or using their IDE. And I believe only a minority, and perhaps a small minority, of software projects have a single, centralized entity performing builds. Also, what do you mean by "Microsoft used to provide an option"? Microsoft is not involved in building our code. "git commit IDs" <- the whole point of this question is asking for an alternative to that. "don't use a build number at all" - if I could only convince people to drop build tagging altogether...
    – einpoklum
    Commented Nov 24 at 14:34
  • I mean you could define your build version in a project file as 1.2.3.x and visual studio would automatically replace the x with a time stamp gnerated build number
    – Ewan
    Commented Nov 24 at 18:50
  • @einpoklum option 4 is dropping the buuld number and just having major minor patch. its fairly popular
    – Ewan
    Commented Nov 24 at 18:53
  • Do you really think that most people don't use a CI pipeline? I mean I'm sure you are right if you are just counting all builds, But local builds are just thrown away due to the "it works on my machine" issue. I'm talking about professional development
    – Ewan
    Commented Nov 24 at 18:59
  • Ewan: Most people don't have a "CI pipeline" to use; and when one exists, most of people's builds happens on their workstations/laptops/accounts on a development server. When they commit something, it then goes through CI. And if they're working on a super-large beast of a software project, the building of which is some big affair, then perhaps they don't do their own builds, although there also I would expect people would want to break off parts of the monolith and build small libraries/modules with shorter cadences.
    – einpoklum
    Commented Nov 24 at 21:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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