Commit def26df0 authored by Clement Ho's avatar Clement Ho

Merge branch 'georgekoltsov/bitbucket-cloud-import-filtering' into 'master'

Add project filtering to Bitbucket Cloud import

See merge request gitlab-org/gitlab!16828
parents acdb7b0f ffeee69c
# frozen_string_literal: true # frozen_string_literal: true
class Import::BitbucketController < Import::BaseController class Import::BitbucketController < Import::BaseController
include ActionView::Helpers::SanitizeHelper
before_action :verify_bitbucket_import_enabled before_action :verify_bitbucket_import_enabled
before_action :bitbucket_auth, except: :callback before_action :bitbucket_auth, except: :callback
...@@ -21,7 +23,7 @@ class Import::BitbucketController < Import::BaseController ...@@ -21,7 +23,7 @@ class Import::BitbucketController < Import::BaseController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def status def status
bitbucket_client = Bitbucket::Client.new(credentials) bitbucket_client = Bitbucket::Client.new(credentials)
repos = bitbucket_client.repos repos = bitbucket_client.repos(filter: sanitized_filter_param)
@repos, @incompatible_repos = repos.partition { |repo| repo.valid? } @repos, @incompatible_repos = repos.partition { |repo| repo.valid? }
...@@ -104,4 +106,8 @@ class Import::BitbucketController < Import::BaseController ...@@ -104,4 +106,8 @@ class Import::BitbucketController < Import::BaseController
refresh_token: session[:bitbucket_refresh_token] refresh_token: session[:bitbucket_refresh_token]
} }
end end
def sanitized_filter_param
@filter ||= sanitize(params[:filter])
end
end end
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
- if @repos.any? - if @repos.any?
%p.light %p.light
= _('Select projects you want to import.') = _('Select projects you want to import.')
%hr
%p %p
- if @incompatible_repos.any? - if @incompatible_repos.any?
= button_tag class: 'btn btn-import btn-success js-import-all' do = button_tag class: 'btn btn-import btn-success js-import-all' do
...@@ -19,6 +18,14 @@ ...@@ -19,6 +18,14 @@
= _('Import all projects') = _('Import all projects')
= icon('spinner spin', class: 'loading-icon') = icon('spinner spin', class: 'loading-icon')
.position-relative.ms-no-clear.d-flex.flex-fill.float-right.append-bottom-10
= form_tag status_import_bitbucket_path, method: 'get' do
= text_field_tag :filter, @filter, class: 'form-control pr-5', placeholder: _('Filter projects'), size: 40, autofocus: true, 'aria-label': _('Search')
.position-absolute.position-top-0.d-flex.align-items-center.text-muted.position-right-0.h-100
.border-left
%button{ class: 'btn btn-transparent btn-secondary', 'aria-label': _('Search Button'), type: 'submit' }
%i{ class: 'fa fa-search', 'aria-hidden': true }
.table-responsive .table-responsive
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col %colgroup.import-jobs-from-col
...@@ -59,7 +66,7 @@ ...@@ -59,7 +66,7 @@
- if current_user.can_select_namespace? - if current_user.can_select_namespace?
- selected = params[:namespace_id] || :current_user - selected = params[:namespace_id] || :current_user
- opts = current_user.can_create_group? ? { extra_group: Group.new(name: repo.owner, path: repo.owner) } : {} - opts = current_user.can_create_group? ? { extra_group: Group.new(name: repo.owner, path: repo.owner) } : {}
= select_tag :namespace_id, namespaces_options(selected, opts.merge({ display_path: true })), { class: 'input-group-text select2 js-select-namespace', tabindex: 1 } = select_tag :namespace_id, namespaces_options(selected, opts.merge({ display_path: true })), { class: 'select2 js-select-namespace', tabindex: 1 }
- else - else
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true = text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend %span.input-group-prepend
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
- if current_user.can_select_namespace? - if current_user.can_select_namespace?
- selected = params[:namespace_id] || :extra_group - selected = params[:namespace_id] || :extra_group
- opts = current_user.can_create_group? ? { extra_group: Group.new(name: sanitize_project_name(repo.project_key), path: sanitize_project_name(repo.project_key)) } : {} - opts = current_user.can_create_group? ? { extra_group: Group.new(name: sanitize_project_name(repo.project_key), path: sanitize_project_name(repo.project_key)) } : {}
= select_tag :namespace_id, namespaces_options(selected, opts.merge({ display_path: true })), { class: 'input-group-text select2 js-select-namespace', tabindex: 1 } = select_tag :namespace_id, namespaces_options(selected, opts.merge({ display_path: true })), { class: 'select2 js-select-namespace', tabindex: 1 }
- else - else
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true = text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend %span.input-group-prepend
......
---
title: Add project filtering to Bitbucket Cloud import
merge_request: 16828
author:
type: added
...@@ -56,10 +56,10 @@ namespace that started the import process. ...@@ -56,10 +56,10 @@ namespace that started the import process.
![Grant access](img/bitbucket_import_grant_access.png) ![Grant access](img/bitbucket_import_grant_access.png)
1. Click on the projects that you'd like to import or **Import all projects**. 1. Click on the projects that you'd like to import or **Import all projects**.
You can also select the namespace under which each project will be You can also filter projects by name and select the namespace under which
imported. each project will be imported.
![Import projects](img/bitbucket_import_select_project.png) ![Import projects](img/bitbucket_import_select_project_v12_3.png)
[bb-import]: ../../../integration/bitbucket.md [bb-import]: ../../../integration/bitbucket.md
[social sign-in]: ../../profile/account/social_sign_in.md [social sign-in]: ../../profile/account/social_sign_in.md
...@@ -38,8 +38,10 @@ module Bitbucket ...@@ -38,8 +38,10 @@ module Bitbucket
Representation::Repo.new(parsed_response) Representation::Repo.new(parsed_response)
end end
def repos def repos(filter: nil)
path = "/repositories?role=member" path = "/repositories?role=member"
path += "&q=name~\"#{filter}\"" if filter
get_collection(path, :repo) get_collection(path, :repo)
end end
......
...@@ -6795,6 +6795,9 @@ msgstr "" ...@@ -6795,6 +6795,9 @@ msgstr ""
msgid "Filter by two-factor authentication" msgid "Filter by two-factor authentication"
msgstr "" msgstr ""
msgid "Filter projects"
msgstr ""
msgid "Filter results by group" msgid "Filter results by group"
msgstr "" msgstr ""
...@@ -13602,6 +13605,9 @@ msgstr "" ...@@ -13602,6 +13605,9 @@ msgstr ""
msgid "Search" msgid "Search"
msgstr "" msgstr ""
msgid "Search Button"
msgstr ""
msgid "Search an environment spec" msgid "Search an environment spec"
msgstr "" msgstr ""
......
...@@ -80,6 +80,21 @@ describe Import::BitbucketController do ...@@ -80,6 +80,21 @@ describe Import::BitbucketController do
expect(assigns(:already_added_projects)).to eq([@project]) expect(assigns(:already_added_projects)).to eq([@project])
expect(assigns(:repos)).to eq([]) expect(assigns(:repos)).to eq([])
end end
context 'when filtering' do
let(:filter) { '<html>test</html>' }
let(:expected_filter) { 'test' }
subject { get :status, params: { filter: filter }, as: :json }
it 'passes sanitized filter param to bitbucket client' do
expect_next_instance_of(Bitbucket::Client) do |client|
expect(client).to receive(:repos).with(filter: expected_filter).and_return([@repo])
end
subject
end
end
end end
describe "POST create" do describe "POST create" 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