Commit 99ddd1dc authored by Rémy Coutable's avatar Rémy Coutable

Modify GithubImport to support Gitea

The reason is that Gitea plan to be GitHub-compatible so it makes sense
to just modify GitHubImport a bit for now, and hopefully we can change
it to GitHubishImport once Gitea is 100%-compatible.
Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 103114e3
...@@ -11,7 +11,7 @@ class Import::GiteaController < Import::GithubController ...@@ -11,7 +11,7 @@ class Import::GiteaController < Import::GithubController
end end
def status def status
@gitea_root_url = session[:host_url] @gitea_host_url = session[:host_url]
super super
end end
......
...@@ -8,8 +8,8 @@ module ImportHelper ...@@ -8,8 +8,8 @@ module ImportHelper
link_to path_with_namespace, github_project_url(path_with_namespace), target: '_blank' link_to path_with_namespace, github_project_url(path_with_namespace), target: '_blank'
end end
def gitea_project_link(root_url, path_with_namespace) def gitea_project_link(path_with_namespace)
link_to path_with_namespace, gitea_project_url(root_url, path_with_namespace), target: '_blank' link_to path_with_namespace, gitea_project_url(path_with_namespace), target: '_blank'
end end
private private
...@@ -25,7 +25,7 @@ module ImportHelper ...@@ -25,7 +25,7 @@ module ImportHelper
@github_url = provider.fetch('url', 'https://github.com') if provider @github_url = provider.fetch('url', 'https://github.com') if provider
end end
def gitea_project_url(root_url, path_with_namespace) def gitea_project_url(path_with_namespace)
"#{root_url}/#{path_with_namespace}" "#{@gitea_host_url.sub(%r{/+\z}, '')}/#{path_with_namespace}"
end end
end end
- page_title "Gitea import" - page_title "Gitea Import"
- header_title "Projects", root_path - header_title "Projects", root_path
%h3.page-title %h3.page-title
= custom_icon('go_logo') = custom_icon('go_logo')
Import projects from Gitea Import Projects from Gitea
%p.light %p.light
Select projects you want to import. Select projects you want to import.
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
- @already_added_projects.each do |project| - @already_added_projects.each do |project|
%tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"} %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
%td %td
= gitea_project_link(@gitea_root_url, project.import_source) = gitea_project_link(project.import_source)
%td %td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
- @repos.each do |repo| - @repos.each do |repo|
%tr{id: "repo_#{repo.id}"} %tr{id: "repo_#{repo.id}"}
%td %td
= gitea_project_link(@gitea_root_url, repo.full_name) = gitea_project_link(repo.full_name)
%td.import-target %td.import-target
%fieldset.row %fieldset.row
.input-group .input-group
......
- page_title "GitHub import" - page_title "GitHub Import"
- header_title "Projects", root_path - header_title "Projects", root_path
%h3.page-title %h3.page-title
%i.fa.fa-github = icon 'github', text: 'Import Projects from GitHub'
Import projects from GitHub
%p.light %p.light
Select projects you want to import. Select projects you want to import.
......
--- ---
title: New Gitea importer title: New Gitea importer
merge_request: 6945 merge_request: 8116
author: author:
...@@ -15,6 +15,10 @@ module Gitlab ...@@ -15,6 +15,10 @@ module Gitlab
end end
end end
def url
raw_data.url || ''
end
private private
def gitlab_user_id(github_id) def gitlab_user_id(github_id)
......
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
def initialize(access_token, host: nil, api_version: 'v3') def initialize(access_token, host: nil, api_version: 'v3')
@access_token = access_token @access_token = access_token
@host = host @host = host.to_s.sub(%r{/+\z}, '')
@api_version = api_version @api_version = api_version
if access_token if access_token
...@@ -16,10 +16,6 @@ module Gitlab ...@@ -16,10 +16,6 @@ module Gitlab
end end
end end
def api_endpoint
host.present? && api_version.present? ? "#{host}/api/#{api_version}" : github_options[:site]
end
def api def api
@api ||= ::Octokit::Client.new( @api ||= ::Octokit::Client.new(
access_token: access_token, access_token: access_token,
...@@ -27,7 +23,7 @@ module Gitlab ...@@ -27,7 +23,7 @@ module Gitlab
# If there is no config, we're connecting to github.com and we # If there is no config, we're connecting to github.com and we
# should verify ssl. # should verify ssl.
connection_options: { connection_options: {
ssl: { verify: config ? config['verify_ssl'] : false } ssl: { verify: config ? config['verify_ssl'] : true }
} }
) )
end end
...@@ -70,6 +66,14 @@ module Gitlab ...@@ -70,6 +66,14 @@ module Gitlab
private private
def api_endpoint
if host.present? && api_version.present?
"#{host}/api/#{api_version}"
else
github_options[:site]
end
end
def config def config
Gitlab.config.omniauth.providers.find { |provider| provider.name == "github" } Gitlab.config.omniauth.providers.find { |provider| provider.name == "github" }
end end
......
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
class Importer class Importer
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
attr_reader :client, :errors, :project, :repo, :repo_url attr_reader :errors, :project, :repo, :repo_url
def initialize(project) def initialize(project)
@project = project @project = project
...@@ -11,12 +11,27 @@ module Gitlab ...@@ -11,12 +11,27 @@ module Gitlab
@repo_url = project.import_url @repo_url = project.import_url
@errors = [] @errors = []
@labels = {} @labels = {}
end
def client
return @client if defined?(@client)
unless credentials
raise Projects::ImportService::Error,
"Unable to find project import data credentials for project ID: #{@project.id}"
end
if credentials opts = {}
@client = Client.new(credentials[:user]) # Gitea plan to be GitHub compliant
else if project.import_type == 'gitea'
raise Projects::ImportService::Error, "Unable to find project import data credentials for project ID: #{@project.id}" uri = URI.parse(project.import_url)
host = "#{uri.scheme}://#{uri.host}:#{uri.port}#{uri.path}".sub(%r{/?[\w-]+/[\w-]+\.git\z}, '')
opts = {
host: host,
api_version: 'v1'
}
end end
@client = Client.new(credentials[:user], opts)
end end
def execute def execute
...@@ -35,7 +50,13 @@ module Gitlab ...@@ -35,7 +50,13 @@ module Gitlab
import_comments(:issues) import_comments(:issues)
import_comments(:pull_requests) import_comments(:pull_requests)
import_wiki import_wiki
import_releases
# Gitea doesn't have a Release API yet
# See https://github.com/go-gitea/gitea/issues/330
unless project.import_type == 'gitea'
import_releases
end
handle_errors handle_errors
true true
...@@ -44,7 +65,9 @@ module Gitlab ...@@ -44,7 +65,9 @@ module Gitlab
private private
def credentials def credentials
@credentials ||= project.import_data.credentials if project.import_data return @credentials if defined?(@credentials)
@credentials = project.import_data ? project.import_data.credentials : nil
end end
def handle_errors def handle_errors
...@@ -60,9 +83,10 @@ module Gitlab ...@@ -60,9 +83,10 @@ module Gitlab
fetch_resources(:labels, repo, per_page: 100) do |labels| fetch_resources(:labels, repo, per_page: 100) do |labels|
labels.each do |raw| labels.each do |raw|
begin begin
GithubImport::LabelFormatter.new(project, raw).create! gh_label = LabelFormatter.new(project, raw)
gh_label.create!
rescue => e rescue => e
errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(gh_label.url), errors: e.message }
end end
end end
end end
...@@ -74,9 +98,10 @@ module Gitlab ...@@ -74,9 +98,10 @@ module Gitlab
fetch_resources(:milestones, repo, state: :all, per_page: 100) do |milestones| fetch_resources(:milestones, repo, state: :all, per_page: 100) do |milestones|
milestones.each do |raw| milestones.each do |raw|
begin begin
GithubImport::MilestoneFormatter.new(project, raw).create! gh_milestone = MilestoneFormatter.new(project, raw)
gh_milestone.create!
rescue => e rescue => e
errors << { type: :milestone, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } errors << { type: :milestone, url: Gitlab::UrlSanitizer.sanitize(gh_milestone.url), errors: e.message }
end end
end end
end end
...@@ -85,7 +110,7 @@ module Gitlab ...@@ -85,7 +110,7 @@ module Gitlab
def import_issues def import_issues
fetch_resources(:issues, repo, state: :all, sort: :created, direction: :asc, per_page: 100) do |issues| fetch_resources(:issues, repo, state: :all, sort: :created, direction: :asc, per_page: 100) do |issues|
issues.each do |raw| issues.each do |raw|
gh_issue = GithubImport::IssueFormatter.new(project, raw) gh_issue = IssueFormatter.new(project, raw)
begin begin
issuable = issuable =
...@@ -97,7 +122,7 @@ module Gitlab ...@@ -97,7 +122,7 @@ module Gitlab
apply_labels(issuable, raw) apply_labels(issuable, raw)
rescue => e rescue => e
errors << { type: :issue, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } errors << { type: :issue, url: Gitlab::UrlSanitizer.sanitize(gh_issue.url), errors: e.message }
end end
end end
end end
...@@ -106,18 +131,23 @@ module Gitlab ...@@ -106,18 +131,23 @@ module Gitlab
def import_pull_requests def import_pull_requests
fetch_resources(:pull_requests, repo, state: :all, sort: :created, direction: :asc, per_page: 100) do |pull_requests| fetch_resources(:pull_requests, repo, state: :all, sort: :created, direction: :asc, per_page: 100) do |pull_requests|
pull_requests.each do |raw| pull_requests.each do |raw|
pull_request = GithubImport::PullRequestFormatter.new(project, raw) gh_pull_request = PullRequestFormatter.new(project, raw)
next unless pull_request.valid? next unless gh_pull_request.valid?
begin begin
restore_source_branch(pull_request) unless pull_request.source_branch_exists? restore_source_branch(gh_pull_request) unless gh_pull_request.source_branch_exists?
restore_target_branch(pull_request) unless pull_request.target_branch_exists? restore_target_branch(gh_pull_request) unless gh_pull_request.target_branch_exists?
merge_request = gh_pull_request.create!
pull_request.create! # Gitea doesn't return PR in the Issue API endpoint, so labels must be assigned at this stage
if project.import_type == 'gitea'
apply_labels(merge_request, raw)
end
rescue => e rescue => e
errors << { type: :pull_request, url: Gitlab::UrlSanitizer.sanitize(pull_request.url), errors: e.message } errors << { type: :pull_request, url: Gitlab::UrlSanitizer.sanitize(gh_pull_request.url), errors: e.message }
ensure ensure
clean_up_restored_branches(pull_request) clean_up_restored_branches(gh_pull_request)
end end
end end
end end
...@@ -179,7 +209,7 @@ module Gitlab ...@@ -179,7 +209,7 @@ module Gitlab
ActiveRecord::Base.no_touching do ActiveRecord::Base.no_touching do
comments.each do |raw| comments.each do |raw|
begin begin
comment = GithubImport::CommentFormatter.new(project, raw) comment = CommentFormatter.new(project, raw)
# GH does not return info about comment's parent, so we guess it by checking its URL! # GH does not return info about comment's parent, so we guess it by checking its URL!
*_, parent, iid = URI(raw.html_url).path.split('/') *_, parent, iid = URI(raw.html_url).path.split('/')
issuable_class = parent == 'issues' ? Issue : MergeRequest issuable_class = parent == 'issues' ? Issue : MergeRequest
...@@ -198,7 +228,7 @@ module Gitlab ...@@ -198,7 +228,7 @@ module Gitlab
last_note_attrs = nil last_note_attrs = nil
cut_off_index = comments.find_index do |raw| cut_off_index = comments.find_index do |raw|
comment = GithubImport::CommentFormatter.new(project, raw) comment = CommentFormatter.new(project, raw)
comment_attrs = comment.attributes comment_attrs = comment.attributes
last_note_attrs ||= last_note.slice(*comment_attrs.keys) last_note_attrs ||= last_note.slice(*comment_attrs.keys)
...@@ -214,7 +244,7 @@ module Gitlab ...@@ -214,7 +244,7 @@ module Gitlab
def import_wiki def import_wiki
unless project.wiki.repository_exists? unless project.wiki.repository_exists?
wiki = GithubImport::WikiFormatter.new(project) wiki = WikiFormatter.new(project)
gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url) gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url)
end end
rescue Gitlab::Shell::Error => e rescue Gitlab::Shell::Error => e
...@@ -230,10 +260,10 @@ module Gitlab ...@@ -230,10 +260,10 @@ module Gitlab
fetch_resources(:releases, repo, per_page: 100) do |releases| fetch_resources(:releases, repo, per_page: 100) do |releases|
releases.each do |raw| releases.each do |raw|
begin begin
gh_release = GithubImport::ReleaseFormatter.new(project, raw) gh_release = ReleaseFormatter.new(project, raw)
gh_release.create! if gh_release.valid? gh_release.create! if gh_release.valid?
rescue => e rescue => e
errors << { type: :release, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } errors << { type: :release, url: Gitlab::UrlSanitizer.sanitize(gh_release.url), errors: e.message }
end end
end end
end end
......
module Gitlab
module GithubImport
class IssuableFormatter < BaseFormatter
def project_association
raise NotImplementedError
end
def number
raw_data.number
end
def find_condition
{ iid: number }
end
private
def state
raw_data.state == 'closed' ? 'closed' : 'opened'
end
def assigned?
raw_data.assignee.present?
end
def assignee_id
if assigned?
gitlab_user_id(raw_data.assignee.id)
end
end
def author
raw_data.user.login
end
def author_id
gitlab_author_id || project.creator_id
end
def body
raw_data.body || ""
end
def description
if gitlab_author_id
body
else
formatter.author_line(author) + body
end
end
def milestone
if raw_data.milestone.present?
milestone = MilestoneFormatter.new(project, raw_data.milestone)
project.milestones.find_by(milestone.find_condition)
end
end
end
end
end
module Gitlab module Gitlab
module GithubImport module GithubImport
class IssueFormatter < BaseFormatter class IssueFormatter < IssuableFormatter
def attributes def attributes
{ {
iid: number, iid: number,
...@@ -24,59 +24,9 @@ module Gitlab ...@@ -24,59 +24,9 @@ module Gitlab
:issues :issues
end end
def find_condition
{ iid: number }
end
def number
raw_data.number
end
def pull_request? def pull_request?
raw_data.pull_request.present? raw_data.pull_request.present?
end end
private
def assigned?
raw_data.assignee.present?
end
def assignee_id
if assigned?
gitlab_user_id(raw_data.assignee.id)
end
end
def author
raw_data.user.login
end
def author_id
gitlab_author_id || project.creator_id
end
def body
raw_data.body || ""
end
def description
if gitlab_author_id
body
else
formatter.author_line(author) + body
end
end
def milestone
if raw_data.milestone.present?
project.milestones.find_by(iid: raw_data.milestone.public_send("Gitlab::#{project.import_type.camelize}Import::MilestoneFormatter".constantize.iid_attr))
end
end
def state
raw_data.state == 'closed' ? 'closed' : 'opened'
end
end end
end end
end end
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
class MilestoneFormatter < BaseFormatter class MilestoneFormatter < BaseFormatter
def attributes def attributes
{ {
iid: raw_data.public_send("Gitlab::#{project.import_type.camelize}Import::MilestoneFormatter".constantize.iid_attr), iid: number,
project: project, project: project,
title: raw_data.title, title: raw_data.title,
description: raw_data.description, description: raw_data.description,
...@@ -19,11 +19,15 @@ module Gitlab ...@@ -19,11 +19,15 @@ module Gitlab
end end
def find_condition def find_condition
{ iid: raw_data.public_send("Gitlab::#{project.import_type.camelize}Import::MilestoneFormatter".constantize.iid_attr) } { iid: number }
end end
def self.iid_attr def number
:number if project.import_type == 'gitea'
raw_data.id
else
raw_data.number
end
end end
private private
......
module Gitlab module Gitlab
module GithubImport module GithubImport
class PullRequestFormatter < BaseFormatter class PullRequestFormatter < IssuableFormatter
delegate :exists?, :project, :ref, :repo, :sha, to: :source_branch, prefix: true delegate :exists?, :project, :ref, :repo, :sha, to: :source_branch, prefix: true
delegate :exists?, :project, :ref, :repo, :sha, to: :target_branch, prefix: true delegate :exists?, :project, :ref, :repo, :sha, to: :target_branch, prefix: true
...@@ -28,14 +28,6 @@ module Gitlab ...@@ -28,14 +28,6 @@ module Gitlab
:merge_requests :merge_requests
end end
def find_condition
{ iid: number }
end
def number
raw_data.number
end
def valid? def valid?
source_branch.valid? && target_branch.valid? source_branch.valid? && target_branch.valid?
end end
...@@ -60,57 +52,15 @@ module Gitlab ...@@ -60,57 +52,15 @@ module Gitlab
end end
end end
def url
raw_data.url
end
private private
def assigned? def state
raw_data.assignee.present? if raw_data.state == 'closed' && raw_data.merged_at.present?
end 'merged'
def assignee_id
if assigned?
gitlab_user_id(raw_data.assignee.id)
end
end
def author
raw_data.user.login
end
def author_id
gitlab_author_id || project.creator_id
end
def body
raw_data.body || ""
end
def description
if gitlab_author_id
body
else else
formatter.author_line(author) + body super
end end
end end
def milestone
if raw_data.milestone.present?
project.milestones.find_by(iid: raw_data.milestone.public_send("Gitlab::#{project.import_type.camelize}Import::MilestoneFormatter".constantize.iid_attr))
end
end
def state
@state ||= if raw_data.state == 'closed' && raw_data.merged_at.present?
'merged'
elsif raw_data.state == 'closed'
'closed'
else
'opened'
end
end
end end
end end
end end
...@@ -29,7 +29,7 @@ describe Import::GiteaController do ...@@ -29,7 +29,7 @@ describe Import::GiteaController do
before do before do
assign_host_url assign_host_url
end end
let(:extra_assign_expectations) { { gitea_root_url: host_url } } let(:extra_assign_expectations) { { gitea_host_url: host_url } }
end end
end end
......
...@@ -45,20 +45,46 @@ describe Gitlab::GithubImport::Client, lib: true do ...@@ -45,20 +45,46 @@ describe Gitlab::GithubImport::Client, lib: true do
end end
end end
context 'when provider does not specity an API endpoint' do describe '#api_endpoint' do
it 'uses GitHub root API endpoint' do context 'when provider does not specity an API endpoint' do
expect(client.api.api_endpoint).to eq 'https://api.github.com/' it 'uses GitHub root API endpoint' do
expect(client.api.api_endpoint).to eq 'https://api.github.com/'
end
end end
end
context 'when provider specify a custom API endpoint' do context 'when provider specify a custom API endpoint' do
before do before do
github_provider['args']['client_options']['site'] = 'https://github.company.com/' github_provider['args']['client_options']['site'] = 'https://github.company.com/'
end
it 'uses the custom API endpoint' do
expect(OmniAuth::Strategies::GitHub).not_to receive(:default_options)
expect(client.api.api_endpoint).to eq 'https://github.company.com/'
end
end
context 'when given a host' do
subject(:client) { described_class.new(token, host: 'https://try.gitea.io/') }
it 'builds a endpoint with the given host and the default API version' do
expect(client.api.api_endpoint).to eq 'https://try.gitea.io/api/v3/'
end
end end
it 'uses the custom API endpoint' do context 'when given an API version' do
expect(OmniAuth::Strategies::GitHub).not_to receive(:default_options) subject(:client) { described_class.new(token, api_version: 'v3') }
expect(client.api.api_endpoint).to eq 'https://github.company.com/'
it 'does not use the API version without a host' do
expect(client.api.api_endpoint).to eq 'https://api.github.com/'
end
end
context 'when given a host and version' do
subject(:client) { described_class.new(token, host: 'https://try.gitea.io/', api_version: 'v3') }
it 'builds a endpoint with the given options' do
expect(client.api.api_endpoint).to eq 'https://try.gitea.io/api/v3/'
end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::GithubImport::Importer, lib: true do describe Gitlab::GithubImport::Importer, lib: true do
describe '#execute' do shared_examples 'Gitlab::GithubImport::Importer#execute' do
let(:expected_not_called) { [] }
before do before do
allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new) allow(project).to receive(:import_data).and_return(double.as_null_object)
end end
context 'when an error occurs' do it 'calls import methods' do
let(:project) { create(:project, import_url: 'https://github.com/octocat/Hello-World.git', wiki_access_level: ProjectFeature::DISABLED) } importer = described_class.new(project)
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
let(:repository) { double(id: 1, fork: false) }
let(:source_sha) { create(:commit, project: project).id }
let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) }
let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) }
let(:label1) do
double(
name: 'Bug',
color: 'ff0000',
url: 'https://api.github.com/repos/octocat/Hello-World/labels/bug'
)
end
let(:label2) do expected_called = [
double( :import_labels, :import_milestones, :import_pull_requests, :import_issues,
name: nil, :import_wiki, :import_releases, :handle_errors
color: 'ff0000', ]
url: 'https://api.github.com/repos/octocat/Hello-World/labels/bug'
)
end
let(:milestone) do expected_called -= expected_not_called
double(
number: 1347,
state: 'open',
title: '1.0',
description: 'Version 1.0',
due_on: nil,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
url: 'https://api.github.com/repos/octocat/Hello-World/milestones/1'
)
end
let(:issue1) do aggregate_failures do
double( expected_called.each do |method_name|
number: 1347, expect(importer).to receive(method_name)
milestone: nil, end
state: 'open',
title: 'Found a bug',
body: "I'm having a problem with this.",
assignee: nil,
user: octocat,
comments: 0,
pull_request: nil,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
url: 'https://api.github.com/repos/octocat/Hello-World/issues/1347',
labels: [double(name: 'Label #1')],
)
end
let(:issue2) do expect(importer).to receive(:import_comments).with(:issues)
double( expect(importer).to receive(:import_comments).with(:pull_requests)
number: 1348,
milestone: nil,
state: 'open',
title: nil,
body: "I'm having a problem with this.",
assignee: nil,
user: octocat,
comments: 0,
pull_request: nil,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
url: 'https://api.github.com/repos/octocat/Hello-World/issues/1348',
labels: [double(name: 'Label #2')],
)
end
let(:pull_request) do expected_not_called.each do |method_name|
double( expect(importer).not_to receive(method_name)
number: 1347, end
milestone: nil,
state: 'open',
title: 'New feature',
body: 'Please pull these awesome changes',
head: source_branch,
base: target_branch,
assignee: nil,
user: octocat,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
merged_at: nil,
url: 'https://api.github.com/repos/octocat/Hello-World/pulls/1347',
)
end end
let(:release1) do importer.execute
double( end
tag_name: 'v1.0.0', end
name: 'First release',
body: 'Release v1.0.0',
draft: false,
created_at: created_at,
updated_at: updated_at,
url: 'https://api.github.com/repos/octocat/Hello-World/releases/1'
)
end
let(:release2) do shared_examples 'Gitlab::GithubImport::Importer#execute an error occurs' do
double( before do
tag_name: 'v2.0.0', allow(project).to receive(:import_data).and_return(double.as_null_object)
name: 'Second release',
body: nil,
draft: false,
created_at: created_at,
updated_at: updated_at,
url: 'https://api.github.com/repos/octocat/Hello-World/releases/2'
)
end
before do allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new)
allow(project).to receive(:import_data).and_return(double.as_null_object)
allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound) allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound)
allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label1, label2]) allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error)
allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone])
allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2]) allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label1, label2])
allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request]) allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone])
allow_any_instance_of(Octokit::Client).to receive(:issues_comments).and_return([]) allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2])
allow_any_instance_of(Octokit::Client).to receive(:pull_requests_comments).and_return([]) allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request])
allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil })) allow_any_instance_of(Octokit::Client).to receive(:issues_comments).and_return([])
allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2]) allow_any_instance_of(Octokit::Client).to receive(:pull_requests_comments).and_return([])
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error) allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil }))
end allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2])
end
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
let(:label1) do
double(
name: 'Bug',
color: 'ff0000',
url: "#{api_root}/repos/octocat/Hello-World/labels/bug"
)
end
let(:label2) do
double(
name: nil,
color: 'ff0000',
url: "#{api_root}/repos/octocat/Hello-World/labels/bug"
)
end
let(:milestone) do
double(
id: 1347, # For Gitea
number: 1347,
state: 'open',
title: '1.0',
description: 'Version 1.0',
due_on: nil,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
url: "#{api_root}/repos/octocat/Hello-World/milestones/1"
)
end
it 'returns true' do let(:issue1) do
expect(described_class.new(project).execute).to eq true double(
number: 1347,
milestone: nil,
state: 'open',
title: 'Found a bug',
body: "I'm having a problem with this.",
assignee: nil,
user: octocat,
comments: 0,
pull_request: nil,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
url: "#{api_root}/repos/octocat/Hello-World/issues/1347",
labels: [double(name: 'Label #1')]
)
end
let(:issue2) do
double(
number: 1348,
milestone: nil,
state: 'open',
title: nil,
body: "I'm having a problem with this.",
assignee: nil,
user: octocat,
comments: 0,
pull_request: nil,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
url: "#{api_root}/repos/octocat/Hello-World/issues/1348",
labels: [double(name: 'Label #2')]
)
end
let(:repository) { double(id: 1, fork: false) }
let(:source_sha) { create(:commit, project: project).id }
let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) }
let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) }
let(:pull_request) do
double(
number: 1347,
milestone: nil,
state: 'open',
title: 'New feature',
body: 'Please pull these awesome changes',
head: source_branch,
base: target_branch,
assignee: nil,
user: octocat,
created_at: created_at,
updated_at: updated_at,
closed_at: nil,
merged_at: nil,
url: "#{api_root}/repos/octocat/Hello-World/pulls/1347",
labels: [double(name: 'Label #2')]
)
end
let(:release1) do
double(
tag_name: 'v1.0.0',
name: 'First release',
body: 'Release v1.0.0',
draft: false,
created_at: created_at,
updated_at: updated_at,
url: "#{api_root}/repos/octocat/Hello-World/releases/1"
)
end
let(:release2) do
double(
tag_name: 'v2.0.0',
name: 'Second release',
body: nil,
draft: false,
created_at: created_at,
updated_at: updated_at,
url: "#{api_root}/repos/octocat/Hello-World/releases/2"
)
end
it 'returns true' do
expect(described_class.new(project).execute).to eq true
end
it 'does not raise an error' do
expect { described_class.new(project).execute }.not_to raise_error
end
it 'stores error messages' do
error = {
message: 'The remote data could not be fully imported.',
errors: [
{ type: :label, url: "#{api_root}/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title can't be blank, Title is invalid" },
{ type: :issue, url: "#{api_root}/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank" },
{ type: :wiki, errors: "Gitlab::Shell::Error" }
]
}
unless project.import_type == 'gitea'
error[:errors] << { type: :release, url: "#{api_root}/repos/octocat/Hello-World/releases/2", errors: "Validation failed: Description can't be blank" }
end end
it 'does not raise an error' do described_class.new(project).execute
expect { described_class.new(project).execute }.not_to raise_error
expect(project.import_error).to eq error.to_json
end
end
let(:project) { create(:project, import_url: "#{repo_root}/octocat/Hello-World.git", wiki_access_level: ProjectFeature::DISABLED) }
let(:credentials) { { user: 'joe' } }
context 'when importing a GitHub project' do
let(:api_root) { 'https://api.github.com' }
let(:repo_root) { 'https://github.com' }
it_behaves_like 'Gitlab::GithubImport::Importer#execute'
it_behaves_like 'Gitlab::GithubImport::Importer#execute an error occurs'
describe '#client' do
it 'instantiates a Client' do
allow(project).to receive(:import_data).and_return(double(credentials: credentials))
expect(Gitlab::GithubImport::Client).to receive(:new).with(
credentials[:user],
{}
)
described_class.new(project).client
end end
end
end
it 'stores error messages' do context 'when importing a Gitea project' do
error = { let(:api_root) { 'https://try.gitea.io/api/v1' }
message: 'The remote data could not be fully imported.', let(:repo_root) { 'https://try.gitea.io' }
errors: [ before do
{ type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title can't be blank, Title is invalid" }, project.update(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git")
{ type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank" }, end
{ type: :wiki, errors: "Gitlab::Shell::Error" },
{ type: :release, url: 'https://api.github.com/repos/octocat/Hello-World/releases/2', errors: "Validation failed: Description can't be blank" }
]
}
described_class.new(project).execute it_behaves_like 'Gitlab::GithubImport::Importer#execute' do
let(:expected_not_called) { [:import_releases] }
end
it_behaves_like 'Gitlab::GithubImport::Importer#execute an error occurs'
describe '#client' do
it 'instantiates a Client' do
allow(project).to receive(:import_data).and_return(double(credentials: credentials))
expect(Gitlab::GithubImport::Client).to receive(:new).with(
credentials[:user],
{ host: "#{repo_root}:443/foo", api_version: 'v1' }
)
expect(project.import_error).to eq error.to_json described_class.new(project).client
end end
end end
end end
......
require 'spec_helper'
describe Gitlab::GithubImport::IssuableFormatter, lib: true do
let(:raw_data) do
double(number: 42)
end
let(:project) { double(import_type: 'github') }
let(:issuable_formatter) { described_class.new(project, raw_data) }
describe '#project_association' do
it { expect { issuable_formatter.project_association }.to raise_error(NotImplementedError) }
end
describe '#number' do
it { expect(issuable_formatter.number).to eq(42) }
end
describe '#find_condition' do
it { expect(issuable_formatter.find_condition).to eq({ iid: 42 }) }
end
end
...@@ -23,9 +23,9 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -23,9 +23,9 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
} }
end end
subject(:issue) { described_class.new(project, raw_data)} subject(:issue) { described_class.new(project, raw_data) }
describe '#attributes' do shared_examples 'Gitlab::GithubImport::IssueFormatter#attributes' do
context 'when issue is open' do context 'when issue is open' do
let(:raw_data) { double(base_data.merge(state: 'open')) } let(:raw_data) { double(base_data.merge(state: 'open')) }
...@@ -83,7 +83,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -83,7 +83,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
end end
context 'when it has a milestone' do context 'when it has a milestone' do
let(:milestone) { double(number: 45) } let(:milestone) { double(id: 42, number: 42) }
let(:raw_data) { double(base_data.merge(milestone: milestone)) } let(:raw_data) { double(base_data.merge(milestone: milestone)) }
it 'returns nil when milestone does not exist' do it 'returns nil when milestone does not exist' do
...@@ -91,7 +91,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -91,7 +91,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
end end
it 'returns milestone when it exists' do it 'returns milestone when it exists' do
milestone = create(:milestone, project: project, iid: 45) milestone = create(:milestone, project: project, iid: 42)
expect(issue.attributes.fetch(:milestone)).to eq milestone expect(issue.attributes.fetch(:milestone)).to eq milestone
end end
...@@ -118,6 +118,28 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -118,6 +118,28 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
end end
end end
shared_examples 'Gitlab::GithubImport::IssueFormatter#number' do
let(:raw_data) { double(base_data.merge(number: 1347)) }
it 'returns issue number' do
expect(issue.number).to eq 1347
end
end
context 'when importing a GitHub project' do
it_behaves_like 'Gitlab::GithubImport::IssueFormatter#attributes'
it_behaves_like 'Gitlab::GithubImport::IssueFormatter#number'
end
context 'when importing a Gitea project' do
before do
project.update(import_type: 'gitea')
end
it_behaves_like 'Gitlab::GithubImport::IssueFormatter#attributes'
it_behaves_like 'Gitlab::GithubImport::IssueFormatter#number'
end
describe '#has_comments?' do describe '#has_comments?' do
context 'when number of comments is greater than zero' do context 'when number of comments is greater than zero' do
let(:raw_data) { double(base_data.merge(comments: 1)) } let(:raw_data) { double(base_data.merge(comments: 1)) }
...@@ -136,14 +158,6 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -136,14 +158,6 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
end end
end end
describe '#number' do
let(:raw_data) { double(base_data.merge(number: 1347)) }
it 'returns pull request number' do
expect(issue.number).to eq 1347
end
end
describe '#pull_request?' do describe '#pull_request?' do
context 'when mention a pull request' do context 'when mention a pull request' do
let(:raw_data) { double(base_data.merge(pull_request: double)) } let(:raw_data) { double(base_data.merge(pull_request: double)) }
......
...@@ -6,7 +6,6 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do ...@@ -6,7 +6,6 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
let(:base_data) do let(:base_data) do
{ {
number: 1347,
state: 'open', state: 'open',
title: '1.0', title: '1.0',
description: 'Version 1.0', description: 'Version 1.0',
...@@ -16,12 +15,15 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do ...@@ -16,12 +15,15 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do
closed_at: nil closed_at: nil
} }
end end
let(:iid_attr) { :number }
subject(:formatter) { described_class.new(project, raw_data)} subject(:formatter) { described_class.new(project, raw_data) }
shared_examples 'Gitlab::GithubImport::MilestoneFormatter#attributes' do
let(:data) { base_data.merge(iid_attr => 1347) }
describe '#attributes' do
context 'when milestone is open' do context 'when milestone is open' do
let(:raw_data) { double(base_data.merge(state: 'open')) } let(:raw_data) { double(data.merge(state: 'open')) }
it 'returns formatted attributes' do it 'returns formatted attributes' do
expected = { expected = {
...@@ -40,7 +42,7 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do ...@@ -40,7 +42,7 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do
end end
context 'when milestone is closed' do context 'when milestone is closed' do
let(:raw_data) { double(base_data.merge(state: 'closed')) } let(:raw_data) { double(data.merge(state: 'closed')) }
it 'returns formatted attributes' do it 'returns formatted attributes' do
expected = { expected = {
...@@ -60,7 +62,7 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do ...@@ -60,7 +62,7 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do
context 'when milestone has a due date' do context 'when milestone has a due date' do
let(:due_date) { DateTime.strptime('2011-01-28T19:01:12Z') } let(:due_date) { DateTime.strptime('2011-01-28T19:01:12Z') }
let(:raw_data) { double(base_data.merge(due_on: due_date)) } let(:raw_data) { double(data.merge(due_on: due_date)) }
it 'returns formatted attributes' do it 'returns formatted attributes' do
expected = { expected = {
...@@ -78,4 +80,17 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do ...@@ -78,4 +80,17 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do
end end
end end
end end
context 'when importing a GitHub project' do
it_behaves_like 'Gitlab::GithubImport::MilestoneFormatter#attributes'
end
context 'when importing a Gitea project' do
let(:iid_attr) { :id }
before do
project.update(import_type: 'gitea')
end
it_behaves_like 'Gitlab::GithubImport::MilestoneFormatter#attributes'
end
end end
...@@ -32,9 +32,9 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -32,9 +32,9 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
} }
end end
subject(:pull_request) { described_class.new(project, raw_data)} subject(:pull_request) { described_class.new(project, raw_data) }
describe '#attributes' do shared_examples 'Gitlab::GithubImport::PullRequestFormatter#attributes' do
context 'when pull request is open' do context 'when pull request is open' do
let(:raw_data) { double(base_data.merge(state: 'open')) } let(:raw_data) { double(base_data.merge(state: 'open')) }
...@@ -149,7 +149,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -149,7 +149,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end end
context 'when it has a milestone' do context 'when it has a milestone' do
let(:milestone) { double(number: 45) } let(:milestone) { double(id: 42, number: 42) }
let(:raw_data) { double(base_data.merge(milestone: milestone)) } let(:raw_data) { double(base_data.merge(milestone: milestone)) }
it 'returns nil when milestone does not exist' do it 'returns nil when milestone does not exist' do
...@@ -157,22 +157,22 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -157,22 +157,22 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end end
it 'returns milestone when it exists' do it 'returns milestone when it exists' do
milestone = create(:milestone, project: project, iid: 45) milestone = create(:milestone, project: project, iid: 42)
expect(pull_request.attributes.fetch(:milestone)).to eq milestone expect(pull_request.attributes.fetch(:milestone)).to eq milestone
end end
end end
end end
describe '#number' do shared_examples 'Gitlab::GithubImport::PullRequestFormatter#number' do
let(:raw_data) { double(base_data.merge(number: 1347)) } let(:raw_data) { double(base_data) }
it 'returns pull request number' do it 'returns pull request number' do
expect(pull_request.number).to eq 1347 expect(pull_request.number).to eq 1347
end end
end end
describe '#source_branch_name' do shared_examples 'Gitlab::GithubImport::PullRequestFormatter#source_branch_name' do
context 'when source branch exists' do context 'when source branch exists' do
let(:raw_data) { double(base_data) } let(:raw_data) { double(base_data) }
...@@ -190,7 +190,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -190,7 +190,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end end
end end
describe '#target_branch_name' do shared_examples 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name' do
context 'when source branch exists' do context 'when source branch exists' do
let(:raw_data) { double(base_data) } let(:raw_data) { double(base_data) }
...@@ -208,6 +208,24 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -208,6 +208,24 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end end
end end
context 'when importing a GitHub project' do
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#attributes'
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#number'
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#source_branch_name'
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name'
end
context 'when importing a Gitea project' do
before do
project.update(import_type: 'gitea')
end
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#attributes'
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#number'
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#source_branch_name'
it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name'
end
describe '#valid?' do describe '#valid?' do
context 'when source, and target repos are not a fork' do context 'when source, and target repos are not a fork' do
let(:raw_data) { double(base_data) } let(:raw_data) { double(base_data) }
......
...@@ -75,7 +75,6 @@ describe Import::GiteaController, 'routing' do ...@@ -75,7 +75,6 @@ describe Import::GiteaController, 'routing' do
it 'to #personal_access_token' do it 'to #personal_access_token' do
expect(post('/import/gitea/personal_access_token')).to route_to('import/gitea#personal_access_token') expect(post('/import/gitea/personal_access_token')).to route_to('import/gitea#personal_access_token')
end end
end end
# status_import_gitlab GET /import/gitlab/status(.:format) import/gitlab#status # status_import_gitlab GET /import/gitlab/status(.:format) import/gitlab#status
......
...@@ -82,7 +82,7 @@ shared_examples 'a GitHub-ish import controller: GET status' do ...@@ -82,7 +82,7 @@ shared_examples 'a GitHub-ish import controller: GET status' do
expect(session[:access_token]).to eq(nil) expect(session[:access_token]).to eq(nil)
expect(controller).to redirect_to(new_import_url) 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.") expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.title(provider.to_s)} account.")
end end
end end
......
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