summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/views/groups/runners/_settings.html.haml186
-rw-r--r--doc/api/projects.md2
-rw-r--r--doc/raketasks/backup_restore.md17
-rw-r--r--doc/user/profile/index.md2
-rw-r--r--lib/backup/manager.rb2
-rw-r--r--spec/features/groups/settings/ci_cd_spec.rb81
-rw-r--r--spec/features/runners_spec.rb1
-rw-r--r--spec/lib/backup/manager_spec.rb17
8 files changed, 183 insertions, 125 deletions
diff --git a/app/views/groups/runners/_settings.html.haml b/app/views/groups/runners/_settings.html.haml
index bbcadc08a8b..087b06ee37d 100644
--- a/app/views/groups/runners/_settings.html.haml
+++ b/app/views/groups/runners/_settings.html.haml
@@ -1,4 +1,6 @@
- if Feature.enabled?(:runner_list_group_view_vue_ui, @group, default_enabled: :yaml)
+ .gl-mb-6
+ #update-shared-runners-form{ data: group_shared_runners_settings_data(@group) }
.gl-card.gl-px-8.gl-py-6.gl-line-height-20
.gl-card-body.gl-display-flex{ :class => "gl-p-0!" }
.gl-banner-illustration
@@ -11,107 +13,107 @@
%a.btn.btn-confirm.btn-md.gl-button{ :href => group_runners_path(@group) }
%span.gl-button-text
= s_('Runners|Take me there!')
+- else
+ = render 'shared/runners/runner_description'
-= render 'shared/runners/runner_description'
-
-%hr
+ %hr
-.row
- .col-sm-6
- = render 'groups/runners/group_runners'
- .col-sm-6
- = render 'groups/runners/shared_runners'
+ .row
+ .col-sm-6
+ = render 'groups/runners/group_runners'
+ .col-sm-6
+ = render 'groups/runners/shared_runners'
-%h4.underlined-title
- = _('Available runners: %{runners}').html_safe % { runners: limited_counter_with_delimiter(@all_group_runners) }
+ %h4.underlined-title
+ = _('Available runners: %{runners}').html_safe % { runners: limited_counter_with_delimiter(@all_group_runners) }
--# haml-lint:disable NoPlainNodes
-.row
- .col-sm-9
- = form_tag group_settings_ci_cd_path, id: 'runners-search', method: :get, class: 'filter-form js-filter-form' do
- .filtered-search-wrapper.d-flex
- .filtered-search-box
- = dropdown_tag(_('Recent searches'),
- options: { wrapper_class: 'filtered-search-history-dropdown-wrapper',
- toggle_class: 'gl-button btn btn-default filtered-search-history-dropdown-toggle-button',
- dropdown_class: 'filtered-search-history-dropdown',
- content_class: 'filtered-search-history-dropdown-content' }) do
- .js-filtered-search-history-dropdown{ data: { full_path: group_settings_ci_cd_path } }
- .filtered-search-box-input-container.droplab-dropdown
- .scroll-container
- %ul.tokens-container.list-unstyled
- %li.input-token
- %input.form-control.filtered-search{ search_filter_input_options('runners') }
- #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
- %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
- %li.filter-dropdown-item{ data: {hint: "#{'{{hint}}'}", tag: "#{'{{tag}}'}", action: "#{'{{hint === \'search\' ? \'submit\' : \'\' }}'}" } }
- = button_tag class: 'gl-button btn btn-link' do
- -# Encapsulate static class name `{{icon}}` inside #{} to bypass
- -# haml lint's ClassAttributeWithStaticValue
- %svg
- %use{ 'xlink:href': "#{'{{icon}}'}" }
- %span.js-filter-hint
- {{formattedKey}}
- #js-dropdown-operator.filtered-search-input-dropdown-menu.dropdown-menu
- %ul.filter-dropdown{ data: { dropdown: true, dynamic: true } }
- %li.filter-dropdown-item{ data: { value: "{{ title }}" } }
- = button_tag class: 'gl-button btn btn-link' do
- {{ title }}
- %span.btn-helptext
- {{ help }}
- #js-dropdown-admin-runner-status.filtered-search-input-dropdown-menu.dropdown-menu
- %ul{ data: { dropdown: true } }
- - Ci::Runner::AVAILABLE_STATUSES.each do |status|
- %li.filter-dropdown-item{ data: { value: status } }
+ -# haml-lint:disable NoPlainNodes
+ .row
+ .col-sm-9
+ = form_tag group_settings_ci_cd_path, id: 'runners-search', method: :get, class: 'filter-form js-filter-form' do
+ .filtered-search-wrapper.d-flex
+ .filtered-search-box
+ = dropdown_tag(_('Recent searches'),
+ options: { wrapper_class: 'filtered-search-history-dropdown-wrapper',
+ toggle_class: 'gl-button btn btn-default filtered-search-history-dropdown-toggle-button',
+ dropdown_class: 'filtered-search-history-dropdown',
+ content_class: 'filtered-search-history-dropdown-content' }) do
+ .js-filtered-search-history-dropdown{ data: { full_path: group_settings_ci_cd_path } }
+ .filtered-search-box-input-container.droplab-dropdown
+ .scroll-container
+ %ul.tokens-container.list-unstyled
+ %li.input-token
+ %input.form-control.filtered-search{ search_filter_input_options('runners') }
+ #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
+ %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
+ %li.filter-dropdown-item{ data: {hint: "#{'{{hint}}'}", tag: "#{'{{tag}}'}", action: "#{'{{hint === \'search\' ? \'submit\' : \'\' }}'}" } }
= button_tag class: 'gl-button btn btn-link' do
- = status.titleize
-
- #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
- %ul{ data: { dropdown: true } }
- - Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
- - next if runner_type == 'instance_type'
- %li.filter-dropdown-item{ data: { value: runner_type } }
+ -# Encapsulate static class name `{{icon}}` inside #{} to bypass
+ -# haml lint's ClassAttributeWithStaticValue
+ %svg
+ %use{ 'xlink:href': "#{'{{icon}}'}" }
+ %span.js-filter-hint
+ {{formattedKey}}
+ #js-dropdown-operator.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul.filter-dropdown{ data: { dropdown: true, dynamic: true } }
+ %li.filter-dropdown-item{ data: { value: "{{ title }}" } }
= button_tag class: 'gl-button btn btn-link' do
- = runner_type.titleize
+ {{ title }}
+ %span.btn-helptext
+ {{ help }}
+ #js-dropdown-admin-runner-status.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ - Ci::Runner::AVAILABLE_STATUSES.each do |status|
+ %li.filter-dropdown-item{ data: { value: status } }
+ = button_tag class: 'gl-button btn btn-link' do
+ = status.titleize
+
+ #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ - Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
+ - next if runner_type == 'instance_type'
+ %li.filter-dropdown-item{ data: { value: runner_type } }
+ = button_tag class: 'gl-button btn btn-link' do
+ = runner_type.titleize
- #js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu
- %ul{ data: { dropdown: true } }
- %li.filter-dropdown-item{ data: { value: 'none' } }
- = button_tag class: 'gl-button btn btn-link' do
- = _('No Tag')
- %li.divider.droplab-item-ignore
- %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
- %li.filter-dropdown-item
- = button_tag class: 'gl-button btn btn-link js-data-value' do
- %span.dropdown-light-content
- {{name}}
+ #js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ %li.filter-dropdown-item{ data: { value: 'none' } }
+ = button_tag class: 'gl-button btn btn-link' do
+ = _('No Tag')
+ %li.divider.droplab-item-ignore
+ %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
+ %li.filter-dropdown-item
+ = button_tag class: 'gl-button btn btn-link js-data-value' do
+ %span.dropdown-light-content
+ {{name}}
- = button_tag class: 'clear-search hidden' do
- = sprite_icon('close', size: 16, css_class: 'clear-search-icon')
- .filter-dropdown-container
- = render 'groups/runners/sort_dropdown'
+ = button_tag class: 'clear-search hidden' do
+ = sprite_icon('close', size: 16, css_class: 'clear-search-icon')
+ .filter-dropdown-container
+ = render 'groups/runners/sort_dropdown'
- .col-sm-3.text-right-lg
- = _('Runners currently online: %{active_runners_count}') % { active_runners_count: limited_counter_with_delimiter(@all_group_runners.online) }
+ .col-sm-3.text-right-lg
+ = _('Runners currently online: %{active_runners_count}') % { active_runners_count: limited_counter_with_delimiter(@all_group_runners.online) }
-- if @group_runners.any?
- .content-list{ data: { testid: 'runners-table' } }
- .table-holder
- .gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-10{ role: 'rowheader' }= _('Type/State')
- .table-section.section-30{ role: 'rowheader' }= s_('Runners|Runner')
- .table-section.section-10{ role: 'rowheader' }= _('Version')
- .table-section.section-10{ role: 'rowheader' }= _('IP Address')
- .table-section.section-5{ role: 'rowheader' }= _('Projects')
- .table-section.section-5{ role: 'rowheader' }= _('Jobs')
- .table-section.section-10{ role: 'rowheader' }= _('Tags')
- .table-section.section-10{ role: 'rowheader' }= _('Last contact')
- .table-section.section-10{ role: 'rowheader' }
+ - if @group_runners.any?
+ .content-list{ data: { testid: 'runners-table' } }
+ .table-holder
+ .gl-responsive-table-row.table-row-header{ role: 'row' }
+ .table-section.section-10{ role: 'rowheader' }= _('Type/State')
+ .table-section.section-30{ role: 'rowheader' }= s_('Runners|Runner')
+ .table-section.section-10{ role: 'rowheader' }= _('Version')
+ .table-section.section-10{ role: 'rowheader' }= _('IP Address')
+ .table-section.section-5{ role: 'rowheader' }= _('Projects')
+ .table-section.section-5{ role: 'rowheader' }= _('Jobs')
+ .table-section.section-10{ role: 'rowheader' }= _('Tags')
+ .table-section.section-10{ role: 'rowheader' }= _('Last contact')
+ .table-section.section-10{ role: 'rowheader' }
- - @group_runners.each do |runner|
- - runner = runner.present(current_user: current_user)
- = render 'groups/runners/runner', runner: runner
- = paginate @group_runners, theme: 'gitlab', :params => { :anchor => 'runners-settings' }
-- else
- .nothing-here-block= _('No runners found')
+ - @group_runners.each do |runner|
+ - runner = runner.present(current_user: current_user)
+ = render 'groups/runners/runner', runner: runner
+ = paginate @group_runners, theme: 'gitlab', :params => { :anchor => 'runners-settings' }
+ - else
+ .nothing-here-block= _('No runners found')
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 1a1b8ffb733..4b8fd0d675b 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -375,7 +375,7 @@ Get a list of visible projects owned by the given user. When accessed without
authentication, only public projects are returned.
NOTE:
-Only the projects in the user's (specified in `user_id`) namespace are returned. Projects owned by the user in any group or subgroups are not returned.
+Only the projects in the user's (specified in `user_id`) namespace are returned. Projects owned by the user in any group or subgroups are not returned. An empty list is returned if a profile is set to private.
This endpoint supports [keyset pagination](index.md#keyset-based-pagination)
for selected `order_by` options.
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index bd4c1021c98..5458e9952fa 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -724,6 +724,23 @@ sudo gitlab-backup create DIRECTORY=weekly
Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
+#### Skip uploading backups to remote storage
+
+If you have configured GitLab to [upload backups in a remote storage](#uploading-backups-to-a-remote-cloud-storage),
+you can use the `SKIP=remote` option to skip uploading your backups to the remote storage.
+
+For Omnibus GitLab packages:
+
+```shell
+sudo gitlab-backup create SKIP=remote
+```
+
+For installations from source:
+
+```shell
+sudo -u git -H bundle exec rake gitlab:backup:create SKIP=remote RAILS_ENV=production
+```
+
#### Uploading to locally mounted shares
You may also send backups to a mounted share (for example, `NFS`,`CIFS`, or
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 6ea0f3cfbe2..a86968654c7 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -88,7 +88,7 @@ The following is hidden from your user profile page (`https://gitlab.example.com
- Tabs for activity, groups, contributed projects, personal projects, starred projects, snippets
NOTE:
-Making your user profile page private does not hide your public resources from the REST or GraphQL APIs.
+Making your user profile page private does not hide all your public resources from the REST or GraphQL APIs.
### User visibility
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 71cb4d818a7..fffaffda71c 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -271,7 +271,7 @@ module Backup
def upload
connection_settings = Gitlab.config.backup.upload.connection
- if connection_settings.blank?
+ if connection_settings.blank? || skipped?('remote')
puts_time "Uploading backup archive to remote storage #{remote_directory} ... ".color(:blue) + "[SKIPPED]".color(:cyan)
return
end
diff --git a/spec/features/groups/settings/ci_cd_spec.rb b/spec/features/groups/settings/ci_cd_spec.rb
index 8851aeb6381..c5ad524e647 100644
--- a/spec/features/groups/settings/ci_cd_spec.rb
+++ b/spec/features/groups/settings/ci_cd_spec.rb
@@ -5,52 +5,73 @@ require 'spec_helper'
RSpec.describe 'Group CI/CD settings' do
include WaitForRequests
- let(:user) { create(:user) }
- let(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group, reload: true) { create(:group) }
- before do
+ before_all do
group.add_owner(user)
+ end
+
+ before do
sign_in(user)
end
- describe 'new group runners view banner' do
- it 'displays banner' do
- visit group_settings_ci_cd_path(group)
+ describe 'Runners section' do
+ let(:shared_runners_toggle) { page.find('[data-testid="enable-runners-toggle"]') }
+
+ context 'with runner_list_group_view_vue_ui enabled' do
+ before do
+ visit group_settings_ci_cd_path(group)
+ end
+
+ it 'displays the new group runners view banner' do
+ expect(page).to have_content(s_('Runners|New group runners view'))
+ expect(page).to have_link(href: group_runners_path(group))
+ end
- expect(page).to have_content(s_('Runners|New group runners view'))
- expect(page).to have_link(href: group_runners_path(group))
+ it 'has "Enable shared runners for this group" toggle', :js do
+ expect(shared_runners_toggle).to have_content(_('Enable shared runners for this group'))
+ end
end
- it 'does not display banner' do
- stub_feature_flags(runner_list_group_view_vue_ui: false)
+ context 'with runner_list_group_view_vue_ui disabled' do
+ before do
+ stub_feature_flags(runner_list_group_view_vue_ui: false)
- visit group_settings_ci_cd_path(group)
+ visit group_settings_ci_cd_path(group)
+ end
- expect(page).not_to have_content(s_('Runners|New group runners view'))
- expect(page).not_to have_link(href: group_runners_path(group))
- end
- end
+ it 'does not display the new group runners view banner' do
+ expect(page).not_to have_content(s_('Runners|New group runners view'))
+ expect(page).not_to have_link(href: group_runners_path(group))
+ end
- describe 'runners registration token' do
- let!(:token) { group.runners_token }
+ it 'has "Enable shared runners for this group" toggle', :js do
+ expect(shared_runners_toggle).to have_content(_('Enable shared runners for this group'))
+ end
- before do
- visit group_settings_ci_cd_path(group)
- end
+ context 'with runners registration token' do
+ let!(:token) { group.runners_token }
- it 'has a registration token' do
- expect(page.find('#registration_token')).to have_content(token)
- end
+ before do
+ visit group_settings_ci_cd_path(group)
+ end
- describe 'reload registration token' do
- let(:page_token) { find('#registration_token').text }
+ it 'displays the registration token' do
+ expect(page.find('#registration_token')).to have_content(token)
+ end
- before do
- click_button 'Reset registration token'
- end
+ describe 'reload registration token' do
+ let(:page_token) { find('#registration_token').text }
+
+ before do
+ click_button 'Reset registration token'
+ end
- it 'changes registration token' do
- expect(page_token).not_to eq token
+ it 'changes the registration token' do
+ expect(page_token).not_to eq token
+ end
+ end
end
end
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 49c468976b9..2dddcd62a6c 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -352,6 +352,7 @@ RSpec.describe 'Runners' do
before do
group.add_owner(user)
+ stub_feature_flags(runner_list_group_view_vue_ui: false)
end
context 'group with no runners' do
diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb
index 24b18ef95a4..192739d05a7 100644
--- a/spec/lib/backup/manager_spec.rb
+++ b/spec/lib/backup/manager_spec.rb
@@ -440,6 +440,23 @@ RSpec.describe Backup::Manager do
connection.directories.create(key: Gitlab.config.backup.upload.remote_directory) # rubocop:disable Rails/SaveBang
end
+ context 'skipped upload' do
+ let(:backup_information) do
+ {
+ backup_created_at: Time.zone.parse('2019-01-01'),
+ gitlab_version: '12.3',
+ skipped: ['remote']
+ }
+ end
+
+ it 'informs the user' do
+ stub_env('SKIP', 'remote')
+ subject.create # rubocop:disable Rails/SaveBang
+
+ expect(Gitlab::BackupLogger).to have_received(:info).with(message: 'Uploading backup archive to remote storage directory ... [SKIPPED]')
+ end
+ end
+
context 'target path' do
it 'uses the tar filename by default' do
expect_any_instance_of(Fog::Collection).to receive(:create)