Commit 8c4f6e12 authored by Shinya Maeda's avatar Shinya Maeda

Surface the error for invalid environment creation

This commit surfaces the error for invalid enviroment
creation, that is currently silently failing and
confusuing users.
parent a61764ba
......@@ -27,6 +27,7 @@ module Enums
no_matching_runner: 18, # not used anymore, but cannot be deleted because of old data
trace_size_exceeded: 19,
builds_disabled: 20,
environment_creation_failure: 21,
insufficient_bridge_permissions: 1_001,
downstream_bridge_project_not_found: 1_002,
invalid_bridge_trigger: 1_003,
......
......@@ -28,7 +28,12 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
ci_quota_exceeded: 'No more CI minutes available',
no_matching_runner: 'No matching runner available',
trace_size_exceeded: 'The job log size limit was reached',
builds_disabled: 'The CI/CD is disabled for this project'
builds_disabled: 'The CI/CD is disabled for this project',
environment_creation_failure: 'This job could not be executed because it would create an environment with an invalid parameter.'
}.freeze
TROUBLESHOOTING_DOC = {
environment_creation_failure: { path: 'ci/environments/index', anchor: 'a-deployment-job-failed-with-this-job-could-not-be-executed-because-it-would-create-an-environment-with-an-invalid-parameter-error' }
}.freeze
private_constant :CALLOUT_FAILURE_MESSAGES
......@@ -40,7 +45,19 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
end
def callout_failure_message
self.class.callout_failure_messages.fetch(failure_reason.to_sym)
message = self.class.callout_failure_messages.fetch(failure_reason.to_sym)
if doc = TROUBLESHOOTING_DOC[failure_reason.to_sym]
message += " #{help_page_link(doc[:path], doc[:anchor])}"
end
message
end
private
def help_page_link(path, anchor)
ActionController::Base.helpers.link_to('How do I fix it?', help_page_path(path, anchor: anchor))
end
end
......
---
name: surface_environment_creation_failure
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69537
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340169
milestone: '14.4'
type: development
group: group::release
default_enabled: false
---
name: surface_environment_creation_failure_override
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69537
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340169
milestone: '14.4'
type: development
group: group::release
default_enabled: false
......@@ -816,3 +816,41 @@ To ensure the `action: stop` can always run when needed, you can:
action: stop
when: manual
```
### A deployment job failed with "This job could not be executed because it would create an environment with an invalid parameter" error
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21182) in GitLab 14.4.
FLAG:
On self-managed GitLab, by default this bug fix is not available. To make it available per project or for your entire instance, ask an administrator to [enable the `surface_environment_creation_failure` flag](../../administration/feature_flags.md). On GitLab.com, this bug fix is not available, but will be rolled out shortly.
If your project is configured to [create a dynamic environment](#create-a-dynamic-environment),
such as a [Review App](../review_apps/index.md), you might encounter this error
because the dynamically generated parameter is invalid for the system.
For example, if you have the following in your `.gitlab-ci.yml`:
```yaml
review:
script: deploy review app
environment: review/$CI_COMMIT_REF_NAME
```
When you create a new merge request with a branch name `bug-fix!`,
the `review` job tries to create an environment with `review/bug-fix!`.
However, the `!` is an invalid character for environments, so the
deployment job fails since it was about to run without an environment.
To fix this, you can:
- Re-create your feature branch without the invalid characters,
such as `bug-fix`.
- Replace the `CI_COMMIT_REF_NAME`
[predefined variable](../variables/predefined_variables.md) with
`CI_COMMIT_REF_SLUG` which strips any invalid characters:
```yaml
review:
script: deploy review app
environment: review/$CI_COMMIT_REF_SLUG
```
......@@ -106,10 +106,15 @@ module Gitlab
environment = Seed::Environment.new(build).to_resource
unless environment.persisted?
if Feature.enabled?(:surface_environment_creation_failure, build.project, default_enabled: :yaml) &&
Feature.disabled?(:surface_environment_creation_failure_override, build.project)
return { status: :failed, failure_reason: :environment_creation_failure }
end
# If there is a validation error on environment creation, such as
# the name contains invalid character, the build falls back to a
# non-environment job.
unless environment.persisted?
Gitlab::ErrorTracking.track_exception(
EnvironmentCreationFailure.new,
project_id: build.project_id,
......
......@@ -33,7 +33,8 @@ module Gitlab
ci_quota_exceeded: 'no more CI minutes available',
no_matching_runner: 'no matching runner available',
trace_size_exceeded: 'log size limit exceeded',
builds_disabled: 'project builds are disabled'
builds_disabled: 'project builds are disabled',
environment_creation_failure: 'environment creation failure'
}.freeze
private_constant :REASONS
......
......@@ -440,6 +440,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
context 'when the environment name is invalid' do
let(:attributes) { { name: 'deploy', ref: 'master', environment: '!!!' } }
it 'fails the job with a failure reason and does not create an environment' do
expect(subject).to be_failed
expect(subject).to be_environment_creation_failure
expect(subject.metadata.expanded_environment_name).to be_nil
expect(Environment.exists?(name: expected_environment_name)).to eq(false)
end
context 'when surface_environment_creation_failure feature flag is disabled' do
before do
stub_feature_flags(surface_environment_creation_failure: false)
end
it_behaves_like 'non-deployment job'
it_behaves_like 'ensures environment inexistence'
......@@ -454,6 +466,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
end
end
end
end
context 'when job starts a review app' do
let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
......
......@@ -15,6 +15,25 @@ RSpec.describe CommitStatusPresenter do
expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated)
end
describe '#callout_failure_message' do
subject { presenter.callout_failure_message }
context 'when troubleshooting doc is available' do
let(:failure_reason) { :environment_creation_failure }
before do
build.failure_reason = failure_reason
end
it 'appends the troubleshooting link' do
doc = described_class::TROUBLESHOOTING_DOC[failure_reason]
expect(subject).to eq("#{described_class.callout_failure_messages[failure_reason]} " \
"<a href=\"#{presenter.help_page_path(doc[:path], anchor: doc[:anchor])}\">How do I fix it?</a>")
end
end
end
describe 'covers all failure reasons' do
let(:message) { presenter.callout_failure_message }
......
......@@ -315,6 +315,10 @@ RSpec.configure do |config|
# For more information check https://gitlab.com/gitlab-org/gitlab/-/issues/339348
stub_feature_flags(new_header_search: false)
# Disable the override flag in order to enable the feature by default.
# See https://docs.gitlab.com/ee/development/feature_flags/#selectively-disable-by-actor
stub_feature_flags(surface_environment_creation_failure_override: false)
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else
unstub_all_feature_flags
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment