简体   繁体   中英

How to inject a deterministic unique buildId into Gradle's java jar manifest?

We have a cache of computed data stored on disk. We want to know if that computed data came from this version or a different version of the build. Currently we use commit + timestamp stored in MANIFEST.MF as a relatively unique way of identifying the build. However, timestamp causes incremental build issues in gradle, as gradle knows the time has changed, regenerates MANIFEST.MF, and re-jars the jar, even though nothing else has changed.

We want to replace the timestamp with a better 'buildId' into the MANIFEST.MF. The requirements are:

  • Unique for different builds : commit alone is not good enough, since there may be uncommitted changes on dev machines
  • Deterministic : timestamp does not work, since Gradle will see it as a 'change' in the dependencies, and rebuild the jar even when the other dependencies don't change

I think the correct solution is to use a hash of the actual dependencies to the 'jar' task, which is 'classes', which is all of the compiled class files that will be included in the jar.

I could, in theory , create a task which takes a hash of all the classes, and injects that into the manifest.

However, Gradle is already doing this, and that is how it determines if a task is up to date. It takes a hash of the input and a hash of the output, and checks if that combo is in it's database. So, is there a way to get access to this information using some rare Gradle API, or by using reflection?

Or maybe there is some other solution?

I think you may want to step back and re-evaluate what you would like to achieve with the buildIds added to your manifest files. Specifically, the first requirement that you stated, regarding builds on dev machines, doesn't make much sense. The reason you generally would like to add some sort of buildIds to a manifest file is so that you can track where and when a jar was built so that you can determine which set of source code to go and look at when something goes wrong. If you are generating builds based on the contents of a dev's filesystem, you are never going to be able to go back and determine where that build came from. If the buildId is based on the generated class files, or even the source files themselves on a developer's machine, then all the dev has to do is change a single character in a single file and that build is gone forever and cannot be re-generated unless that dev can do an undo that puts the filesystem back into the shape that it was originally.

Instead, you should base your buildIds on something that can be recreated without the need for developers to remember anything. In order for that to happen, the buildIds need to be both searchable and readily available to all members of the team at all times. Revision control commits satisfy all of these requirements and, by the sounds of it, are something that you already use so there is no additional overhead to add it into your workflow.

I'd recommend forgetting about basing your buildIds on the contents of the filesystem and base it on commits instead. If you are worried about devs being able to generate a build that does not come from master/trunk/etc all major revision control systems provide some method for branch creation which will still allow a dev to check in code that won't interfere with the primary production build. If you use a revision number/hash to track the version of a jar, you then have a way to go back and reproduce the build exactly, even if it is just from a local branch on a developer's machine. I don't recommend that last bit about using a local branch unless you know the build will be very short lived, however, since buildIds based on branches local to a single dev's machine cannot be searched by anyone else on the team. Instead, if you are using a distributed version control system I'd recommend that you push any changes used in a build to a central location so that anybody else that may be trouble shooting the build has access to the code used for it.

You could make a task to generate the build id and use the classes as input and the output is a file with the build id.

The build id doesn't have to be a hash of the inputs, but can be just a timestamp.

However since the task to generate the build id depends on the classes it only regenerates the build id timestamp when there was a change.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM