Maven build as GitLab artifact is being ignored by following jobs

Viewed 788

I have a pipeline where the first 2 stages are one for the build and one for unit tests, on a Maven project.

The two stages can be summarized with the following commands:

  • [build] mvn -s ci/settings.xml test-compile
  • [unit_tests] mvn -s ci/settings.xml verify

When running them on a local machine, the first one prints:

[INFO] Changes detected - recompiling the module!
[INFO] Compiling 133 source files to <mydir>

while the second one, given that the project was already built, prints:

[INFO] Nothing to compile - all classes are up to date

and this is the expected behavior on GitLab too.

What happens on GitLab, however, is that the unit tests stage prints the very same thing as the build one, meaning that it's not correctly using the artifact that I exported in the previous stage.

This is the build job:

build:
  stage: build
  image: maven:3.6-jdk-11
  script:
    - 'mvn -s ci/settings.xml test-compile'
  except:
    - tags
  artifacts:
    paths:
      - target/

This job ends with the following log:

Uploading artifacts...
target/: found 226 matching files and directories  
Uploading artifacts as "archive" to coordinator... ok  id=1964 responseStatus=201 Created token=qwYzjEeM

meaning that the target folder has been uploaded correctly.

This is the unit tests job:

junit:
  stage: unit_tests
  script:    
    - 'mvn -s ci/settings.xml verify'
  artifacts:
    reports:
      junit:
        - target/surefire-reports/TEST-*.xml

This job starts with the following log:

Downloading artifacts for build (1964)...
Downloading artifacts from coordinator... ok        id=1964 responseStatus=200 OK token=qwYzjEeM

meaning that the target folder was correctly received (I also added an ls -la target to see if files were there and they seemed right).

Given that artifacts seem to be uploaded/downloaded correctly, why does the unit tests job rebuild the entire project?

1 Answers

So, in the end the issue is caused by both how GitLab restores the artifacts and by how git clone works.

Basically GitLab will preserve artifact's last modified timestamp, while git clone won't.

This leads to the following scenario:

  1. git clone is executed, and now all the files in the src directory have the current timestamp
  2. GitLab extracts the artifact archive and preserves the timestamps, so now files in the target directory have the timestamp that they had in the previous CI job
  3. This means that files in the target directory will look older than files in the src one, and this triggers a full recompile in Maven

The issue has been reported to GitLab and can be tracked here.

A temporary workaround is to manually create the artifact archive and manually extract it once the other job begins.

This is a sample pipeline that's used as a workaround (the -DD option is the one that doesn't preserve timestamps when extracting, which is what makes this workaround actually work):

.prepare-build-artifact: &prepare-build-artifact |
  apt update && apt install -y zip
  zip -r -q target.zip target/

.extract-build-artifact: &extract-build-artifact |
  unzip -DD -q target.zip

build:
  stage: build
  image: maven:3.6-jdk-11
  script:
    - 'mvn test-compile'
    - *prepare-build-artifact
  except:
    - tags
  artifacts:
    paths:
      - target.zip

junit:
  stage: unit_tests
  script:
    - *extract-build-artifact
    - 'mvn verify'
  artifacts:
    reports:
      junit:
        - target/surefire-reports/TEST-*.xml
Related