reifyhealth / lein-git-down

A Leiningen plugin for resolving dependencies from Git
MIT License
82 stars 5 forks source link

lein-git-down

A Leiningen plugin for resolving Clojure(Script) dependencies from a Git repository.

A message from the author

This project is no longer maintained. We would be happy to link to a fork here if anyone is interested in taking over as maintainer of this project, please let us know.

Usage

Add the plugin to the :plugins vector of your project.clj:

:plugins [[reifyhealth/lein-git-down "0.4.1"]]

If you have dependency specific configurations (see below), add the plugin's inject-properties function to your :middleware vector:

:middleware [lein-git-down.plugin/inject-properties]

Finally, configure your remote Git repository in the :repositories vector. Can optionally specify the protocol to use for connecting with the repository. Options are :https (default; for public repositories) and :ssh (for private repositories). Supports any Git remote conforming repository provider (eg: GitHub, GitLab, Bitbucket). For example, if you want to retrieve dependencies from public and private repositories in GitHub, you would add:

:repositories [["public-github" {:url "git://github.com"}]
               ["private-github" {:url "git://github.com" :protocol :ssh}]]

Now, simply add the rev (Commit SHA or Tag) you want to pull in from the remote Git repository as the dependency's version and everything should "just work" as if you were pulling it from Maven Central or Clojars. Swap the rev back to the Maven version and the artifact will be resolved as it always has.

Configuration

The plugin provides some optional configuration properties. First, add the inject-properties function to your middleware as specified above, then add a :git-down key to your project definition. It should point to a map where the dependency's Maven coordinates symbol is the key and a map of properties is the value, for example:

:git-down {group/artifact {:property "value"}}

The available properties are:

Example

Below is an example project.clj that uses the plugin:

(defproject test-project "0.1.0"
    :description "A test project"
    ;; Include the plugin
    :plugins [[reifyhealth/lein-git-down "0.4.1"]]
    ;; Add the middleware to parse the custom configurations
    :middleware [lein-git-down.plugin/inject-properties]
    ;; Specify your dependencies. This is the same as any other project.clj and
    ;; should use the Maven coordinates. The version for Git resolution should be
    ;; a valid rev (Commit SHA, Tag, etc) in the repository. Note, that Clojure
    ;; core uses a release version and will be resolved via Maven Central.
    :dependencies [[clj-time "66ea91e68583e7ee246d375859414b9a9b7aba57"]
                   [cheshire "c79ebaa3f56c365a1810f80617c80a3b62999701"]
                   [org.clojure/clojure "1.9.0"]]
    ;; Specify the remote repository to use. Supports any Git remote conforming
    ;; repository provider (eg: GitHub, GitLab, Bitbucket)
    :repositories [["public-github" {:url "git://github.com"}]]
    ;; The `clj-time` repository uses the same Git coordinates on GitHub as its
    ;; Maven coordinates, so no need to add anything here. `cheshire`, however,
    ;; does not, so we need to add the Git coordinates to our configuration.
    :git-down {cheshire {:coordinates dakrone/cheshire}})

Transitive Dependencies

The plugin supports target projects that have one of the following manifests available:

When a manifest is available, it allows the plugin to resolve the repository's transitive dependencies. If a target repository does not have one of the above manifests available, then it will be provided as a standalone project without any transitive dependencies.

The plugin does support a dependency's git transitive dependencies as well if they are specified in either a Leiningen project.clj (from a project that also uses this plugin) or a tools.deps deps.edn.

Private Repositories (SSH Authentication)

As mentioned at the top of this section, when the repository has a :protocol :ssh value set the plugin will attempt to use SSH with Public Key Authentication to resolve the dependency from a private repository. Under the covers the code uses jsch with jsch-agent-proxy, which depends on ssh-agent running on the machine and properly configured with your keys. Both of the below links provide good information on how to create your SSH keys and get them loaded into ssh-agent:

One caveat to the above articles, the SSH library used by this plugin does not support private keys in OpenSSH format, which is now the default format used by ssh-keygen. You will need to generate your key pair in PEM format using the -m PEM flag. This plugin has been patched to skip any keys in an unsupported format instead of failing, but the key used to access the remote git repository must be in a supported format even if others in your environment are not.

Side note: by default the plugin overrides an internal implementation in tools.gitlibs to provide the above fix for skipping unsupported keys and to provide a fix for an error that occurs if your private key has a password. You can opt-out of this override by specifying :monkeypatch-tools-gitlibs false at the top level of your project.clj file.

SSH Config

The jsch library does not support all HostKeyAlgorithms, Ciphers, MACs, and KexAlgorithms and will warn you about unsupported configurations in your ~/.ssh/config file. If you do want to configure these and not rely on the defaults, then the below is an example snippet that is fully supported:

Host github.com
  HostKeyAlgorithms ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
  Ciphers aes128-ctr,aes192-ctr,aes256-ctr
  MACs hmac-sha2-256,hmac-sha1
  KexAlgorithms ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1

Rationale

At a high level, the rationale is essentially the same as that of tools.deps:

Clojure build tools have traditionally taken the approach of wrapping the Maven ecosystem to gain access to Java libraries. However, they have also forced this approach on Clojure code as well, requiring a focus on artifacts that must be built and deployed (which Clojure does not require).

The ability to resolve dependencies via a remote Git repository opens up many previously unavailable workflows. For example:

While adding Git as a an option for resolving dependencies adds considerable flexibility, there is still a rich and mature ecosystem built around Maven for the subtleties and nuance of managing a complex dependency graph. This plugin seeks to bring in the best of both worlds by opening up Git as a remote repository option, but doing it "native" to the tooling by leveraging the Maven protocol. Under the covers, the plugin implements a Maven Wagon, to "translate" between the Git protocol and the Maven protocol. This allows all of the standard Leiningen dependency tooling that relies on Maven to "just work" (eg: lein deps :tree).

There are several other tools that are available. Below is a brief, non-exhaustive rundown of these tools and how this project is different:

All of these listed are great projects and may be what solves your problem. If they are, use them! We found that we needed a slightly different approach and so created this project. We hope it is useful and furthers the larger discussion around continually improving development workflows and tools.

Contributing

See CONTRIBUTING.md

License

Source Copyright © 2022 Reify Health, Inc.

Distributed under the MIT License. See the file LICENSE.