Fix NoMethodError in Job#artifacts_with_pages_publish_path when artifacts[:paths] is nil

Summary

A NoMethodError is occurring in lib/gitlab/ci/config/entry/job.rb when the artifacts_with_pages_publish_path method attempts to call include? on a nil value for artifacts[:paths].

Error Details

NoMethodError: undefined method `include?' for nil:NilClass (NoMethodError)

            return artifacts if artifacts[:paths].include?(pages_publish_path)
                                                 ^^^^^^^^^
  from lib/gitlab/ci/config/entry/job.rb:244:in `artifacts_with_pages_publish_path'
  from lib/gitlab/ci/config/entry/job.rb:205:in `value'
  from ee/gitlab/ci/config/entry/job.rb:42:in `value'
  from lib/gitlab/config/entry/node.rb:80:in `block in value'
  from lib/gitlab/config/entry/node.rb:80:in `transform_values'

Sentry Error: https://new-sentry.gitlab.net/organizations/gitlab/issues/2707974

Root Cause

In the artifacts_with_pages_publish_path method, the code uses reverse_merge(paths: []) to ensure a default paths key exists. However, this doesn't guarantee that artifacts[:paths] will be an array if:

  • The artifacts_value returns a hash with other keys but no :paths key
  • There's a symbol/string key mismatch

The current code at line 244:

return artifacts if artifacts[:paths].include?(pages_publish_path)

This fails when artifacts[:paths] is nil.

Proposed Solution

Replace the reverse_merge approach with a direct nil-safe assignment:

def artifacts_with_pages_publish_path
  return artifacts_value unless pages_job?

  artifacts = artifacts_value || {}
  artifacts[:paths] ||= []

  return artifacts if artifacts[:paths].include?(pages_publish_path)

  artifacts.merge(paths: artifacts[:paths] + [pages_publish_path])
end

This ensures artifacts[:paths] is always an array before calling include?.

Test Coverage

Add test case to spec/lib/gitlab/ci/config/entry/job_spec.rb:

context 'when artifacts has no paths key' do
  let(:config) { { artifacts: { name: 'my-artifact' } } }

  before do
    allow_next_instance_of(described_class) do |job|
      allow(job).to receive(:artifacts_value).and_return({ name: 'my-artifact' })
    end
  end

  it 'does not raise NoMethodError' do
    expect { described_class.new(config, name: :pages).artifacts_with_pages_publish_path }.not_to raise_error
  end

  it 'adds the default publish path' do
    result = described_class.new(config, name: :pages).artifacts_with_pages_publish_path
    expect(result).to eq({ name: 'my-artifact', paths: ['public'] })
  end
end

Impact

This bug affects pages jobs where artifacts are configured without an explicit paths key, causing pipeline configuration parsing to fail.

Edited by 🤖 GitLab Bot 🤖