Resolving private dependencies from GitLab in Leiningen - clojure

I'm having problems setting up Leiningen to resolve private dependencies from GitLab.
It works well in Maven projects. I configured it by providing configuration with HTTP header (Private-Token:abcd) that is stored in the ~/.m2/settings.xml (as described in the GitLab docs).
I've tried setting something similar with lein by following the docs, but it always fails on resolving the dependency printing Could not find artifact ... in releases. Here is what I added to project.clj:
:repositories [["releases" {:url "https://gitlab.com/api/v4/projects/.../packages/maven"
:creds :gpg}]]
I'm probably adding the private token incorrectly (or using wrong credentials provider). Tried different combinations of username/password/passhprase added to ~/.lein/credentials.clj (and later encrypted with gpg), but nothing worked correctly.
Any hints?

According to gitlab's authentication with registry docs the authentication is performed using access tokens, which, according to this gitlab doc, can either be passed in the private_token url query parameter or the PRIVATE-TOKEN header.
Unfortunately, Leiningen does not allow either of those authentication methods. So — you guessed it — there's a plugin for it.
The plugin is really just a tiny piece of code which represents what is called a "wagon" factory.
You use it like so:
;; inside project.clj file
:dependencies [[your-lib "0.1.0"]] ;; "your-lib" is the name of the package you published to to your gitlab's package registry
;; group and name of the package are usually the same, so you can mention just one of them
;; and it will be expanded to look like this:
;; your-lib/your-lib/0.1.0/your-lib-0.1.0.jar
:plugins [[net.clojars.hissyfit/lein-gitlab-cart "1.0.0"]]
:repositories [["this-name-doesnt-matter" {:url "gitlab://<your_gitlab_domain>/api/v4/projects/<your_project_id>/packages/maven"
:username "Private-Token"
:password <actual_token_value_here>}]]
A few important notes:
Notice the value for :url key begins with "gitlab://". This is needed for the lein-gitlab-cart plugin to recognize which url it should register to use its factory class. Behind the scenes the plugin converts the "gitlab://" back into the regular "https://".
If you have multiple packages from different projects under the same gitlab group, you can specify :url key to be "gitlab://<your_gitlab_domain>/api/v4/groups/<your_group_id>/-/packages/maven". (You can use the tokens of a group to access the packages of the projects it contains)
I found that when using deploy tokens instead of project/group access tokens you do need to replace the :username key to be "Deploy-Token" instead of a "Private-Token".
It is up to you to decide on a way of getting the actual value of the token into the :password key, but I found it most convenient to just use ~(System/getenv "MY_GITLAB_TOKEN") to retrieve it from an environment variable.
And, after a few days and many unsuccessful attempts, I've also reached conclusion that the plugin can only be used to resolve the dependencies mentioned in the :dependencies vector, it will NOT work for any private lein plugins you might mention in the :plugins vector. And it seems to be more of an issue with the order in which Leiningen currently(v2.10) resolves the plugin dependencies as the custom wagon factories are only allowed to be registered after all the plugins are resolved (and it cannot happen, because we require lein-gitlab-cart plugin's wagon factory to resolve the address of our private plugin).

Related

JavaPackage org.wso2.carbon.apimgt.impl.APIManagerAnalyticsConfiguration]. It is not a function, it is "object".)

I encounter the following exception in the WSO API Manager
ERROR {JAGGERY.modules.analytics.add.jag}Error occurred while saving
Analytics configuration (Cause:Cannot call property getInstance in
object [JavaPackage
org.wso2.carbon.apimgt.impl.APIManagerAnalyticsConfiguration]. It is
not a function, it is "object".){JAGGERY.modules.analytics.add.jag}
We have no clue what leads to this problem, we are sure that we didn't change the jag files,but we did replace one class file(within the jar) with our own compiled class and replace it into the jar.
When we change back to the original jar and restart the server,the problem is still there,does anyone know what may lead to this problem and how to fix?
This can happen if APIManagerAnalyticsConfiguration class is not available in OSGi rumtime. Most possible reason is that corresponding jar is not ACTIVE. You can start the server with -DosgiConsole and see if that's the case. Here is a guide.
Did you replace a jar in plugins directory? That's actually not recommended. And that can cause OSGi activating issues too. If you really want to replace a jar, you should patch the jar by placing the jar inside <APIM_HOME>/repository/components/patches/patch0100/. Here 0100 is an arbitrary number.
We are deploying our own war app on the APIM Console. Looks the war contains a CXF jar, which conflicts with APIM's own CXF jar that leads to the problem.We are simply un-deploy the war,and the problem is gone

Load .env file in clojure

Is there any recommended way to load configuration inside a .env file in clojure?
I've found https://github.com/rentpath/clj-dotenv and https://github.com/jackmorrill/dotenv which seemed to do what I want, but both of them are not available on clojars.org anymore with github activity being very low.
There also is https://github.com/weavejester/environ/ but I have not quite gotten my head around how to use it, since the project.clj is tracked inside my git repository and my configuration (in dev also) contains potentially sensible information such as API tokens.
Any help would be greatly appreciated.
The most basic approach is to edn/read an .edn file that contains a map of configuration. You don't need a library to do this. You just need to manage the file (don't check it in if it contains passwords, but do deploy it to where it needs to go).
Environ is great for getting values from the environment, but how you get them into your environment is up to you. One way would be source an env file before launching your application.
This library https://github.com/outpace/config can help for more complicated needs. It allows you to pull configuration from many different sources (files, environment, or specify something else) in different formats (edn/string).
Ultimately you have to decide where you want configuration to be and how it will get there, both of which are not directly something you do from your Clojure project, but are instead deployment concerns. Feel free to add more specifics if this is missing your needs.

Working on a multiple leiningen project

I'm building a web apps that uses http-kit and clojurescript. At some point, I want to separate the front and back each into a lein project on its own. The scenario is:
For the front, if on development mode, uses a lein ring server to serve directory and the app will display a mock data.
The back will serve any resources/public in the front lein project.
I'm thinking of doing a nested lein project, but not sure how to handle it. Any suggestion or pointer is very much appreciated.
The way your question is posted it is not very clear "why two projects?". It seems that you may be confusing different projects with different profiles, e.g. .. classpaths?
In order to work with multiple lein projects at once, similar to the way you would work with master pom => child poms with maven, there is a lein-sub.
But in your case, it seems that what you want is different lein profiles, classpaths. Take a look at lein profiles documentation, it should solve "in dev do this, in test do this, in production do this" behavior you are after.

How do you configure proprietary dependencies for Leiningen?

We're working on a project that has some Clojure-Java interop. At this point we have a single class that has a variety of dependencies which we put into a user library in Eclipse for development, but of course that doesn't help when using Leiningen (2.x). Most of our dependencies are proprietary, so they aren't on a repository somewhere.
What is the easiest/right way to do this?
I've seen leiningen - how to add dependencies for local jars?, but it appears to be out of date?
Update: So I made a local maven repository for my jar following these instructions and the lein deployment docs on github, and edited my project.clj file like this:
:dependencies [[...]
[usc "0.1.0"]]
:repositories {"usc" "file://maven_repository"}
Where maven_repository is under the project directory (hence not using file:///). When I ran "lein deps"--I got this message:
Retrieving usc/usc/0.1.0/usc-0.1.0.pom from usc
Could not transfer artifact usc:usc:pom:0.1.0 from/to usc (file://maven_repository): no supported algorithms found
This could be due to a typo in :dependencies or network issues.
Could not resolve dependencies
What is meant by "no supported algorithms found" and how do I fix it?
Update2: Found the last bit of the answer here.
add them as a dependency to your leiningen project. You can make up the names and versions.
then run lein deps and the error message when it fails to find it will give you the exact command to run so you can install the jar to your local repo then sould you decide to use a shared repo you can use this same process to put your dependencies there.
#Arthur's answer is good but I figured I'd flesh it out a bit more since it leaves some details lacking.
Always keep in mind Repeatability. If you don't make it so that anyone who needs access to the artifacts can get access to the artifacts in a standard way, you're asking for support hell.
The documentation on deployment is a good place to go to find out everything you need to know about deploying your artifacts. Since you're in a polyglot environment you probably can't have lein take care of deploying all your artifacts but at least you can get your clojure specific jars up into S3 or even a file share if you like. The rest of your artifacts will have to use Maven or Ant directly to upload the artifacts to the Maven repo on the file server or S3. At my current company we are using technomancy's excellent s3 wagon private to great effect for hosting our closed source artifacts and clojars for hosting anything that we can open-source.
What #Arthur is referring to is doing a lein install. All that does is install a copy of the current project into your local .m2 directory so that other projects on your box can reference them. Unless you have configured your install of maven to use a shared directory for your .m2 folder (maybe not a bad idea in your environment?), this will mean that anyone else who checks out your project will not be able to build it. If you wanted to go this route, you need to set the localRepository node in your $M2_HOME/conf/settings.xml to be the shared location that the rest of your team has access to. See the docs for more information.
YMMV but I've found it best to use Maven rather than Leiningen when you are working with Polyglot Clojure / Java projects.
It's mainly because the Java based tools (Eclipse etc.) understand Maven projects but don't really understand Leiningen projects. It's getting slowly better with the excellent Counterclockwise Clojure plugin, but the integration still isn't quite good enough yet for an efficient IDE based workflow.
On the repository side of things, I'd suggest setting up a private shared Maven repository. You're going to need it sooner or later if you plan to manage a complex set of dependencies within your team: might as well bite the bullet and get it done now.

How to share a dependency that isn't in Clojars

I need to use the mongo-storm library and Clojars doesn't have it. So I cloned the project, compiled and copied the jar to my lib folder by hand. But it is a team project and it is unacceptable for every member to do those steps by hand.
Are there any better and standard ideas on how to solve this issue?
Your team should have a private repository for this purpose. S3 is an ideal substrate for this, and you can use the s3-wagon-private Leiningen plugin to deploy and consume artifacts to/from a secured S3 bucket:
https://github.com/technomancy/s3-wagon-private
If the project has a license that allows it (if it's open source) you are allowed to push your own unofficial version to Clojars yourself using your own group ID. Clojars reserves the "org.clojars.username" group IDs for this purpose. This is described in https://github.com/ato/clojars-web/wiki/tutorial and https://github.com/technomancy/leiningen/blob/master/doc/DEPLOY.md .
The best way would probably be if you could contact the author and to urge him/her to do a proper release. (Also, the readme doesn't tell what license the project has.)
A solution that doesn't require setting up a private repository would be to leverage the checkouts capability in leiningen.
Ideally, if your team is using a maven based dependency management system (like Leiningen), you would have a repository manager set up. You can then deploy the library to your team's repository manager.
Most repository managers have Maven Central already included and make it easy to both add additional repositories to proxy (e.g. Clojars) and host your own repositories (for mongo-storm and the project being developed).
After getting one set up, one of the things you'll want to make sure your team does is either set as a repository proxy or as an additional repository to pull jars from.
You can find a list of repository managers on the maven site.