Commit 6fd7149e authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch '52447-auto-devops-at-group-level' into 'master'

Enable/disable Auto DevOps at the Group level

Closes #52447

See merge request gitlab-org/gitlab-ce!25533
parents db37b5a4 7e9348f3
...@@ -17,6 +17,16 @@ module Groups ...@@ -17,6 +17,16 @@ module Groups
redirect_to group_settings_ci_cd_path redirect_to group_settings_ci_cd_path
end end
def update_auto_devops
if auto_devops_service.execute
flash[:notice] = s_('GroupSettings|Auto DevOps pipeline was updated for the group')
else
flash[:alert] = s_("GroupSettings|There was a problem updating Auto DevOps pipeline: %{error_messages}." % { error_messages: group.errors.full_messages })
end
redirect_to group_settings_ci_cd_path
end
private private
def define_ci_variables def define_ci_variables
...@@ -29,6 +39,14 @@ module Groups ...@@ -29,6 +39,14 @@ module Groups
def authorize_admin_group! def authorize_admin_group!
return render_404 unless can?(current_user, :admin_group, group) return render_404 unless can?(current_user, :admin_group, group)
end end
def auto_devops_params
params.require(:group).permit(:auto_devops_enabled)
end
def auto_devops_service
Groups::AutoDevopsService.new(group, current_user, auto_devops_params)
end
end end
end end
end end
...@@ -9,4 +9,17 @@ module AutoDevopsHelper ...@@ -9,4 +9,17 @@ module AutoDevopsHelper
!project.repository.gitlab_ci_yml && !project.repository.gitlab_ci_yml &&
!project.ci_service !project.ci_service
end end
def badge_for_auto_devops_scope(auto_devops_receiver)
return unless auto_devops_receiver.auto_devops_enabled?
case auto_devops_receiver.first_auto_devops_config[:scope]
when :project
nil
when :group
s_('CICD|group enabled')
when :instance
s_('CICD|instance enabled')
end
end
end end
...@@ -11,6 +11,7 @@ class Namespace < ApplicationRecord ...@@ -11,6 +11,7 @@ class Namespace < ApplicationRecord
include IgnorableColumn include IgnorableColumn
include FeatureGate include FeatureGate
include FromUnion include FromUnion
include Gitlab::Utils::StrongMemoize
ignore_column :deleted_at ignore_column :deleted_at
...@@ -267,6 +268,22 @@ class Namespace < ApplicationRecord ...@@ -267,6 +268,22 @@ class Namespace < ApplicationRecord
owner.refresh_authorized_projects owner.refresh_authorized_projects
end end
def auto_devops_enabled?
first_auto_devops_config[:status]
end
def first_auto_devops_config
return { scope: :group, status: auto_devops_enabled } unless auto_devops_enabled.nil?
strong_memoize(:first_auto_devops_config) do
if has_parent?
parent.first_auto_devops_config
else
{ scope: :instance, status: Gitlab::CurrentSettings.auto_devops_enabled? }
end
end
end
private private
def path_or_parent_changed? def path_or_parent_changed?
......
...@@ -631,12 +631,21 @@ class Project < ActiveRecord::Base ...@@ -631,12 +631,21 @@ class Project < ActiveRecord::Base
end end
def has_auto_devops_implicitly_enabled? def has_auto_devops_implicitly_enabled?
auto_devops&.enabled.nil? && auto_devops_config = first_auto_devops_config
(Gitlab::CurrentSettings.auto_devops_enabled? || Feature.enabled?(:force_autodevops_on_by_default, self))
auto_devops_config[:scope] != :project && auto_devops_config[:status]
end end
def has_auto_devops_implicitly_disabled? def has_auto_devops_implicitly_disabled?
auto_devops&.enabled.nil? && !(Gitlab::CurrentSettings.auto_devops_enabled? || Feature.enabled?(:force_autodevops_on_by_default, self)) auto_devops_config = first_auto_devops_config
auto_devops_config[:scope] != :project && !auto_devops_config[:status]
end
def first_auto_devops_config
return namespace.first_auto_devops_config if auto_devops&.enabled.nil?
{ scope: :project, status: auto_devops&.enabled || Feature.enabled?(:force_autodevops_on_by_default, self) }
end end
def daily_statistics_enabled? def daily_statistics_enabled?
......
# frozen_string_literal: true
module Groups
class AutoDevopsService < Groups::BaseService
def execute
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :admin_group, group)
group.update(auto_devops_enabled: auto_devops_enabled)
end
private
def auto_devops_enabled
params[:auto_devops_enabled]
end
end
end
= form_for group, url: update_auto_devops_group_settings_ci_cd_path(group), method: :patch do |f|
= form_errors(group)
%fieldset
.form-group
.card.auto-devops-card
.card-body
.form-check
= f.check_box :auto_devops_enabled, class: 'form-check-input', checked: group.auto_devops_enabled?
= f.label :auto_devops_enabled, class: 'form-check-label' do
%strong= s_('GroupSettings|Default to Auto DevOps pipeline for all projects within this group')
%span.badge.badge-info#auto-devops-badge= badge_for_auto_devops_scope(group)
.form-text.text-muted
= s_('GroupSettings|The Auto DevOps pipeline will run if no alternative CI configuration file is found.')
= link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank'
= f.submit _('Save changes'), class: 'btn btn-success prepend-top-15'
...@@ -19,3 +19,17 @@ ...@@ -19,3 +19,17 @@
= _('Register and see your runners for this group.') = _('Register and see your runners for this group.')
.settings-content .settings-content
= render 'groups/runners/index' = render 'groups/runners/index'
%section.settings#auto-devops-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Auto DevOps')
%button.btn.btn-default.js-settings-toggle{ type: "button" }
= expanded ? _('Collapse') : _('Expand')
%p
- auto_devops_url = help_page_path('topics/autodevops/index')
- auto_devops_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: auto_devops_url }
= s_('GroupSettings|Auto DevOps will automatically build, test and deploy your application based on a predefined Continuous Integration and Delivery configuration. %{auto_devops_start}Learn more about Auto DevOps%{auto_devops_end}').html_safe % { auto_devops_start: auto_devops_start, auto_devops_end: '</a>'.html_safe }
.settings-content
= render 'groups/settings/ci_cd/auto_devops_form', group: @group
...@@ -8,15 +8,15 @@ ...@@ -8,15 +8,15 @@
.card.auto-devops-card .card.auto-devops-card
.card-body .card-body
.form-check .form-check
= form.check_box :enabled, class: 'form-check-input js-toggle-extra-settings', checked: @project.auto_devops_enabled? = form.check_box :enabled, class: 'form-check-input js-toggle-extra-settings', checked: auto_devops_enabled
= form.label :enabled, class: 'form-check-label' do = form.label :enabled, class: 'form-check-label' do
%strong= s_('CICD|Default to Auto DevOps pipeline') %strong= s_('CICD|Default to Auto DevOps pipeline')
- if @project.has_auto_devops_implicitly_enabled? - if auto_devops_enabled
%span.badge.badge-info.js-instance-default-badge= s_('CICD|instance enabled') %span.badge.badge-info.js-instance-default-badge= badge_for_auto_devops_scope(@project)
.form-text.text-muted .form-text.text-muted
= s_('CICD|The Auto DevOps pipeline will run if no alternative CI configuration file is found.') = s_('CICD|The Auto DevOps pipeline will run if no alternative CI configuration file is found.')
= link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank' = link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank'
.card-footer.js-extra-settings{ class: @project.auto_devops_enabled? || 'hidden' } .card-footer.js-extra-settings{ class: auto_devops_enabled || 'hidden' }
%p.settings-message.text-center %p.settings-message.text-center
- kubernetes_cluster_link = help_page_path('user/project/clusters/index') - kubernetes_cluster_link = help_page_path('user/project/clusters/index')
- kubernetes_cluster_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: kubernetes_cluster_link } - kubernetes_cluster_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: kubernetes_cluster_link }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
= s_('CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.') = s_('CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.')
= link_to s_('CICD|Learn more about Auto DevOps'), help_page_path('topics/autodevops/index.md') = link_to s_('CICD|Learn more about Auto DevOps'), help_page_path('topics/autodevops/index.md')
.settings-content .settings-content
= render 'autodevops_form' = render 'autodevops_form', auto_devops_enabled: @project.auto_devops_enabled?
= render_if_exists 'projects/settings/ci_cd/protected_environments', expanded: expanded = render_if_exists 'projects/settings/ci_cd/protected_environments', expanded: expanded
......
---
title: Enable/disable Auto DevOps at the Group level
merge_request: 25533
author:
type: added
...@@ -31,6 +31,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do ...@@ -31,6 +31,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
namespace :settings do namespace :settings do
resource :ci_cd, only: [:show], controller: 'ci_cd' do resource :ci_cd, only: [:show], controller: 'ci_cd' do
put :reset_registration_token put :reset_registration_token
patch :update_auto_devops
end end
end end
......
# frozen_string_literal: true
class AddAutoDevOpsEnabledToNamespaces < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
add_column :namespaces, :auto_devops_enabled, :boolean
end
end
...@@ -1377,6 +1377,7 @@ ActiveRecord::Schema.define(version: 20190301182457) do ...@@ -1377,6 +1377,7 @@ ActiveRecord::Schema.define(version: 20190301182457) do
t.integer "cached_markdown_version" t.integer "cached_markdown_version"
t.string "runners_token" t.string "runners_token"
t.string "runners_token_encrypted" t.string "runners_token_encrypted"
t.boolean "auto_devops_enabled"
t.index ["created_at"], name: "index_namespaces_on_created_at", using: :btree t.index ["created_at"], name: "index_namespaces_on_created_at", using: :btree
t.index ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree t.index ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree
t.index ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} t.index ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
......
...@@ -1332,6 +1332,9 @@ msgstr "" ...@@ -1332,6 +1332,9 @@ msgstr ""
msgid "CICD|You must add a %{kubernetes_cluster_start}Kubernetes cluster integration%{kubernetes_cluster_end} to this project with a domain in order for your deployment strategy to work correctly." msgid "CICD|You must add a %{kubernetes_cluster_start}Kubernetes cluster integration%{kubernetes_cluster_end} to this project with a domain in order for your deployment strategy to work correctly."
msgstr "" msgstr ""
msgid "CICD|group enabled"
msgstr ""
msgid "CICD|instance enabled" msgid "CICD|instance enabled"
msgstr "" msgstr ""
...@@ -3828,18 +3831,33 @@ msgstr "" ...@@ -3828,18 +3831,33 @@ msgstr ""
msgid "Group: %{group_name}" msgid "Group: %{group_name}"
msgstr "" msgstr ""
msgid "GroupSettings|Auto DevOps pipeline was updated for the group"
msgstr ""
msgid "GroupSettings|Auto DevOps will automatically build, test and deploy your application based on a predefined Continuous Integration and Delivery configuration. %{auto_devops_start}Learn more about Auto DevOps%{auto_devops_end}"
msgstr ""
msgid "GroupSettings|Badges" msgid "GroupSettings|Badges"
msgstr "" msgstr ""
msgid "GroupSettings|Customize your group badges." msgid "GroupSettings|Customize your group badges."
msgstr "" msgstr ""
msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within this group"
msgstr ""
msgid "GroupSettings|Learn more about badges." msgid "GroupSettings|Learn more about badges."
msgstr "" msgstr ""
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups" msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "" msgstr ""
msgid "GroupSettings|The Auto DevOps pipeline will run if no alternative CI configuration file is found."
msgstr ""
msgid "GroupSettings|There was a problem updating Auto DevOps pipeline: %{error_messages}."
msgstr ""
msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup." msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
msgstr "" msgstr ""
......
...@@ -66,4 +66,77 @@ describe Groups::Settings::CiCdController do ...@@ -66,4 +66,77 @@ describe Groups::Settings::CiCdController do
end end
end end
end end
describe 'PATCH #update_auto_devops' do
let(:auto_devops_param) { '1' }
subject do
patch :update_auto_devops, params: {
group_id: group,
group: { auto_devops_enabled: auto_devops_param }
}
end
context 'when user does not have enough permission' do
before do
group.add_maintainer(user)
end
it { is_expected.to have_gitlab_http_status(404) }
end
context 'when user has enough privileges' do
before do
group.add_owner(user)
end
it { is_expected.to redirect_to(group_settings_ci_cd_path) }
context 'when service execution went wrong' do
before do
allow_any_instance_of(Groups::AutoDevopsService).to receive(:execute).and_return(false)
allow_any_instance_of(Group).to receive_message_chain(:errors, :full_messages)
.and_return(['Error 1'])
subject
end
it 'returns a flash alert' do
expect(response).to set_flash[:alert]
.to eq("There was a problem updating Auto DevOps pipeline: [\"Error 1\"].")
end
end
context 'when service execution was successful' do
it 'returns a flash notice' do
subject
expect(response).to set_flash[:notice]
.to eq('Auto DevOps pipeline was updated for the group')
end
end
context 'when changing auto devops value' do
before do
subject
group.reload
end
context 'when explicitly enabling auto devops' do
it 'should update group attribute' do
expect(group.auto_devops_enabled).to eq(true)
end
end
context 'when explicitly disabling auto devops' do
let(:auto_devops_param) { '0' }
it 'should update group attribute' do
expect(group.auto_devops_enabled).to eq(false)
end
end
end
end
end
end end
...@@ -36,5 +36,13 @@ FactoryBot.define do ...@@ -36,5 +36,13 @@ FactoryBot.define do
trait :nested do trait :nested do
parent factory: :group parent factory: :group
end end
trait :auto_devops_enabled do
auto_devops_enabled true
end
trait :auto_devops_disabled do
auto_devops_enabled false
end
end end
end end
...@@ -271,6 +271,10 @@ FactoryBot.define do ...@@ -271,6 +271,10 @@ FactoryBot.define do
trait :auto_devops do trait :auto_devops do
association :auto_devops, factory: :project_auto_devops association :auto_devops, factory: :project_auto_devops
end end
trait :auto_devops_disabled do
association :auto_devops, factory: [:project_auto_devops, :disabled]
end
end end
# Project with empty repository # Project with empty repository
......
...@@ -5,8 +5,8 @@ require 'spec_helper' ...@@ -5,8 +5,8 @@ require 'spec_helper'
describe 'Group CI/CD settings' do describe 'Group CI/CD settings' do
include WaitForRequests include WaitForRequests
let(:user) {create(:user)} let(:user) { create(:user) }
let(:group) {create(:group)} let(:group) { create(:group) }
before do before do
group.add_owner(user) group.add_owner(user)
...@@ -36,4 +36,45 @@ describe 'Group CI/CD settings' do ...@@ -36,4 +36,45 @@ describe 'Group CI/CD settings' do
end end
end end
end end
describe 'Auto DevOps form' do
before do
stub_application_setting(auto_devops_enabled: true)
end
context 'as owner first visiting group settings' do
it 'should see instance enabled badge' do
visit group_settings_ci_cd_path(group)
page.within '#auto-devops-settings' do
expect(page).to have_content('instance enabled')
end
end
end
context 'when Auto DevOps group has been enabled' do
it 'should see group enabled badge' do
group.update!(auto_devops_enabled: true)
visit group_settings_ci_cd_path(group)
page.within '#auto-devops-settings' do
expect(page).to have_content('group enabled')
end
end
end
context 'when Auto DevOps group has been disabled' do
it 'should not see a badge' do
group.update!(auto_devops_enabled: false)
visit group_settings_ci_cd_path(group)
page.within '#auto-devops-settings' do
expect(page).not_to have_content('instance enabled')
expect(page).not_to have_content('group enabled')
end
end
end
end
end end
...@@ -110,6 +110,37 @@ describe "Projects > Settings > Pipelines settings" do ...@@ -110,6 +110,37 @@ describe "Projects > Settings > Pipelines settings" do
expect(page).not_to have_content('instance enabled') expect(page).not_to have_content('instance enabled')
end end
end end
context 'when auto devops is turned on group level' do
before do
project.update!(namespace: create(:group, :auto_devops_enabled))
end
it 'renders group enabled badge' do
visit project_settings_ci_cd_path(project)
page.within '#autodevops-settings' do
expect(page).to have_content('group enabled')
expect(find_field('project_auto_devops_attributes_enabled')).to be_checked
end
end
end
context 'when auto devops is turned on group parent level', :nested_groups do
before do
group = create(:group, parent: create(:group, :auto_devops_enabled))
project.update!(namespace: group)
end
it 'renders group enabled badge' do
visit project_settings_ci_cd_path(project)
page.within '#autodevops-settings' do
expect(page).to have_content('group enabled')
expect(find_field('project_auto_devops_attributes_enabled')).to be_checked
end
end
end
end end
end end
......
...@@ -29,11 +29,11 @@ describe AutoDevopsHelper do ...@@ -29,11 +29,11 @@ describe AutoDevopsHelper do
end end
context 'when the banner is disabled by feature flag' do context 'when the banner is disabled by feature flag' do
it 'allows the feature flag to disable' do before do
Feature.get(:auto_devops_banner_disabled).enable Feature.get(:auto_devops_banner_disabled).enable
expect(subject).to be(false)
end end
it { is_expected.to be_falsy }
end end
context 'when dismissed' do context 'when dismissed' do
...@@ -90,4 +90,136 @@ describe AutoDevopsHelper do ...@@ -90,4 +90,136 @@ describe AutoDevopsHelper do
it { is_expected.to eq(false) } it { is_expected.to eq(false) }
end end
end end
describe '#badge_for_auto_devops_scope' do
subject { helper.badge_for_auto_devops_scope(receiver) }
context 'when receiver is a group' do
context 'when explicitly enabled' do
let(:receiver) { create(:group, :auto_devops_enabled) }
it { is_expected.to eq('group enabled') }
end
context 'when explicitly disabled' do
let(:receiver) { create(:group, :auto_devops_disabled) }
it { is_expected.to be_nil }
end
context 'when auto devops is implicitly enabled' do
let(:receiver) { create(:group) }
context 'by instance' do
before do
stub_application_setting(auto_devops_enabled: true)
end
it { is_expected.to eq('instance enabled') }
end
context 'with groups', :nested_groups do
before do
receiver.update(parent: parent)
end
context 'when auto devops is enabled on parent' do
let(:parent) { create(:group, :auto_devops_enabled) }
it { is_expected.to eq('group enabled') }
end
context 'when auto devops is enabled on parent group' do
let(:root_parent) { create(:group, :auto_devops_enabled) }
let(:parent) { create(:group, parent: root_parent) }
it { is_expected.to eq('group enabled') }
end
context 'when auto devops disabled set on parent group' do
let(:root_parent) { create(:group, :auto_devops_disabled) }
let(:parent) { create(:group, parent: root_parent) }
it { is_expected.to be_nil }
end
end
end
end
context 'when receiver is a project' do
context 'when auto devops is enabled at project level' do
let(:receiver) { create(:project, :auto_devops) }
it { is_expected.to be_nil }
end
context 'when auto devops is disabled at project level' do
let(:receiver) { create(:project, :auto_devops_disabled) }
it { is_expected.to be_nil }
end
context 'when auto devops is implicitly enabled' do
let(:receiver) { create(:project) }
context 'by instance' do
before do
stub_application_setting(auto_devops_enabled: true)
end
it { is_expected.to eq('instance enabled') }
end
context 'with groups', :nested_groups do
let(:receiver) { create(:project, :repository, namespace: group) }
before do
stub_application_setting(auto_devops_enabled: false)
end
context 'when auto devops is enabled on group level' do
let(:group) { create(:group, :auto_devops_enabled) }
it { is_expected.to eq('group enabled') }
end
context 'when auto devops is enabled on root group' do
let(:root_parent) { create(:group, :auto_devops_enabled) }
let(:group) { create(:group, parent: root_parent) }
it { is_expected.to eq('group enabled') }
end
end
end
context 'when auto devops is implicitly disabled' do
let(:receiver) { create(:project) }
context 'by instance' do
before do
stub_application_setting(auto_devops_enabled: false)
end
it { is_expected.to be_nil }
end
context 'with groups', :nested_groups do
let(:receiver) { create(:project, :repository, namespace: group) }
context 'when auto devops is disabled on group level' do
let(:group) { create(:group, :auto_devops_disabled) }
it { is_expected.to be_nil }
end
context 'when root group is enabled and parent disabled' do
let(:root_parent) { create(:group, :auto_devops_enabled) }
let(:group) { create(:group, :auto_devops_disabled, parent: root_parent) }
it { is_expected.to be_nil }
end
end
end
end
end
end end
...@@ -810,4 +810,125 @@ describe Group do ...@@ -810,4 +810,125 @@ describe Group do
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
end end
describe '#first_auto_devops_config' do
using RSpec::Parameterized::TableSyntax
let(:group) { create(:group) }
subject { group.first_auto_devops_config }
where(:instance_value, :group_value, :config) do
# Instance level enabled
true | nil | { status: true, scope: :instance }
true | true | { status: true, scope: :group }
true | false | { status: false, scope: :group }
# Instance level disabled
false | nil | { status: false, scope: :instance }
false | true | { status: true, scope: :group }
false | false | { status: false, scope: :group }
end
with_them do
before do
stub_application_setting(auto_devops_enabled: instance_value)
group.update_attribute(:auto_devops_enabled, group_value)
end
it { is_expected.to eq(config) }
end
context 'with parent groups', :nested_groups do
where(:instance_value, :parent_value, :group_value, :config) do
# Instance level enabled
true | nil | nil | { status: true, scope: :instance }
true | nil | true | { status: true, scope: :group }
true | nil | false | { status: false, scope: :group }
true | true | nil | { status: true, scope: :group }
true | true | true | { status: true, scope: :group }
true | true | false | { status: false, scope: :group }
true | false | nil | { status: false, scope: :group }
true | false | true | { status: true, scope: :group }
true | false | false | { status: false, scope: :group }
# Instance level disable
false | nil | nil | { status: false, scope: :instance }
false | nil | true | { status: true, scope: :group }
false | nil | false | { status: false, scope: :group }
false | true | nil | { status: true, scope: :group }
false | true | true | { status: true, scope: :group }
false | true | false | { status: false, scope: :group }
false | false | nil | { status: false, scope: :group }
false | false | true | { status: true, scope: :group }
false | false | false | { status: false, scope: :group }
end
with_them do
before do
stub_application_setting(auto_devops_enabled: instance_value)
parent = create(:group, auto_devops_enabled: parent_value)
group.update!(
auto_devops_enabled: group_value,
parent: parent
)
end
it { is_expected.to eq(config) }
end
end
end
describe '#auto_devops_enabled?' do
subject { group.auto_devops_enabled? }
context 'when auto devops is explicitly enabled on group' do
let(:group) { create(:group, :auto_devops_enabled) }
it { is_expected.to be_truthy }
end
context 'when auto devops is explicitly disabled on group' do
let(:group) { create(:group, :auto_devops_disabled) }
it { is_expected.to be_falsy }
end
context 'when auto devops is implicitly enabled or disabled' do
before do
stub_application_setting(auto_devops_enabled: false)
group.update!(parent: parent_group)
end
context 'when auto devops is enabled on root group' do
let(:root_group) { create(:group, :auto_devops_enabled) }
let(:subgroup) { create(:group, parent: root_group) }
let(:parent_group) { create(:group, parent: subgroup) }
it { is_expected.to be_truthy }
end
context 'when auto devops is disabled on root group' do
let(:root_group) { create(:group, :auto_devops_disabled) }
let(:subgroup) { create(:group, parent: root_group) }
let(:parent_group) { create(:group, parent: subgroup) }
it { is_expected.to be_falsy }
end
context 'when auto devops is disabled on parent group and enabled on root group' do
let(:root_group) { create(:group, :auto_devops_enabled) }
let(:parent_group) { create(:group, :auto_devops_disabled, parent: root_group) }
it { is_expected.to be_falsy }
end
end
end
end end
...@@ -775,4 +775,28 @@ describe Namespace do ...@@ -775,4 +775,28 @@ describe Namespace do
end end
end end
end end
describe '#auto_devops_enabled' do
context 'with users' do
let(:user) { create(:user) }
subject { user.namespace.auto_devops_enabled? }
before do
user.namespace.update!(auto_devops_enabled: auto_devops_enabled)
end
context 'when auto devops is explicitly enabled' do
let(:auto_devops_enabled) { true }
it { is_expected.to eq(true) }
end
context 'when auto devops is explicitly disabled' do
let(:auto_devops_enabled) { false }
it { is_expected.to eq(false) }
end
end
end
end end
...@@ -3631,12 +3631,36 @@ describe Project do ...@@ -3631,12 +3631,36 @@ describe Project do
subject { project.auto_devops_enabled? } subject { project.auto_devops_enabled? }
context 'when explicitly enabled' do
before do
create(:project_auto_devops, project: project)
end
it { is_expected.to be_truthy }
end
context 'when explicitly disabled' do
before do
create(:project_auto_devops, project: project, enabled: false)
end
it { is_expected.to be_falsey }
end
context 'when enabled in settings' do context 'when enabled in settings' do
before do before do
stub_application_setting(auto_devops_enabled: true) stub_application_setting(auto_devops_enabled: true)
end end
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end
context 'when disabled in settings' do
before do
stub_application_setting(auto_devops_enabled: false)
end
it { is_expected.to be_falsey }
context 'when explicitly enabled' do context 'when explicitly enabled' do
before do before do
...@@ -3648,34 +3672,91 @@ describe Project do ...@@ -3648,34 +3672,91 @@ describe Project do
context 'when explicitly disabled' do context 'when explicitly disabled' do
before do before do
create(:project_auto_devops, project: project, enabled: false) create(:project_auto_devops, :disabled, project: project)
end end
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
end end
context 'when disabled in settings' do context 'when force_autodevops_on_by_default is enabled for the project' do
it { is_expected.to be_truthy }
end
context 'with group parents' do
let(:instance_enabled) { true }
before do before do
stub_application_setting(auto_devops_enabled: false) stub_application_setting(auto_devops_enabled: instance_enabled)
project.update!(namespace: parent_group)
end end
it { is_expected.to be_falsey } context 'when enabled on parent' do
let(:parent_group) { create(:group, :auto_devops_enabled) }
context 'when explicitly enabled' do context 'when auto devops instance enabled' do
before do it { is_expected.to be_truthy }
create(:project_auto_devops, project: project)
end end
it { is_expected.to be_truthy } context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_truthy }
end
end end
context 'when force_autodevops_on_by_default is enabled for the project' do context 'when disabled on parent' do
before do let(:parent_group) { create(:group, :auto_devops_disabled) }
Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(100)
context 'when auto devops instance enabled' do
it { is_expected.to be_falsy }
end end
it { is_expected.to be_truthy } context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_falsy }
end
end
context 'when enabled on root parent', :nested_groups do
let(:parent_group) { create(:group, parent: create(:group, :auto_devops_enabled)) }
context 'when auto devops instance enabled' do
it { is_expected.to be_truthy }
end
context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_truthy }
end
context 'when explicitly disabled on parent' do
let(:parent_group) { create(:group, :auto_devops_disabled, parent: create(:group, :auto_devops_enabled)) }
it { is_expected.to be_falsy }
end
end
context 'when disabled on root parent', :nested_groups do
let(:parent_group) { create(:group, parent: create(:group, :auto_devops_disabled)) }
context 'when auto devops instance enabled' do
it { is_expected.to be_falsy }
end
context 'when auto devops instance disabled' do
let(:instance_disabled) { false }
it { is_expected.to be_falsy }
end
context 'when explicitly disabled on parent' do
let(:parent_group) { create(:group, :auto_devops_disabled, parent: create(:group, :auto_devops_enabled)) }
it { is_expected.to be_falsy }
end
end end
end end
end end
...@@ -3722,15 +3803,52 @@ describe Project do ...@@ -3722,15 +3803,52 @@ describe Project do
end end
end end
end end
context 'when enabled on group' do
it 'has auto devops implicitly enabled' do
project.update(namespace: create(:group, :auto_devops_enabled))
expect(project).to have_auto_devops_implicitly_enabled
end
end
context 'when enabled on parent group' do
it 'has auto devops implicitly enabled' do
subgroup = create(:group, parent: create(:group, :auto_devops_enabled))
project.update(namespace: subgroup)
expect(project).to have_auto_devops_implicitly_enabled
end
end
end end
describe '#has_auto_devops_implicitly_disabled?' do describe '#has_auto_devops_implicitly_disabled?' do
set(:project) { create(:project) }
before do before do
allow(Feature).to receive(:enabled?).and_call_original allow(Feature).to receive(:enabled?).and_call_original
Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(0) Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(0)
end end
set(:project) { create(:project) } context 'when explicitly disabled' do
before do
create(:project_auto_devops, project: project, enabled: false)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_disabled
end
end
context 'when explicitly enabled' do
before do
create(:project_auto_devops, project: project, enabled: true)
end
it 'does not have auto devops implicitly disabled' do
expect(project).not_to have_auto_devops_implicitly_disabled
end
end
context 'when enabled in settings' do context 'when enabled in settings' do
before do before do
...@@ -3753,6 +3871,8 @@ describe Project do ...@@ -3753,6 +3871,8 @@ describe Project do
context 'when force_autodevops_on_by_default is enabled for the project' do context 'when force_autodevops_on_by_default is enabled for the project' do
before do before do
create(:project_auto_devops, project: project, enabled: false)
Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(100) Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(100)
end end
...@@ -3761,23 +3881,20 @@ describe Project do ...@@ -3761,23 +3881,20 @@ describe Project do
end end
end end
context 'when explicitly disabled' do context 'when disabled on group' do
before do it 'has auto devops implicitly disabled' do
create(:project_auto_devops, project: project, enabled: false) project.update!(namespace: create(:group, :auto_devops_disabled))
end
it 'does not have auto devops implicitly disabled' do expect(project).to have_auto_devops_implicitly_disabled
expect(project).not_to have_auto_devops_implicitly_disabled
end end
end end
context 'when explicitly enabled' do context 'when disabled on parent group' do
before do it 'has auto devops implicitly disabled' do
create(:project_auto_devops, project: project, enabled: true) subgroup = create(:group, parent: create(:group, :auto_devops_disabled))
end project.update!(namespace: subgroup)
it 'does not have auto devops implicitly disabled' do expect(project).to have_auto_devops_implicitly_disabled
expect(project).not_to have_auto_devops_implicitly_disabled
end end
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe Groups::AutoDevopsService, '#execute' do
set(:group) { create(:group) }
set(:user) { create(:user) }
let(:group_params) { { auto_devops_enabled: '0' } }
let(:service) { described_class.new(group, user, group_params) }
context 'when user does not have enough privileges' do
it 'raises exception' do
group.add_developer(user)
expect do
service.execute
end.to raise_exception(Gitlab::Access::AccessDeniedError)
end
end
context 'when user has enough privileges' do
before do
group.add_owner(user)
end
it 'updates group auto devops enabled accordingly' do
service.execute
expect(group.auto_devops_enabled).to eq(false)
end
context 'when group has projects' do
it 'reflects changes on projects' do
project_1 = create(:project, namespace: group)
service.execute
expect(project_1).not_to have_auto_devops_implicitly_enabled
end
end
context 'when group has subgroups' do
it 'reflects changes on subgroups' do
subgroup_1 = create(:group, parent: group)
service.execute
expect(subgroup_1.auto_devops_enabled?).to eq(false)
end
context 'when subgroups have projects', :nested_groups do
it 'reflects changes on projects' do
subgroup_1 = create(:group, parent: group)
project_1 = create(:project, namespace: subgroup_1)
service.execute
expect(project_1).not_to have_auto_devops_implicitly_enabled
end
end
end
end
end
...@@ -5,6 +5,7 @@ describe 'projects/settings/ci_cd/_autodevops_form' do ...@@ -5,6 +5,7 @@ describe 'projects/settings/ci_cd/_autodevops_form' do
before do before do
assign :project, project assign :project, project
allow(view).to receive(:auto_devops_enabled) { true }
end end
it 'shows a warning message about Kubernetes cluster' do it 'shows a warning message about Kubernetes cluster' do
......
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