Is it possible to implement snapshot versioning with Paket? - maven

Maven is a dependency manager in the Java world. It supports snapshot versioning. In Maven-speak a dependency is called an artifact. An artifact with a fixed version number (e.g. 1.0.1) will be downloaded only once because it will never change. On the contrary a snapshot version (e.g. 1.0.1-Snapshot) will be considered as a moving target. It is a current development copy and will likely change in the near future. Therefore it has to be updated on a regular basis. With snapshot versioning you are able to provide the current state of an ongoing development as an artifact through your artifact delivery mechanism (for example with Nexus or Artifactory). In combination with a CI build which creates the snapshot artifacts you are able to setup a development infrastructure with can handle fairly complex projects.
In essence I think snapshot versioning means the dependency manager needs to check and download artifacts with a version tag which it has already downloaded before.
In the .NET world Nuget is the prefered package manager. As a dependency manager it does a very lousy job. In particlur it does not support snapshot versioning:
NuGet Cache And Versioning Issues
Paket is an alternative package manager. It is clearly better suited to do the dependency management in real life projects but I could not find something in the documentation about snapshot versioning.
https://fsprojects.github.io/Paket/
My question: Is it possible to implement snapshot versioning with Paket?
Futher explanations about snapshot versioning:
What exactly is a Maven Snapshot and why do we need it?
http://www.tutorialspoint.com/maven/maven_snapshots.htm
https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855

Olaf, I don't think this is supported in paket.dependencies but consider this alternative:
1 put a flexible version restriction in paket.dependencies
nuget GreatDependency ~> 1.0.1
2 invoke custom paket update on build
.paket\paket update nuget GreatDependency

Related

How to manage maven dependant artifacts after creating release versions

We are using release plugin to convert snapshots to releases, but snapshots were already added as dependencies in other projects. Do we need to update every project pom, to use the new releases.
Eg: ArtifactA is included in ArtifactB,
ArtifactA is included in ArtifactC
ArtifactB and ArtifactC is included in Artifact D
Is there an alternate way to push dependent releases in place of snapshots
[We use Jenkins to build and push to Nexus]
Our build server runs versions:use-releases followed by a commit to the SVN before the build. This replaces all SNAPSHOT versions by their respective release versions if they exist.
A less cumbersome way of dealing with releases - keep using snapshots. Technically there's nothing wrong with snapshots and there's no need to change them to release versions. Just don't use versions with SNAPSHOT suffix - use resolved snapshots (with timestamp and build number).
As for the dependencies - usually there's no big need to change the version immediately after the release. It's only when clients need the updates - then they should change to newer versions manually.
If we're talking about remote API and its client lib as a dependency - such remote API needs to keep backward compatibility to give some time for others to upgrade.

Publish snapshot artifacts to azure devops artifacts

I have a Gradle build set up in Azure DevOps, which compiles the code in an Azure DevOps git repository, then publishes the generated JARs (as Maven artifacts) to Azure Artifacts, as explained here. Code in other Azure DevOps git repositories can then reference these components as dependencies. This is fine for formal releases of these components (with unique version numbers), but I also need a way to get this working for in-progress snapshot releases. The problem is that I cannot publish an artifact with the same version number (e.g. 1.2.3-SNAPSHOT) more than once. This seems to be because packages in Azure are immutable.
From my understanding, that would mean that Azure Artifacts cannot be used to store in-progress snapshot artifacts. Is that correct?
If it is, is there any alternative that still uses Azure DevOps? I can see that I can publish artifacts to Azure Blob Storage, but presumably this is something you have to pay for on top of existing use of Azure Artifacts. I can also see that there's a number of GitHub Maven plugins for treating a GitHub repo as a Maven repo, but I can't find anything similar for using an Azure DevOps repo as a place to publish Maven artifacts.
In case it makes a difference, I'm talking about the cloud-based Azure stuff, nothing on-premise.
Specifically for maven, there's a difference in how a jar is packaged in a SNAPSHOT as compared to other versions.
Eg. let's say I version my jar as 1.0.0-PRERELEASE, now this version is immutable. Once I publish this to any artifact repository it cannot be overridden. Usually package management systems store the artifact in this kind of logical path - <group_id>/<artifact_id>/<version>/<artifact_id>_<version>.jar.
But for SNAPSHOTs this is slightly different. In maven, SNAPSHOTs are mutable. This means you can override a SNAPSHOT. And this makes sense as by definition SNAPSHOTs are like an image of your code in active development. How SNAPSHOTs are stored in a package management feed is something like <group_id>/<artifact_id>/<version(SNAPSHOT)>/<artifact_id>_<version>_<jar_timestamp>.jar.
This naming convention of the jar in this case makes it mutable. In a single SNAPSHOT version, there can be multiple jars present with different timestamps. And when maven looks for a SNAPSHOT dependency to download, it always picks the most recent one (again logical as that's the most recent snapshot).
At present azure artifacts implements these concepts exactly how they are supposed to. Perhaps this wasn't there before and has been pushed in an update.
http://maven.apache.org/guides/getting-started/index.html#What_is_a_SNAPSHOT_version
https://xebia.com/blog/continuous-releasing-of-maven-artifacts/
The premise of Package Management is that a package is immutable. This enables a whole bunch of caching options that would otherwise not exist. Packages are stored in your local package cache, possibly on a proxy feed package cache and all of these elements assume that packages with the same name+version are unchanged and will serve the cached version instead of the latest version you've pushed. Most package systems are built on this premise, including Nuget and NPM.
The trick to creating development snapshots is to use semantic versioning and adding a unique suffix to your version. For example 1.2.3-SNAPSHOT.1 followed by 1.2.3-SNAPSHOT.2, there are tools available for Azure Pipelines, like GitVersion that can automatically generate a unique version + suffix that you can pass into the version for your artifact.
If you don't want to "mess up" your main package feed, you can setup a second feed for development purposes which holds all your intermediate packages, you can then either promote one of these packages to your main feed or you can run a specific pipeline (configuration) to push the final package to the feed used for your stable packages.
It looks like this is mostly a feature and not a bug as to preserve the immutability of the build results - meaning, that no matter when that build is ran, it will always return the same result. See: How to update a maven dependency with a same version number in Azure Artifacts & Azure Artifact Publishing Fails for Artifact Version Containing '+'

Release Candidate behaving like SNAPSHOT in Maven repository

In development, I can reference the latest version of an artifact as 1.2.3-SNAPSHOT. Now I need the same behaviour for release candidates, i.e. I would like to be able to depend on the latest release candidate (there should also be a procedure for the developer to declare development versions as release candidates).
I am not sure how to implement this behaviour properly. Should I use an additional repository for release candidates and move development versions to this repository if the developer requests it? Or can I somehow define a "second snapshot list", like 1.2.3-RC?
You can get there be re-configure a few things:
use a version range for the dependency
change the updatePolicy for the repository you store the release candidates. see https://maven.apache.org/settings.html (updatePolicy). If you store the artifacts in a maven proxy usually you need to allow to overwrite releases.
Remember in a multi module build that they might upload modules before detecting a failed build (due to mvn deploy being a phase not a goal). You need to verify the complete build is ok before starting to upload artifacts in the maven repository. Or stage them somehow.
Remember this will most certainly prevent your builds being reproducible. Since an RC dependency might change between builds. You would need to change the version range - which is not always an issue. Ranges may work for you.
I've better experience to let developers stay on snapshots but have the CI server set an explicit version (for example using the versions plugin) prior to deployment / releasing for the dependency the artifact uses.

Promoting semantically versioned artifacts when an upstream dependency has changed

I am in the midst of an initiative to convert our build.gradle files to use semantic versions. In addition to using Gradle, we also use Git and are following the Gitflow Workflow. Jenkins is used to build the projects.
Versions for released artifacts follow a MAJOR.MINOR.PATCH format. When declaring dependencies in the build.gradle file, we use dynamic versions, such as 10.0.+ (i.e. take the latest 10.0.PATCH version).
We promote our artifacts from a Release Candidates repository to a Releases repository in Nexus. The repository has its policy set to "Releases". Because of the complexity of the product (200+ projects, with many upstream and downstream dependencies), a lot of the promotion plugins available for Jenkins appear to fall short. We were thinking of having Jenkins build the master branch as a way to rename artifacts (10.0.0-rc.1-abcdefg becomes 10.0.0) and upload them to the correct Nexus repository.
I am unsure of how to handle a situation where an upstream dependency has a patch version incremented. The downstream project - a WAR - is re-built by Jenkins and bundles the new JAR, but the version of the downstream project doesn't change. When an attempt is made to upload to Nexus, it fails because only one artifact can have the same version.
Here is an example:
The Releases Nexus repository has upstream-api versioned at 10.0.0, and downstream-project versioned at 10.0.0
downstream-project depends on 10.0.+ of upstream-api
upstream-api.jar is bundled into the downstream-project.war file
The two artifacts are deployed as part of Release X of the product
When a hotfix branch has been merged into master, the upstream-api version has changed to 10.0.1
The fix means that when deployed, the product is now Release X'
downstream-project stays at 10.0.0, but is re-built because of the change in the upstream dependency
Jenkins fails to upload downstream-project-10.0.0.war to Nexus because it already exists
I could have the old artifact replaced with the new artifact, but then that means that Release X can no longer be deployed from artifacts in Nexus (eg. in the case of a rollback, or needing to replicate an issue on an older release).
How is this typically handled?
How is this typically handled?
I don’t have a universal answer here. I would assume that these are the most “common” possibilities:
Don’t distribute your dependencies with the release and continue to use dependency version declarations such as 10.0.+. The assumption is then that the software will indeed work with any 10.0.x version – at least as far as your users will tolerate it. That usually happens for free software which is distributed in source or in a package system of a Linux distribution. The dependency version declaration is only updated when there is a required improvement in the dependency, i.e., when the change is so important that your users won’t tolerate any earlier version.
Distribute your dependencies with the release and either:
Use a build number in addition to the main/semantic version number of the original code – for example 1.3.4-b3. If I’m not mistaken, then this is often being done for proprietary Windows software.
Increment the main/semantic version number when a dependency changes and make the dependency requirement explicit.
Some more General Thoughts on the Issue
I think the core issue is the dynamic dependency declaration – the 10.0.+ version declaration. What you state with this declaration is that your release will work equally well with any 10.0.x version.
If that is really the case, i.e., the bugs that are fixed by a patch in the dependency are guaranteed to never affect the release, then your release should probably simply not be rebuilt, since its functionality wouldn’t change anyway. The version of the dependency wouldn’t matter, your release could stay with the older dependency version.
More likely, though, the upstream bugfixes will also make a difference in your downstream project, i.e., they will affect the functionality of the release. In that case you should make the “new” dependency explicit in your build.gradle. Since that’s a change to your release artifact, a new release version is due.

how do i tell maven to get latest version of artifact from custom nexus repository

i have following requirement.
i need to download the latest version of artifact from custom nexus repository rather than snapshot repository.
please suggest
Thanks.
To get the latest version of any artifact, just omit the <version> tag from the dependency. This way maven will always fetch the latest version of this artifact from the remote repo.
Warning: Keep in mind that this is not the preferred way to handle dependencies nor it is the proper flow of dependency management. By keeping the version number open ended, there is a very high probability that your project may fetch a particular version of any library that is now not backward compatible and may break your functionality in the project. It is, therefore, always recommended to specify a particular version number of all artifacts that are required for any application and when updating any library version, one should properly test it.
EDIT
For maven3 you can use the facility of an open ended version tag. Something like this
<version>[1.12.4,)</version>
Take a look into this page for further details about version ranges
According to this issue: https://issues.apache.org/jira/browse/MNG-3092 snapshots cannot be excluded (at least until this is fixed).

Resources