how-to

How to Set Up Codacy with Jenkins for Automated Review

Set up Codacy with Jenkins for automated code review. Covers plugin setup, Jenkinsfile config, quality gates, coverage, and multibranch pipelines.

Published:

Why integrate Codacy with Jenkins

Jenkins remains one of the most widely used CI/CD servers in enterprise environments, powering build and deployment pipelines for millions of projects worldwide. If your team relies on Jenkins for continuous integration, adding Codacy to your pipeline gives you automated code quality analysis, security scanning, and coverage tracking without switching to a different CI platform.

The core value of a Codacy Jenkins integration is consistency. Every commit and pull request that passes through your Jenkins pipeline gets the same level of automated scrutiny - static analysis across 49 languages, SAST scanning, secrets detection, duplication checks, and coverage reporting. Developers get feedback directly in their pull requests, and your team gets a centralized dashboard to track quality trends over time.

This guide covers the complete setup process for integrating Codacy with Jenkins. You will learn how to configure the Codacy Coverage Reporter in your Jenkinsfile, set up quality gate checks that can pass or fail your builds, handle multibranch pipelines for PR-based workflows, upload coverage reports from Java, JavaScript, and Python projects, and troubleshoot the most common issues that arise during integration.

Codacy code quality platform homepage screenshot
Codacy homepage

If you are new to Codacy, start with our how to setup Codacy guide to create your account and connect your repositories before configuring the Jenkins integration.

Prerequisites

Before setting up the Codacy Jenkins integration, make sure you have the following in place:

  • A running Jenkins instance - Jenkins 2.346 or later is recommended. The instance should have network access to the internet (or to your Codacy Self-Hosted server if you are using the on-premise version).
  • A Codacy account with a connected repository - Sign up at app.codacy.com and connect your GitHub, GitLab, or Bitbucket repository. See our Codacy review for an overview of what Codacy offers.
  • A Codacy project API token - Navigate to your repository in Codacy, go to Settings, and copy the Project API Token from the Coverage section.
  • Jenkins Pipeline plugin installed - This is included by default in modern Jenkins installations, but verify it is present in your Jenkins plugin manager.
  • A Jenkinsfile in your repository - While Freestyle jobs work, this guide focuses on Pipeline (Jenkinsfile) configuration because it is version-controlled, reproducible, and the recommended approach for modern Jenkins usage.

You should also have your test suite configured to generate coverage reports in a supported format. Codacy accepts LCOV, Cobertura XML, JaCoCo XML, Clover, and OpenCover.

Step 1: Store the Codacy project token in Jenkins

The first step is to securely store your Codacy project API token in Jenkins so your pipeline can authenticate with the Codacy API without exposing the token in your Jenkinsfile.

  1. Open your Jenkins dashboard and navigate to Manage Jenkins then Manage Credentials
  2. Select the appropriate credentials store (typically the global store or the store for your specific folder/pipeline)
  3. Click Add Credentials
  4. Set the following fields:
    • Kind: Secret text
    • Scope: Global (or the appropriate scope for your pipeline)
    • Secret: Paste your Codacy project API token
    • ID: CODACY_PROJECT_TOKEN
    • Description: Codacy project API token for coverage upload
// This is how you will reference the credential in your Jenkinsfile
withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
    // Codacy commands go here
}

If you have multiple repositories connected to Codacy, each one has its own project API token. You can either create separate credentials for each repository or use a naming convention like CODACY_TOKEN_<repo-name> to keep them organized.

For organization-level API access - which you may need later for quality gate checks via the Codacy API - store an account API token as a separate credential. You can generate an account API token from your Codacy account settings page.

Step 2: Configure the Jenkinsfile for Codacy coverage upload

The Codacy Coverage Reporter is a CLI tool that uploads your test coverage reports to the Codacy platform. You download it in your Jenkins pipeline, then run it after your tests complete.

Here is a basic Jenkinsfile that runs tests, generates a coverage report, and uploads it to Codacy:

Java project with Maven and JaCoCo

pipeline {
    agent any

    tools {
        maven 'Maven-3.9'
        jdk 'JDK-17'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build and Test') {
            steps {
                sh 'mvn clean test'
            }
            post {
                always {
                    junit '**/target/surefire-reports/*.xml'
                }
            }
        }

        stage('Upload Coverage to Codacy') {
            steps {
                withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
                    sh '''
                        curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
                        bash codacy-coverage-reporter.sh report \
                            -r target/site/jacoco/jacoco.xml \
                            --project-token $CODACY_PROJECT_TOKEN \
                            --commit-uuid $(git rev-parse HEAD)
                    '''
                }
            }
        }
    }
}

JavaScript/TypeScript project with npm

pipeline {
    agent any

    tools {
        nodejs 'Node-20'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install Dependencies') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Test with Coverage') {
            steps {
                sh 'npm test -- --coverage'
            }
        }

        stage('Upload Coverage to Codacy') {
            steps {
                withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
                    sh '''
                        curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
                        bash codacy-coverage-reporter.sh report \
                            -r coverage/lcov.info \
                            --project-token $CODACY_PROJECT_TOKEN \
                            --commit-uuid $(git rev-parse HEAD)
                    '''
                }
            }
        }
    }
}

Python project with pytest

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Setup Python Environment') {
            steps {
                sh '''
                    python3 -m venv venv
                    . venv/bin/activate
                    pip install -r requirements.txt
                    pip install pytest pytest-cov
                '''
            }
        }

        stage('Test with Coverage') {
            steps {
                sh '''
                    . venv/bin/activate
                    pytest --cov=src --cov-report=xml:coverage.xml
                '''
            }
        }

        stage('Upload Coverage to Codacy') {
            steps {
                withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
                    sh '''
                        curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
                        bash codacy-coverage-reporter.sh report \
                            -r coverage.xml \
                            --project-token $CODACY_PROJECT_TOKEN \
                            --commit-uuid $(git rev-parse HEAD)
                    '''
                }
            }
        }
    }
}

The --commit-uuid flag is important. It tells Codacy which specific commit the coverage data belongs to, ensuring the coverage information appears on the correct commit and pull request in the Codacy dashboard. Without it, Codacy tries to detect the commit automatically, which can fail in some Jenkins checkout configurations where the HEAD commit does not match the PR head.

Step 3: Running Codacy Analysis CLI in Jenkins

While Codacy’s GitHub or GitLab App handles static analysis automatically when you push code, you can also run the Codacy Analysis CLI directly in your Jenkins pipeline for more control. This is particularly useful when:

  • You want analysis to run as a Jenkins stage that you can monitor and gate on
  • Your repositories are on a Git server that Codacy’s apps do not natively support
  • You are using Codacy Self-Hosted and want tighter CI integration
  • You want to run analysis on branches or commits that are not tied to pull requests

Here is how to add the Codacy Analysis CLI to your Jenkinsfile:

stage('Codacy Analysis') {
    steps {
        withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
            sh '''
                curl -Ls https://github.com/codacy/codacy-analysis-cli/releases/latest/download/codacy-analysis-cli.sh \
                    -o codacy-analysis-cli.sh
                chmod +x codacy-analysis-cli.sh
                bash codacy-analysis-cli.sh analyze \
                    --project-token $CODACY_PROJECT_TOKEN \
                    --upload \
                    --commit-uuid $(git rev-parse HEAD) \
                    --verbose
            '''
        }
    }
}

The --upload flag sends the analysis results to the Codacy dashboard. Without it, the CLI only prints results locally. The --verbose flag provides detailed output for debugging purposes - you can remove it once the integration is stable.

You can also limit the analysis to specific directories or languages:

sh '''
    bash codacy-analysis-cli.sh analyze \
        --project-token $CODACY_PROJECT_TOKEN \
        --upload \
        --directory src \
        --tool eslint \
        --commit-uuid $(git rev-parse HEAD)
'''

This runs only the ESLint analysis tool on the src directory, which is useful for large repositories where full analysis takes too long or where you want to run specific tools in specific pipeline stages.

Step 4: Setting up quality gates in Jenkins

Quality gates are where the Codacy Jenkins integration becomes genuinely useful for enforcing standards. Instead of just uploading data to a dashboard, you can make your Jenkins build pass or fail based on whether the code meets your team’s quality thresholds.

Configuring quality gates in Codacy

Before you can check quality gates from Jenkins, configure them in the Codacy dashboard:

  1. Navigate to your repository in Codacy
  2. Click Quality settings in the left sidebar
  3. Set thresholds for the metrics that matter to your team

Common thresholds for a Jenkins-gated pipeline:

MetricRecommended ThresholdPurpose
New issues0 critical, 5 totalPrevent introduction of severe bugs
Coverage on new code60% minimumEnsure new code has tests
Coverage variation-1% maximum decreasePrevent coverage regression
Duplication3% maximumAvoid copy-paste code

Checking quality gates via the Codacy API

After your coverage is uploaded and analysis is complete, you can query the Codacy API to check whether the commit passes the quality gate:

stage('Check Codacy Quality Gate') {
    steps {
        withCredentials([
            string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN'),
            string(credentialsId: 'CODACY_ACCOUNT_TOKEN', variable: 'CODACY_ACCOUNT_TOKEN')
        ]) {
            script {
                def commitSha = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
                def provider = 'gh' // Use 'gl' for GitLab or 'bb' for Bitbucket
                def org = 'your-org'
                def repo = 'your-repo'

                // Wait for Codacy to finish analysis
                sleep(time: 30, unit: 'SECONDS')

                def response = sh(
                    script: """
                        curl -s -X GET \
                            "https://app.codacy.com/api/v3/analysis/organizations/${provider}/${org}/repositories/${repo}/commits/${commitSha}/quality" \
                            -H "api-token: \$CODACY_ACCOUNT_TOKEN" \
                            -H "Accept: application/json"
                    """,
                    returnStdout: true
                ).trim()

                def quality = readJSON(text: response)

                if (quality.data?.isUpToStandards == false) {
                    error "Codacy quality gate failed. Check the Codacy dashboard for details."
                }

                echo "Codacy quality gate passed."
            }
        }
    }
}

This stage queries the Codacy API for the quality gate status of the current commit. If the commit does not meet the configured thresholds, the error step fails the Jenkins build. The 30-second sleep gives Codacy time to process the analysis - for larger repositories, you may need to increase this or implement a polling loop.

Implementing a polling-based quality gate check

For more robust quality gate enforcement, use a polling approach that waits for Codacy to complete analysis rather than relying on a fixed sleep:

stage('Check Codacy Quality Gate') {
    steps {
        withCredentials([
            string(credentialsId: 'CODACY_ACCOUNT_TOKEN', variable: 'CODACY_ACCOUNT_TOKEN')
        ]) {
            script {
                def commitSha = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
                def maxAttempts = 20
                def sleepSeconds = 15
                def gatePassed = false

                for (int i = 0; i < maxAttempts; i++) {
                    def response = sh(
                        script: """
                            curl -s -o /dev/null -w '%{http_code}' \
                                "https://app.codacy.com/api/v3/analysis/organizations/gh/your-org/repositories/your-repo/commits/${commitSha}/quality" \
                                -H "api-token: \$CODACY_ACCOUNT_TOKEN"
                        """,
                        returnStdout: true
                    ).trim()

                    if (response == '200') {
                        def result = sh(
                            script: """
                                curl -s \
                                    "https://app.codacy.com/api/v3/analysis/organizations/gh/your-org/repositories/your-repo/commits/${commitSha}/quality" \
                                    -H "api-token: \$CODACY_ACCOUNT_TOKEN" \
                                    -H "Accept: application/json"
                            """,
                            returnStdout: true
                        ).trim()

                        def quality = readJSON(text: result)

                        if (quality.data?.isUpToStandards == true) {
                            gatePassed = true
                            break
                        } else if (quality.data?.isUpToStandards == false) {
                            error "Codacy quality gate failed. Issues found exceed thresholds."
                        }
                    }

                    echo "Waiting for Codacy analysis to complete (attempt ${i + 1}/${maxAttempts})..."
                    sleep(time: sleepSeconds, unit: 'SECONDS')
                }

                if (!gatePassed) {
                    error "Codacy quality gate check timed out after ${maxAttempts * sleepSeconds} seconds."
                }
            }
        }
    }
}

This approach retries the API call up to 20 times with 15-second intervals, giving Codacy up to 5 minutes to complete analysis before timing out. Adjust these values based on your repository size and typical analysis duration.

Step 5: Multibranch pipeline configuration

Multibranch pipelines are the standard Jenkins approach for handling pull request-based workflows. When you configure a multibranch pipeline, Jenkins automatically discovers branches and pull requests in your repository and creates a pipeline for each one. This maps naturally to Codacy’s PR-based analysis model.

Creating the multibranch pipeline job

  1. In Jenkins, click New Item
  2. Enter a name for the pipeline and select Multibranch Pipeline
  3. Under Branch Sources, add your Git source:
    • For GitHub, use the GitHub source and provide credentials
    • For GitLab, use the Git source with the repository URL
    • For Bitbucket, use the Bitbucket source
  4. Under Build Configuration, set:
    • Mode: by Jenkinsfile
    • Script Path: Jenkinsfile (or wherever your Jenkinsfile lives in the repo)
  5. Under Scan Multibranch Pipeline Triggers, set a periodic scan interval (e.g., every 5 minutes) or rely on webhooks

Multibranch-aware Jenkinsfile

When running in a multibranch pipeline, your Jenkinsfile needs to handle both branch builds and PR builds. Here is a complete Jenkinsfile that adapts its behavior based on the build context:

pipeline {
    agent any

    tools {
        maven 'Maven-3.9'
        jdk 'JDK-17'
    }

    environment {
        CODACY_PROJECT_TOKEN = credentials('CODACY_PROJECT_TOKEN')
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                sh 'mvn clean compile'
            }
        }

        stage('Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit '**/target/surefire-reports/*.xml'
                    jacoco(
                        execPattern: '**/target/jacoco.exec',
                        classPattern: '**/target/classes',
                        sourcePattern: '**/src/main/java'
                    )
                }
            }
        }

        stage('Upload Coverage to Codacy') {
            steps {
                sh '''
                    curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
                    bash codacy-coverage-reporter.sh report \
                        -r target/site/jacoco/jacoco.xml \
                        --project-token $CODACY_PROJECT_TOKEN \
                        --commit-uuid $(git rev-parse HEAD)
                '''
            }
        }

        stage('Quality Gate') {
            when {
                anyOf {
                    branch 'main'
                    branch 'develop'
                    changeRequest()
                }
            }
            steps {
                withCredentials([string(credentialsId: 'CODACY_ACCOUNT_TOKEN', variable: 'CODACY_ACCOUNT_TOKEN')]) {
                    script {
                        def commitSha = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()

                        // Wait and check quality gate
                        sleep(time: 45, unit: 'SECONDS')

                        def response = sh(
                            script: """
                                curl -s \
                                    "https://app.codacy.com/api/v3/analysis/organizations/gh/your-org/repositories/your-repo/commits/${commitSha}/quality" \
                                    -H "api-token: \$CODACY_ACCOUNT_TOKEN" \
                                    -H "Accept: application/json"
                            """,
                            returnStdout: true
                        ).trim()

                        def quality = readJSON(text: response)

                        if (quality.data?.isUpToStandards == false) {
                            unstable "Codacy quality gate failed - marking build as unstable."
                        }
                    }
                }
            }
        }
    }

    post {
        failure {
            echo 'Pipeline failed. Check Codacy dashboard for quality details.'
        }
        success {
            echo 'Pipeline passed. Codacy analysis and quality gate succeeded.'
        }
    }
}

Notice the when block on the Quality Gate stage. It runs only on the main and develop branches and on change requests (pull requests). This prevents the quality gate check from running on every feature branch push where it may not be relevant, while ensuring that PRs and protected branches always get quality gate enforcement.

The stage uses unstable instead of error for the quality gate failure. This marks the build as yellow (unstable) rather than red (failed), which is a common pattern for quality gate enforcement - you want visibility into quality issues without blocking the entire build. If you prefer hard enforcement, replace unstable with error.

Step 6: Uploading multiple coverage reports

Projects that have separate test suites - unit tests, integration tests, end-to-end tests - or monorepos with multiple components often generate multiple coverage reports. Codacy supports partial coverage uploads that get aggregated into a single coverage metric.

stage('Upload Coverage to Codacy') {
    steps {
        withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
            sh '''
                curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh

                # Upload unit test coverage as partial
                bash codacy-coverage-reporter.sh report \
                    -r target/site/jacoco-unit/jacoco.xml \
                    --partial \
                    --project-token $CODACY_PROJECT_TOKEN \
                    --commit-uuid $(git rev-parse HEAD)

                # Upload integration test coverage as partial
                bash codacy-coverage-reporter.sh report \
                    -r target/site/jacoco-integration/jacoco.xml \
                    --partial \
                    --project-token $CODACY_PROJECT_TOKEN \
                    --commit-uuid $(git rev-parse HEAD)

                # Finalize the coverage
                bash codacy-coverage-reporter.sh final \
                    --project-token $CODACY_PROJECT_TOKEN \
                    --commit-uuid $(git rev-parse HEAD)
            '''
        }
    }
}

The --partial flag tells Codacy that more coverage data is coming. The final command signals that all partial reports have been uploaded and Codacy should aggregate them. Without the final command, Codacy waits indefinitely for more partial uploads and the coverage never appears on the dashboard.

For monorepos where different components run in parallel Jenkins stages, you can upload partial coverage from each stage and then finalize in a downstream stage:

stage('Test Components') {
    parallel {
        stage('API Tests') {
            steps {
                dir('api') {
                    sh 'mvn test'
                    withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
                        sh '''
                            bash codacy-coverage-reporter.sh report \
                                -r target/site/jacoco/jacoco.xml \
                                --partial \
                                --project-token $CODACY_PROJECT_TOKEN \
                                --commit-uuid $(git rev-parse HEAD)
                        '''
                    }
                }
            }
        }
        stage('Frontend Tests') {
            steps {
                dir('frontend') {
                    sh 'npm ci && npm test -- --coverage'
                    withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
                        sh '''
                            bash codacy-coverage-reporter.sh report \
                                -r coverage/lcov.info \
                                --partial \
                                --project-token $CODACY_PROJECT_TOKEN \
                                --commit-uuid $(git rev-parse HEAD)
                        '''
                    }
                }
            }
        }
    }
}

stage('Finalize Coverage') {
    steps {
        withCredentials([string(credentialsId: 'CODACY_PROJECT_TOKEN', variable: 'CODACY_PROJECT_TOKEN')]) {
            sh '''
                bash codacy-coverage-reporter.sh final \
                    --project-token $CODACY_PROJECT_TOKEN \
                    --commit-uuid $(git rev-parse HEAD)
            '''
        }
    }
}

Step 7: Using Docker-based Jenkins agents with Codacy

Many Jenkins setups use Docker-based agents for clean, reproducible build environments. When running Codacy tools inside a Docker container, you need to ensure the container has network access and the necessary tools installed.

pipeline {
    agent {
        docker {
            image 'maven:3.9-eclipse-temurin-17'
            args '-v $HOME/.m2:/root/.m2'
        }
    }

    environment {
        CODACY_PROJECT_TOKEN = credentials('CODACY_PROJECT_TOKEN')
    }

    stages {
        stage('Build and Test') {
            steps {
                sh 'mvn clean test'
            }
        }

        stage('Upload Coverage') {
            steps {
                sh '''
                    apt-get update && apt-get install -y curl
                    curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
                    bash codacy-coverage-reporter.sh report \
                        -r target/site/jacoco/jacoco.xml \
                        --project-token $CODACY_PROJECT_TOKEN \
                        --commit-uuid $(git rev-parse HEAD)
                '''
            }
        }
    }
}

If your Docker agent does not have curl installed, you need to install it before downloading the Codacy Coverage Reporter. Alternatively, you can create a custom Docker image that includes curl and the Codacy Coverage Reporter pre-installed to speed up your pipeline.

For Jenkins setups behind a corporate proxy, pass the proxy configuration to the Codacy Coverage Reporter:

sh '''
    export HTTP_PROXY=http://proxy.company.com:8080
    export HTTPS_PROXY=http://proxy.company.com:8080
    curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
    bash codacy-coverage-reporter.sh report \
        -r target/site/jacoco/jacoco.xml \
        --project-token $CODACY_PROJECT_TOKEN \
        --commit-uuid $(git rev-parse HEAD)
'''

Step 8: Integrating Codacy with Jenkins shared libraries

If your organization has multiple repositories that all need Codacy integration, duplicating the same Jenkinsfile stages across every repository is wasteful and error-prone. Jenkins Shared Libraries let you define reusable pipeline steps that any repository can call.

Create a shared library with a Codacy upload step:

// vars/codacyCoverage.groovy
def call(Map config = [:]) {
    def reportPath = config.reportPath ?: 'target/site/jacoco/jacoco.xml'
    def tokenCredentialId = config.tokenCredentialId ?: 'CODACY_PROJECT_TOKEN'
    def partial = config.partial ?: false

    withCredentials([string(credentialsId: tokenCredentialId, variable: 'CODACY_PROJECT_TOKEN')]) {
        sh '''
            curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
        '''

        def partialFlag = partial ? '--partial' : ''

        sh """
            bash codacy-coverage-reporter.sh report \
                -r ${reportPath} \
                ${partialFlag} \
                --project-token \$CODACY_PROJECT_TOKEN \
                --commit-uuid \$(git rev-parse HEAD)
        """
    }
}

Then in any repository’s Jenkinsfile:

@Library('your-shared-library') _

pipeline {
    agent any

    stages {
        stage('Test') {
            steps {
                sh 'mvn clean test'
            }
        }

        stage('Upload Coverage') {
            steps {
                codacyCoverage(reportPath: 'target/site/jacoco/jacoco.xml')
            }
        }
    }
}

This approach keeps the Codacy configuration centralized. When you need to update the Coverage Reporter version or change how uploads work, you update the shared library once instead of every repository’s Jenkinsfile.

Codacy Jenkins integration vs. GitHub Actions

If your team is evaluating whether to run Codacy through Jenkins or through GitHub Actions (or another native CI provider), it is worth understanding the tradeoffs.

Jenkins strengths for Codacy integration:

  • Full control over the build environment - you can run analysis on your own hardware behind your firewall
  • Integration with existing Jenkins infrastructure - no need to adopt a new CI system
  • Shared libraries for organization-wide standardization
  • Complex pipeline orchestration with approval stages, deployment gates, and environment-specific configurations

GitHub Actions strengths for Codacy integration:

  • Codacy provides an official GitHub Action (codacy/codacy-coverage-reporter-action) that simplifies setup
  • Codacy’s GitHub App handles static analysis automatically through webhooks - no CI configuration needed
  • Tighter integration with pull request status checks and comments
  • Less infrastructure to maintain since GitHub hosts the runners

For most teams, the best approach is to let Codacy’s GitHub or GitLab App handle static analysis (it runs automatically on every PR) and use Jenkins only for coverage uploads and quality gate checks. This gives you the benefits of Codacy’s native Git provider integration while keeping your existing Jenkins pipeline for builds, tests, and deployments.

For a detailed walkthrough of the GitHub-native approach, see our guide on Codacy GitHub integration.

Alternative: CodeAnt AI for Jenkins CI/CD

If you are evaluating code quality tools for your Jenkins pipeline and want to compare options beyond Codacy, CodeAnt AI is worth considering. Priced at $24-40 per user per month, CodeAnt AI offers AI-powered code review with CI/CD integration capabilities that complement or replace traditional static analysis tools.

CodeAnt AI focuses on AI-driven issue detection that goes beyond pattern matching. While Codacy relies primarily on rule-based static analysis tools (ESLint, Pylint, SpotBugs, etc.) augmented by its AI Reviewer feature, CodeAnt AI uses AI models as the primary analysis engine. This means it can catch logic errors, design issues, and context-dependent problems that rule-based tools typically miss.

For Jenkins integration, CodeAnt AI provides a CLI tool that can be invoked in your Jenkinsfile similar to the Codacy Coverage Reporter. The setup process follows the same general pattern - store an API token in Jenkins credentials, run the analysis tool in a pipeline stage, and check results via the API.

For a broader comparison of tools in this space, see our Codacy alternatives guide which covers CodeAnt AI, SonarQube, DeepSource, Semgrep, and other options.

Troubleshooting common issues

Coverage reporter download fails

If the curl command to download the Codacy Coverage Reporter fails, it is usually a network issue. Check the following:

  • Proxy settings - If your Jenkins instance is behind a corporate proxy, ensure HTTP_PROXY and HTTPS_PROXY environment variables are set in your pipeline
  • SSL certificates - Corporate proxies often intercept SSL traffic. If you get certificate errors, you may need to add the proxy’s CA certificate to your Jenkins agent’s trust store
  • Firewall rules - Ensure your Jenkins agents can reach coverage.codacy.com and github.com on port 443

As a workaround, you can download the Coverage Reporter binary ahead of time and make it available on your Jenkins agents:

// If pre-installed on the agent
sh '/usr/local/bin/codacy-coverage-reporter report -r coverage.xml --project-token $CODACY_PROJECT_TOKEN'

Commit SHA mismatch

When Jenkins checks out code for a pull request, it often creates a merge commit that does not match the PR head SHA. This causes Codacy to receive coverage data for a commit it does not recognize, and the coverage never appears on the dashboard.

To fix this, always pass the correct commit SHA explicitly:

// For GitHub PRs in a multibranch pipeline
def commitSha = env.CHANGE_ID ?
    sh(script: "git rev-parse origin/${env.CHANGE_BRANCH}", returnStdout: true).trim() :
    sh(script: 'git rev-parse HEAD', returnStdout: true).trim()

sh """
    bash codacy-coverage-reporter.sh report \
        -r coverage.xml \
        --project-token \$CODACY_PROJECT_TOKEN \
        --commit-uuid ${commitSha}
"""

Quality gate API returns 404

A 404 response from the Codacy API typically means one of the following:

  • The organization name or repository name is incorrect - Double-check the values in your API URL. They must match exactly what appears in your Codacy dashboard URL.
  • The commit has not been analyzed yet - Codacy may not have finished processing the commit. Increase the sleep time or implement the polling approach described in Step 4.
  • The API token does not have access - Ensure you are using an account API token (not a project token) for the quality gate API endpoint, and that the token belongs to a user with access to the repository.

Coverage report format not recognized

Codacy is strict about coverage report formats. Common issues include:

  • Empty coverage reports - If your test suite has no tests or tests are skipped, the coverage report may be empty. The Codacy Coverage Reporter will reject it.
  • Wrong file path - The coverage report path in your Jenkinsfile must match the actual output location. Add an ls or find step to debug:
sh 'find . -name "*.xml" -path "*/jacoco/*" -o -name "lcov.info" | head -20'
  • Malformed XML - Some coverage tools produce XML that is not strictly valid. Validate the report file before uploading.

Jenkins agent cannot access Codacy API

If your Jenkins agents run in a restricted network environment, they may not be able to reach Codacy’s cloud API endpoints. Solutions include:

  • Configure proxy settings at the Jenkins system level under Manage Jenkins then Manage Plugins then Advanced
  • Use Codacy Self-Hosted if your organization requires all tools to run on internal infrastructure
  • Allowlist Codacy domains in your firewall rules: app.codacy.com, coverage.codacy.com, and api.codacy.com

Complete production Jenkinsfile example

Here is a comprehensive Jenkinsfile that combines all the elements covered in this guide - build, test, coverage upload, analysis, and quality gate checking:

pipeline {
    agent any

    tools {
        maven 'Maven-3.9'
        jdk 'JDK-17'
    }

    environment {
        CODACY_PROJECT_TOKEN = credentials('CODACY_PROJECT_TOKEN')
    }

    options {
        timeout(time: 30, unit: 'MINUTES')
        timestamps()
        disableConcurrentBuilds()
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                sh 'mvn clean compile -DskipTests'
            }
        }

        stage('Unit Tests') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit '**/target/surefire-reports/*.xml'
                }
            }
        }

        stage('Upload Coverage to Codacy') {
            steps {
                sh '''
                    curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage-reporter.sh
                    bash codacy-coverage-reporter.sh report \
                        -r target/site/jacoco/jacoco.xml \
                        --project-token $CODACY_PROJECT_TOKEN \
                        --commit-uuid $(git rev-parse HEAD)
                '''
            }
        }

        stage('Codacy Quality Gate') {
            when {
                anyOf {
                    branch 'main'
                    branch 'develop'
                    changeRequest()
                }
            }
            steps {
                withCredentials([string(credentialsId: 'CODACY_ACCOUNT_TOKEN', variable: 'CODACY_ACCOUNT_TOKEN')]) {
                    script {
                        def commitSha = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
                        def maxAttempts = 15
                        def passed = false

                        for (int i = 0; i < maxAttempts; i++) {
                            sleep(time: 15, unit: 'SECONDS')

                            def httpCode = sh(
                                script: """
                                    curl -s -o response.json -w '%{http_code}' \
                                        "https://app.codacy.com/api/v3/analysis/organizations/gh/your-org/repositories/your-repo/commits/${commitSha}/quality" \
                                        -H "api-token: \$CODACY_ACCOUNT_TOKEN" \
                                        -H "Accept: application/json"
                                """,
                                returnStdout: true
                            ).trim()

                            if (httpCode == '200') {
                                def quality = readJSON(file: 'response.json')

                                if (quality.data?.isUpToStandards == true) {
                                    echo "Codacy quality gate PASSED."
                                    passed = true
                                    break
                                } else if (quality.data?.isUpToStandards == false) {
                                    unstable "Codacy quality gate FAILED. Check Codacy dashboard for details."
                                    passed = true // Exit loop, build marked unstable
                                    break
                                }
                            }

                            echo "Waiting for Codacy analysis (${i + 1}/${maxAttempts})..."
                        }

                        if (!passed) {
                            echo "WARNING: Codacy quality gate check timed out. Proceeding with build."
                        }
                    }
                }
            }
        }
    }

    post {
        always {
            cleanWs()
        }
        failure {
            echo 'Build failed. Review Jenkins console output and Codacy dashboard.'
        }
    }
}

This Jenkinsfile includes sensible defaults - a 30-minute timeout, timestamps in the console output, prevention of concurrent builds, and workspace cleanup. The quality gate check uses a polling loop that times out gracefully rather than blocking the pipeline indefinitely. For Codacy’s pricing details and plan comparisons, review our Codacy pricing breakdown.

Summary

Integrating Codacy with Jenkins requires a few moving pieces - the Coverage Reporter for uploading test coverage, the Analysis CLI for running static analysis within your pipeline, and the Codacy API for quality gate enforcement. Unlike tools with dedicated Jenkins plugins (like SonarQube), Codacy’s Jenkins integration relies on CLI tools and API calls, which gives you more flexibility but requires more configuration upfront.

The recommended approach for most teams is to let Codacy’s native Git provider integration handle static analysis automatically through webhooks, and use Jenkins specifically for coverage uploads and quality gate checks. This minimizes the Jenkins-side configuration while still giving you build-level enforcement of quality standards.

For teams evaluating alternatives, CodeAnt AI ($24-40/user/month) offers AI-first code review that integrates with CI/CD pipelines, while SonarQube provides the most mature Jenkins plugin ecosystem. See our Codacy alternatives guide for detailed comparisons across the full landscape of code quality tools.

Frequently Asked Questions

How do I integrate Codacy with Jenkins?

Install the Codacy Coverage Reporter plugin from the Jenkins plugin manager, then add a post-build step in your Jenkinsfile that uploads coverage reports and triggers Codacy analysis. You need a Codacy project API token stored as a Jenkins credential. The integration works with both Freestyle and Pipeline jobs, though Pipeline (Jenkinsfile) is the recommended approach for better version control and flexibility.

Does Codacy have a Jenkins plugin?

Codacy does not have a dedicated all-in-one Jenkins plugin. Instead, you integrate Codacy with Jenkins by using the Codacy Coverage Reporter CLI tool in your pipeline steps. The Coverage Reporter uploads test coverage data to Codacy, while Codacy's GitHub, GitLab, or Bitbucket App handles the static analysis and PR feedback. This approach keeps the integration lightweight and works with any Jenkins pipeline configuration.

How do I upload code coverage from Jenkins to Codacy?

Generate a coverage report in your Jenkins pipeline using your test framework (JaCoCo, Istanbul, pytest-cov, etc.), then use the Codacy Coverage Reporter CLI to upload it. Download the reporter with curl, then run the report command with your project token and the path to the coverage file. Supported formats include LCOV, Cobertura XML, JaCoCo XML, Clover, and OpenCover.

Can I use Codacy quality gates in Jenkins?

Yes. Configure quality gates in the Codacy dashboard under Quality settings, then use the Codacy API in your Jenkinsfile to check whether the current commit passes the quality gate. If the gate fails, you can mark the Jenkins build as failed or unstable using the Codacy API response. This lets you block deployments when code quality falls below your thresholds.

How do I set up Codacy with a Jenkins multibranch pipeline?

Create a Jenkinsfile in your repository root with Codacy coverage upload and quality gate check stages. When you create a multibranch pipeline job in Jenkins that scans your repository, it automatically discovers branches and pull requests with the Jenkinsfile. Each branch and PR gets its own pipeline run with Codacy analysis, and results appear on the Codacy dashboard under the corresponding branch.

What credentials do I need for Codacy Jenkins integration?

You need a Codacy project API token, which you can find in your Codacy repository settings under Coverage or Integrations. Store this token as a Secret Text credential in Jenkins with an ID like CODACY_PROJECT_TOKEN. For organization-level operations or API-based quality gate checks, you may also need a Codacy account API token from your Codacy account settings.

How do I configure Codacy coverage for a Java project in Jenkins?

Add the JaCoCo Maven or Gradle plugin to your build configuration to generate coverage reports. In your Jenkinsfile, run your tests with coverage enabled (mvn test for Maven, gradle test jacocoTestReport for Gradle), then use the Codacy Coverage Reporter to upload the JaCoCo XML report. The reporter automatically detects the JaCoCo format and uploads it to Codacy.

Why is my Codacy coverage not showing up from Jenkins?

The most common causes are an incorrect or expired project API token, a coverage report path that does not match the actual file location, or a commit SHA mismatch between the Jenkins build and what Codacy expects. Verify the token is correct, check that the coverage file exists at the specified path using an ls step in your Jenkinsfile, and ensure the git commit SHA matches by passing it explicitly with the --commit-uuid flag.

Can I run Codacy analysis locally in Jenkins instead of using the Codacy cloud?

Yes. Codacy offers a self-hosted version called Codacy Self-Hosted that runs on your own infrastructure. For the cloud version, you can also run the Codacy Analysis CLI tool in your Jenkins pipeline to perform analysis locally and upload results. This gives you more control over when and how analysis runs, and keeps your code within your own infrastructure during the analysis step.

How does Codacy compare to SonarQube for Jenkins integration?

SonarQube has a more mature Jenkins integration with a dedicated Jenkins plugin, SonarQube Scanner, and a built-in quality gate webhook. Codacy's Jenkins integration requires more manual configuration using the CLI tools, but Codacy offers broader language support (49 languages), built-in SAST and secrets detection, and AI-powered code review features that SonarQube does not include. For teams already using Jenkins heavily, SonarQube may be easier to set up, while Codacy offers more features per tool.

Is there a better alternative to Codacy for Jenkins CI/CD pipelines?

CodeAnt AI is a strong alternative at $24-40 per user per month that offers AI-powered code review with CI/CD integration. SonarQube has the most mature Jenkins plugin ecosystem. DeepSource and Semgrep are also worth considering - both offer CLI tools that integrate easily with Jenkins pipelines. The best choice depends on whether you prioritize plugin maturity (SonarQube), AI features (CodeAnt AI, Codacy), or security scanning (Semgrep).

How do I troubleshoot a failed Codacy Jenkins build?

Start by checking the Jenkins console output for the specific error message. Common failures include network connectivity issues reaching the Codacy API (check proxy settings), expired or incorrect API tokens (regenerate in Codacy settings), coverage report format errors (validate the report file locally), and Git commit SHA mismatches (ensure Jenkins checks out the correct commit). Enable verbose logging in the Coverage Reporter with the --verbose flag for more detailed output.

Explore More

Free Newsletter

Stay ahead with AI dev tools

Weekly insights on AI code review, static analysis, and developer productivity. No spam, unsubscribe anytime.

Join developers getting weekly AI tool insights.

Related Articles