One of the main concepts in software development is releasing. There is a distinct lack of good solutions for releasing software as most build tools drop the ball when it comes to releasing.
Before we dive into how you configure Savant to perform a release, let’s first talk about publishing artifacts. Savant defines a repository structure that is similar to the Maven repository structure. This structure uses the artifact group and project names as well as the project version to define the target directory and the artifact name, version and type form the file name.
Here’s an example for the artifact com.mycompany:database-project:mysql:3.0.1:sql:
In order to configure your Savant project to publish artifacts, you must include a publications definition. This definition is broken into two groups. The first is the main group and the second is the test group. The main group are the primary publications of your project that are used at runtime. The test group are the publications of your project that are used at test time.
Savant is a bit different than other build tools. Savant doesn’t allow plugins to define build targets. This was a major design decision that we made based on our use of various build tools over the past 10 years.
Here’s the reason we decided not to allow plugins to define build targets. Let’s say that we are using the Java, Groovy and JRuby plugins and that our project has source code in all three languages. Let’s also assume we have tests written in all three languages. The Java plugin defines two build targets: compile and test. These targets compile the Java source code in the directory src/main/java and src/test/java and then execute the tests.
Now, let’s assume that our Groovy and JRuby plugins also define these exact same targets. However, our project’s Groovy classes use our Java classes and our JRuby classes use our Groovy classes. How do we ensure that our plugins are executed in the correct order?
In our first blog post, we briefly touched on the concept of licenses in Savant. Project licenses are a concept that is often overlooked in software development, but is extremely important. The legal nature of software licenses, both open and closed, can impact how a library, tool or product is used and deployed.
Most build tools allow projects to define their license, but it is often a free form text field in the project definition file. This causes a number of problems. First, these are impossible to parse reliably. Second, it is usually optional. This means that with most build tools it is impossible to correctly determine what licenses your software is currently using. Any lawyers reading this are probably starting to sweat and shift uncomfortably in their chairs.
Savant is built and maintained by Inversoft. Inversoft has a number of products that are commercially licensed. All of our products are on-premise and therefore downloaded by our customers and installed on their servers. This means that we need to be extremely meticulous about our use of open source licenses. If we were to use a library that was licensed under the GPL, it could have drastic ramifications on our products.
Image by Manu Cornet
Version compatibility is a core concept in Savant. Even before Semantic Versioning was first published, Savant was built on the concept of major, minor, patch compatibility. This concept was formalized into the Semantic Versioning specification. This specification is quickly becoming the industry standard for versioning software.
The quick overview of Semantic Versioning goes like this. Versions are broken up into 4 parts:
Compatibility between versions is determined as follows:
Major versions are not compatible. That means that 1.0.0 and 2.0.0 are not compatible.
When we first started writing Savant, we realized that the first requirement was a dependency management system. This is necessary for nearly every feature in a good build tool. We wanted Savant plugins to be resolved as dependencies and to be loaded into separate classloaders along with their dependencies. We also knew that the Java compiler plugin would need the project’s dependencies for the compiler classpath and the TestNG plugin would need the dependencies to run the tests.
For years we had been using a strict versioning system that broke versions into 4 different groups:
This versioning is expressed as <major>.<minor>.<patch>-<pre-release>
We found that the Semantic Versioning (SemVer) specification was nearly identical to our versioning methodology. Rather than continue to use our own system, we fully embraced SemVer. The problem was that no other dependency management system implemented SemVer.