Commit 1d291312 authored by Illya Klymov's avatar Illya Klymov Committed by David O'Regan

Remove Google Code importer

Remove relevant backend parts and tests
parent 19b26b12
import $ from 'jquery';
import { escape } from 'lodash';
import { __, sprintf } from './locale';
import axios from './lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from './flash';
import { parseBoolean, spriteIcon } from './lib/utils/common_utils';
class ImporterStatus {
constructor({ jobsUrl, importUrl, ciCdOnly }) {
this.jobsUrl = jobsUrl;
this.importUrl = importUrl;
this.ciCdOnly = ciCdOnly;
this.initStatusPage();
this.setAutoUpdate();
}
initStatusPage() {
$('.js-add-to-import')
.off('click')
.on('click', this.addToImport.bind(this));
$('.js-import-all')
.off('click')
.on('click', function onClickImportAll() {
const $btn = $(this);
$btn.disable().addClass('is-loading');
return $('.js-add-to-import').each(function triggerAddImport() {
return $(this).trigger('click');
});
});
}
addToImport(event) {
const $btn = $(event.currentTarget);
const $tr = $btn.closest('tr');
const $targetField = $tr.find('.import-target');
const $namespaceInput = $targetField.find('.js-select-namespace option:selected');
const repoData = $tr.data();
const id = repoData.id || $tr.attr('id').replace('repo_', '');
let targetNamespace;
let newName;
if ($namespaceInput.length > 0) {
targetNamespace = $namespaceInput[0].innerHTML;
newName = $targetField.find('#path').prop('value');
$targetField.empty().append(`${targetNamespace}/${newName}`);
}
$btn.disable().addClass('is-loading');
this.id = id;
let attributes = {
repo_id: id,
target_namespace: targetNamespace,
new_name: newName,
ci_cd_only: this.ciCdOnly,
};
if (repoData) {
attributes = Object.assign(repoData, attributes);
}
return axios
.post(this.importUrl, attributes)
.then(({ data }) => {
const job = $tr;
job.attr('id', `project_${data.id}`);
job.find('.import-target').html(`<a href="${data.full_path}">${data.full_path}</a>`);
$('table.import-jobs tbody').prepend(job);
job.addClass('table-active');
const connectingVerb = this.ciCdOnly ? __('connecting') : __('importing');
job.find('.import-actions').html(
sprintf(
escape(__('%{loadingIcon} Started')),
{
loadingIcon: `<i class="fa fa-spinner fa-spin" aria-label="${escape(
connectingVerb,
)}"></i>`,
},
false,
),
);
})
.catch(error => {
let details = error;
const $statusField = $tr.find('.job-status');
$statusField.text(__('Failed'));
if (error.response && error.response.data && error.response.data.errors) {
details = error.response.data.errors;
}
flash(sprintf(__('An error occurred while importing project: %{details}'), { details }));
});
}
autoUpdate() {
return axios.get(this.jobsUrl).then(({ data = [] }) => {
data.forEach(job => {
const jobItem = $(`#project_${job.id}`);
const statusField = jobItem.find('.job-status');
const spinner = '<i class="fa fa-spinner fa-spin"></i>';
switch (job.import_status) {
case 'finished':
jobItem.removeClass('table-active').addClass('table-success');
statusField.html(`<span>${spriteIcon('check', 's16')} ${__('Done')}</span>`);
break;
case 'scheduled':
statusField.html(`${spinner} ${__('Scheduled')}`);
break;
case 'started':
statusField.html(`${spinner} ${__('Started')}`);
break;
case 'failed':
statusField.html(__('Failed'));
break;
default:
statusField.html(job.import_status);
break;
}
});
});
}
setAutoUpdate() {
setInterval(this.autoUpdate.bind(this), 4000);
}
}
// eslint-disable-next-line consistent-return
function initImporterStatus() {
const importerStatus = document.querySelector('.js-importer-status');
if (importerStatus) {
const data = importerStatus.dataset;
return new ImporterStatus({
jobsUrl: data.jobsImportPath,
importUrl: data.importPath,
ciCdOnly: parseBoolean(data.ciCdOnly),
});
}
}
export { initImporterStatus as default, ImporterStatus };
......@@ -23,7 +23,6 @@ import { getLocationHash, visitUrl } from './lib/utils/url_utility';
// everything else
import { deprecatedCreateFlash as Flash, removeFlashClickListener } from './flash';
import initTodoToggle from './header';
import initImporterStatus from './importer_status';
import initLayoutNav from './layout_nav';
import initAlertHandler from './alert_handler';
import './feature_highlight/feature_highlight_options';
......@@ -107,7 +106,6 @@ function deferredInitialisation() {
const $body = $('body');
initBreadcrumbs();
initImporterStatus();
initTodoToggle();
initLogoAnimation();
initUsagePingConsent();
......
......@@ -39,15 +39,3 @@
.import-projects-loading-icon {
margin-top: $gl-padding-32;
}
.btn-import {
.loading-icon {
display: none;
}
&.is-loading {
.loading-icon {
display: inline-block;
}
}
}
......@@ -61,8 +61,7 @@ class ApplicationController < ActionController::Base
:gitea_import_enabled?, :github_import_configured?,
:gitlab_import_enabled?, :gitlab_import_configured?,
:bitbucket_import_enabled?, :bitbucket_import_configured?,
:bitbucket_server_import_enabled?,
:google_code_import_enabled?, :fogbugz_import_enabled?,
:bitbucket_server_import_enabled?, :fogbugz_import_enabled?,
:git_import_enabled?, :gitlab_project_import_enabled?,
:manifest_import_enabled?, :phabricator_import_enabled?
......@@ -434,10 +433,6 @@ class ApplicationController < ActionController::Base
Gitlab::Auth::OAuth::Provider.enabled?(:bitbucket)
end
def google_code_import_enabled?
Gitlab::CurrentSettings.import_sources.include?('google_code')
end
def fogbugz_import_enabled?
Gitlab::CurrentSettings.import_sources.include?('fogbugz')
end
......
# frozen_string_literal: true
class Import::GoogleCodeController < Import::BaseController
before_action :verify_google_code_import_enabled
before_action :user_map, only: [:new_user_map, :create_user_map]
def new
end
def callback
dump_file = params[:dump_file]
unless dump_file.respond_to?(:read)
return redirect_back_or_default(options: { alert: _("You need to upload a Google Takeout archive.") })
end
begin
dump = Gitlab::Json.parse(dump_file.read)
rescue
return redirect_back_or_default(options: { alert: _("The uploaded file is not a valid Google Takeout archive.") })
end
client = Gitlab::GoogleCodeImport::Client.new(dump)
unless client.valid?
return redirect_back_or_default(options: { alert: _("The uploaded file is not a valid Google Takeout archive.") })
end
session[:google_code_dump] = dump
if params[:create_user_map] == "1"
redirect_to new_user_map_import_google_code_path
else
redirect_to status_import_google_code_path
end
end
def new_user_map
end
def create_user_map
user_map_json = params[:user_map]
user_map_json = "{}" if user_map_json.blank?
begin
user_map = Gitlab::Json.parse(user_map_json)
rescue
flash.now[:alert] = _("The entered user map is not a valid JSON user map.")
return render "new_user_map"
end
unless user_map.is_a?(Hash) && user_map.all? { |k, v| k.is_a?(String) && v.is_a?(String) }
flash.now[:alert] = _("The entered user map is not a valid JSON user map.")
return render "new_user_map"
end
# This is the default, so let's not save it into the database.
user_map.reject! do |key, value|
value == Gitlab::GoogleCodeImport::Client.mask_email(key)
end
session[:google_code_user_map] = user_map
flash[:notice] = _("The user map has been saved. Continue by selecting the projects you want to import.")
redirect_to status_import_google_code_path
end
# rubocop: disable CodeReuse/ActiveRecord
def status
unless client.valid?
return redirect_to new_import_google_code_path
end
@repos = client.repos
@incompatible_repos = client.incompatible_repos
@already_added_projects = find_already_added_projects('google_code')
already_added_projects_names = @already_added_projects.pluck(:import_source)
@repos.reject! { |repo| already_added_projects_names.include? repo.name }
end
# rubocop: enable CodeReuse/ActiveRecord
def jobs
render json: find_jobs('google_code')
end
def create
repo = client.repo(params[:repo_id])
user_map = session[:google_code_user_map]
project = Gitlab::GoogleCodeImport::ProjectCreator.new(repo, current_user.namespace, current_user, user_map).execute
if project.persisted?
render json: ProjectSerializer.new.represent(project)
else
render json: { errors: project_save_error(project) }, status: :unprocessable_entity
end
end
private
def client
@client ||= Gitlab::GoogleCodeImport::Client.new(session[:google_code_dump])
end
def verify_google_code_import_enabled
render_404 unless google_code_import_enabled?
end
def user_map
@user_map ||= begin
user_map = client.user_map
stored_user_map = session[:google_code_user_map]
user_map.update(stored_user_map) if stored_user_map
Hash[user_map.sort]
end
end
end
- page_title _("Google Code import")
- header_title _("Projects"), root_path
%h3.page-title.gl-display-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('google', css_class: 'gl-mr-2')
= _('Import projects from Google Code')
%hr
= form_tag callback_import_google_code_path, multipart: true do
%p
= _('Follow the steps below to export your Google Code project data.')
= _("In the next step, you'll be able to select the projects you want to import.")
%ol
%li
%p
- link_to_google_takeout = link_to(_("Google Takeout"), "https://www.google.com/settings/takeout", target: '_blank', rel: 'noopener noreferrer')
= _("Go to %{link_to_google_takeout}.").html_safe % { link_to_google_takeout: link_to_google_takeout }
%li
%p
= _("Make sure you're logged into the account that owns the projects you'd like to import.")
%li
%p
= html_escape(_('Click the %{strong_open}Select none%{strong_close} button on the right, since we only need "Google Code Project Hosting".')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
%li
%p
= html_escape(_('Scroll down to %{strong_open}Google Code Project Hosting%{strong_close} and enable the switch on the right.')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
%li
%p
= html_escape(_('Choose %{strong_open}Next%{strong_close} at the bottom of the page.')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
%li
%p
= _('Leave the "File type" and "Delivery method" options on their default values.')
%li
%p
= html_escape(_('Choose %{strong_open}Create archive%{strong_close} and wait for archiving to complete.')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
%li
%p
= html_escape(_('Click the %{strong_open}Download%{strong_close} button and wait for downloading to complete.')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
%li
%p
= _('Find the downloaded ZIP file and decompress it.')
%li
%p
= html_escape(_('Find the newly extracted %{code_open}Takeout/Google Code Project Hosting/GoogleCodeProjectHosting.json%{code_close} file.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
%p
= html_escape(_('Upload %{code_open}GoogleCodeProjectHosting.json%{code_close} here:')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%p
%input{ type: "file", name: "dump_file", id: "dump_file" }
%li
%p
= _('Do you want to customize how Google Code email addresses and usernames are imported into GitLab?')
%p
= label_tag :create_user_map_0 do
= radio_button_tag :create_user_map, 0, true
= _('No, directly import the existing email addresses and usernames.')
%p
= label_tag :create_user_map_1 do
= radio_button_tag :create_user_map, 1, false
= _('Yes, let me map Google Code users to full names or GitLab users.')
%span
= submit_tag _('Continue to the next step'), class: "btn btn-success"
- page_title _("User map"), _("Google Code import")
- header_title _("Projects"), root_path
%h3.page-title.gl-display-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('google', css_class: 'gl-mr-2')
= _('Import projects from Google Code')
%hr
= form_tag create_user_map_import_google_code_path do
%p
= _("Customize how Google Code email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import.")
%p
= html_escape(_("The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of %{code_open}:%{code_close}. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%ul
%li
%strong= _("Default: Directly import the Google Code email address or username")
%p
= html_escape(_('%{code_open}"johnsmith@example.com": "johnsm...@example.com"%{code_close} will add "By johnsm...@example.com" to all issues and comments originally created by johnsmith@example.com. The email address or username is masked to ensure the user\'s privacy.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
%strong= _("Map a Google Code user to a GitLab user")
%p
= html_escape(_('%{code_open}"johnsmith@example.com": "@johnsmith"%{code_close} will add "By %{link_open}@johnsmith%{link_close}" to all issues and comments originally created by johnsmith@example.com, and will set %{link_open}@johnsmith%{link_close} as the assignee on all issues originally assigned to johnsmith@example.com.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe, link_open: '<a href="#">'.html_safe, link_close: '</a>'.html_safe }
%li
%strong= _("Map a Google Code user to a full name")
%p
= html_escape(_('%{code_open}"johnsmith@example.com": "John Smith"%{code_close} will add "By John Smith" to all issues and comments originally created by johnsmith@example.com.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
%strong= _("Map a Google Code user to a full email address")
%p
= html_escape(_('%{code_open}"johnsmith@example.com": "johnsmith@example.com"%{code_close} will add "By %{link_open}johnsmith@example.com%{link_close}" to all issues and comments originally created by johnsmith@example.com. By default, the email address or username is masked to ensure the user\'s privacy. Use this option if you want to show the full email address.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe, link_open: '<a href="#">'.html_safe, link_close: '</a>'.html_safe }
.form-group.row
.col-sm-12
= text_area_tag :user_map, Gitlab::Json.pretty_generate(@user_map), class: 'form-control', rows: 15
.form-actions
= submit_tag _('Continue to the next step'), class: "btn btn-success"
- page_title _("Google Code import")
- header_title _("Projects"), root_path
%h3.page-title.gl-display-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('google', css_class: 'gl-mr-2')
= _('Import projects from Google Code')
- if @repos.any?
%p.light
= _('Select projects you want to import.')
%p.light
- link_to_customize = link_to(_("customize"), new_user_map_import_google_code_path)
= _("Optionally, you can %{link_to_customize} how Google Code email addresses and usernames are imported into GitLab.").html_safe % { link_to_customize: link_to_customize }
%hr
%p
- if @incompatible_repos.any?
= button_tag class: "btn btn-import btn-success js-import-all" do
= _("Import all compatible projects")
= loading_icon(css_class: 'loading-icon')
- else
= button_tag class: "btn btn-import btn-success js-import-all" do
= _("Import all projects")
= loading_icon(css_class: 'loading-icon')
.table-responsive
%table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead
%tr
%th= _("From Google Code")
%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
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer'
%td
= link_to project.full_path, project
%td.job-status
- case project.import_status
- when 'finished'
%span
= sprite_icon('check')
= _("done")
- when 'started'
= loading_icon
= _("started")
- else
= project.human_import_status_name
- @repos.each do |repo|
%tr{ id: "repo_#{repo.id}" }
%td
= link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank", rel: 'noopener noreferrer'
%td.import-target
#{current_user.username}/#{repo.name}
%td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do
= _("Import")
= loading_icon(css_class: 'loading-icon')
- @incompatible_repos.each do |repo|
%tr{ id: "repo_#{repo.id}" }
%td
= link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank", rel: 'noopener noreferrer'
%td.import-target
%td.import-actions-job-status
= label_tag _("Incompatible Project"), nil, class: "label badge-danger"
- if @incompatible_repos.any?
%p
= _("One or more of your Google Code projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git.")
- link_to_import_flow = link_to(_("import flow"), new_import_google_code_path)
= _("Please convert them to Git on Google Code, and go through the %{link_to_import_flow} again.").html_safe % { link_to_import_flow: link_to_import_flow }
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_google_code_path}", import_path: "#{import_google_code_path}" } }
......@@ -41,12 +41,6 @@
- unless gitlab_import_configured?
= render 'projects/gitlab_import_modal'
- if google_code_import_enabled?
%div
= link_to new_import_google_code_path, class: 'btn import_google_code', **tracking_attrs(track_label, 'click_button', 'google_code') do
= sprite_icon('google')
Google Code
- if fogbugz_import_enabled?
%div
= link_to new_import_fogbugz_path, class: 'btn import_fogbugz', **tracking_attrs(track_label, 'click_button', 'fogbugz') do
......
---
title: "Remove Google Code importer"
merge_request: 48139
author: Getulio Valentin Sánchez
type: removed
......@@ -42,15 +42,6 @@ namespace :import do
get :realtime_changes
end
resource :google_code, only: [:create, :new], controller: :google_code do
get :status
post :callback
get :jobs
get :new_user_map, path: :user_map
post :create_user_map, path: :user_map
end
resource :fogbugz, only: [:create, :new], controller: :fogbugz do
get :status
post :callback
......
......@@ -292,7 +292,7 @@ listed in the descriptions of the relevant settings.
| `housekeeping_gc_period` | integer | required by: `housekeeping_enabled` | Number of Git pushes after which `git gc` is run. |
| `housekeeping_incremental_repack_period` | integer | required by: `housekeeping_enabled` | Number of Git pushes after which an incremental `git repack` is run. |
| `html_emails_enabled` | boolean | no | Enable HTML emails. |
| `import_sources` | array of strings | no | Sources to allow project import from, possible values: `github`, `bitbucket`, `bitbucket_server`, `gitlab`, `google_code`, `fogbugz`, `git`, `gitlab_project`, `gitea`, `manifest`, and `phabricator`. |
| `import_sources` | array of strings | no | Sources to allow project import from, possible values: `github`, `bitbucket`, `bitbucket_server`, `gitlab`, `fogbugz`, `git`, `gitlab_project`, `gitea`, `manifest`, and `phabricator`. |
| `issues_create_limit` | integer | no | Max number of issue creation requests per minute per user. Disabled by default.|
| `local_markdown_version` | integer | no | Increase this value when any cached Markdown should be invalidated. |
| `maintenance_mode_message` | string | no | **(PREMIUM)** Message displayed when instance is in maintenance mode |
......
......@@ -88,7 +88,7 @@ module API
end
optional :html_emails_enabled, type: Boolean, desc: 'By default GitLab sends emails in HTML and plain text formats so mail clients can choose what format to use. Disable this option if you only want to send emails in plain text format.'
optional :import_sources, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce,
values: %w[github bitbucket bitbucket_server gitlab google_code fogbugz git gitlab_project gitea manifest phabricator],
values: %w[github bitbucket bitbucket_server gitlab fogbugz git gitlab_project gitea manifest phabricator],
desc: 'Enabled sources for code import during project creation. OmniAuth must be configured for GitHub, Bitbucket, and GitLab.com'
optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts"
optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB'
......
# frozen_string_literal: true
module Gitlab
module GoogleCodeImport
class Client
attr_reader :raw_data
def self.mask_email(author)
parts = author.split("@", 2)
parts[0] = "#{parts[0][0...-3]}..."
parts.join("@")
end
def initialize(raw_data)
@raw_data = raw_data
end
def valid?
raw_data.is_a?(Hash) && raw_data["kind"] == "projecthosting#user" && raw_data.key?("projects")
end
def repos
@repos ||= raw_data["projects"].map { |raw_repo| GoogleCodeImport::Repository.new(raw_repo) }.select(&:git?)
end
def incompatible_repos
@incompatible_repos ||= raw_data["projects"].map { |raw_repo| GoogleCodeImport::Repository.new(raw_repo) }.reject(&:git?)
end
def repo(id)
repos.find { |repo| repo.id == id }
end
def user_map
user_map = Hash.new { |hash, user| hash[user] = self.class.mask_email(user) }
repos.each do |repo|
next unless repo.valid? && repo.issues
repo.issues.each do |raw_issue|
# Touching is enough to add the entry and masked email.
user_map[raw_issue["author"]["name"]]
raw_issue["comments"]["items"].each do |raw_comment|
user_map[raw_comment["author"]["name"]]
end
end
end
Hash[user_map.sort]
end
end
end
end
# frozen_string_literal: true
module Gitlab
module GoogleCodeImport
class Importer
attr_reader :project, :repo, :closed_statuses
NICE_LABEL_COLOR_HASH =
{
'Status: New' => '#428bca',
'Status: Accepted' => '#5cb85c',
'Status: Started' => '#8e44ad',
'Priority: Critical' => '#ffcfcf',
'Priority: High' => '#deffcf',
'Priority: Medium' => '#fff5cc',
'Priority: Low' => '#cfe9ff',
'Type: Defect' => '#d9534f',
'Type: Enhancement' => '#44ad8e',
'Type: Task' => '#4b6dd0',
'Type: Review' => '#8e44ad',
'Type: Other' => '#7f8c8d'
}.freeze
def initialize(project)
@project = project
import_data = project.import_data.try(:data)
repo_data = import_data["repo"] if import_data
@repo = GoogleCodeImport::Repository.new(repo_data)
@closed_statuses = []
@known_labels = Set.new
end
def execute
return true unless repo.valid?
import_status_labels
import_labels
import_issues
true
end
private
def user_map
@user_map ||= begin
user_map = Hash.new do |hash, user|
# Replace ... by \.\.\., so `johnsm...@gmail.com` isn't autolinked.
Client.mask_email(user).sub("...", "\\.\\.\\.")
end
import_data = project.import_data.try(:data)
stored_user_map = import_data["user_map"] if import_data
user_map.update(stored_user_map) if stored_user_map
user_map
end
end
def import_status_labels
repo.raw_data["issuesConfig"]["statuses"].each do |status|
closed = !status["meansOpen"]
@closed_statuses << status["status"] if closed
name = nice_status_name(status["status"])
create_label(name)
@known_labels << name
end
end
def import_labels
repo.raw_data["issuesConfig"]["labels"].each do |label|
name = nice_label_name(label["label"])
create_label(name)
@known_labels << name
end
end
# rubocop: disable CodeReuse/ActiveRecord
def import_issues
return unless repo.issues
while raw_issue = repo.issues.shift
author = user_map[raw_issue["author"]["name"]]
date = DateTime.parse(raw_issue["published"]).to_formatted_s(:long)
comments = raw_issue["comments"]["items"]
issue_comment = comments.shift
content = format_content(issue_comment["content"])
attachments = format_attachments(raw_issue["id"], 0, issue_comment["attachments"])
body = format_issue_body(author, date, content, attachments)
labels = import_issue_labels(raw_issue)
assignee_id = nil
if raw_issue.key?("owner")
username = user_map[raw_issue["owner"]["name"]]
if username.start_with?("@")
username = username[1..-1]
if user = UserFinder.new(username).find_by_username
assignee_id = user.id
end
end
end
issue = Issue.create!(
iid: raw_issue['id'],
project_id: project.id,
title: raw_issue['title'],
description: body,
author_id: project.creator_id,
assignee_ids: [assignee_id],
state_id: raw_issue['state'] == 'closed' ? Issue.available_states[:closed] : Issue.available_states[:opened]
)
issue_labels = ::LabelsFinder.new(nil, project_id: project.id, title: labels).execute(skip_authorization: true)
issue.update_attribute(:label_ids, issue_labels.pluck(:id))
import_issue_comments(issue, comments)
end
end
# rubocop: enable CodeReuse/ActiveRecord
def import_issue_labels(raw_issue)
labels = []
raw_issue["labels"].each do |label|
name = nice_label_name(label)
labels << name
unless @known_labels.include?(name)
create_label(name)
@known_labels << name
end
end
labels << nice_status_name(raw_issue["status"])
labels
end
def import_issue_comments(issue, comments)
Note.transaction do
while raw_comment = comments.shift
next if raw_comment.key?("deletedBy")
content = format_content(raw_comment["content"])
updates = format_updates(raw_comment["updates"])
attachments = format_attachments(issue.iid, raw_comment["id"], raw_comment["attachments"])
next if content.blank? && updates.blank? && attachments.blank?
author = user_map[raw_comment["author"]["name"]]
date = DateTime.parse(raw_comment["published"]).to_formatted_s(:long)
body = format_issue_comment_body(
raw_comment["id"],
author,
date,
content,
updates,
attachments
)
# Needs to match order of `comment_columns` below.
Note.create!(
project_id: project.id,
noteable_type: "Issue",
noteable_id: issue.id,
author_id: project.creator_id,
note: body
)
end
end
end
def nice_label_color(name)
NICE_LABEL_COLOR_HASH[name] ||
case name
when /\AComponent:/
'#fff39e'
when /\AOpSys:/
'#e2e2e2'
when /\AMilestone:/
'#fee3ff'
when *closed_statuses.map { |s| nice_status_name(s) }
'#cfcfcf'
else
'#e2e2e2'
end
end
def nice_label_name(name)
name.sub("-", ": ")
end
def nice_status_name(name)
"Status: #{name}"
end
def linkify_issues(str)
str = str.gsub(/([Ii]ssue) ([0-9]+)/, '\1 #\2')
str = str.gsub(/([Cc]omment) #([0-9]+)/, '\1 \2')
str
end
def escape_for_markdown(str)
# No headings and lists
str = str.gsub(/^#/, "\\#")
str = str.gsub(/^-/, "\\-")
# No inline code
str = str.gsub("`", "\\`")
# Carriage returns make me sad
str = str.delete("\r")
# Markdown ignores single newlines, but we need them as <br />.
str = str.gsub("\n", " \n")
str
end
def create_label(name)
params = { name: name, color: nice_label_color(name) }
::Labels::FindOrCreateService.new(nil, project, params).execute(skip_authorization: true)
end
def format_content(raw_content)
linkify_issues(escape_for_markdown(raw_content))
end
def format_updates(raw_updates)
updates = []
if raw_updates.key?("status")
updates << "*Status: #{raw_updates["status"]}*"
end
if raw_updates.key?("owner")
updates << "*Owner: #{user_map[raw_updates["owner"]]}*"
end
if raw_updates.key?("cc")
cc = raw_updates["cc"].map do |l|
deleted = l.start_with?("-")
l = l[1..-1] if deleted
l = user_map[l]
l = "~~#{l}~~" if deleted
l
end
updates << "*Cc: #{cc.join(", ")}*"
end
if raw_updates.key?("labels")
labels = raw_updates["labels"].map do |l|
deleted = l.start_with?("-")
l = l[1..-1] if deleted
l = nice_label_name(l)
l = "~~#{l}~~" if deleted
l
end
updates << "*Labels: #{labels.join(", ")}*"
end
if raw_updates.key?("mergedInto")
updates << "*Merged into: ##{raw_updates["mergedInto"]}*"
end
if raw_updates.key?("blockedOn")
blocked_ons = raw_updates["blockedOn"].map do |raw_blocked_on|
format_blocking_updates(raw_blocked_on)
end
updates << "*Blocked on: #{blocked_ons.join(", ")}*"
end
if raw_updates.key?("blocking")
blockings = raw_updates["blocking"].map do |raw_blocked_on|
format_blocking_updates(raw_blocked_on)
end
updates << "*Blocking: #{blockings.join(", ")}*"
end
updates
end
def format_blocking_updates(raw_blocked_on)
name, id = raw_blocked_on.split(":", 2)
deleted = name.start_with?("-")
name = name[1..-1] if deleted
text =
if name == project.import_source
"##{id}"
else
"#{project.namespace.full_path}/#{name}##{id}"
end
text = "~~#{text}~~" if deleted
text
end
def format_attachments(issue_id, comment_id, raw_attachments)
return [] unless raw_attachments
raw_attachments.map do |attachment|
next if attachment["isDeleted"]
filename = attachment["fileName"]
link = "https://storage.googleapis.com/google-code-attachments/#{@repo.name}/issue-#{issue_id}/comment-#{comment_id}/#{filename}"
text = "[#{filename}](#{link})"
text = "!#{text}" if filename =~ /\.(png|jpg|jpeg|gif|bmp|tiff)\z/i
text
end.compact
end
def format_issue_comment_body(id, author, date, content, updates, attachments)
body = []
body << "*Comment #{id} by #{author} on #{date}*"
body << "---"
if content.blank?
content = "*(No comment has been entered for this change)*"
end
body << content
if updates.any?
body << "---"
body += updates
end
if attachments.any?
body << "---"
body += attachments
end
body.join("\n\n")
end
def format_issue_body(author, date, content, attachments)
body = []
body << "*By #{author} on #{date} (imported from Google Code)*"
body << "---"
if content.blank?
content = "*(No description has been entered for this issue)*"
end
body << content
if attachments.any?
body << "---"
body += attachments
end
body.join("\n\n")
end
end
end
end
# frozen_string_literal: true
module Gitlab
module GoogleCodeImport
class ProjectCreator
attr_reader :repo, :namespace, :current_user, :user_map
def initialize(repo, namespace, current_user, user_map = nil)
@repo = repo
@namespace = namespace
@current_user = current_user
@user_map = user_map
end
def execute
::Projects::CreateService.new(
current_user,
name: repo.name,
path: repo.name,
description: repo.summary,
namespace: namespace,
creator: current_user,
visibility_level: Gitlab::VisibilityLevel::PUBLIC,
import_type: "google_code",
import_source: repo.name,
import_url: repo.import_url,
import_data: { data: { 'repo' => repo.raw_data, 'user_map' => user_map } }
).execute
end
end
end
end
# frozen_string_literal: true
module Gitlab
module GoogleCodeImport
class Repository
attr_accessor :raw_data
def initialize(raw_data)
@raw_data = raw_data
end
def valid?
raw_data.is_a?(Hash) && raw_data["kind"] == "projecthosting#project"
end
def id
raw_data["externalId"]
end
def name
raw_data["name"]
end
def summary
raw_data["summary"]
end
def description
raw_data["description"]
end
def git?
raw_data["versionControlSystem"] == "git"
end
def import_url
raw_data["repositoryUrls"].first
end
def issues
raw_data["issues"] && raw_data["issues"]["items"]
end
end
end
end
......@@ -15,7 +15,6 @@ module Gitlab
ImportSource.new('bitbucket', 'Bitbucket Cloud', Gitlab::BitbucketImport::Importer),
ImportSource.new('bitbucket_server', 'Bitbucket Server', Gitlab::BitbucketServerImport::Importer),
ImportSource.new('gitlab', 'GitLab.com', Gitlab::GitlabImport::Importer),
ImportSource.new('google_code', 'Google Code', Gitlab::GoogleCodeImport::Importer),
ImportSource.new('fogbugz', 'FogBugz', Gitlab::FogbugzImport::Importer),
ImportSource.new('git', 'Repo by URL', nil),
ImportSource.new('gitlab_project', 'GitLab export', Gitlab::ImportExport::Importer),
......
......@@ -370,18 +370,6 @@ msgstr ""
msgid "%{authorsName}'s thread"
msgstr ""
msgid "%{code_open}\"johnsmith@example.com\": \"@johnsmith\"%{code_close} will add \"By %{link_open}@johnsmith%{link_close}\" to all issues and comments originally created by johnsmith@example.com, and will set %{link_open}@johnsmith%{link_close} as the assignee on all issues originally assigned to johnsmith@example.com."
msgstr ""
msgid "%{code_open}\"johnsmith@example.com\": \"John Smith\"%{code_close} will add \"By John Smith\" to all issues and comments originally created by johnsmith@example.com."
msgstr ""
msgid "%{code_open}\"johnsmith@example.com\": \"johnsm...@example.com\"%{code_close} will add \"By johnsm...@example.com\" to all issues and comments originally created by johnsmith@example.com. The email address or username is masked to ensure the user's privacy."
msgstr ""
msgid "%{code_open}\"johnsmith@example.com\": \"johnsmith@example.com\"%{code_close} will add \"By %{link_open}johnsmith@example.com%{link_close}\" to all issues and comments originally created by johnsmith@example.com. By default, the email address or username is masked to ensure the user's privacy. Use this option if you want to show the full email address."
msgstr ""
msgid "%{code_open}Masked%{code_close} variables are hidden in job logs (though they must match certain regexp requirements to do so)."
msgstr ""
......@@ -623,9 +611,6 @@ msgstr ""
msgid "%{listToShow}, and %{awardsListLength} more."
msgstr ""
msgid "%{loadingIcon} Started"
msgstr ""
msgid "%{location} is missing required keys: %{keys}"
msgstr ""
......@@ -3128,9 +3113,6 @@ msgstr ""
msgid "An error occurred while getting projects"
msgstr ""
msgid "An error occurred while importing project: %{details}"
msgstr ""
msgid "An error occurred while initializing path locks"
msgstr ""
......@@ -5361,12 +5343,6 @@ msgstr ""
msgid "Chinese language support using"
msgstr ""
msgid "Choose %{strong_open}Create archive%{strong_close} and wait for archiving to complete."
msgstr ""
msgid "Choose %{strong_open}Next%{strong_close} at the bottom of the page."
msgstr ""
msgid "Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request."
msgstr ""
......@@ -5619,12 +5595,6 @@ msgstr ""
msgid "Click %{link_to} to view the request."
msgstr ""
msgid "Click the %{strong_open}Download%{strong_close} button and wait for downloading to complete."
msgstr ""
msgid "Click the %{strong_open}Select none%{strong_close} button on the right, since we only need \"Google Code Project Hosting\"."
msgstr ""
msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
msgstr ""
......@@ -8260,9 +8230,6 @@ msgstr ""
msgid "Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import."
msgstr ""
msgid "Customize how Google Code email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import."
msgstr ""
msgid "Customize icon"
msgstr ""
......@@ -8823,9 +8790,6 @@ msgstr ""
msgid "Default stages"
msgstr ""
msgid "Default: Directly import the Google Code email address or username"
msgstr ""
msgid "Default: Map a FogBugz account ID to a full name"
msgstr ""
......@@ -9803,9 +9767,6 @@ msgstr ""
msgid "Do not display offers from third parties within GitLab"
msgstr ""
msgid "Do you want to customize how Google Code email addresses and usernames are imported into GitLab?"
msgstr ""
msgid "Dockerfile"
msgstr ""
......@@ -12073,12 +12034,6 @@ msgstr ""
msgid "Find file"
msgstr ""
msgid "Find the downloaded ZIP file and decompress it."
msgstr ""
msgid "Find the newly extracted %{code_open}Takeout/Google Code Project Hosting/GoogleCodeProjectHosting.json%{code_close} file."
msgstr ""
msgid "Fingerprint"
msgstr ""
......@@ -12148,9 +12103,6 @@ msgstr ""
msgid "Folder/%{name}"
msgstr ""
msgid "Follow the steps below to export your Google Code project data."
msgstr ""
msgid "Font Color"
msgstr ""
......@@ -12262,9 +12214,6 @@ msgstr ""
msgid "From %{providerTitle}"
msgstr ""
msgid "From Google Code"
msgstr ""
msgid "From issue creation until deploy to production"
msgstr ""
......@@ -13003,9 +12952,6 @@ msgstr ""
msgid "Go full screen"
msgstr ""
msgid "Go to %{link_to_google_takeout}."
msgstr ""
msgid "Go to %{strongStart}Issues%{strongEnd} &gt; %{strongStart}Boards%{strongEnd} to access your personalized learning issue board."
msgstr ""
......@@ -13120,12 +13066,6 @@ msgstr ""
msgid "Google Cloud Platform"
msgstr ""
msgid "Google Code import"
msgstr ""
msgid "Google Takeout"
msgstr ""
msgid "Google authentication is not %{link_start}properly configured%{link_end}. Ask your GitLab administrator if you want to use this service."
msgstr ""
......@@ -14205,12 +14145,6 @@ msgstr ""
msgid "Import Projects from Gitea"
msgstr ""
msgid "Import all compatible projects"
msgstr ""
msgid "Import all projects"
msgstr ""
msgid "Import an exported GitLab project"
msgstr ""
......@@ -14262,9 +14196,6 @@ msgstr ""
msgid "Import projects from GitLab.com"
msgstr ""
msgid "Import projects from Google Code"
msgstr ""
msgid "Import repositories from Bitbucket Server"
msgstr ""
......@@ -14364,9 +14295,6 @@ msgstr ""
msgid "In progress"
msgstr ""
msgid "In the next step, you'll be able to select the projects you want to import."
msgstr ""
msgid "Incident"
msgstr ""
......@@ -14544,9 +14472,6 @@ msgstr ""
msgid "Incoming!"
msgstr ""
msgid "Incompatible Project"
msgstr ""
msgid "Incompatible options set!"
msgstr ""
......@@ -16030,9 +15955,6 @@ msgstr ""
msgid "Leave project"
msgstr ""
msgid "Leave the \"File type\" and \"Delivery method\" options on their default values."
msgstr ""
msgid "Leave zen mode"
msgstr ""
......@@ -16488,9 +16410,6 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
msgid "Make sure you're logged into the account that owns the projects you'd like to import."
msgstr ""
msgid "Make this epic confidential"
msgstr ""
......@@ -16554,15 +16473,6 @@ msgstr ""
msgid "Map a FogBugz account ID to a GitLab user"
msgstr ""
msgid "Map a Google Code user to a GitLab user"
msgstr ""
msgid "Map a Google Code user to a full email address"
msgstr ""
msgid "Map a Google Code user to a full name"
msgstr ""
msgid "Mar"
msgstr ""
......@@ -18736,9 +18646,6 @@ msgstr ""
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} to renew your subscription."
msgstr ""
msgid "No, directly import the existing email addresses and usernames."
msgstr ""
msgid "No. of commits"
msgstr ""
......@@ -19125,9 +19032,6 @@ msgstr ""
msgid "One or more of your %{provider} projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
msgstr ""
msgid "One or more of your Google Code projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
msgstr ""
msgid "One or more of your dependency files are not supported, and the dependency list may be incomplete. Below is a list of supported file types."
msgstr ""
......@@ -19278,9 +19182,6 @@ msgstr ""
msgid "Optionally, you can %{link_to_customize} how FogBugz email addresses and usernames are imported into GitLab."
msgstr ""
msgid "Optionally, you can %{link_to_customize} how Google Code email addresses and usernames are imported into GitLab."
msgstr ""
msgid "Options"
msgstr ""
......@@ -20313,9 +20214,6 @@ msgstr ""
msgid "Please convert %{linkStart}them to Git%{linkEnd}, and go through the %{linkToImportFlow} again."
msgstr ""
msgid "Please convert them to Git on Google Code, and go through the %{link_to_import_flow} again."
msgstr ""
msgid "Please create a password for your new account."
msgstr ""
......@@ -23799,9 +23697,6 @@ msgstr ""
msgid "Scroll down"
msgstr ""
msgid "Scroll down to %{strong_open}Google Code Project Hosting%{strong_close} and enable the switch on the right."
msgstr ""
msgid "Scroll left"
msgstr ""
......@@ -24504,9 +24399,6 @@ msgstr ""
msgid "Select projects"
msgstr ""
msgid "Select projects you want to import."
msgstr ""
msgid "Select required regulatory standard"
msgstr ""
......@@ -27057,9 +26949,6 @@ msgstr ""
msgid "The download link will expire in 24 hours."
msgstr ""
msgid "The entered user map is not a valid JSON user map."
msgstr ""
msgid "The errors we encountered were:"
msgstr ""
......@@ -27329,9 +27218,6 @@ msgstr ""
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
msgid "The uploaded file is not a valid Google Takeout archive."
msgstr ""
msgid "The usage ping is disabled, and cannot be configured through this form."
msgstr ""
......@@ -27341,9 +27227,6 @@ msgstr ""
msgid "The user map has been saved. Continue by selecting the projects you want to import."
msgstr ""
msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of %{code_open}:%{code_close}. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side."
msgstr ""
msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
msgstr ""
......@@ -29388,9 +29271,6 @@ msgstr ""
msgid "Upgrade your plan to improve Merge Requests."
msgstr ""
msgid "Upload %{code_open}GoogleCodeProjectHosting.json%{code_close} here:"
msgstr ""
msgid "Upload CSV file"
msgstr ""
......@@ -30972,9 +30852,6 @@ msgstr ""
msgid "Yes, delete project"
msgstr ""
msgid "Yes, let me map Google Code users to full names or GitLab users."
msgstr ""
msgid "Yesterday"
msgstr ""
......@@ -31404,9 +31281,6 @@ msgstr ""
msgid "You need to upload a GitLab project export archive (ending in .gz)."
msgstr ""
msgid "You need to upload a Google Takeout archive."
msgstr ""
msgid "You successfully declined the invitation"
msgstr ""
......@@ -32122,9 +31996,6 @@ msgstr ""
msgid "committed"
msgstr ""
msgid "connecting"
msgstr ""
msgid "container_name can contain only lowercase letters, digits, '-', and '.' and must start and end with an alphanumeric character"
msgstr ""
......@@ -32140,9 +32011,6 @@ msgstr ""
msgid "created %{timeAgo}"
msgstr ""
msgid "customize"
msgstr ""
msgid "data"
msgstr ""
......@@ -32181,9 +32049,6 @@ msgstr ""
msgid "does not have a supported extension. Only %{extension_list} are supported"
msgstr ""
msgid "done"
msgstr ""
msgid "download it"
msgstr ""
......@@ -32322,9 +32187,6 @@ msgstr ""
msgid "import flow"
msgstr ""
msgid "importing"
msgstr ""
msgid "in group %{link_to_group}"
msgstr ""
......@@ -33098,9 +32960,6 @@ msgstr ""
msgid "ssh:"
msgstr ""
msgid "started"
msgstr ""
msgid "started a discussion on %{design_link}"
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Import::GoogleCodeController do
include ImportSpecHelper
let(:user) { create(:user) }
let(:dump_file) { fixture_file_upload('spec/fixtures/GoogleCodeProjectHosting.json', 'application/json') }
before do
sign_in(user)
end
describe "POST callback" do
it "stores Google Takeout dump list in session" do
post :callback, params: { dump_file: dump_file }
expect(session[:google_code_dump]).to be_a(Hash)
expect(session[:google_code_dump]["kind"]).to eq("projecthosting#user")
expect(session[:google_code_dump]).to have_key("projects")
end
end
describe "GET status" do
before do
@repo = OpenStruct.new(name: 'vim')
stub_client(valid?: true)
end
it "assigns variables" do
@project = create(:project, import_type: 'google_code', creator_id: user.id)
stub_client(repos: [@repo], incompatible_repos: [])
get :status
expect(assigns(:already_added_projects)).to eq([@project])
expect(assigns(:repos)).to eq([@repo])
expect(assigns(:incompatible_repos)).to eq([])
end
it "does not show already added project" do
@project = create(:project, import_type: 'google_code', creator_id: user.id, import_source: 'vim')
stub_client(repos: [@repo], incompatible_repos: [])
get :status
expect(assigns(:already_added_projects)).to eq([@project])
expect(assigns(:repos)).to eq([])
end
it "does not show any invalid projects" do
stub_client(repos: [], incompatible_repos: [@repo])
get :status
expect(assigns(:repos)).to be_empty
expect(assigns(:incompatible_repos)).to eq([@repo])
end
end
describe "POST create" do
it_behaves_like 'project import rate limiter'
end
end
......@@ -56,7 +56,6 @@ RSpec.describe 'New project', :js do
expect(page).to have_link('GitHub')
expect(page).to have_link('Bitbucket')
expect(page).to have_link('GitLab.com')
expect(page).to have_link('Google Code')
expect(page).to have_button('Repo by URL')
expect(page).to have_link('GitLab export')
end
......@@ -292,17 +291,6 @@ RSpec.describe 'New project', :js do
end
end
context 'from Google Code' do
before do
first('.import_google_code').click
end
it 'shows import instructions' do
expect(page).to have_content('Import projects from Google Code')
expect(current_path).to eq new_import_google_code_path
end
end
context 'from manifest file' do
before do
first('.import_manifest').click
......
import MockAdapter from 'axios-mock-adapter';
import { ImporterStatus } from '~/importer_status';
import axios from '~/lib/utils/axios_utils';
describe('Importer Status', () => {
let instance;
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('addToImport', () => {
const importUrl = '/import_url';
const fixtures = `
<table>
<tr id="repo_123">
<td class="import-target"></td>
<td class="import-actions job-status">
<button name="button" type="submit" class="btn btn-import js-add-to-import">
</button>
</td>
</tr>
</table>
`;
beforeEach(() => {
setFixtures(fixtures);
jest.spyOn(ImporterStatus.prototype, 'initStatusPage').mockImplementation(() => {});
jest.spyOn(ImporterStatus.prototype, 'setAutoUpdate').mockImplementation(() => {});
instance = new ImporterStatus({
jobsUrl: '',
importUrl,
});
});
it('sets table row to active after post request', done => {
mock.onPost(importUrl).reply(200, {
id: 1,
full_path: '/full_path',
});
instance
.addToImport({
currentTarget: document.querySelector('.js-add-to-import'),
})
.then(() => {
expect(document.querySelector('tr').classList.contains('table-active')).toEqual(true);
done();
})
.catch(done.fail);
});
it('shows error message after failed POST request', done => {
setFixtures(`${fixtures}<div class="flash-container"></div>`);
mock.onPost(importUrl).reply(422, {
errors: 'You forgot your lunch',
});
instance
.addToImport({
currentTarget: document.querySelector('.js-add-to-import'),
})
.then(() => {
const flashMessage = document.querySelector('.flash-text');
expect(flashMessage.textContent.trim()).toEqual(
'An error occurred while importing project: You forgot your lunch',
);
done();
})
.catch(done.fail);
});
});
describe('autoUpdate', () => {
const jobsUrl = '/jobs_url';
beforeEach(() => {
const div = document.createElement('div');
div.innerHTML = `
<div id="project_1">
<div class="job-status">
</div>
</div>
`;
document.body.appendChild(div);
jest.spyOn(ImporterStatus.prototype, 'initStatusPage').mockImplementation(() => {});
jest.spyOn(ImporterStatus.prototype, 'setAutoUpdate').mockImplementation(() => {});
instance = new ImporterStatus({
jobsUrl,
});
});
function setupMock(importStatus) {
mock.onGet(jobsUrl).reply(200, [
{
id: 1,
import_status: importStatus,
},
]);
}
function expectJobStatus(done, status) {
instance
.autoUpdate()
.then(() => {
expect(document.querySelector('#project_1').innerText.trim()).toEqual(status);
done();
})
.catch(done.fail);
}
it('sets the job status to done', done => {
setupMock('finished');
expectJobStatus(done, 'Done');
});
it('sets the job status to scheduled', done => {
setupMock('scheduled');
expectJobStatus(done, 'Scheduled');
});
it('sets the job status to started', done => {
setupMock('started');
expectJobStatus(done, 'Started');
});
it('sets the job status to custom status', done => {
setupMock('custom status');
expectJobStatus(done, 'custom status');
});
});
});
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Gitlab::GoogleCodeImport::Client do
let(:raw_data) { Gitlab::Json.parse(fixture_file("GoogleCodeProjectHosting.json")) }
subject { described_class.new(raw_data) }
describe "#valid?" do
context "when the data is valid" do
it "returns true" do
expect(subject).to be_valid
end
end
context "when the data is invalid" do
let(:raw_data) { "No clue" }
it "returns true" do
expect(subject).not_to be_valid
end
end
end
describe "#repos" do
it "returns only Git repositories" do
expect(subject.repos.length).to eq(1)
expect(subject.incompatible_repos.length).to eq(1)
end
end
describe "#repo" do
it "returns the referenced repository" do
expect(subject.repo("tint2").name).to eq("tint2")
end
end
end
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Gitlab::GoogleCodeImport::Importer do
let(:mapped_user) { create(:user, username: "thilo123") }
let(:raw_data) { Gitlab::Json.parse(fixture_file("GoogleCodeProjectHosting.json")) }
let(:client) { Gitlab::GoogleCodeImport::Client.new(raw_data) }
let(:import_data) do
{
'repo' => client.repo('tint2').raw_data,
'user_map' => { 'thilo...' => "@#{mapped_user.username}" }
}
end
let(:project) { create(:project) }
subject { described_class.new(project) }
before do
project.add_maintainer(project.creator)
project.create_import_data(data: import_data)
end
describe "#execute" do
it "imports status labels" do
subject.execute
%w(New NeedInfo Accepted Wishlist Started Fixed Invalid Duplicate WontFix Incomplete).each do |status|
expect(project.labels.find_by(name: "Status: #{status}")).not_to be_nil
end
end
it "imports labels" do
subject.execute
%w(
Type-Defect Type-Enhancement Type-Task Type-Review Type-Other Milestone-0.12 Priority-Critical
Priority-High Priority-Medium Priority-Low OpSys-All OpSys-Windows OpSys-Linux OpSys-OSX Security
Performance Usability Maintainability Component-Panel Component-Taskbar Component-Battery
Component-Systray Component-Clock Component-Launcher Component-Tint2conf Component-Docs Component-New
).each do |label|
label = label.sub("-", ": ")
expect(project.labels.find_by(name: label)).not_to be_nil
end
end
it "imports issues" do
subject.execute
issue = project.issues.first
expect(issue).not_to be_nil
expect(issue.iid).to eq(169)
expect(issue.author).to eq(project.creator)
expect(issue.assignees).to eq([mapped_user])
expect(issue.state).to eq("closed")
expect(issue.label_names).to include("Priority: Medium")
expect(issue.label_names).to include("Status: Fixed")
expect(issue.label_names).to include("Type: Enhancement")
expect(issue.title).to eq("Scrolling through tasks")
expect(issue.state).to eq("closed")
expect(issue.description).to include("schattenpr\\.\\.\\.")
expect(issue.description).to include("November 18, 2009 00:20")
expect(issue.description).to include("Google Code")
expect(issue.description).to include('I like to scroll through the tasks with my scrollwheel (like in fluxbox).')
expect(issue.description).to include('Patch is attached that adds two new mouse-actions (next_task+prev_task)')
expect(issue.description).to include('that can be used for exactly that purpose.')
expect(issue.description).to include('all the best!')
expect(issue.description).to include('[tint2_task_scrolling.diff](https://storage.googleapis.com/google-code-attachments/tint2/issue-169/comment-0/tint2_task_scrolling.diff)')
expect(issue.description).to include('![screenshot.png](https://storage.googleapis.com/google-code-attachments/tint2/issue-169/comment-0/screenshot.png)')
expect(issue.description).to include('![screenshot1.PNG](https://storage.googleapis.com/google-code-attachments/tint2/issue-169/comment-0/screenshot1.PNG)')
end
it "imports issue comments" do
subject.execute
note = project.issues.first.notes.first
expect(note).not_to be_nil
expect(note.note).to include("Comment 1")
expect(note.note).to include("@#{mapped_user.username}")
expect(note.note).to include("November 18, 2009 05:14")
expect(note.note).to include("applied, thanks.")
expect(note.note).to include("Status: Fixed")
expect(note.note).to include("~~Type: Defect~~")
expect(note.note).to include("Type: Enhancement")
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::GoogleCodeImport::ProjectCreator do
let(:user) { create(:user) }
let(:repo) do
Gitlab::GoogleCodeImport::Repository.new(
"name" => 'vim',
"summary" => 'VI Improved',
"repositoryUrls" => ["https://vim.googlecode.com/git/"]
)
end
let(:namespace) { create(:group) }
before do
namespace.add_owner(user)
end
it 'creates project' do
expect_next_instance_of(Project) do |project|
expect(project).to receive(:add_import_job)
end
project_creator = described_class.new(repo, namespace, user)
project = project_creator.execute
expect(project.import_url).to eq("https://vim.googlecode.com/git/")
expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
end
......@@ -11,7 +11,6 @@ RSpec.describe Gitlab::ImportSources do
'Bitbucket Cloud' => 'bitbucket',
'Bitbucket Server' => 'bitbucket_server',
'GitLab.com' => 'gitlab',
'Google Code' => 'google_code',
'FogBugz' => 'fogbugz',
'Repo by URL' => 'git',
'GitLab export' => 'gitlab_project',
......@@ -32,7 +31,6 @@ RSpec.describe Gitlab::ImportSources do
bitbucket
bitbucket_server
gitlab
google_code
fogbugz
git
gitlab_project
......@@ -53,7 +51,6 @@ RSpec.describe Gitlab::ImportSources do
bitbucket
bitbucket_server
gitlab
google_code
fogbugz
gitlab_project
gitea
......@@ -70,7 +67,6 @@ RSpec.describe Gitlab::ImportSources do
'bitbucket' => Gitlab::BitbucketImport::Importer,
'bitbucket_server' => Gitlab::BitbucketServerImport::Importer,
'gitlab' => Gitlab::GitlabImport::Importer,
'google_code' => Gitlab::GoogleCodeImport::Importer,
'fogbugz' => Gitlab::FogbugzImport::Importer,
'git' => nil,
'gitlab_project' => Gitlab::ImportExport::Importer,
......@@ -92,7 +88,6 @@ RSpec.describe Gitlab::ImportSources do
'bitbucket' => 'Bitbucket Cloud',
'bitbucket_server' => 'Bitbucket Server',
'gitlab' => 'GitLab.com',
'google_code' => 'Google Code',
'fogbugz' => 'FogBugz',
'git' => 'Repo by URL',
'gitlab_project' => 'GitLab export',
......
......@@ -126,32 +126,6 @@ RSpec.describe Import::BitbucketServerController, 'routing' do
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
RSpec.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
# realtime_changes_import_fogbugz GET /import/fogbugz/realtime_changes(.:format) import/fogbugz#realtime_changes
......
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