From 103114e3d73819f76bed9d8ad1bbdb8964875579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 15 Dec 2016 17:31:14 +0100 Subject: [PATCH] Rename Gogs to Gitea, DRY the controller and improve views MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/assets/images/gogs-logo.svg | 1 - app/controllers/application_controller.rb | 6 +- app/controllers/import/gitea_controller.rb | 41 ++++ app/controllers/import/github_controller.rb | 91 ++++--- app/controllers/import/gogs_controller.rb | 76 ------ app/helpers/import_helper.rb | 8 +- app/services/projects/import_service.rb | 29 ++- app/views/import/gitea/new.html.haml | 23 ++ .../import/{gogs => gitea}/status.html.haml | 14 +- app/views/import/gogs/new.html.haml | 17 -- app/views/projects/new.html.haml | 10 +- app/views/shared/icons/_go_logo.svg.erb | 1 + .../unreleased/22348-gitea-importer.yml | 4 + changelogs/unreleased/22348-gogs-importer.yml | 4 - config/initializers/1_settings.rb | 2 +- config/routes/import.rb | 2 +- lib/gitlab/current_settings.rb | 2 +- lib/gitlab/gogs_import/importer.rb | 54 ----- lib/gitlab/gogs_import/milestone_formatter.rb | 9 - lib/gitlab/import_sources.rb | 4 +- .../import/gitea_controller_spec.rb | 43 ++++ .../import/github_controller_spec.rb | 218 +---------------- spec/routing/import_routing_spec.rb | 166 +++++++++++++ ...hubish_import_controller_shared_context.rb | 10 + ...ubish_import_controller_shared_examples.rb | 228 ++++++++++++++++++ spec/support/import_spec_helper.rb | 4 + 26 files changed, 633 insertions(+), 434 deletions(-) delete mode 100644 app/assets/images/gogs-logo.svg create mode 100644 app/controllers/import/gitea_controller.rb delete mode 100644 app/controllers/import/gogs_controller.rb create mode 100644 app/views/import/gitea/new.html.haml rename app/views/import/{gogs => gitea}/status.html.haml (86%) delete mode 100644 app/views/import/gogs/new.html.haml create mode 100644 app/views/shared/icons/_go_logo.svg.erb create mode 100644 changelogs/unreleased/22348-gitea-importer.yml delete mode 100644 changelogs/unreleased/22348-gogs-importer.yml delete mode 100644 lib/gitlab/gogs_import/importer.rb delete mode 100644 lib/gitlab/gogs_import/milestone_formatter.rb create mode 100644 spec/controllers/import/gitea_controller_spec.rb create mode 100644 spec/routing/import_routing_spec.rb create mode 100644 spec/support/githubish_import_controller_shared_context.rb create mode 100644 spec/support/githubish_import_controller_shared_examples.rb diff --git a/app/assets/images/gogs-logo.svg b/app/assets/images/gogs-logo.svg deleted file mode 100644 index 60a18263033..00000000000 --- a/app/assets/images/gogs-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3ac4975f815..bb47e2a8bf7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -25,7 +25,7 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception helper_method :can?, :current_application_settings - helper_method :import_sources_enabled?, :github_import_enabled?, :gogs_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled? + helper_method :import_sources_enabled?, :github_import_enabled?, :gitea_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled? rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) @@ -245,8 +245,8 @@ class ApplicationController < ActionController::Base current_application_settings.import_sources.include?('github') end - def gogs_import_enabled? - current_application_settings.import_sources.include?('gogs') + def gitea_import_enabled? + current_application_settings.import_sources.include?('gitea') end def github_import_configured? diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb new file mode 100644 index 00000000000..c82a20be04c --- /dev/null +++ b/app/controllers/import/gitea_controller.rb @@ -0,0 +1,41 @@ +class Import::GiteaController < Import::GithubController + def new + if session[:access_token].present? && session[:host_url].present? + redirect_to status_import_url + end + end + + def personal_access_token + session[:host_url] = params[:gitea_host_url] + super + end + + def status + @gitea_root_url = session[:host_url] + super + end + + private + + # Overriden methods + def provider + :gitea + end + + # Gitea is not yet an OAuth provider + # See https://github.com/go-gitea/gitea/issues/27 + def logged_in_with_provider? + false + end + + def provider_auth + if session[:access_token].blank? || session[:host_url].blank? + redirect_to new_import_gitea_url, + alert: 'You need to specify both an Access Token and a Host URL.' + end + end + + def client_options + { host: session[:host_url], api_version: 'v1' } + end +end diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index ee7d498c59c..343ca51e510 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -1,39 +1,37 @@ class Import::GithubController < Import::BaseController - before_action :verify_github_import_enabled - before_action :github_auth, only: [:status, :jobs, :create] + before_action :verify_import_enabled + before_action :provider_auth, only: [:status, :jobs, :create] - rescue_from Octokit::Unauthorized, with: :github_unauthorized - - helper_method :logged_in_with_github? + rescue_from Octokit::Unauthorized, with: :provider_unauthorized def new - if logged_in_with_github? - go_to_github_for_permissions - elsif session[:github_access_token] - redirect_to status_import_github_url + if logged_in_with_provider? + go_to_provider_for_permissions + elsif session[:access_token] + redirect_to status_import_url end end def callback - session[:github_access_token] = client.get_token(params[:code]) - redirect_to status_import_github_url + session[:access_token] = client.get_token(params[:code]) + redirect_to status_import_url end def personal_access_token - session[:github_access_token] = params[:personal_access_token] - redirect_to status_import_github_url + session[:access_token] = params[:personal_access_token] + redirect_to status_import_url end def status @repos = client.repos - @already_added_projects = current_user.created_projects.where(import_type: "github") + @already_added_projects = current_user.created_projects.where(import_type: provider) already_added_projects_names = @already_added_projects.pluck(:import_source) - @repos.reject!{ |repo| already_added_projects_names.include? repo.full_name } + @repos.reject! { |repo| already_added_projects_names.include? repo.full_name } end def jobs - jobs = current_user.created_projects.where(import_type: "github").to_json(only: [:id, :import_status]) + jobs = current_user.created_projects.where(import_type: provider).to_json(only: [:id, :import_status]) render json: jobs end @@ -44,8 +42,8 @@ class Import::GithubController < Import::BaseController namespace_path = params[:target_namespace].presence || current_user.namespace_path @target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path) - if current_user.can?(:create_projects, @target_namespace) - @project = Gitlab::GithubImport::ProjectCreator.new(repo, @project_name, @target_namespace, current_user, access_params).execute + if can?(current_user, :create_projects, @target_namespace) + @project = Gitlab::GithubImport::ProjectCreator.new(repo, @project_name, @target_namespace, current_user, access_params, type: provider).execute else render 'unauthorized' end @@ -54,34 +52,59 @@ class Import::GithubController < Import::BaseController private def client - @client ||= Gitlab::GithubImport::Client.new(session[:github_access_token]) + @client ||= Gitlab::GithubImport::Client.new(session[:access_token], client_options) end - def verify_github_import_enabled - render_404 unless github_import_enabled? + def verify_import_enabled + render_404 unless import_enabled? end - def github_auth - if session[:github_access_token].blank? - go_to_github_for_permissions - end + def go_to_provider_for_permissions + redirect_to client.authorize_url(callback_import_url) end - def go_to_github_for_permissions - redirect_to client.authorize_url(callback_import_github_url) + def import_enabled? + __send__("#{provider}_import_enabled?") end - def github_unauthorized - session[:github_access_token] = nil - redirect_to new_import_github_url, - alert: 'Access denied to your GitHub account.' + def new_import_url + public_send("new_import_#{provider}_url") end - def logged_in_with_github? - current_user.identities.exists?(provider: 'github') + def status_import_url + public_send("status_import_#{provider}_url") + end + + def callback_import_url + public_send("callback_import_#{provider}_url") + end + + def provider_unauthorized + session[:access_token] = nil + redirect_to new_import_url, + alert: "Access denied to your #{Gitlab::ImportSources.options.key(provider.to_s)} account." end def access_params - { github_access_token: session[:github_access_token] } + { github_access_token: session[:access_token] } + end + + # The following methods are overriden in subclasses + def provider + :github + end + + def logged_in_with_provider? + current_user.identities.exists?(provider: provider) + end + + def provider_auth + if session[:access_token].blank? + go_to_provider_for_permissions + end + end + + def client_options + {} end end diff --git a/app/controllers/import/gogs_controller.rb b/app/controllers/import/gogs_controller.rb deleted file mode 100644 index 4caf7d2605a..00000000000 --- a/app/controllers/import/gogs_controller.rb +++ /dev/null @@ -1,76 +0,0 @@ -class Import::GogsController < Import::BaseController - before_action :verify_gogs_import_enabled - before_action :gogs_auth, only: [:status, :jobs, :create] - - rescue_from Octokit::Unauthorized, with: :gogs_unauthorized - - helper_method :logged_in_with_gogs? - - def new - if session[:gogs_access_token] - redirect_to status_import_gogs_url - end - end - - def personal_access_token - session[:gogs_access_token] = params[:personal_access_token] - session[:gogs_host_url] = params[:gogs_host_url] - redirect_to status_import_gogs_url - end - - def status - @repos = client.repos - @already_added_projects = current_user.created_projects.where(import_type: "gogs") - already_added_projects_names = @already_added_projects.pluck(:import_source) - - @gogs_root_url = session[:gogs_host_url] - - @repos.reject!{ |repo| already_added_projects_names.include? repo.full_name } - end - - def jobs - jobs = current_user.created_projects.where(import_type: "gogs").to_json(only: [:id, :import_status]) - render json: jobs - end - - def create - @repo_id = params[:repo_id].to_i - repo = client.repo(@repo_id) - @project_name = params[:new_name].presence || repo.name - namespace_path = params[:target_namespace].presence || current_user.namespace_path - @target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path) - - if current_user.can?(:create_projects, @target_namespace) - @project = Gitlab::GithubImport::ProjectCreator.new(repo, @project_name, @target_namespace, current_user, access_params, type: 'gogs').execute - else - render 'unauthorized' - end - end - - private - - def client - @client ||= Gitlab::GithubImport::Client.new(session[:gogs_access_token], host: session[:gogs_host_url], api_version: 'v1') - end - - def verify_gogs_import_enabled - render_404 unless gogs_import_enabled? - end - - def gogs_auth - if session[:gogs_access_token].blank? || session[:gogs_host_url].blank? - redirect_to new_import_gogs_url, - alert: 'You need to specify both an Access Token and a Host URL.' - end - end - - def gogs_unauthorized - session[:gogs_access_token] = nil - redirect_to new_import_gogs_url, - alert: 'Access denied to your Gogs account.' - end - - def access_params - { github_access_token: session[:gogs_access_token] } - end -end diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb index 29df2703d52..fb79e2a4eef 100644 --- a/app/helpers/import_helper.rb +++ b/app/helpers/import_helper.rb @@ -8,8 +8,8 @@ module ImportHelper link_to path_with_namespace, github_project_url(path_with_namespace), target: '_blank' end - def gogs_project_link(path_with_namespace) - link_to path_with_namespace, gogs_project_url(path_with_namespace), target: '_blank' + def gitea_project_link(root_url, path_with_namespace) + link_to path_with_namespace, gitea_project_url(root_url, path_with_namespace), target: '_blank' end private @@ -25,7 +25,7 @@ module ImportHelper @github_url = provider.fetch('url', 'https://github.com') if provider end - def gogs_project_url(path_with_namespace) - "#{@gogs_root_url}/#{path_with_namespace}" + def gitea_project_url(root_url, path_with_namespace) + "#{root_url}/#{path_with_namespace}" end end diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index 8cac0b01881..287c0a4257f 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -5,13 +5,13 @@ module Projects class Error < StandardError; end ALLOWED_TYPES = [ - 'gogs', - 'bitbucket', - 'fogbugz', - 'gitlab', 'github', + 'bitbucket', + 'gitlab', 'google_code', - 'gitlab_project' + 'fogbugz', + 'gitlab_project', + 'gitea' ] def execute @@ -71,8 +71,23 @@ module Projects def importer return Gitlab::ImportExport::Importer.new(project) if @project.gitlab_project_import? - class_name = "Gitlab::#{project.import_type.camelize}Import::Importer" - class_name.constantize.new(project) + class_name = + case project.import_type + when 'github', 'gitea' + Gitlab::GithubImport::Importer + when 'bitbucket' + Gitlab::BitbucketImport::Importer + when 'gitlab' + Gitlab::GitlabImport::Importer + when 'google_code' + Gitlab::GoogleCodeImport::Importer + when 'fogbugz' + Gitlab::FogbugzImport::Importer + else + raise 'Unknown importer type!' + end + + class_name.new(project) end def unknown_url? diff --git a/app/views/import/gitea/new.html.haml b/app/views/import/gitea/new.html.haml new file mode 100644 index 00000000000..02a116f996b --- /dev/null +++ b/app/views/import/gitea/new.html.haml @@ -0,0 +1,23 @@ +- page_title "Gitea Import" +- header_title "Projects", root_path + +%h3.page-title + = custom_icon('go_logo') + Import Projects from Gitea + +%p + To get started, please enter your Gitea Host URL and a + = succeed '.' do + = link_to 'Personal Access Token', 'https://github.com/gogits/go-gogs-client/wiki#access-token' + += form_tag personal_access_token_import_gitea_path, class: 'form-horizontal' do + .form-group + = label_tag :gitea_host_url, 'Gitea Host URL', class: 'control-label' + .col-sm-4 + = text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control' + .form-group + = label_tag :personal_access_token, 'Personal Access Token', class: 'control-label' + .col-sm-4 + = text_field_tag :personal_access_token, nil, class: 'form-control' + .form-actions + = submit_tag 'List Your Gitea Repositories', class: 'btn btn-create' diff --git a/app/views/import/gogs/status.html.haml b/app/views/import/gitea/status.html.haml similarity index 86% rename from app/views/import/gogs/status.html.haml rename to app/views/import/gitea/status.html.haml index 86ccc79efc8..2b25892c0da 100644 --- a/app/views/import/gogs/status.html.haml +++ b/app/views/import/gitea/status.html.haml @@ -1,8 +1,8 @@ -- page_title "Gogs import" +- page_title "Gitea import" - header_title "Projects", root_path %h3.page-title - %i.fa.fa-github - Import projects from Gogs + = custom_icon('go_logo') + Import projects from Gitea %p.light Select projects you want to import. @@ -19,14 +19,14 @@ %colgroup.import-jobs-status-col %thead %tr - %th From Gogs + %th From Gitea %th To GitLab %th Status %tbody - @already_added_projects.each do |project| %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"} %td - = gogs_project_link(project.import_source) + = gitea_project_link(@gitea_root_url, project.import_source) %td = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status @@ -43,7 +43,7 @@ - @repos.each do |repo| %tr{id: "repo_#{repo.id}"} %td - = gogs_project_link(repo.full_name) + = gitea_project_link(@gitea_root_url, repo.full_name) %td.import-target %fieldset.row .input-group @@ -61,4 +61,4 @@ Import = icon("spinner spin", class: "loading-icon") -.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gogs_path}", import_path: "#{import_gogs_path}" } } +.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitea_path}", import_path: "#{import_gitea_path}" } } diff --git a/app/views/import/gogs/new.html.haml b/app/views/import/gogs/new.html.haml deleted file mode 100644 index e1ae1be283c..00000000000 --- a/app/views/import/gogs/new.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -- page_title "Gogs Import" -- header_title "Projects", root_path - -%h3.page-title - = image_tag(image_path('gogs-logo.svg'), alt: 'Gogs', size: "16x16") - Gogs - -%p - To import a Gogs project, you can use a - = succeed '.' do - = link_to 'Personal Access Token', 'https://github.com/gogits/go-gogs-client/wiki#access-token' - -= form_tag personal_access_token_import_gogs_path, method: :post, class: 'form-inline' do - .form-group - = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40 - = text_field_tag :gogs_host_url, '', class: 'form-control', placeholder: "Gogs Host URL", size: 128 - = submit_tag 'List Your Gogs Repositories', class: 'btn btn-success' diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 5edb9b69ed2..866b278ce57 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -48,11 +48,6 @@ - if github_import_enabled? = link_to new_import_github_path, class: 'btn import_github' do = icon('github', text: 'GitHub') - %div - - if gogs_import_enabled? - = link_to new_import_gogs_url, class: 'btn import_gogs' do - = image_tag(image_path('gogs-logo.svg'), alt: 'Gogs', size: "14x14") - Gogs %div - if bitbucket_import_enabled? = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}", "data-no-turbolink" => "true" do @@ -73,6 +68,11 @@ - if fogbugz_import_enabled? = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do = icon('bug', text: 'Fogbugz') + %div + - if gitea_import_enabled? + = link_to new_import_gitea_url, class: 'btn import_gitea' do + = custom_icon('go_logo') + Gitea %div - if git_import_enabled? = link_to "#", class: 'btn js-toggle-button import_git' do diff --git a/app/views/shared/icons/_go_logo.svg.erb b/app/views/shared/icons/_go_logo.svg.erb new file mode 100644 index 00000000000..5052651c110 --- /dev/null +++ b/app/views/shared/icons/_go_logo.svg.erb @@ -0,0 +1 @@ + diff --git a/changelogs/unreleased/22348-gitea-importer.yml b/changelogs/unreleased/22348-gitea-importer.yml new file mode 100644 index 00000000000..ce81a3cfefb --- /dev/null +++ b/changelogs/unreleased/22348-gitea-importer.yml @@ -0,0 +1,4 @@ +--- +title: New Gitea importer +merge_request: 6945 +author: diff --git a/changelogs/unreleased/22348-gogs-importer.yml b/changelogs/unreleased/22348-gogs-importer.yml deleted file mode 100644 index 9543d2a4d26..00000000000 --- a/changelogs/unreleased/22348-gogs-importer.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Gogs importer -merge_request: 6945 -author: Kim Carlbäcker diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index c0dbf62bfa2..ee97b4e42b9 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -213,7 +213,7 @@ Settings.gitlab.default_projects_features['builds'] = true if Settin Settings.gitlab.default_projects_features['container_registry'] = true if Settings.gitlab.default_projects_features['container_registry'].nil? Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE) Settings.gitlab['domain_whitelist'] ||= [] -Settings.gitlab['import_sources'] ||= %w[gogs github bitbucket gitlab google_code fogbugz git gitlab_project] +Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab google_code fogbugz git gitlab_project gitea] Settings.gitlab['trusted_proxies'] ||= [] Settings.gitlab['no_todos_messages'] ||= YAML.load_file(Rails.root.join('config', 'no_todos_messages.yml')) diff --git a/config/routes/import.rb b/config/routes/import.rb index a0427dade99..c378253bf15 100644 --- a/config/routes/import.rb +++ b/config/routes/import.rb @@ -6,7 +6,7 @@ namespace :import do get :jobs end - resource :gogs, only: [:create, :new], controller: :gogs do + resource :gitea, only: [:create, :new], controller: :gitea do post :personal_access_token get :status get :jobs diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index eb3d9f29451..9d142f1b82e 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -45,7 +45,7 @@ module Gitlab default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], domain_whitelist: Settings.gitlab['domain_whitelist'], - import_sources: %w[gogs github bitbucket gitlab google_code fogbugz git gitlab_project], + import_sources: %w[gitea github bitbucket gitlab google_code fogbugz git gitlab_project], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], max_artifacts_size: Settings.artifacts['max_size'], require_two_factor_authentication: false, diff --git a/lib/gitlab/gogs_import/importer.rb b/lib/gitlab/gogs_import/importer.rb deleted file mode 100644 index 604e31d35a3..00000000000 --- a/lib/gitlab/gogs_import/importer.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'uri' - -module Gitlab - module GogsImport - class Importer < Gitlab::GithubImport::Importer - include Gitlab::ShellAdapter - - attr_reader :client, :errors, :project, :repo, :repo_url - - def initialize(project) - @project = project - @repo = project.import_source - @repo_url = project.import_url - @errors = [] - @labels = {} - - if credentials - uri = URI.parse(project.import_url) - host = "#{uri.scheme}://#{uri.host}:#{uri.port}#{uri.path}".sub(/[\w-]+\/[\w-]+\.git\z/, '') - @client = GithubImport::Client.new(credentials[:user], host: host, api_version: 'v1') - else - raise Projects::ImportService::Error, "Unable to find project import data credentials for project ID: #{@project.id}" - end - end - - def execute - import_labels - import_milestones - import_pull_requests - import_issues - import_comments(:issues) - import_comments(:pull_requests) - import_wiki - # NOTE: this is commented out since Gogs doesn't have release-API yet - # import_releases - handle_errors - - true - end - - def import_milestones - fetch_resources(:milestones, repo, state: :all, per_page: 100) do |milestones| - milestones.each do |raw| - begin - GogsImport::MilestoneFormatter.new(project, raw).create! - rescue => e - errors << { type: :milestone, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } - end - end - end - end - end - end -end diff --git a/lib/gitlab/gogs_import/milestone_formatter.rb b/lib/gitlab/gogs_import/milestone_formatter.rb deleted file mode 100644 index 990e792929a..00000000000 --- a/lib/gitlab/gogs_import/milestone_formatter.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Gitlab - module GogsImport - class MilestoneFormatter < GithubImport::MilestoneFormatter - def self.iid_attr - :id - end - end - end -end diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb index 9564c4cc134..34587582bd1 100644 --- a/lib/gitlab/import_sources.rb +++ b/lib/gitlab/import_sources.rb @@ -14,14 +14,14 @@ module Gitlab def options { - 'Gogs' => 'gogs', 'GitHub' => 'github', 'Bitbucket' => 'bitbucket', 'GitLab.com' => 'gitlab', 'Google Code' => 'google_code', 'FogBugz' => 'fogbugz', 'Repo by URL' => 'git', - 'GitLab export' => 'gitlab_project' + 'GitLab export' => 'gitlab_project', + 'Gitea' => 'gitea' } end end diff --git a/spec/controllers/import/gitea_controller_spec.rb b/spec/controllers/import/gitea_controller_spec.rb new file mode 100644 index 00000000000..3064d1dd58a --- /dev/null +++ b/spec/controllers/import/gitea_controller_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe Import::GiteaController do + include ImportSpecHelper + + let(:provider) { :gitea } + let(:host_url) { 'https://try.gitea.io' } + + include_context 'a GitHub-ish import controller' + + def assign_host_url + session[:host_url] = host_url + end + + describe "GET new" do + it_behaves_like 'a GitHub-ish import controller: GET new' do + before do + assign_host_url + end + end + end + + describe "POST personal_access_token" do + it_behaves_like 'a GitHub-ish import controller: POST personal_access_token' + end + + describe "GET status" do + it_behaves_like 'a GitHub-ish import controller: GET status' do + before do + assign_host_url + end + let(:extra_assign_expectations) { { gitea_root_url: host_url } } + end + end + + describe 'POST create' do + it_behaves_like 'a GitHub-ish import controller: POST create' do + before do + assign_host_url + end + end + end +end diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index 4f96567192d..55820a7cc65 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -3,35 +3,19 @@ require 'spec_helper' describe Import::GithubController do include ImportSpecHelper - let(:user) { create(:user) } - let(:token) { "asdasd12345" } - let(:access_params) { { github_access_token: token } } + let(:provider) { :github } - def assign_session_token - session[:github_access_token] = token - end - - before do - sign_in(user) - allow(controller).to receive(:github_import_enabled?).and_return(true) - end + include_context 'a GitHub-ish import controller' describe "GET new" do + it_behaves_like 'a GitHub-ish import controller: GET new' + it "redirects to GitHub for an access token if logged in with GitHub" do - allow(controller).to receive(:logged_in_with_github?).and_return(true) - expect(controller).to receive(:go_to_github_for_permissions) + allow(controller).to receive(:logged_in_with_provider?).and_return(true) + expect(controller).to receive(:go_to_provider_for_permissions) get :new end - - it "redirects to status if we already have a token" do - assign_session_token - allow(controller).to receive(:logged_in_with_github?).and_return(false) - - get :new - - expect(controller).to redirect_to(status_import_github_url) - end end describe "GET callback" do @@ -45,202 +29,20 @@ describe Import::GithubController do get :callback - expect(session[:github_access_token]).to eq(token) + expect(session[:access_token]).to eq(token) expect(controller).to redirect_to(status_import_github_url) end end describe "POST personal_access_token" do - it "updates access token" do - token = "asdfasdf9876" - - allow_any_instance_of(Gitlab::GithubImport::Client). - to receive(:user).and_return(true) - - post :personal_access_token, personal_access_token: token - - expect(session[:github_access_token]).to eq(token) - expect(controller).to redirect_to(status_import_github_url) - end + it_behaves_like 'a GitHub-ish import controller: POST personal_access_token' end describe "GET status" do - before do - @repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim') - @org = OpenStruct.new(login: 'company') - @org_repo = OpenStruct.new(login: 'company', full_name: 'company/repo') - assign_session_token - end - - it "assigns variables" do - @project = create(:project, import_type: 'github', creator_id: user.id) - stub_client(repos: [@repo, @org_repo], orgs: [@org], org_repos: [@org_repo]) - - get :status - - expect(assigns(:already_added_projects)).to eq([@project]) - expect(assigns(:repos)).to eq([@repo, @org_repo]) - end - - it "does not show already added project" do - @project = create(:project, import_type: 'github', creator_id: user.id, import_source: 'asd/vim') - stub_client(repos: [@repo], orgs: []) - - get :status - - expect(assigns(:already_added_projects)).to eq([@project]) - expect(assigns(:repos)).to eq([]) - end - - it "handles an invalid access token" do - allow_any_instance_of(Gitlab::GithubImport::Client). - to receive(:repos).and_raise(Octokit::Unauthorized) - - get :status - - expect(session[:github_access_token]).to eq(nil) - expect(controller).to redirect_to(new_import_github_url) - expect(flash[:alert]).to eq('Access denied to your GitHub account.') - end + it_behaves_like 'a GitHub-ish import controller: GET status' end describe "POST create" do - let(:github_username) { user.username } - let(:github_user) { OpenStruct.new(login: github_username) } - let(:github_repo) do - OpenStruct.new( - name: 'vim', - full_name: "#{github_username}/vim", - owner: OpenStruct.new(login: github_username) - ) - end - - before do - stub_client(user: github_user, repo: github_repo) - assign_session_token - end - - context "when the repository owner is the GitHub user" do - context "when the GitHub user and GitLab user's usernames match" do - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - - context "when the GitHub user and GitLab user's usernames don't match" do - let(:github_username) { "someone_else" } - - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context "when the repository owner is not the GitHub user" do - let(:other_username) { "someone_else" } - - before do - github_repo.owner = OpenStruct.new(login: other_username) - assign_session_token - end - - context "when a namespace with the GitHub user's username already exists" do - let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } - - context "when the namespace is owned by the GitLab user" do - it "takes the existing namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, existing_namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - - context "when the namespace is not owned by the GitLab user" do - before do - existing_namespace.owner = create(:user) - existing_namespace.save - end - - it "creates a project using user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context "when a namespace with the GitHub user's username doesn't exist" do - context "when current user can create namespaces" do - it "creates the namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).and_return(double(execute: true)) - - expect { post :create, target_namespace: github_repo.name, format: :js }.to change(Namespace, :count).by(1) - end - - it "takes the new namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, an_instance_of(Group), user, access_params). - and_return(double(execute: true)) - - post :create, target_namespace: github_repo.name, format: :js - end - end - - context "when current user can't create namespaces" do - before do - user.update_attribute(:can_create_group, false) - end - - it "doesn't create the namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).and_return(double(execute: true)) - - expect { post :create, format: :js }.not_to change(Namespace, :count) - end - - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context 'user has chosen a namespace and name for the project' do - let(:test_namespace) { create(:namespace, name: 'test_namespace', owner: user) } - let(:test_name) { 'test_name' } - - it 'takes the selected namespace and name' do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, test_name, test_namespace, user, access_params). - and_return(double(execute: true)) - - post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js } - end - - it 'takes the selected name and default namespace' do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, test_name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, { new_name: test_name, format: :js } - end - end - end + it_behaves_like 'a GitHub-ish import controller: POST create' end end diff --git a/spec/routing/import_routing_spec.rb b/spec/routing/import_routing_spec.rb new file mode 100644 index 00000000000..f1234ff470b --- /dev/null +++ b/spec/routing/import_routing_spec.rb @@ -0,0 +1,166 @@ +require 'spec_helper' + +# Shared examples for a resource inside a Project +# +# By default it tests all the default REST actions: index, create, new, edit, +# show, update, and destroy. You can remove actions by customizing the +# `actions` variable. +# +# It also expects a `controller` variable to be available which defines both +# the path to the resource as well as the controller name. +# +# Examples +# +# # Default behavior +# it_behaves_like 'RESTful project resources' do +# let(:controller) { 'issues' } +# end +# +# # Customizing actions +# it_behaves_like 'RESTful project resources' do +# let(:actions) { [:index] } +# let(:controller) { 'issues' } +# end +shared_examples 'importer routing' do + let(:except_actions) { [] } + + it 'to #create' do + expect(post("/import/#{provider}")).to route_to("import/#{provider}#create") unless except_actions.include?(:create) + end + + it 'to #new' do + expect(get("/import/#{provider}/new")).to route_to("import/#{provider}#new") unless except_actions.include?(:new) + end + + it 'to #status' do + expect(get("/import/#{provider}/status")).to route_to("import/#{provider}#status") unless except_actions.include?(:status) + end + + it 'to #callback' do + expect(get("/import/#{provider}/callback")).to route_to("import/#{provider}#callback") unless except_actions.include?(:callback) + end + + it 'to #jobs' do + expect(get("/import/#{provider}/jobs")).to route_to("import/#{provider}#jobs") unless except_actions.include?(:jobs) + end +end + +# personal_access_token_import_github POST /import/github/personal_access_token(.:format) import/github#personal_access_token +# status_import_github GET /import/github/status(.:format) import/github#status +# callback_import_github GET /import/github/callback(.:format) import/github#callback +# jobs_import_github GET /import/github/jobs(.:format) import/github#jobs +# import_github POST /import/github(.:format) import/github#create +# new_import_github GET /import/github/new(.:format) import/github#new +describe Import::GithubController, 'routing' do + it_behaves_like 'importer routing' do + let(:provider) { 'github' } + end + + it 'to #personal_access_token' do + expect(post('/import/github/personal_access_token')).to route_to('import/github#personal_access_token') + end +end + +# personal_access_token_import_gitea POST /import/gitea/personal_access_token(.:format) import/gitea#personal_access_token +# status_import_gitea GET /import/gitea/status(.:format) import/gitea#status +# jobs_import_gitea GET /import/gitea/jobs(.:format) import/gitea#jobs +# import_gitea POST /import/gitea(.:format) import/gitea#create +# new_import_gitea GET /import/gitea/new(.:format) import/gitea#new +describe Import::GiteaController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:callback] } + let(:provider) { 'gitea' } + end + + it 'to #personal_access_token' do + expect(post('/import/gitea/personal_access_token')).to route_to('import/gitea#personal_access_token') + end + +end + +# status_import_gitlab GET /import/gitlab/status(.:format) import/gitlab#status +# callback_import_gitlab GET /import/gitlab/callback(.:format) import/gitlab#callback +# jobs_import_gitlab GET /import/gitlab/jobs(.:format) import/gitlab#jobs +# import_gitlab POST /import/gitlab(.:format) import/gitlab#create +describe Import::GitlabController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:new] } + let(:provider) { 'gitlab' } + end +end + +# status_import_bitbucket GET /import/bitbucket/status(.:format) import/bitbucket#status +# callback_import_bitbucket GET /import/bitbucket/callback(.:format) import/bitbucket#callback +# jobs_import_bitbucket GET /import/bitbucket/jobs(.:format) import/bitbucket#jobs +# import_bitbucket POST /import/bitbucket(.:format) import/bitbucket#create +describe Import::BitbucketController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:new] } + let(:provider) { 'bitbucket' } + end +end + +# status_import_google_code GET /import/google_code/status(.:format) import/google_code#status +# callback_import_google_code POST /import/google_code/callback(.:format) import/google_code#callback +# jobs_import_google_code GET /import/google_code/jobs(.:format) import/google_code#jobs +# new_user_map_import_google_code GET /import/google_code/user_map(.:format) import/google_code#new_user_map +# create_user_map_import_google_code POST /import/google_code/user_map(.:format) import/google_code#create_user_map +# import_google_code POST /import/google_code(.:format) import/google_code#create +# new_import_google_code GET /import/google_code/new(.:format) import/google_code#new +describe Import::GoogleCodeController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:callback] } + let(:provider) { 'google_code' } + end + + it 'to #callback' do + expect(post("/import/google_code/callback")).to route_to("import/google_code#callback") + end + + it 'to #new_user_map' do + expect(get('/import/google_code/user_map')).to route_to('import/google_code#new_user_map') + end + + it 'to #create_user_map' do + expect(post('/import/google_code/user_map')).to route_to('import/google_code#create_user_map') + end +end + +# status_import_fogbugz GET /import/fogbugz/status(.:format) import/fogbugz#status +# callback_import_fogbugz POST /import/fogbugz/callback(.:format) import/fogbugz#callback +# jobs_import_fogbugz GET /import/fogbugz/jobs(.:format) import/fogbugz#jobs +# new_user_map_import_fogbugz GET /import/fogbugz/user_map(.:format) import/fogbugz#new_user_map +# create_user_map_import_fogbugz POST /import/fogbugz/user_map(.:format) import/fogbugz#create_user_map +# import_fogbugz POST /import/fogbugz(.:format) import/fogbugz#create +# new_import_fogbugz GET /import/fogbugz/new(.:format) import/fogbugz#new +describe Import::FogbugzController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:callback] } + let(:provider) { 'fogbugz' } + end + + it 'to #callback' do + expect(post("/import/fogbugz/callback")).to route_to("import/fogbugz#callback") + end + + it 'to #new_user_map' do + expect(get('/import/fogbugz/user_map')).to route_to('import/fogbugz#new_user_map') + end + + it 'to #create_user_map' do + expect(post('/import/fogbugz/user_map')).to route_to('import/fogbugz#create_user_map') + end +end + +# import_gitlab_project POST /import/gitlab_project(.:format) import/gitlab_projects#create +# POST /import/gitlab_project(.:format) import/gitlab_projects#create +# new_import_gitlab_project GET /import/gitlab_project/new(.:format) import/gitlab_projects#new +describe Import::GitlabProjectsController, 'routing' do + it 'to #create' do + expect(post('/import/gitlab_project')).to route_to('import/gitlab_projects#create') + end + + it 'to #new' do + expect(get('/import/gitlab_project/new')).to route_to('import/gitlab_projects#new') + end +end diff --git a/spec/support/githubish_import_controller_shared_context.rb b/spec/support/githubish_import_controller_shared_context.rb new file mode 100644 index 00000000000..e71994edec6 --- /dev/null +++ b/spec/support/githubish_import_controller_shared_context.rb @@ -0,0 +1,10 @@ +shared_context 'a GitHub-ish import controller' do + let(:user) { create(:user) } + let(:token) { "asdasd12345" } + let(:access_params) { { github_access_token: token } } + + before do + sign_in(user) + allow(controller).to receive(:"#{provider}_import_enabled?").and_return(true) + end +end diff --git a/spec/support/githubish_import_controller_shared_examples.rb b/spec/support/githubish_import_controller_shared_examples.rb new file mode 100644 index 00000000000..aa2d8aed0bd --- /dev/null +++ b/spec/support/githubish_import_controller_shared_examples.rb @@ -0,0 +1,228 @@ +# Specifications for behavior common to all objects with an email attribute. +# Takes a list of email-format attributes and requires: +# - subject { "the object with a attribute= setter" } +# Note: You have access to `email_value` which is the email address value +# being currently tested). + +shared_examples 'a GitHub-ish import controller: POST personal_access_token' do + let(:status_import_url) { public_send("status_import_#{provider}_url") } + + it "updates access token" do + token = 'asdfasdf9876' + + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:user).and_return(true) + + post :personal_access_token, personal_access_token: token + + expect(session[:access_token]).to eq(token) + expect(controller).to redirect_to(status_import_url) + end +end + +shared_examples 'a GitHub-ish import controller: GET new' do + let(:status_import_url) { public_send("status_import_#{provider}_url") } + + it "redirects to status if we already have a token" do + assign_session_token + allow(controller).to receive(:logged_in_with_provider?).and_return(false) + + get :new + + expect(controller).to redirect_to(status_import_url) + end + + it "renders the :new page if no token is present in session" do + get :new + + expect(response).to render_template(:new) + end +end + +shared_examples 'a GitHub-ish import controller: GET status' do + let(:new_import_url) { public_send("new_import_#{provider}_url") } + let(:user) { create(:user) } + let(:repo) { OpenStruct.new(login: 'vim', full_name: 'asd/vim') } + let(:org) { OpenStruct.new(login: 'company') } + let(:org_repo) { OpenStruct.new(login: 'company', full_name: 'company/repo') } + let(:extra_assign_expectations) { {} } + + before do + assign_session_token + end + + it "assigns variables" do + project = create(:empty_project, import_type: provider, creator_id: user.id) + stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo]) + + get :status + + expect(assigns(:already_added_projects)).to eq([project]) + expect(assigns(:repos)).to eq([repo, org_repo]) + extra_assign_expectations.each do |key, value| + expect(assigns(key)).to eq(value) + end + end + + it "does not show already added project" do + project = create(:empty_project, import_type: provider, creator_id: user.id, import_source: 'asd/vim') + stub_client(repos: [repo], orgs: []) + + get :status + + expect(assigns(:already_added_projects)).to eq([project]) + expect(assigns(:repos)).to eq([]) + end + + it "handles an invalid access token" do + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:repos).and_raise(Octokit::Unauthorized) + + get :status + + expect(session[:access_token]).to eq(nil) + expect(controller).to redirect_to(new_import_url) + expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.options.key(provider.to_s)} account.") + end +end + +shared_examples 'a GitHub-ish import controller: POST create' do + let(:user) { create(:user) } + let(:provider_username) { user.username } + let(:provider_user) { OpenStruct.new(login: provider_username) } + let(:provider_repo) do + OpenStruct.new( + name: 'vim', + full_name: "#{provider_username}/vim", + owner: OpenStruct.new(login: provider_username) + ) + end + + before do + stub_client(user: provider_user, repo: provider_repo) + assign_session_token + end + + context "when the repository owner is the Gitea user" do + context "when the Gitea user and GitLab user's usernames match" do + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + + context "when the Gitea user and GitLab user's usernames don't match" do + let(:provider_username) { "someone_else" } + + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context "when the repository owner is not the Gitea user" do + let(:other_username) { "someone_else" } + + before do + provider_repo.owner = OpenStruct.new(login: other_username) + assign_session_token + end + + context "when a namespace with the Gitea user's username already exists" do + let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } + + context "when the namespace is owned by the GitLab user" do + it "takes the existing namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + + context "when the namespace is not owned by the GitLab user" do + before do + existing_namespace.owner = create(:user) + existing_namespace.save + end + + it "creates a project using user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context "when a namespace with the Gitea user's username doesn't exist" do + context "when current user can create namespaces" do + it "creates the namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).and_return(double(execute: true)) + + expect { post :create, target_namespace: provider_repo.name, format: :js }.to change(Namespace, :count).by(1) + end + + it "takes the new namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, target_namespace: provider_repo.name, format: :js + end + end + + context "when current user can't create namespaces" do + before do + user.update_attribute(:can_create_group, false) + end + + it "doesn't create the namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).and_return(double(execute: true)) + + expect { post :create, format: :js }.not_to change(Namespace, :count) + end + + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context 'user has chosen a namespace and name for the project' do + let(:test_namespace) { create(:namespace, name: 'test_namespace', owner: user) } + let(:test_name) { 'test_name' } + + it 'takes the selected namespace and name' do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js } + end + + it 'takes the selected name and default namespace' do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, { new_name: test_name, format: :js } + end + end + end +end diff --git a/spec/support/import_spec_helper.rb b/spec/support/import_spec_helper.rb index 6710962f082..cd25e05ac4b 100644 --- a/spec/support/import_spec_helper.rb +++ b/spec/support/import_spec_helper.rb @@ -30,4 +30,8 @@ module ImportSpecHelper ) allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider]) end + + def assign_session_token + session[:access_token] = 'asdasd12345' + end end