Leiningen Repositories

This section provides comprehensive documentation for configuring and using Leiningen with CloudRepo Maven repositories.

Overview

Leiningen is the traditional and most widely-adopted build automation tool for Clojure projects. Created in 2009, it remains the preferred choice for many Clojure developers and teams, offering a comprehensive solution for project management, dependency resolution, and build automation.

What is Leiningen?

Leiningen is a build automation and dependency management tool that:

  • Manages Dependencies: Fetches and manages JVM libraries from Maven repositories

  • Builds Projects: Compiles Clojure code and creates JAR artifacts

  • Runs Tasks: Executes tests, starts REPLs, and runs custom tasks

  • Generates Projects: Provides templates for creating new projects

  • Handles Deployment: Publishes libraries to Maven repositories

Leiningen uses a project.clj file written in Clojure syntax to define project configuration, making it familiar and intuitive for Clojure developers.

Leiningen vs deps.edn

Choosing Between Leiningen and deps.edn

Aspect

Leiningen

deps.edn / tools.deps

Use Case

Full-featured builds, traditional projects

Minimal tooling, modern CLI approach

Configuration

project.clj (Clojure syntax)

deps.edn (EDN data)

Build Features

Comprehensive built-in tasks

Requires additional tools

Plugin Ecosystem

Extensive plugin system

Tool-based extensions

Learning Curve

Steeper but more features

Minimal, focused on dependencies

JAR Creation

Built-in uberjar support

Requires tools.build

Templates

Rich template system

Limited templates

Note

Many teams use both tools: Leiningen for established projects and complex builds, deps.edn for new projects and library development. CloudRepo supports both approaches seamlessly.

Why Private Maven Repositories?

Teams using Leiningen need private Maven repositories to:

  • Share Internal Libraries: Distribute proprietary Clojure libraries within the organization

  • Control Dependencies: Ensure consistent, reliable access to third-party libraries

  • Maintain Privacy: Keep sensitive code and algorithms secure

  • Version Management: Control library versions across teams and projects

  • Reduce External Dependencies: Cache external libraries for reliability

  • Comply with Regulations: Meet data residency and security requirements

Prerequisites

Before configuring Leiningen with CloudRepo, ensure you have:

  1. A CloudRepo Maven Repository

    Create a Maven repository in the CloudRepo Admin Portal:

    • Navigate to RepositoriesCreate Repository

    • Select Maven as the repository type

    • Note your repository URL: https://[organization-id].mycloudrepo.io/repositories/[repository-id]

    See Creating a Repository for detailed instructions.

  2. A Repository User

    Create a dedicated user for repository access:

    • Navigate to UsersCreate User

    • Assign appropriate permissions (read/write)

    • Save the credentials securely

    See Creating Users for detailed instructions.

Warning

For security reasons, the admin user cannot access repositories directly. Always create dedicated repository users.

  1. Leiningen Installed

    Install Leiningen following the official instructions:

    Verify Leiningen Installation
    lein --version
    # Output: Leiningen 2.11.2 on Java 17.0.8 OpenJDK 64-Bit Server VM
    

Configuring project.clj

Repository Configuration

Configure CloudRepo repositories in your project.clj file for both fetching and deploying artifacts.

Basic Repository Setup

project.clj - Basic CloudRepo Configuration
 1(defproject com.example/my-library "0.1.0-SNAPSHOT"
 2  :description "A private Clojure library"
 3  :url "https://github.com/example/my-library"
 4  :license {:name "Proprietary"
 5            :url ""}
 6
 7  :dependencies [[org.clojure/clojure "1.11.1"]
 8                 [com.example/internal-lib "1.2.3"]]
 9
10  ;; Repository for fetching dependencies
11  :repositories [["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
12                               :username :env/cloudrepo_username
13                               :password :env/cloudrepo_password}]
14                 ["central" {:url "https://repo1.maven.org/maven2/"
15                            :snapshots false}]
16                 ["clojars" {:url "https://clojars.org/repo/"}]]
17
18  ;; Repository for deploying artifacts
19  :deploy-repositories [["releases" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
20                                     :username :env/cloudrepo_username
21                                     :password :env/cloudrepo_password
22                                     :sign-releases false}]
23                       ["snapshots" {:url "https://mycompany.mycloudrepo.io/repositories/maven-snapshots"
24                                    :username :env/cloudrepo_username
25                                    :password :env/cloudrepo_password
26                                    :sign-releases false}]])

Advanced Repository Configuration

project.clj - Advanced Repository Features
 1(defproject com.example/advanced-library "2.0.0"
 2  :description "Advanced Leiningen configuration example"
 3
 4  ;; Repository configuration with mirrors and policies
 5  :repositories [["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
 6                               :username :env/cloudrepo_username
 7                               :password :env/cloudrepo_password
 8                               :update :always  ; :daily, :always, or :never
 9                               :checksum :fail  ; :fail, :warn, or :ignore
10                               :releases {:enabled true
11                                         :update :daily}
12                               :snapshots {:enabled false}}]
13
14                 ;; Mirror configuration for Maven Central
15                 ["cloudrepo-central" {:url "https://mycompany.mycloudrepo.io/repositories/maven-central-proxy"
16                                      :username :env/cloudrepo_username
17                                      :password :env/cloudrepo_password
18                                      :mirror-of "central"
19                                      :mirror-exclude "clojars"}]]
20
21  ;; Separate repositories for different artifact types
22  :deploy-repositories [["releases" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
23                                     :username :env/cloudrepo_username
24                                     :password :env/cloudrepo_password}]
25                       ["snapshots" {:url "https://mycompany.mycloudrepo.io/repositories/maven-snapshots"
26                                    :username :env/cloudrepo_username
27                                    :password :env/cloudrepo_password}]]
28
29  ;; Repository authentication via GPG
30  :signing {:gpg-key "your-gpg-key@example.com"})

Authentication Setup

Leiningen supports multiple authentication methods. Choose the most appropriate for your security requirements.

Profiles Configuration (~/.lein/profiles.clj)

Store credentials in your Leiningen profiles for user-specific configuration:

~/.lein/profiles.clj - User Authentication
 1{:auth {:repository-auth {#"https://mycompany\.mycloudrepo\.io/.*"
 2                          {:username "your-repository-user@example.com"
 3                           :password "your-secure-password"}}}}
 4
 5;; Alternative: Separate profiles for different environments
 6{:dev {:repository-auth {#"https://mycompany\.mycloudrepo\.io/.*"
 7                        {:username "dev-user@example.com"
 8                         :password "dev-password"}}}
 9
10 :prod {:repository-auth {#"https://mycompany\.mycloudrepo\.io/.*"
11                         {:username "prod-user@example.com"
12                          :password "prod-password"}}}}

Warning

The profiles.clj file contains plaintext passwords. Ensure proper file permissions: chmod 600 ~/.lein/profiles.clj

GPG Encrypted Credentials

For enhanced security, use GPG to encrypt credentials:

~/.lein/profiles.clj - GPG Encrypted Credentials
1{:auth {:repository-auth {#"https://mycompany\.mycloudrepo\.io/.*"
2                          {:username "your-repository-user@example.com"
3                           :password [:gpg :env/cloudrepo_password_gpg]}}}}
Creating GPG Encrypted Password
# Encrypt password
echo -n "your-password" | gpg --armor --encrypt -r your-gpg-key@example.com > password.gpg

# Set as environment variable
export CLOUDREPO_PASSWORD_GPG=$(cat password.gpg)

Publishing Clojure Libraries

Basic Deployment

Deploy your Clojure library to CloudRepo using Leiningen’s deploy command:

Basic Library Deployment
1# Deploy a release version
2lein deploy releases
3
4# Deploy a snapshot version
5lein deploy snapshots
6
7# Deploy to default repository (based on version)
8lein deploy

Version Management

Leiningen automatically determines the target repository based on version:

project.clj - Version-based Deployment
1;; SNAPSHOT version - deploys to snapshots repository
2(defproject com.example/my-lib "1.0.0-SNAPSHOT"
3  ;; ... configuration ...
4  )
5
6;; Release version - deploys to releases repository
7(defproject com.example/my-lib "1.0.0"
8  ;; ... configuration ...
9  )

Artifact Generation

Leiningen generates multiple artifacts during deployment:

Generated Artifacts
 1# Standard JAR with compiled Clojure code
 2my-library-1.0.0.jar
 3
 4# POM file with project metadata
 5my-library-1.0.0.pom
 6
 7# Sources JAR (optional)
 8my-library-1.0.0-sources.jar
 9
10# Javadoc JAR (optional)
11my-library-1.0.0-javadoc.jar

Configure additional artifacts in project.clj:

project.clj - Artifact Configuration
 1(defproject com.example/my-library "1.0.0"
 2  ;; Include source files
 3  :source-paths ["src"]
 4  :java-source-paths ["java-src"]
 5
 6  ;; Generate additional artifacts
 7  :classifiers {:sources {:source-paths ["src"]
 8                         :resource-paths []}
 9                :javadoc {:source-paths []
10                         :resource-paths []
11                         :javadoc-opts {:package-names ["com.example"]
12                                      :output-dir "target/javadoc"}}}
13
14  ;; Include resources
15  :resource-paths ["resources"]
16
17  ;; AOT compilation for better performance
18  :aot [com.example.my-library.core]
19
20  ;; Metadata for POM
21  :pom-addition [:developers [:developer
22                              [:id "developer1"]
23                              [:name "Jane Developer"]
24                              [:email "jane@example.com"]]])

Deployment Workflow

Follow this workflow for reliable deployments:

Complete Deployment Workflow
 1# 1. Clean previous builds
 2lein clean
 3
 4# 2. Run tests
 5lein test
 6
 7# 3. Check for reflection warnings (Clojure best practice)
 8lein check
 9
10# 4. Generate JAR locally for verification
11lein jar
12
13# 5. Deploy to CloudRepo
14lein deploy
15
16# Alternative: All-in-one command
17lein do clean, test, check, deploy

Consuming Dependencies

Adding Private Dependencies

Include CloudRepo-hosted libraries in your project:

project.clj - Using Private Dependencies
 1(defproject com.example/my-application "0.1.0"
 2  :dependencies [[org.clojure/clojure "1.11.1"]
 3                 ;; Public dependencies from Clojars/Maven Central
 4                 [ring/ring-core "1.10.0"]
 5                 [compojure "1.7.0"]
 6
 7                 ;; Private dependencies from CloudRepo
 8                 [com.mycompany/auth-library "2.3.1"]
 9                 [com.mycompany/data-processor "1.5.0-SNAPSHOT"]
10                 [com.mycompany/utils "3.0.0" :classifier "sources"]]
11
12  :repositories [["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
13                               :username :env/cloudrepo_username
14                               :password :env/cloudrepo_password}]
15                 ["cloudrepo-snapshots" {:url "https://mycompany.mycloudrepo.io/repositories/maven-snapshots"
16                                        :username :env/cloudrepo_username
17                                        :password :env/cloudrepo_password}]])

Dependency Resolution Order

Control how Leiningen resolves dependencies:

project.clj - Repository Priority
 1(defproject com.example/my-app "1.0.0"
 2  ;; Repositories are checked in order
 3  :repositories [;; 1. Check CloudRepo first for internal libraries
 4                 ["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
 5                              :username :env/cloudrepo_username
 6                              :password :env/cloudrepo_password}]
 7
 8                 ;; 2. Then check Clojars for Clojure libraries
 9                 ["clojars" {:url "https://clojars.org/repo/"}]
10
11                 ;; 3. Finally check Maven Central
12                 ["central" {:url "https://repo1.maven.org/maven2/"
13                            :snapshots false}]]
14
15  ;; Disable automatic repository inclusion
16  :omit-default-repositories true)

Repository Mirrors

Use CloudRepo as a proxy/mirror for external repositories:

project.clj - Repository Mirroring
 1(defproject com.example/my-app "1.0.0"
 2  :repositories [;; CloudRepo proxy for Maven Central
 3                 ["cloudrepo-central" {:url "https://mycompany.mycloudrepo.io/repositories/maven-central-proxy"
 4                                      :username :env/cloudrepo_username
 5                                      :password :env/cloudrepo_password
 6                                      :mirror-of "central"}]
 7
 8                 ;; CloudRepo proxy for Clojars
 9                 ["cloudrepo-clojars" {:url "https://mycompany.mycloudrepo.io/repositories/clojars-proxy"
10                                      :username :env/cloudrepo_username
11                                      :password :env/cloudrepo_password
12                                      :mirror-of "clojars"}]
13
14                 ;; Direct CloudRepo repository
15                 ["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
16                              :username :env/cloudrepo_username
17                              :password :env/cloudrepo_password}]])

Dependency Management

Advanced dependency management techniques:

project.clj - Dependency Management
 1(defproject com.example/my-app "1.0.0"
 2  :dependencies [[org.clojure/clojure "1.11.1"]
 3
 4                 ;; Exclude transitive dependencies
 5                 [com.mycompany/lib-with-deps "1.0.0"
 6                  :exclusions [commons-logging
 7                              log4j]]
 8
 9                 ;; Override transitive dependency versions
10                 [com.mycompany/another-lib "2.0.0"]
11                 [org.slf4j/slf4j-api "2.0.9"]] ; Override version
12
13  ;; Global exclusions
14  :exclusions [commons-logging
15               commons-codec]
16
17  ;; Dependency version management
18  :managed-dependencies [[org.slf4j/slf4j-api "2.0.9"]
19                        [org.clojure/data.json "2.4.0"]]
20
21  ;; Pedantic mode for version conflicts
22  :pedantic? :abort) ; :abort, :warn, or false

Advanced Leiningen Features

Profiles for Different Environments

Use profiles to manage environment-specific configurations:

project.clj - Environment Profiles
 1(defproject com.example/my-app "1.0.0"
 2  :description "Application with environment profiles"
 3
 4  ;; Base configuration
 5  :dependencies [[org.clojure/clojure "1.11.1"]]
 6
 7  :profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]
 8                                 [criterium "0.4.6"]]
 9                  :repositories [["cloudrepo-dev"
10                                 {:url "https://mycompany.mycloudrepo.io/repositories/maven-dev"
11                                  :username :env/cloudrepo_dev_username
12                                  :password :env/cloudrepo_dev_password}]]
13                  :resource-paths ["dev-resources"]
14                  :jvm-opts ["-Dconf=dev-config.edn"]}
15
16            :test {:dependencies [[test-runner "1.0.0"]]
17                  :resource-paths ["test-resources"]}
18
19            :staging {:repositories [["cloudrepo-staging"
20                                     {:url "https://mycompany.mycloudrepo.io/repositories/maven-staging"
21                                      :username :env/cloudrepo_staging_username
22                                      :password :env/cloudrepo_staging_password}]]
23                     :jvm-opts ["-Dconf=staging-config.edn"]}
24
25            :production {:repositories [["cloudrepo-prod"
26                                        {:url "https://mycompany.mycloudrepo.io/repositories/maven-prod"
27                                         :username :env/cloudrepo_prod_username
28                                         :password :env/cloudrepo_prod_password}]]
29                        :jvm-opts ["-Dconf=prod-config.edn"
30                                  "-Xmx2g"]
31                        :aot :all}
32
33            ;; Composite profile
34            :dev-all [:dev :test]})
Using Profiles
# Activate dev profile
lein with-profile dev repl

# Run tests with test profile
lein with-profile test test

# Deploy with production profile
lein with-profile production deploy

# Combine profiles
lein with-profile dev,test deps

Plugins and Middleware

Extend Leiningen with plugins:

project.clj - Plugins Configuration
 1(defproject com.example/my-app "1.0.0"
 2  ;; Global plugins
 3  :plugins [[lein-ancient "1.0.0-RC3"]      ; Check for outdated dependencies
 4            [lein-cloverage "1.2.4"]         ; Code coverage
 5            [lein-kibit "0.1.8"]             ; Static code analysis
 6            [lein-bikeshed "0.5.2"]          ; Code style checking
 7            [lein-release "1.0.9"]]          ; Release automation
 8
 9  ;; Plugin repositories (if needed)
10  :plugin-repositories [["cloudrepo-plugins"
11                        {:url "https://mycompany.mycloudrepo.io/repositories/maven-plugins"
12                         :username :env/cloudrepo_username
13                         :password :env/cloudrepo_password}]]
14
15  ;; Plugin-specific configuration
16  :cloverage {:output "target/coverage"
17             :codecov? true
18             :html? true}
19
20  :release-tasks [["vcs" "assert-committed"]
21                 ["change" "version" "leiningen.release/bump-version" "release"]
22                 ["vcs" "commit"]
23                 ["vcs" "tag" "--no-sign"]
24                 ["deploy"]
25                 ["change" "version" "leiningen.release/bump-version"]
26                 ["vcs" "commit"]
27                 ["vcs" "push"]])

Multi-Module Projects

Manage multi-module projects with lein-modules:

Parent project.clj - Multi-Module Configuration
 1(defproject com.example/parent-project "1.0.0"
 2  :description "Parent project for multi-module application"
 3  :plugins [[lein-modules "0.3.11"]]
 4
 5  :modules {:versions {org.clojure/clojure "1.11.1"
 6                      com.example/shared-lib :version}
 7
 8            :dirs ["modules/core"
 9                  "modules/api"
10                  "modules/web"
11                  "modules/shared"]
12
13            :inherited {:repositories [["cloudrepo"
14                                       {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
15                                        :username :env/cloudrepo_username
16                                        :password :env/cloudrepo_password}]]
17
18                       :deploy-repositories [["releases"
19                                             {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
20                                              :username :env/cloudrepo_username
21                                              :password :env/cloudrepo_password}]]
22
23                       :license {:name "Proprietary"
24                                :url ""}
25
26                       :organization {:name "Example Corp"
27                                    :url "https://example.com"}}
28
29            :subprocess nil})
modules/core/project.clj - Child Module
1(defproject com.example/core-module "1.0.0"
2  :description "Core module"
3  :dependencies [[org.clojure/clojure "_"]  ; Version from parent
4                 [com.example/shared-lib "_"]])
Multi-Module Commands
# Install all modules
lein modules install

# Deploy all modules
lein modules deploy

# Run tests in all modules
lein modules test

# Run command in specific module
lein modules :dirs "modules/core" test

Uberjar Deployment

Deploy standalone executable JARs:

project.clj - Uberjar Configuration
 1(defproject com.example/standalone-app "1.0.0"
 2  :description "Standalone application"
 3  :dependencies [[org.clojure/clojure "1.11.1"]
 4                 [com.mycompany/internal-lib "2.0.0"]]
 5
 6  :repositories [["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
 7                               :username :env/cloudrepo_username
 8                               :password :env/cloudrepo_password}]]
 9
10  :main com.example.standalone-app.core
11
12  ;; Uberjar configuration
13  :profiles {:uberjar {:aot :all
14                      :jvm-opts ["-Dclojure.compiler.direct-linking=true"]
15                      :uberjar-name "standalone-app.jar"
16                      :omit-source true}}
17
18  ;; Deploy uberjar to CloudRepo
19  :deploy-repositories [["releases" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
20                                     :username :env/cloudrepo_username
21                                     :password :env/cloudrepo_password}]]
22
23  ;; Custom deployment for uberjar
24  :classifiers {:standalone {:jar-name "standalone-app.jar"
25                             :uberjar true}})
Building and Deploying Uberjars
# Build uberjar
lein uberjar

# Deploy regular JAR and uberjar
lein deploy releases

# Deploy only uberjar with classifier
lein deploy releases com.example/standalone-app "1.0.0" target/standalone-app.jar :classifier "standalone"

ClojureScript Projects

Configure Leiningen for ClojureScript projects:

project.clj - ClojureScript Configuration
 1(defproject com.example/cljs-app "1.0.0"
 2  :description "ClojureScript application"
 3  :dependencies [[org.clojure/clojure "1.11.1"]
 4                 [org.clojure/clojurescript "1.11.132"]
 5                 ;; Private ClojureScript libraries from CloudRepo
 6                 [com.mycompany/cljs-components "1.2.0"]]
 7
 8  :repositories [["cloudrepo" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
 9                               :username :env/cloudrepo_username
10                               :password :env/cloudrepo_password}]]
11
12  :plugins [[lein-cljsbuild "1.1.8"]
13            [lein-figwheel "0.5.20"]]
14
15  :cljsbuild {:builds [{:id "dev"
16                       :source-paths ["src"]
17                       :figwheel {:on-jsload "com.example.app/reload"}
18                       :compiler {:main com.example.app
19                                :asset-path "js/compiled/out"
20                                :output-to "resources/public/js/compiled/app.js"
21                                :output-dir "resources/public/js/compiled/out"
22                                :source-map-timestamp true}}
23
24                      {:id "prod"
25                       :source-paths ["src"]
26                       :compiler {:main com.example.app
27                                :output-to "resources/public/js/compiled/app.js"
28                                :optimizations :advanced
29                                :pretty-print false}}]}
30
31  ;; Deploy compiled JavaScript to CloudRepo Raw repository
32  :deploy-repositories [["js-releases" {:url "https://mycompany.mycloudrepo.io/repositories/raw-releases"
33                                        :username :env/cloudrepo_username
34                                        :password :env/cloudrepo_password}]])

CI/CD Integration

GitHub Actions

Configure GitHub Actions for automated deployments:

.github/workflows/deploy.yml - GitHub Actions Configuration
 1name: Deploy to CloudRepo
 2
 3on:
 4  push:
 5    branches: [ main ]
 6    tags: [ 'v*' ]
 7
 8jobs:
 9  test:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v4
13
14      - name: Set up JDK
15        uses: actions/setup-java@v4
16        with:
17          java-version: '17'
18          distribution: 'temurin'
19
20      - name: Cache Leiningen dependencies
21        uses: actions/cache@v3
22        with:
23          path: ~/.m2
24          key: ${{ runner.os }}-m2-${{ hashFiles('**/project.clj') }}
25          restore-keys: |
26            ${{ runner.os }}-m2-
27
28      - name: Install Leiningen
29        run: |
30          curl -O https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
31          chmod +x lein
32          sudo mv lein /usr/local/bin/
33          lein version
34
35      - name: Run tests
36        run: lein test
37
38      - name: Check code quality
39        run: |
40          lein kibit
41          lein bikeshed
42
43  deploy:
44    needs: test
45    runs-on: ubuntu-latest
46    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
47
48    steps:
49      - uses: actions/checkout@v4
50
51      - name: Set up JDK
52        uses: actions/setup-java@v4
53        with:
54          java-version: '17'
55          distribution: 'temurin'
56
57      - name: Install Leiningen
58        run: |
59          curl -O https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
60          chmod +x lein
61          sudo mv lein /usr/local/bin/
62
63      - name: Deploy to CloudRepo
64        env:
65          CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
66          CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
67        run: |
68          lein deploy releases

GitLab CI

Configure GitLab CI for continuous deployment:

.gitlab-ci.yml - GitLab CI Configuration
 1image: clojure:temurin-17-lein-2.11.2
 2
 3variables:
 4  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
 5
 6cache:
 7  paths:
 8    - .m2/repository/
 9
10stages:
11  - test
12  - deploy
13
14test:
15  stage: test
16  script:
17    - lein test
18    - lein cloverage
19  artifacts:
20    reports:
21      coverage_report:
22        coverage_format: cobertura
23        path: target/coverage/cobertura.xml
24
25deploy-snapshot:
26  stage: deploy
27  script:
28    - lein deploy snapshots
29  environment:
30    name: development
31  only:
32    - develop
33  variables:
34    CLOUDREPO_USERNAME: ${CI_CLOUDREPO_USERNAME}
35    CLOUDREPO_PASSWORD: ${CI_CLOUDREPO_PASSWORD}
36
37deploy-release:
38  stage: deploy
39  script:
40    - lein deploy releases
41  environment:
42    name: production
43  only:
44    - tags
45  variables:
46    CLOUDREPO_USERNAME: ${CI_CLOUDREPO_PROD_USERNAME}
47    CLOUDREPO_PASSWORD: ${CI_CLOUDREPO_PROD_PASSWORD}

Jenkins Pipeline

Configure Jenkins for Leiningen deployments:

Jenkinsfile - Jenkins Pipeline Configuration
 1pipeline {
 2    agent any
 3
 4    tools {
 5        jdk 'JDK-17'
 6    }
 7
 8    environment {
 9        CLOUDREPO_USERNAME = credentials('cloudrepo-username')
10        CLOUDREPO_PASSWORD = credentials('cloudrepo-password')
11    }
12
13    stages {
14        stage('Checkout') {
15            steps {
16                checkout scm
17            }
18        }
19
20        stage('Setup Leiningen') {
21            steps {
22                sh '''
23                    if ! command -v lein &> /dev/null; then
24                        curl -O https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
25                        chmod +x lein
26                        sudo mv lein /usr/local/bin/
27                    fi
28                    lein version
29                '''
30            }
31        }
32
33        stage('Test') {
34            steps {
35                sh 'lein test'
36                junit 'target/test-results/**/*.xml'
37            }
38        }
39
40        stage('Code Quality') {
41            parallel {
42                stage('Coverage') {
43                    steps {
44                        sh 'lein cloverage'
45                        publishHTML(target: [
46                            reportDir: 'target/coverage',
47                            reportFiles: 'index.html',
48                            reportName: 'Coverage Report'
49                        ])
50                    }
51                }
52                stage('Static Analysis') {
53                    steps {
54                        sh 'lein kibit'
55                        sh 'lein bikeshed'
56                    }
57                }
58            }
59        }
60
61        stage('Deploy') {
62            when {
63                anyOf {
64                    branch 'main'
65                    tag pattern: "v\\d+\\.\\d+\\.\\d+", comparator: "REGEXP"
66                }
67            }
68            steps {
69                script {
70                    if (env.TAG_NAME) {
71                        sh 'lein deploy releases'
72                    } else {
73                        sh 'lein deploy snapshots'
74                    }
75                }
76            }
77        }
78    }
79
80    post {
81        always {
82            cleanWs()
83        }
84    }
85}

CircleCI

Configure CircleCI for automated deployments:

.circleci/config.yml - CircleCI Configuration
 1version: 2.1
 2
 3executors:
 4  clojure:
 5    docker:
 6      - image: cimg/clojure:1.11.1-openjdk-17.0
 7    environment:
 8      JVM_OPTS: -Xmx3200m
 9
10jobs:
11  test:
12    executor: clojure
13    steps:
14      - checkout
15      - restore_cache:
16          keys:
17            - v1-dependencies-{{ checksum "project.clj" }}
18            - v1-dependencies-
19
20      - run:
21          name: Install dependencies
22          command: lein deps
23
24      - save_cache:
25          paths:
26            - ~/.m2
27          key: v1-dependencies-{{ checksum "project.clj" }}
28
29      - run:
30          name: Run tests
31          command: lein test
32
33      - store_test_results:
34          path: target/test-results
35
36  deploy:
37    executor: clojure
38    steps:
39      - checkout
40      - restore_cache:
41          keys:
42            - v1-dependencies-{{ checksum "project.clj" }}
43
44      - run:
45          name: Deploy to CloudRepo
46          command: |
47            if [ "${CIRCLE_TAG}" ]; then
48              lein deploy releases
49            else
50              lein deploy snapshots
51            fi
52
53workflows:
54  test-and-deploy:
55    jobs:
56      - test:
57          filters:
58            tags:
59              only: /.*/
60      - deploy:
61          requires:
62            - test
63          filters:
64            branches:
65              only: main
66            tags:
67              only: /^v.*/
68          context:
69            - cloudrepo-credentials

Secure Credential Management

Best practices for managing CloudRepo credentials in CI/CD:

  1. Use Secret Management Services

    AWS Secrets Manager Example
    # Retrieve credentials in CI/CD pipeline
    export CLOUDREPO_USERNAME=$(aws secretsmanager get-secret-value \
      --secret-id cloudrepo/username \
      --query SecretString --output text)
    
    export CLOUDREPO_PASSWORD=$(aws secretsmanager get-secret-value \
      --secret-id cloudrepo/password \
      --query SecretString --output text)
    
  2. Rotate Credentials Regularly

    project.clj - Multiple Credential Sets
    (defproject com.example/my-app "1.0.0"
      :deploy-repositories [["releases"
                            {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
                             :username :env/cloudrepo_username_v2
                             :password :env/cloudrepo_password_v2}]])
    
  3. Use Service Accounts

    Create dedicated CI/CD users with minimal permissions in CloudRepo Admin Portal.

  4. Audit Access

    Regularly review CloudRepo access logs and repository user permissions.

Troubleshooting

Common Issues and Solutions

Authentication Failures

Problem: 401 Unauthorized or 403 Forbidden errors

Debugging Authentication
# Verify environment variables
echo $CLOUDREPO_USERNAME
echo $CLOUDREPO_PASSWORD | wc -c  # Check password is set (don't echo it)

# Test with explicit credentials
lein deploy releases com.example/test "0.0.1" \
  target/test-0.0.1.jar \
  pom.xml \
  :repository [["test" {:url "https://mycompany.mycloudrepo.io/repositories/maven-releases"
                       :username "user@example.com"
                       :password "password"}]]

# Check profiles.clj
cat ~/.lein/profiles.clj

Solutions:

  • Verify credentials in CloudRepo Admin Portal

  • Ensure repository user has appropriate permissions

  • Check for typos in repository URLs

  • Confirm environment variables are exported correctly

Dependency Resolution Issues

Problem: Could not find artifact errors

Debugging Dependencies
;; Add verbose output to project.clj
(defproject com.example/debug "1.0.0"
  :dependencies [[com.mycompany/missing-lib "1.0.0"]]
  :repositories [["cloudrepo" {:url "..."
                               :update :always}]]  ; Force update
  ;; Enable debug output
  :jvm-opts ["-Dclojure.debug=true"])
Debug Commands
# Show dependency tree
lein deps :tree

# Force re-download
lein deps :force

# Check specific artifact
lein deps :why com.mycompany/missing-lib

# Clear local cache
rm -rf ~/.m2/repository/com/mycompany/missing-lib

SSL/TLS Certificate Issues

Problem: SSLHandshakeException or certificate errors

SSL Troubleshooting
# Test SSL connection
openssl s_client -connect mycompany.mycloudrepo.io:443 -showcerts

# Import CloudRepo certificate (if using self-signed)
keytool -import -trustcacerts \
  -keystore $JAVA_HOME/lib/security/cacerts \
  -storepass changeit \
  -alias cloudrepo \
  -file cloudrepo.crt

# Disable SSL verification (development only!)
export JVM_OPTS="-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true"

Deployment Failures

Problem: Artifacts don’t appear in CloudRepo after deployment

Deployment Debugging
# Enable verbose logging
DEBUG=1 lein deploy releases

# Check local artifact generation
lein jar
ls -la target/

# Verify POM generation
lein pom
cat pom.xml

# Manual deployment test
mvn deploy:deploy-file \
  -DgroupId=com.example \
  -DartifactId=test \
  -Dversion=1.0.0 \
  -Dpackaging=jar \
  -Dfile=target/test-1.0.0.jar \
  -DrepositoryId=cloudrepo \
  -Durl=https://mycompany.mycloudrepo.io/repositories/maven-releases

Performance Optimization

Improve Leiningen performance with CloudRepo:

project.clj - Performance Optimizations
 1(defproject com.example/optimized "1.0.0"
 2  ;; Parallel dependency downloads
 3  :jvm-opts ["-Dmaven.artifact.threads=10"]
 4
 5  ;; Local repository caching
 6  :local-repo ".m2"
 7
 8  ;; Minimize repository checks
 9  :repositories [["cloudrepo" {:url "..."
10                               :update :daily  ; Not :always
11                               :checksum :warn}]]  ; Not :fail
12
13  ;; Offline mode for CI builds
14  :offline? false  ; Set to true when possible
15
16  ;; Repository caching proxy
17  :mirrors {#".*" {:name "cloudrepo-mirror"
18                  :url "https://mycompany.mycloudrepo.io/repositories/all-proxy"}})

Best Practices

  1. Version Management

    • Use semantic versioning (MAJOR.MINOR.PATCH)

    • Deploy SNAPSHOT versions during development

    • Tag releases in version control

  2. Security

    • Never commit credentials to version control

    • Use environment variables or encrypted storage

    • Rotate credentials regularly

    • Use separate credentials for different environments

  3. Repository Organization

    • Separate repositories for releases and snapshots

    • Use repository groups for simplified configuration

    • Implement retention policies for snapshots

  4. Build Hygiene

    • Always run tests before deployment

    • Use lein clean to ensure fresh builds

    • Version control your project.clj carefully

  5. Documentation

    • Document repository URLs and access requirements

    • Maintain README files with setup instructions

    • Include license and contributor information

Summary

This guide has covered comprehensive Leiningen integration with CloudRepo, including:

  • Basic Setup: Repository configuration and authentication

  • Publishing: Deploying Clojure libraries and applications

  • Consumption: Using private dependencies effectively

  • Advanced Features: Profiles, plugins, and multi-module projects

  • CI/CD: Automated deployments across major platforms

  • Troubleshooting: Common issues and solutions

Leiningen’s mature ecosystem and comprehensive feature set make it an excellent choice for teams building production Clojure applications. CloudRepo provides the secure, reliable Maven repository infrastructure needed to share and manage your Clojure artifacts effectively.

For teams also using the newer deps.edn tooling, see our Clojure deps.edn Repositories guide. Many organizations successfully use both tools, leveraging each for their respective strengths.

See Also