GitLab CI runner uploads artifacts for failed job

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Summary

I have a GitLab CI job which, if successful, produces an environments file "product_versions.env" which is then captured as an artifact as follows:

artifacts: reports: dotenv: product_versions.env

As documented here (https://docs.gitlab.com/ee/ci/yaml/#artifactswhen) if the job fails, the artifact should not be uploaded if the job fails.

However, when my job fails it is still trying to upload the artifact which fails because it doesn't exist. Add "when: on_success" doesn't make a difference.

GitLab CI knows the job has failed as can be seen in the log output:

Uploading artifacts for failed job 00:01
Uploading artifacts...
Runtime platform                                    arch=amd64 os=linux pid=3438 revision=f761588f version=14.10.1
WARNING: product_versions.env: no matching files   
ERROR: No files to upload                          
ERROR: Job failed: exit status 1

Steps to reproduce

This test job reproduces the problem:

check_variables:
  stage: validate
  tags:
    - dev
  script:
    - exit 1
  artifacts:
    reports:
      dotenv: product_versions.env

Example Project

What is the current bug behavior?

Artifact uploaded / tries to upload even when the job fails.

What is the expected correct behavior?

Should not try to upload artifact because default for artifacts:when should be on_success

Relevant logs and/or screenshots

$ exit 1 Uploading artifacts for failed job 00:01 Updating CA certificates... WARNING: ca-certificates.crt does not contain exactly one certificate or CRL: skipping WARNING: ca-cert-ca.pem does not contain exactly one certificate or CRL: skipping Uploading artifacts... WARNING: product_versions.env: no matching files
ERROR: No files to upload
ERROR: Job failed: exit code 1

Output of checks

Results of GitLab environment info

GitLab Enterprise Edition 14.10.2-ee

Expand for output related to GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:env:info`)

(For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)

Results of GitLab application Check

Expand for output related to the GitLab application check

(For installations with omnibus-gitlab package run and paste the output of: sudo gitlab-rake gitlab:check SANITIZE=true)

(For installations from source run and paste the output of: sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)

(we will only investigate if the tests are passing)

Possible fixes

Wrote a quick boring solution which prevents uploading the artifact that problem (not final) 👇

See diff
+++ b/app/services/ci/job_artifacts/create_service.rb
@@ -43,7 +43,7 @@ def execute(artifacts_file, params, metadata_file: nil)
         return success if sha256_matches_existing_artifact?(params[:artifact_type], artifacts_file)

         artifact, artifact_metadata = build_artifact(artifacts_file, params, metadata_file)
-        result = parse_artifact(artifact)
+        result = parse_artifact(artifact, job)

         track_artifact_uploader(artifact)

@@ -117,9 +117,9 @@ def build_artifact(artifacts_file, params, metadata_file)
         [artifact, artifact_metadata]
       end

-      def parse_artifact(artifact)
+      def parse_artifact(artifact, job)
         case artifact.file_type
-        when 'dotenv' then parse_dotenv_artifact(artifact)
+        when 'dotenv' then parse_dotenv_artifact(artifact, job)
         else success
         end
       end
diff --git a/app/services/ci/parse_dotenv_artifact_service.rb b/app/services/ci/parse_dotenv_artifact_service.rb
index 40e2cd82b4f..12b8e752c60 100644
--- a/app/services/ci/parse_dotenv_artifact_service.rb
+++ b/app/services/ci/parse_dotenv_artifact_service.rb
@@ -7,8 +7,8 @@ class ParseDotenvArtifactService < ::BaseService
     SizeLimitError = Class.new(StandardError)
     ParserError = Class.new(StandardError)

-    def execute(artifact)
-      validate!(artifact)
+    def execute(artifact, job)
+      validate!(artifact, job)

       variables = parse!(artifact)
       Ci::JobVariable.bulk_insert!(variables)
@@ -21,7 +21,7 @@ def execute(artifact)

     private

-    def validate!(artifact)
+    def validate!(artifact, job)
       unless artifact&.dotenv?
         raise ArgumentError, 'Artifact is not dotenv file type'
       end
@@ -30,6 +30,10 @@ def validate!(artifact)
         raise SizeLimitError,
           "Dotenv Artifact Too Big. Maximum Allowable Size: #{dotenv_size_limit}"
       end
+
+      if job.failed?
+        raise ArgumentError, 'Job failed'
+      end
     end

We should probably don't parse this dotenv artifact at all if the job has failed.

Edited by 🤖 GitLab Bot 🤖