Search code examples
gitlab-cigitlab-ci-runnerapexpmdsfdx

Running PMD in GitLab CI Script doesn't work unless echo command is added after the script runs


This is an interesting issue. I have a GitLab project, and I've created a .gitlab-ci.yml to run a PMD that will scan my code after every commit. The ci.yml file looks like this:

image: "node:latest"

stages:
  - preliminary-testing

apex-code-scan:
  stage: preliminary-testing
  allow_failure: false
  script:
    - install_java
    - install_pmd
  artifacts:
    paths:
      - pmd-reports/

####################################################
# Helper Methods
####################################################

.sfdx_helpers: &sfdx_helpers |

  function install_java() {
    local JAVA_VERSION=11
    local JAVA_INSTALLATION=openjdk-$JAVA_VERSION-jdk
    echo "Installing ${JAVA_INSTALLATION}"
    apt update && apt -y install $JAVA_INSTALLATION
  }

  function install_pmd() {
    local PMD_VERSION=6.52.0
    local RULESET_PATH=ruleset.xml
    local OUTPUT_DIRECTORY=pmd-reports
    local SOURCE_DIRECTORY=force-app
    local URL=https://github.com/pmd/pmd/releases/download/pmd_releases%2F$PMD_VERSION/pmd-bin-$PMD_VERSION.zip
    
    # Here I would download and unzip the PMD source code. But for now I have the PMD source already in my project for testing purposes

    # apt update && apt -y install unzip
    # wget $URL
    # unzip -o pmd-bin-$PMD_VERSION.zip
    # rm pmd-bin-$PMD_VERSION.zip
    echo "Installed PMD!"

    mkdir -p $OUTPUT_DIRECTORY
    echo "Going to run PMD!"
    ls
    echo "Start"
    pmd-bin-$PMD_VERSION/bin/run.sh pmd -d $SOURCE_DIRECTORY -R $RULESET_PATH -f xslt -P xsltFilename=pmd_report.xsl -r $OUTPUT_DIRECTORY/pmd-apex.html
    echo "Done"
    rm -r pmd-bin-$PMD_VERSION
    echo "Remove pmd"
  }

before_script:
  - *sfdx_helpers

When I try to run this pipeline, it will fail after starting the PMD: enter image description here

However, if I make a small change to the PMD's .sh file and add an echo command at the very end. Then the pipeline succeeds:

PMD /bin/run.sh before (doesn't work):

...
java ${HEAPSIZE} ${PMD_JAVA_OPTS} $(jre_specific_vm_options) -cp "${classpath}" "${CLASSNAME}" "$@"

PMD /bin/run.sh after (does work):

...
java ${HEAPSIZE} ${PMD_JAVA_OPTS} $(jre_specific_vm_options) -cp "${classpath}" "${CLASSNAME}" "$@"
echo "Done1" // This is the last line in the file

enter image description here

I don't have the slightest idea why this is the case. Does anyone know why adding this echo command at the end of the .sh file would cause the pipeline to succeed? I could keep it as is with the echo command, but I would like to understand why it is behaving this way. I don't want to be that guy that just leaves a comment saying Hey don't touch this line of code, I don't know why, but without it the whole thing fails. Thank you!


Solution

  • PMD exits with a specific exit code depending whether it found some violations or not, see https://pmd.github.io/latest/pmd_userdocs_cli_reference.html#exit-status

    I guess, your PMD run finds some violations, and PMD exits with exit code 4 - which is not a success exit code.

    In general, this is used to make the CI build fail, in case any PMD violations are present - forcing to fix the violations before you get a green build.

    If that is not what you want, e.g. you only want to report the violations but not fail the build, then you need to add the following command line option:

    --fail-on-violation false

    Then PMD will exit with exit code 0, even when there are violations.