summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile6
-rw-r--r--Gemfile.lock20
-rw-r--r--app/assets/javascripts/groups_select.js3
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss5
-rw-r--r--app/assets/stylesheets/framework/lists.scss2
-rw-r--r--app/assets/stylesheets/framework/typography.scss3
-rw-r--r--app/assets/stylesheets/new_sidebar.scss11
-rw-r--r--app/assets/stylesheets/pages/issuable.scss2
-rw-r--r--app/models/concerns/referable.rb9
-rw-r--r--app/models/project.rb30
-rw-r--r--app/models/user.rb5
-rw-r--r--app/views/admin/users/_user.html.haml3
-rw-r--r--app/views/profiles/accounts/show.html.haml37
-rw-r--r--app/views/projects/_project_templates.html.haml2
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/shared/_import_form.html.haml2
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml2
-rw-r--r--app/workers/namespaceless_project_destroy_worker.rb4
-rw-r--r--app/workers/repository_fork_worker.rb16
-rw-r--r--app/workers/repository_import_worker.rb24
-rw-r--r--app/workers/stuck_import_jobs_worker.rb50
-rw-r--r--changelogs/unreleased/35072-fix-pages-delete.yml5
-rw-r--r--changelogs/unreleased/36087-users-cannot-delete-their-account.yml5
-rw-r--r--changelogs/unreleased/issue_35580.yml4
-rw-r--r--changelogs/unreleased/zj-upgrade-grape.yml5
-rw-r--r--doc/README.md2
-rw-r--r--doc/articles/index.md105
-rw-r--r--doc/articles/numerous_undo_possibilities_in_git/img/branching.pngbin0 -> 26245 bytes
-rw-r--r--doc/articles/numerous_undo_possibilities_in_git/img/rebase_reset.pngbin0 -> 43609 bytes
-rw-r--r--doc/articles/numerous_undo_possibilities_in_git/img/revert.pngbin0 -> 28112 bytes
-rw-r--r--doc/articles/numerous_undo_possibilities_in_git/index.md497
-rw-r--r--doc/ci/docker/using_docker_images.md40
-rw-r--r--doc/gitlab-basics/create-project.md12
-rw-r--r--doc/topics/git/index.md1
-rw-r--r--doc/user/group/index.md7
-rw-r--r--doc/user/group/subgroups/index.md7
-rw-r--r--doc/user/project/import/bitbucket.md62
-rw-r--r--doc/user/project/import/fogbugz.md28
-rw-r--r--doc/user/project/import/gitea.md77
-rw-r--r--doc/user/project/import/github.md122
-rw-r--r--doc/user/project/import/gitlab_com.md20
-rw-r--r--doc/user/project/import/img/bitbucket_import_grant_access.png (renamed from doc/workflow/importing/img/bitbucket_import_grant_access.png)bin7248 -> 7248 bytes
-rw-r--r--doc/user/project/import/img/bitbucket_import_new_project.png (renamed from doc/workflow/importing/img/bitbucket_import_new_project.png)bin1316 -> 1316 bytes
-rw-r--r--doc/user/project/import/img/bitbucket_import_select_project.png (renamed from doc/workflow/importing/img/bitbucket_import_select_project.png)bin8688 -> 8688 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_finished.png (renamed from doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png)bin17744 -> 17744 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_login.png (renamed from doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png)bin13751 -> 13751 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_select_fogbogz.png (renamed from doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png)bin12289 -> 12289 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_select_project.png (renamed from doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png)bin20905 -> 20905 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_user_map.png (renamed from doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png)bin51238 -> 51238 bytes
-rw-r--r--doc/user/project/import/img/gitlab_importer.png (renamed from doc/workflow/importing/gitlab_importer/importer.png)bin12864 -> 12864 bytes
-rw-r--r--doc/user/project/import/img/gitlab_new_project_page.png (renamed from doc/workflow/importing/gitlab_importer/new_project_page.png)bin21251 -> 21251 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_gitea_new_import.png (renamed from doc/workflow/importing/img/import_projects_from_gitea_new_import.png)bin15561 -> 15561 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_github_importer.png (renamed from doc/workflow/importing/img/import_projects_from_github_importer.png)bin17953 -> 17953 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_github_select_auth_method.png (renamed from doc/workflow/importing/img/import_projects_from_github_select_auth_method.png)bin17612 -> 17612 bytes
-rw-r--r--doc/user/project/import/img/import_projects_from_new_project_page.png (renamed from doc/workflow/importing/img/import_projects_from_new_project_page.png)bin36821 -> 36821 bytes
-rw-r--r--doc/user/project/import/index.md20
-rw-r--r--doc/user/project/import/svn.md183
-rw-r--r--doc/user/project/index.md10
-rw-r--r--doc/user/reserved_names.md109
-rw-r--r--doc/workflow/importing/README.md18
-rw-r--r--doc/workflow/importing/import_projects_from_bitbucket.md63
-rw-r--r--doc/workflow/importing/import_projects_from_fogbugz.md30
-rw-r--r--doc/workflow/importing/import_projects_from_gitea.md78
-rw-r--r--doc/workflow/importing/import_projects_from_github.md123
-rw-r--r--doc/workflow/importing/import_projects_from_gitlab_com.md22
-rw-r--r--doc/workflow/importing/migrating_from_svn.md184
-rw-r--r--lib/after_commit_queue.rb30
-rw-r--r--lib/api/helpers.rb2
-rw-r--r--lib/api/jobs.rb4
-rw-r--r--lib/api/templates.rb6
-rw-r--r--lib/api/v3/builds.rb2
-rw-r--r--lib/api/v3/templates.rb6
-rw-r--r--lib/gitlab/gitaly_client/blob_service.rb13
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb18
-rw-r--r--lib/gitlab/import_export/project_tree_restorer.rb21
-rw-r--r--lib/gitlab/sidekiq_status.rb9
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/features/profile_spec.rb15
-rw-r--r--spec/features/projects_spec.rb2
-rw-r--r--spec/lib/after_commit_queue_spec.rb15
-rw-r--r--spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb21
-rw-r--r--spec/lib/gitlab/import_export/project.light.json100
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb38
-rw-r--r--spec/migrations/README.md10
-rw-r--r--spec/models/project_spec.rb65
-rw-r--r--spec/spec_helper.rb13
-rw-r--r--spec/support/db_cleaner.rb2
-rw-r--r--spec/support/migrations_helpers.rb29
-rw-r--r--spec/workers/repository_import_worker_spec.rb2
-rw-r--r--spec/workers/stuck_import_jobs_worker_spec.rb34
90 files changed, 1734 insertions, 802 deletions
diff --git a/Gemfile b/Gemfile
index d10269d7aac..62d6b1e6446 100644
--- a/Gemfile
+++ b/Gemfile
@@ -16,7 +16,7 @@ gem 'mysql2', '~> 0.4.5', group: :mysql
gem 'pg', '~> 0.18.2', group: :postgres
gem 'rugged', '~> 0.26.0'
-gem 'grape-route-helpers', '~> 2.0.0'
+gem 'grape-route-helpers', '~> 2.1.0'
gem 'faraday', '~> 0.12'
@@ -76,7 +76,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.4', require: false
gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API
-gem 'grape', '~> 0.19.2'
+gem 'grape', '~> 1.0'
gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
@@ -144,8 +144,6 @@ end
# State machine
gem 'state_machines-activerecord', '~> 0.4.0'
-# Run events after state machine commits
-gem 'after_commit_queue', '~> 1.3.0'
# Issue tags
gem 'acts-as-taggable-on', '~> 4.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index f7ad7bcbc6e..ae1df783a80 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -46,8 +46,6 @@ GEM
ice_nine (~> 0.11.0)
memoizable (~> 0.4.0)
addressable (2.3.8)
- after_commit_queue (1.3.0)
- activerecord (>= 3.0)
akismet (2.0.0)
allocations (1.0.5)
arel (6.0.4)
@@ -342,12 +340,9 @@ GEM
signet (~> 0.7)
gpgme (2.0.13)
mini_portile2 (~> 2.1)
- grape (0.19.2)
+ grape (1.0.0)
activesupport
builder
- hashie (>= 2.1.0)
- multi_json (>= 1.3.2)
- multi_xml (>= 0.5.2)
mustermann-grape (~> 1.0.0)
rack (>= 1.3.0)
rack-accept
@@ -355,11 +350,11 @@ GEM
grape-entity (0.6.0)
activesupport
multi_json (>= 1.3.2)
- grape-route-helpers (2.0.0)
+ grape-route-helpers (2.1.0)
activesupport
- grape (~> 0.16, >= 0.16.0)
+ grape (>= 0.16.0)
rake
- grpc (1.4.0)
+ grpc (1.4.5)
google-protobuf (~> 3.1)
googleauth (~> 0.5.1)
haml (4.0.7)
@@ -375,7 +370,7 @@ GEM
thor
tilt
hashdiff (0.3.4)
- hashie (3.5.5)
+ hashie (3.5.6)
hashie-forbidden_attributes (0.1.1)
hashie (>= 3.0)
health_check (2.6.0)
@@ -963,7 +958,6 @@ DEPENDENCIES
activerecord_sane_schema_dumper (= 0.2)
acts-as-taggable-on (~> 4.0)
addressable (~> 2.3.8)
- after_commit_queue (~> 1.3.0)
akismet (~> 2.0)
allocations (~> 1.0)
asana (~> 0.6.0)
@@ -1035,9 +1029,9 @@ DEPENDENCIES
gon (~> 6.1.0)
google-api-client (~> 0.8.6)
gpgme
- grape (~> 0.19.2)
+ grape (~> 1.0)
grape-entity (~> 0.6.0)
- grape-route-helpers (~> 2.0.0)
+ grape-route-helpers (~> 2.1.0)
haml_lint (~> 0.26.0)
hamlit (~> 2.6.1)
hashie-forbidden_attributes
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index b5975295329..4d629bc6326 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -111,8 +111,7 @@ window.GroupsSelect = (function() {
};
GroupsSelect.prototype.forceOverflow = function (e) {
- const itemHeight = this.dropdown.querySelector('.select2-result:first-child').clientHeight;
- this.dropdown.style.height = `${Math.floor(this.dropdown.scrollHeight - (itemHeight * 0.9))}px`;
+ this.dropdown.style.height = `${Math.floor(this.dropdown.scrollHeight)}px`;
};
GroupsSelect.PER_PAGE = 20;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 1bb04b59a2a..958159b507a 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -743,6 +743,11 @@
border-radius: 0;
padding: 8px 16px;
+ // make sure the text color is not overriden
+ &.text-danger {
+ @extend .text-danger;
+ }
+
&.is-focused,
&:hover,
&:active,
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index ab754f4a492..df2bf561194 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -132,6 +132,8 @@ ul.content-list {
}
.controls {
+ @include new-style-dropdown;
+
float: right;
> .control-text {
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 96409b10b99..0bd84c9e08c 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -18,7 +18,8 @@
background-color: $gray-lightest;
}
- img.js-lazy-loaded {
+ img.js-lazy-loaded,
+ img.emoji {
min-width: inherit;
min-height: inherit;
background-color: inherit;
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index d078c8b956b..cee5b22adb9 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -103,7 +103,10 @@ $new-sidebar-collapsed-width: 50px;
&.sidebar-icons-only {
width: $new-sidebar-collapsed-width;
- overflow-x: hidden;
+
+ .nav-sidebar-inner-scroll {
+ overflow-x: hidden;
+ }
.badge,
.project-title {
@@ -111,7 +114,11 @@ $new-sidebar-collapsed-width: 50px;
}
.nav-item-name {
- opacity: 0;
+ display: none;
+ }
+
+ .sidebar-top-level-items > li > a {
+ min-height: 44px;
}
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 1dac38f2b6d..49839a9b528 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -260,7 +260,7 @@
padding-top: 10px;
}
- &:not(.issue-boards-sidebar):not([data-signed-in]) {
+ &:not(.issue-boards-sidebar):not([data-signed-in]):not([data-always-show-toggle]) {
.issuable-sidebar-header {
display: none;
}
diff --git a/app/models/concerns/referable.rb b/app/models/concerns/referable.rb
index 10f4be72016..78ac4f324e7 100644
--- a/app/models/concerns/referable.rb
+++ b/app/models/concerns/referable.rb
@@ -25,6 +25,11 @@ module Referable
to_reference(from_project)
end
+ included do
+ alias_method :non_referable_inspect, :inspect
+ alias_method :inspect, :referable_inspect
+ end
+
def referable_inspect
if respond_to?(:id)
"#<#{self.class.name} id:#{id} #{to_reference(full: true)}>"
@@ -33,10 +38,6 @@ module Referable
end
end
- def inspect
- referable_inspect
- end
-
module ClassMethods
# The character that prefixes the actual reference identifier
#
diff --git a/app/models/project.rb b/app/models/project.rb
index 22b347cc8f9..be248bc99e1 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -60,7 +60,7 @@ class Project < ActiveRecord::Base
end
before_destroy :remove_private_deploy_keys
- after_destroy :remove_pages
+ after_destroy -> { run_after_commit { remove_pages } }
# update visibility_level of forks
after_update :update_forks_visibility_level
@@ -369,7 +369,10 @@ class Project < ActiveRecord::Base
state :failed
after_transition [:none, :finished, :failed] => :scheduled do |project, _|
- project.run_after_commit { add_import_job }
+ project.run_after_commit do
+ job_id = add_import_job
+ update(import_jid: job_id) if job_id
+ end
end
after_transition started: :finished do |project, _|
@@ -524,17 +527,26 @@ class Project < ActiveRecord::Base
def add_import_job
job_id =
if forked?
- RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
- forked_from_project.full_path,
- self.namespace.full_path)
+ RepositoryForkWorker.perform_async(id,
+ forked_from_project.repository_storage_path,
+ forked_from_project.full_path,
+ self.namespace.full_path)
else
RepositoryImportWorker.perform_async(self.id)
end
+ log_import_activity(job_id)
+
+ job_id
+ end
+
+ def log_import_activity(job_id, type: :import)
+ job_type = type.to_s.capitalize
+
if job_id
- Rails.logger.info "Import job started for #{full_path} with job ID #{job_id}"
+ Rails.logger.info("#{job_type} job scheduled for #{full_path} with job ID #{job_id}.")
else
- Rails.logger.error "Import job failed to start for #{full_path}"
+ Rails.logger.error("#{job_type} job failed to create for #{full_path}.")
end
end
@@ -543,6 +555,7 @@ class Project < ActiveRecord::Base
ProjectCacheWorker.perform_async(self.id)
end
+ update(import_error: nil)
remove_import_data
end
@@ -1224,6 +1237,9 @@ class Project < ActiveRecord::Base
# TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
def remove_pages
+ # Projects with a missing namespace cannot have their pages removed
+ return unless namespace
+
::Projects::UpdatePagesConfigurationService.new(self).execute
# 1. We rename pages to temporary directory
diff --git a/app/models/user.rb b/app/models/user.rb
index 0e2654ff757..02c3ab6654b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -47,11 +47,6 @@ class User < ActiveRecord::Base
devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
- # devise overrides #inspect, so we manually use the Referable one
- def inspect
- referable_inspect
- end
-
# Override Devise::Models::Trackable#update_tracked_fields!
# to limit database writes to at most once every hour
def update_tracked_fields!(request)
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index 4cf4a57ba18..ca6e43e091c 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -40,9 +40,10 @@
%li
= link_to 'Remove user', admin_user_path(user),
data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" },
+ class: 'text-danger',
method: :delete
%li
= link_to 'Remove user and contributions', admin_user_path(user, hard_delete: true),
data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and comments authored by this user, and groups owned solely by them, will also be removed! Are you sure?" },
- class: 'btn btn-remove btn-block',
+ class: 'text-danger',
method: :delete
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index ed079ed7dfb..5d778d67ae7 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -92,25 +92,24 @@
Update username
%hr
-- if signup_enabled?
- .row.prepend-top-default
- .col-lg-4.profile-settings-sidebar
- %h4.prepend-top-0.danger-title
- Remove account
- .col-lg-8
- - if @user.can_be_removed? && can?(current_user, :destroy_user, @user)
+.row.prepend-top-default
+ .col-lg-4.profile-settings-sidebar
+ %h4.prepend-top-0.danger-title
+ Remove account
+ .col-lg-8
+ - if @user.can_be_removed? && can?(current_user, :destroy_user, @user)
+ %p
+ Deleting an account has the following effects:
+ = render 'users/deletion_guidance', user: current_user
+ = link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove"
+ - else
+ - if @user.solo_owned_groups.present?
%p
- Deleting an account has the following effects:
- = render 'users/deletion_guidance', user: current_user
- = link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove"
+ Your account is currently an owner in these groups:
+ %strong= @user.solo_owned_groups.map(&:name).join(', ')
+ %p
+ You must transfer ownership or delete these groups before you can delete your account.
- else
- - if @user.solo_owned_groups.present?
- %p
- Your account is currently an owner in these groups:
- %strong= @user.solo_owned_groups.map(&:name).join(', ')
- %p
- You must transfer ownership or delete these groups before you can delete your account.
- - else
- %p
- You don't have access to delete this user.
+ %p
+ You don't have access to delete this user.
.append-bottom-default
diff --git a/app/views/projects/_project_templates.html.haml b/app/views/projects/_project_templates.html.haml
index 21baf35f2ac..97cf13df070 100644
--- a/app/views/projects/_project_templates.html.haml
+++ b/app/views/projects/_project_templates.html.haml
@@ -5,6 +5,6 @@
Blank
- Gitlab::ProjectTemplate.all.each do |template|
.btn
- %input{ type: "radio", autocomplete: "off", name: "project_templates", id: template.name }
+ %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name }
= custom_icon(template.logo)
= template.title
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index e3bbebbcf4c..647e0a772b1 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -25,7 +25,7 @@
.form-group
= f.label :template_project, class: 'label-light' do
Create from template
- = link_to icon('question-circle'), help_page_path("public_access/public_access"), aria: { label: "What’s included in a template?" }, title: "What’s included in a template?", class: 'has-tooltip', data: { placement: 'top'}
+ = link_to icon('question-circle'), help_page_path("gitlab-basics/create-project"), target: '_blank', aria: { label: "What’s included in a template?" }, title: "What’s included in a template?", class: 'has-tooltip', data: { placement: 'top'}
%div
= render 'project_templates', f: f
.second-column
diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml
index 873179339dc..233d8c95eda 100644
--- a/app/views/shared/_import_form.html.haml
+++ b/app/views/shared/_import_form.html.haml
@@ -13,4 +13,4 @@
%li
The import will time out after 15 minutes. For repositories that take longer, use a clone/push combination.
%li
- To migrate an SVN repository, check out #{link_to "this document", help_page_path('workflow/importing/migrating_from_svn')}.
+ To migrate an SVN repository, check out #{link_to "this document", help_page_path('user/project/import/svn')}.
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index 66ac8196f2f..40379f48393 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -1,7 +1,7 @@
- affix_offset = local_assigns.fetch(:affix_offset, "50")
- project = local_assigns[:project]
-%aside.right-sidebar.js-right-sidebar{ data: { "offset-top" => affix_offset, "spy" => "affix" }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
+%aside.right-sidebar.js-right-sidebar{ data: { "offset-top" => affix_offset, "spy" => "affix", "always-show-toggle" => true }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
.issuable-sidebar.milestone-sidebar
.block.milestone-progress.issuable-sidebar-header
%a.gutter-toggle.pull-right.js-sidebar-toggle{ role: "button", href: "#", "aria-label" => "Toggle sidebar" }
diff --git a/app/workers/namespaceless_project_destroy_worker.rb b/app/workers/namespaceless_project_destroy_worker.rb
index bfae0c77700..a9073742ff7 100644
--- a/app/workers/namespaceless_project_destroy_worker.rb
+++ b/app/workers/namespaceless_project_destroy_worker.rb
@@ -24,10 +24,6 @@ class NamespacelessProjectDestroyWorker
unlink_fork(project) if project.forked?
- # Override Project#remove_pages for this instance so it doesn't do anything
- def project.remove_pages
- end
-
project.destroy!
end
diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb
index a338523dc6b..cde5b45ad41 100644
--- a/app/workers/repository_fork_worker.rb
+++ b/app/workers/repository_fork_worker.rb
@@ -5,14 +5,17 @@ class RepositoryForkWorker
include Gitlab::ShellAdapter
include DedicatedSidekiqQueue
+ sidekiq_options status_expiration: StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION
+
def perform(project_id, forked_from_repository_storage_path, source_path, target_path)
+ project = Project.find(project_id)
+
+ return unless start_fork(project)
+
Gitlab::Metrics.add_event(:fork_repository,
source_path: source_path,
target_path: target_path)
- project = Project.find(project_id)
- project.import_start
-
result = gitlab_shell.fork_repository(forked_from_repository_storage_path, source_path,
project.repository_storage_path, target_path)
raise ForkError, "Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}" unless result
@@ -33,6 +36,13 @@ class RepositoryForkWorker
private
+ def start_fork(project)
+ return true if project.import_start
+
+ Rails.logger.info("Project #{project.full_path} was in inconsistent state (#{project.import_status}) while forking.")
+ false
+ end
+
def fail_fork(project, message)
Rails.logger.error(message)
project.mark_import_as_failed(message)
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index 6be541abd3e..2c2d1e8b91f 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -4,23 +4,18 @@ class RepositoryImportWorker
include Sidekiq::Worker
include DedicatedSidekiqQueue
- sidekiq_options status_expiration: StuckImportJobsWorker::IMPORT_EXPIRATION
-
- attr_accessor :project, :current_user
+ sidekiq_options status_expiration: StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION
def perform(project_id)
- @project = Project.find(project_id)
- @current_user = @project.creator
+ project = Project.find(project_id)
- project.import_start
+ return unless start_import(project)
Gitlab::Metrics.add_event(:import_repository,
- import_url: @project.import_url,
- path: @project.full_path)
-
- project.update_columns(import_jid: self.jid, import_error: nil)
+ import_url: project.import_url,
+ path: project.full_path)
- result = Projects::ImportService.new(project, current_user).execute
+ result = Projects::ImportService.new(project, project.creator).execute
raise ImportError, result[:message] if result[:status] == :error
project.repository.after_import
@@ -37,6 +32,13 @@ class RepositoryImportWorker
private
+ def start_import(project)
+ return true if project.import_start
+
+ Rails.logger.info("Project #{project.full_path} was in inconsistent state (#{project.import_status}) while importing.")
+ false
+ end
+
def fail_import(project, message)
project.mark_import_as_failed(message)
end
diff --git a/app/workers/stuck_import_jobs_worker.rb b/app/workers/stuck_import_jobs_worker.rb
index bfc5e667bb6..f850e459cd9 100644
--- a/app/workers/stuck_import_jobs_worker.rb
+++ b/app/workers/stuck_import_jobs_worker.rb
@@ -2,36 +2,60 @@ class StuckImportJobsWorker
include Sidekiq::Worker
include CronjobQueue
- IMPORT_EXPIRATION = 15.hours.to_i
+ IMPORT_JOBS_EXPIRATION = 15.hours.to_i
def perform
- stuck_projects.find_in_batches(batch_size: 500) do |group|
+ projects_without_jid_count = mark_projects_without_jid_as_failed!
+ projects_with_jid_count = mark_projects_with_jid_as_failed!
+
+ Gitlab::Metrics.add_event(:stuck_import_jobs,
+ projects_without_jid_count: projects_without_jid_count,
+ projects_with_jid_count: projects_with_jid_count)
+ end
+
+ private
+
+ def mark_projects_without_jid_as_failed!
+ started_projects_without_jid.each do |project|
+ project.mark_import_as_failed(error_message)
+ end.count
+ end
+
+ def mark_projects_with_jid_as_failed!
+ completed_jids_count = 0
+
+ started_projects_with_jid.find_in_batches(batch_size: 500) do |group|
jids = group.map(&:import_jid)
# Find the jobs that aren't currently running or that exceeded the threshold.
- completed_jids = Gitlab::SidekiqStatus.completed_jids(jids)
+ completed_jids = Gitlab::SidekiqStatus.completed_jids(jids).to_set
if completed_jids.any?
- completed_ids = group.select { |project| completed_jids.include?(project.import_jid) }.map(&:id)
+ completed_jids_count += completed_jids.count
+ group.each do |project|
+ project.mark_import_as_failed(error_message) if completed_jids.include?(project.import_jid)
+ end
- fail_batch!(completed_jids, completed_ids)
+ Rails.logger.info("Marked stuck import jobs as failed. JIDs: #{completed_jids.to_a.join(', ')}")
end
end
- end
- private
+ completed_jids_count
+ end
- def stuck_projects
- Project.select('id, import_jid').with_import_status(:started).where.not(import_jid: nil)
+ def started_projects
+ Project.with_import_status(:started)
end
- def fail_batch!(completed_jids, completed_ids)
- Project.where(id: completed_ids).update_all(import_status: 'failed', import_error: error_message)
+ def started_projects_with_jid
+ started_projects.where.not(import_jid: nil)
+ end
- Rails.logger.info("Marked stuck import jobs as failed. JIDs: #{completed_jids.join(', ')}")
+ def started_projects_without_jid
+ started_projects.where(import_jid: nil)
end
def error_message
- "Import timed out. Import took longer than #{IMPORT_EXPIRATION} seconds"
+ "Import timed out. Import took longer than #{IMPORT_JOBS_EXPIRATION} seconds"
end
end
diff --git a/changelogs/unreleased/35072-fix-pages-delete.yml b/changelogs/unreleased/35072-fix-pages-delete.yml
new file mode 100644
index 00000000000..21af2bde201
--- /dev/null
+++ b/changelogs/unreleased/35072-fix-pages-delete.yml
@@ -0,0 +1,5 @@
+---
+title: Fix deleting GitLab Pages files when a project is removed
+merge_request: 13631
+author:
+type: fixed
diff --git a/changelogs/unreleased/36087-users-cannot-delete-their-account.yml b/changelogs/unreleased/36087-users-cannot-delete-their-account.yml
new file mode 100644
index 00000000000..9ba75d8b1d0
--- /dev/null
+++ b/changelogs/unreleased/36087-users-cannot-delete-their-account.yml
@@ -0,0 +1,5 @@
+---
+title: allow all users to delete their account
+merge_request: 13636
+author: Jacopo Beschi @jacopo-beschi
+type: changed
diff --git a/changelogs/unreleased/issue_35580.yml b/changelogs/unreleased/issue_35580.yml
new file mode 100644
index 00000000000..3a94e771e25
--- /dev/null
+++ b/changelogs/unreleased/issue_35580.yml
@@ -0,0 +1,4 @@
+---
+title: Fix project milestones import when projects belongs to a group
+merge_request:
+author:
diff --git a/changelogs/unreleased/zj-upgrade-grape.yml b/changelogs/unreleased/zj-upgrade-grape.yml
new file mode 100644
index 00000000000..daa6a234c07
--- /dev/null
+++ b/changelogs/unreleased/zj-upgrade-grape.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade grape to 1.0
+merge_request:
+author:
+type: other
diff --git a/doc/README.md b/doc/README.md
index 547541c4876..267487520cd 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -102,7 +102,7 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i
### Migrate and import your projects from other platforms
-- [Importing to GitLab](workflow/importing/README.md): Import your projects from GitHub, Bitbucket, GitLab.com, FogBugz and SVN into GitLab.
+- [Importing to GitLab](user/project/import/index.md): Import your projects from GitHub, Bitbucket, GitLab.com, FogBugz and SVN into GitLab.
- [Migrating from SVN](workflow/importing/migrating_from_svn.md): Convert a SVN repository to Git and GitLab.
### Continuous Integration, Delivery, and Deployment
diff --git a/doc/articles/index.md b/doc/articles/index.md
index 3039faca411..1aa65504852 100644
--- a/doc/articles/index.md
+++ b/doc/articles/index.md
@@ -17,8 +17,8 @@ Explore GitLab's supported [authentications methods](../topics/authentication/in
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
| **LDAP** |
-| [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md)| Admin guide | 2017/05/03 |
-| [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) | Admin guide | 2017/05/03 |
+| [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md)| Admin guide | 2017-05-03 |
+| [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) | Admin guide | 2017-05-03 |
## Build, test, and deploy with GitLab CI/CD
@@ -27,17 +27,17 @@ Build, test, and deploy the software you develop with [GitLab CI/CD](../ci/READM
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
| [How to deploy Maven projects to Artifactory with GitLab CI/CD](artifactory_and_gitlab/index.md) | Tutorial | 2017-08-15 |
-| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 |
-| [Dockerizing GitLab Review Apps](https://about.gitlab.com/2017/07/11/dockerizing-review-apps/) | Concepts | 2017/07/11 |
-| [Continuous Integration: From Jenkins to GitLab Using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/) | Concepts | 2017/07/27 |
-| [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) | Tutorial | 2016/12/14 |
-| [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) | Tutorial | 2016/11/30 |
-| [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) | Tutorial | 2016/10/12 |
-| [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) | Tutorial | 2016/08/11 |
-| [Continuous Delivery with GitLab and Convox](https://about.gitlab.com/2016/06/09/continuous-delivery-with-gitlab-and-convox/) | Technical overview | 2016/06/09 |
-| [GitLab Container Registry](https://about.gitlab.com/2016/05/23/gitlab-container-registry/) | Technical overview | 2016/05/23 |
-| [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) | Technical overview | 2017/05/15 |
-| [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) | Tutorial | 2016/03/10 |
+| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017-07-13 |
+| [Dockerizing GitLab Review Apps](https://about.gitlab.com/2017/07/11/dockerizing-review-apps/) | Concepts | 2017-07-11 |
+| [Continuous Integration: From Jenkins to GitLab Using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/) | Concepts | 2017-07-27 |
+| [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) | Tutorial | 2016-12-14 |
+| [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) | Tutorial | 2016-11-30 |
+| [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) | Tutorial | 2016-10-12 |
+| [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) | Tutorial | 2016-08-11 |
+| [Continuous Delivery with GitLab and Convox](https://about.gitlab.com/2016/06/09/continuous-delivery-with-gitlab-and-convox/) | Technical overview | 2016-06-09 |
+| [GitLab Container Registry](https://about.gitlab.com/2016/05/23/gitlab-container-registry/) | Technical overview | 2016-05-23 |
+| [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) | Technical overview | 2017-05-15 |
+| [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) | Tutorial | 2016-03-10 |
## Git
@@ -45,10 +45,11 @@ Learn how to use [Git with GitLab](../topics/git/index.md):
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
-| [Why Git is Worth the Learning Curve](https://about.gitlab.com/2017/05/17/learning-curve-is-the-biggest-challenge-developers-face-with-git/) | Concepts | 2017/05/17 |
-| [How to install Git](how_to_install_git/index.md) | Tutorial | 2017/05/15 |
-| [Getting Started with Git LFS](https://about.gitlab.com/2017/01/30/getting-started-with-git-lfs-tutorial/) | Tutorial | 2017/01/30 |
-| [Git Tips & Tricks](https://about.gitlab.com/2016/12/08/git-tips-and-tricks/) | Technical overview | 2016/12/08 |
+| [Numerous _undo_ possibilities in Git](numerous_undo_possibilities_in_git/index.md) | Tutorial | 2017-08-17 |
+| [Why Git is Worth the Learning Curve](https://about.gitlab.com/2017/05/17/learning-curve-is-the-biggest-challenge-developers-face-with-git/) | Concepts | 2017-05-17 |
+| [How to install Git](how_to_install_git/index.md) | Tutorial | 2017-05-15 |
+| [Getting Started with Git LFS](https://about.gitlab.com/2017/01/30/getting-started-with-git-lfs-tutorial/) | Tutorial | 2017-01-30 |
+| [Git Tips & Tricks](https://about.gitlab.com/2016/12/08/git-tips-and-tricks/) | Technical overview | 2016-12-08 |
## GitLab Pages
@@ -57,21 +58,21 @@ Learn how to deploy a static website with [GitLab Pages](../user/project/pages/i
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
| **Series: GitLab Pages from A to Z:** |
-| [- Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md)| User guide | 2017/02/22 |
-| [- Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)| User guide | 2017/02/22 |
-| [- Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)| User guide | 2017/02/22 |
-| [- Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)| User guide | 2017/02/22 |
-| [Setting up GitLab Pages with CloudFlare Certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Tutorial | 2017/02/07 |
-| [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) | Tutorial | 2016/12/07 |
-| [Publish Code Coverage Report with GitLab Pages](https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/) | Tutorial | 2016/11/03 |
-| [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) | Tutorial | 2016/08/26 |
-| [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/) | Tutorial | 2016/08/19 |
+| [- Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md)| User guide | 2017-02-22 |
+| [- Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)| User guide | 2017-02-22 |
+| [- Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)| User guide | 2017-02-22 |
+| [- Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)| User guide | 2017-02-22 |
+| [Setting up GitLab Pages with CloudFlare Certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Tutorial | 2017-02-07 |
+| [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) | Tutorial | 2016-12-07 |
+| [Publish Code Coverage Report with GitLab Pages](https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/) | Tutorial | 2016-11-03 |
+| [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) | Tutorial | 2016-08-26 |
+| [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/) | Tutorial | 2016-08-19 |
| **Series: Static Site Generator:** |
-| [- Part 1: Dynamic vs Static Websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/) | Tutorial | 2016/06/03 |
-| [- Part 2: Modern Static Site Generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/) | Tutorial | 2016/06/10 |
-| [- Part 3: Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) | Tutorial | 2016/06/17 |
-| [Securing your GitLab Pages with TLS and Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) | Tutorial | 2016/04/11 |
-| [Hosting on GitLab.com with GitLab Pages](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/) | Tutorial | 2016/04/07 |
+| [- Part 1: Dynamic vs Static Websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/) | Tutorial | 2016-06-03 |
+| [- Part 2: Modern Static Site Generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/) | Tutorial | 2016-06-10 |
+| [- Part 3: Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) | Tutorial | 2016-06-17 |
+| [Securing your GitLab Pages with TLS and Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) | Tutorial | 2016-04-11 |
+| [Hosting on GitLab.com with GitLab Pages](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/) | Tutorial | 2016-04-07 |
## Install and maintain GitLab
@@ -79,10 +80,10 @@ Install, upgrade, integrate, migrate to GitLab:
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
-| [Video Tutorial: Idea to Production on Google Container Engine (GKE)](https://about.gitlab.com/2017/01/23/video-tutorial-idea-to-production-on-google-container-engine-gke/) | Tutorial | 2017/01/23 |
-| [How to Setup a GitLab Instance on Microsoft Azure](https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) | Tutorial | 2016/07/13 |
-| [Get started with OpenShift Origin 3 and GitLab](openshift_and_gitlab/index.md) | Tutorial | 2016/06/28 |
-| [Getting started with GitLab and DigitalOcean](https://about.gitlab.com/2016/04/27/getting-started-with-gitlab-and-digitalocean/) | Tutorial | 2016/04/27 |
+| [Video Tutorial: Idea to Production on Google Container Engine (GKE)](https://about.gitlab.com/2017/01/23/video-tutorial-idea-to-production-on-google-container-engine-gke/) | Tutorial | 2017-01-23 |
+| [How to Setup a GitLab Instance on Microsoft Azure](https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) | Tutorial | 2016-07-13 |
+| [Get started with OpenShift Origin 3 and GitLab](openshift_and_gitlab/index.md) | Tutorial | 2016-06-28 |
+| [Getting started with GitLab and DigitalOcean](https://about.gitlab.com/2016/04/27/getting-started-with-gitlab-and-digitalocean/) | Tutorial | 2016-04-27 |
## Software development
@@ -90,25 +91,25 @@ Explore the best of GitLab's software development's capabilities:
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
-| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 |
-| [From 2/3 of the Self-Hosted Git Market, to the Next-Generation CI System, to Auto DevOps](https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/)| Concepts | 2017/06/29 |
-| [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) | Concepts | 2017/05/22 |
-| [Demo: Auto-Deploy from GitLab to an OpenShift Container Cluster](https://about.gitlab.com/2017/05/16/devops-containers-gitlab-openshift/) | Technical overview | 2017/05/16 |
-| [Demo: GitLab Service Desk](https://about.gitlab.com/2017/05/09/demo-service-desk/) | Feature highlight | 2017/05/09 |
-| [Demo: Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/) | Feature highlight | 2017/04/25 |
-| [Demo: Cloud Native Development with GitLab](https://about.gitlab.com/2017/04/18/cloud-native-demo/) | Feature highlight | 2017/04/18 |
-| [Demo: Mastering Code Review With GitLab](https://about.gitlab.com/2017/03/17/demo-mastering-code-review-with-gitlab/) | Feature highlight | 2017/03/17 |
-| [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) | Technical overview | 2016/11/14 |
-| [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Technical overview | 2016/10/25 |
-| [Trends in Version Control Land: Microservices](https://about.gitlab.com/2016/08/16/trends-in-version-control-land-microservices/) | Concepts | 2016/08/16 |
-| [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) | Concepts | 2016/08/05 |
-| [Trends in Version Control Land: Innersourcing](https://about.gitlab.com/2016/07/07/trends-version-control-innersourcing/) | Concepts | 2016/07/07 |
-| [Tutorial: It's all connected in GitLab](https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected/) | Technical overview | 2016/03/08 |
+| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017-07-13 |
+| [From 2/3 of the Self-Hosted Git Market, to the Next-Generation CI System, to Auto DevOps](https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/)| Concepts | 2017-06-29 |
+| [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) | Concepts | 2017-05-22 |
+| [Demo: Auto-Deploy from GitLab to an OpenShift Container Cluster](https://about.gitlab.com/2017/05/16/devops-containers-gitlab-openshift/) | Technical overview | 2017-05-16 |
+| [Demo: GitLab Service Desk](https://about.gitlab.com/2017/05/09/demo-service-desk/) | Feature highlight | 2017-05-09 |
+| [Demo: Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/) | Feature highlight | 2017-04-25 |
+| [Demo: Cloud Native Development with GitLab](https://about.gitlab.com/2017/04/18/cloud-native-demo/) | Feature highlight | 2017-04-18 |
+| [Demo: Mastering Code Review With GitLab](https://about.gitlab.com/2017/03/17/demo-mastering-code-review-with-gitlab/) | Feature highlight | 2017-03-17 |
+| [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) | Technical overview | 2016-11-14 |
+| [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Technical overview | 2016-10-25 |
+| [Trends in Version Control Land: Microservices](https://about.gitlab.com/2016/08/16/trends-in-version-control-land-microservices/) | Concepts | 2016-08-16 |
+| [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) | Concepts | 2016-08-05 |
+| [Trends in Version Control Land: Innersourcing](https://about.gitlab.com/2016/07/07/trends-version-control-innersourcing/) | Concepts | 2016-07-07 |
+| [Tutorial: It's all connected in GitLab](https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected/) | Technical overview | 2016-03-08 |
## Technologies
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
-| [Why we are not leaving the cloud](https://about.gitlab.com/2017/03/02/why-we-are-not-leaving-the-cloud/) | Concepts | 2017/03/02 |
-| [Why We Chose Vue.js](https://about.gitlab.com/2016/10/20/why-we-chose-vue/) | Concepts | 2016/10/20 |
-| [Markdown Kramdown Tips & Tricks](https://about.gitlab.com/2016/07/19/markdown-kramdown-tips-and-tricks/) | Technical overview | 2016/07/19 |
+| [Why we are not leaving the cloud](https://about.gitlab.com/2017/03/02/why-we-are-not-leaving-the-cloud/) | Concepts | 2017-03-02 |
+| [Why We Chose Vue.js](https://about.gitlab.com/2016/10/20/why-we-chose-vue/) | Concepts | 2016-10-20 |
+| [Markdown Kramdown Tips & Tricks](https://about.gitlab.com/2016/07/19/markdown-kramdown-tips-and-tricks/) | Technical overview | 2016-07-19 |
diff --git a/doc/articles/numerous_undo_possibilities_in_git/img/branching.png b/doc/articles/numerous_undo_possibilities_in_git/img/branching.png
new file mode 100644
index 00000000000..9a80c211c99
--- /dev/null
+++ b/doc/articles/numerous_undo_possibilities_in_git/img/branching.png
Binary files differ
diff --git a/doc/articles/numerous_undo_possibilities_in_git/img/rebase_reset.png b/doc/articles/numerous_undo_possibilities_in_git/img/rebase_reset.png
new file mode 100644
index 00000000000..ac7ea9ecddc
--- /dev/null
+++ b/doc/articles/numerous_undo_possibilities_in_git/img/rebase_reset.png
Binary files differ
diff --git a/doc/articles/numerous_undo_possibilities_in_git/img/revert.png b/doc/articles/numerous_undo_possibilities_in_git/img/revert.png
new file mode 100644
index 00000000000..13b3a35ca45
--- /dev/null
+++ b/doc/articles/numerous_undo_possibilities_in_git/img/revert.png
Binary files differ
diff --git a/doc/articles/numerous_undo_possibilities_in_git/index.md b/doc/articles/numerous_undo_possibilities_in_git/index.md
new file mode 100644
index 00000000000..9f1239b8f88
--- /dev/null
+++ b/doc/articles/numerous_undo_possibilities_in_git/index.md
@@ -0,0 +1,497 @@
+# Numerous undo possibilities in Git
+
+> **Article [Type](../../development/writing_documentation.md#types-of-technical-articles):** tutorial ||
+> **Level:** intermediary ||
+> **Author:** [Crt Mori](https://gitlab.com/Letme) ||
+> **Publication date:** 2017/08/17
+
+## Introduction
+
+In this tutorial, we will show you different ways of undoing your work in Git, for which
+we will assume you have a basic working knowledge of. Check GitLab's
+[Git documentation](../../topics/git/index.md#git-documentation) for reference.
+Also, we will only provide some general info of the commands, which is enough
+to get you started for the easy cases/examples, but for anything more advanced please refer to the [Git book](https://git-scm.com/book/en/v2).
+
+We will explain a few different techniques to undo your changes based on the stage
+of the change in your current development. Also, keep in mind that [nothing in
+Git is really deleted.][git-autoclean-ref]
+This means that until Git automatically cleans detached commits (which cannot be
+accessed by branch or tag) it will be possible to view them with `git reflog` command
+and access them with direct commit-id. Read more about _[redoing the undo](#redoing-the-undo)_ on the section below.
+
+This guide is organized depending on the [stage of development][git-basics]
+where you want to undo your changes from and if they were shared with other developers
+or not. Because Git is tracking changes a created or edited file is in the unstaged state
+(if created it is untracked by Git). After you add it to a repository (`git add`) you put
+a file into the **staged** state, which is then committed (`git commit`) to your
+local repository. After that, file can be shared with other developers (`git push`).
+Here's what we'll cover in this tutorial:
+
+ - [Undo local changes](#undo-local-changes) which were not pushed to remote repository
+
+ - Before you commit, in both unstaged and staged state
+ - After you committed
+
+ - Undo changes after they are pushed to remote repository
+
+ - [Without history modification](#undo-remote-changes-without-changing-history) (preferred way)
+ - [With history modification](#undo-remote-changes-with-modifying-history) (requires
+ coordination with team and force pushes).
+
+ - [Usecases when modifying history is generally acceptable](#where-modifying-history-is-generally-acceptable)
+ - [How to modify history](#how-modifying-history-is-done)
+ - [How to remove sensitive information from repository](#deleting-sensitive-information-from-commits)
+
+
+### Branching strategy
+
+[Git][git-official] is a de-centralized version control system, which means that beside regular
+versioning of the whole repository, it has possibilities to exchange changes
+with other repositories. To avoid chaos with
+[multiple sources of truth][git-distributed], various
+development workflows have to be followed, and it depends on your internal
+workflow how certain changes or commits can be undone or changed.
+[GitLab Flow][gitlab-flow] provides a good
+balance between developers clashing with each other while
+developing the same feature and cooperating seamlessly, but it does not enable
+joined development of the same feature by multiple developers by default.
+When multiple developers develop the same feature on the same branch, clashing
+with every synchronization is unavoidable, but a proper or chosen Git Workflow will
+prevent that anything is lost or out of sync when feature is complete. You can also
+read through this blog post on [Git Tips & Tricks][gitlab-git-tips-n-tricks]
+to learn how to easily **do** things in Git.
+
+
+## Undo local changes
+
+Until you push your changes to any remote repository, they will only affect you.
+That broadens your options on how to handle undoing them. Still, local changes
+can be on various stages and each stage has a different approach on how to tackle them.
+
+
+### Unstaged local changes (before you commit)
+
+When a change is made, but it is not added to the staged tree, Git itself
+proposes a solution to discard changes to certain file.
+
+Suppose you edited a file to change the content using your favorite editor:
+
+```shell
+vim <file>
+```
+
+Since you did not `git add <file>` to staging, it should be under unstaged files (or
+untracked if file was created). You can confirm that with:
+
+```shell
+$ git status
+On branch master
+Your branch is up-to-date with 'origin/master'.
+Changes not staged for commit:
+ (use "git add <file>..." to update what will be committed)
+ (use "git checkout -- <file>..." to discard changes in working directory)
+
+ modified: <file>
+no changes added to commit (use "git add" and/or "git commit -a")
+```
+
+At this point there are 3 options to undo the local changes you have:
+
+ - Discard all local changes, but save them for possible re-use [later](#quickly-save-local-changes)
+
+ ```shell
+ git stash
+ ```
+
+ - Discarding local changes (permanently) to a file
+
+ ```shell
+ git checkout -- <file>
+ ```
+
+ - Discard all local changes to all files permanently
+
+ ```shell
+ git reset --hard
+ ```
+
+
+Before executing `git reset --hard`, keep in mind that there is also a way to
+just temporary store the changes without committing them using `git stash`.
+This command resets the changes to all files, but it also saves them in case
+you would like to apply them at some later time. You can read more about it in
+[section below](#quickly-save-local-changes).
+
+### Quickly save local changes
+
+You are working on a feature when a boss drops by with an urgent task. Since your
+feature is not complete, but you need to swap to another branch, you can use
+`git stash` to save what you had done, swap to another branch, commit, push,
+test, then get back to previous feature branch, do `git stash pop` and continue
+where you left.
+
+The example above shows that discarding all changes is not always a preferred option,
+but Git provides a way to save them for later, while resetting the repository to state without
+them. This is achieved by Git stashing command `git stash`, which in fact saves your
+current work and runs `git reset --hard`, but it also has various
+additional options like:
+
+ - `git stash save`, which enables including temporary commit message, which will help you identify changes, among with other options
+ - `git stash list`, which lists all previously stashed commits (yes, there can be more) that were not `pop`ed
+ - `git stash pop`, which redoes previously stashed changes and removes them from stashed list
+ - `git stash apply`, which redoes previously stashed changes, but keeps them on stashed list
+
+### Staged local changes (before you commit)
+
+Let's say you have added some files to staging, but you want to remove them from the
+current commit, yet you want to retain those changes - just move them outside
+of the staging tree. You also have an option to discard all changes with
+`git reset --hard` or think about `git stash` [as described earlier.](#quickly-save-local-changes)
+
+Lets start the example by editing a file, with your favorite editor, to change the
+content and add it to staging
+
+```
+vim <file>
+git add <file>
+```
+
+The file is now added to staging as confirmed by `git status` command:
+
+```shell
+$ git status
+On branch master
+Your branch is up-to-date with 'origin/master'.
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: <file>
+```
+
+Now you have 4 options to undo your changes:
+
+ - Unstage the file to current commit (HEAD)
+
+ ```shell
+ git reset HEAD <file>
+ ```
+
+ - Unstage everything - retain changes
+
+ ```shell
+ git reset
+ ```
+
+ - Discard all local changes, but save them for [later](#quickly-save-local-changes)
+
+ ```shell
+ git stash
+ ```
+
+ - Discard everything permanently
+
+ ```shell
+ git reset --hard
+ ```
+
+## Committed local changes
+
+Once you commit, your changes are recorded by the version control system.
+Because you haven't pushed to your remote repository yet, your changes are
+still not public (or shared with other developers). At this point, undoing
+things is a lot easier, we have quite some workaround options. Once you push
+your code, you'll have less options to troubleshoot your work.
+
+### Without modifying history
+
+Through the development process some of the previously committed changes do not
+fit anymore in the end solution, or are source of the bugs. Once you find the
+commit which triggered bug, or once you have a faulty commit, you can simply
+revert it with `git revert commit-id`. This command inverts (swaps) the additions and
+deletions in that commit, so that it does not modify history. Retaining history
+can be helpful in future to notice that some changes have been tried
+unsuccessfully in the past.
+
+In our example we will assume there are commits `A`,`B`,`C`,`D`,`E` committed in this order: `A-B-C-D-E`,
+and `B` is the commit you want to undo. There are many different ways to identify commit
+`B` as bad, one of them is to pass a range to `git bisect` command. The provided range includes
+last known good commit (we assume `A`) and first known bad commit (where bug was detected - we will assume `E`).
+
+```shell
+git bisect A..E
+```
+
+Bisect will provide us with commit-id of the middle commit to test, and then guide us
+through simple bisection process. You can read more about it [in official Git Tools][git-debug]
+In our example we will end up with commit `B`, that introduced bug/error. We have
+4 options on how to remove it (or part of it) from our repository.
+
+- Undo (swap additions and deletions) changes introduced by commit `B`.
+
+ ```shell
+ git revert commit-B-id
+ ```
+
+- Undo changes on a single file or directory from commit `B`, but retain them in the staged state
+
+ ```shell
+ git checkout commit-B-id <file>
+ ```
+
+- Undo changes on a single file or directory from commit `B`, but retain them in the unstaged state
+
+ ```shell
+ git reset commit-B-id <file>
+ ```
+
+ - There is one command we also must not forget: **creating a new branch**
+ from the point where changes are not applicable or where the development has hit a
+ dead end. For example you have done commits `A-B-C-D` on your feature-branch
+ and then you figure `C` and `D` are wrong. At this point you either reset to `B`
+ and do commit `F` (which will cause problems with pushing and if forced pushed also with other developers)
+ since branch now looks `A-B-F`, which clashes with what other developers have locally (you will
+ [change history](#with-history-modification)), or you simply checkout commit `B` create
+ a new branch and do commit `F`. In the last case, everyone else can still do their work while you
+ have your new way to get it right and merge it back in later. Alternatively, with GitLab,
+ you can [cherry-pick](../../user/project/merge_requests/cherry_pick_changes.md#cherry-picking-a-commit)
+ that commit into a new merge request.
+
+ ![Create a new branch to avoid clashing](img/branching.png)
+
+ ```shell
+ git checkout commit-B-id
+ git checkout -b new-path-of-feature
+ # Create <commit F>
+ git commit -a
+ ```
+
+### With history modification
+
+There is one command for history modification and that is `git rebase`. Command
+provides interactive mode (`-i` flag) which enables you to:
+
+ - **reword** commit messages (there is also `git commit --amend` for editing
+ last commit message)
+ - **edit** the commit content (changes introduced by commit) and message
+ - **squash** multiple commits into a single one, and have a custom or aggregated
+ commit message
+ - **drop** commits - simply delete them
+ - and few more options
+
+Let us check few examples. Again there are commits `A-B-C-D` where you want to
+delete commit `B`.
+
+- Rebase the range from current commit D to A:
+
+ ```shell
+ git rebase -i A
+ ```
+
+- Command opens your favorite editor where you write `drop` in front of commit
+ `B`, but you leave default `pick` with all other commits. Save and exit the
+ editor to perform a rebase. Remember: if you want to cancel delete whole
+ file content before saving and exiting the editor
+
+In case you want to modify something introduced in commit `B`.
+
+- Rebase the range from current commit D to A:
+
+ ```shell
+ git rebase -i A
+ ```
+
+- Command opens your favorite text editor where you write `edit` in front of commit
+ `B`, but leave default `pick` with all other commits. Save and exit the editor to
+ perform a rebase
+
+- Now do your edits and commit changes:
+
+ ```shell
+ git commit -a
+ ```
+
+You can find some more examples in [below section where we explain how to modify
+history](#how-modifying-history-is-done)
+
+
+### Redoing the Undo
+
+Sometimes you realize that the changes you undid were useful and you want them
+back. Well because of first paragraph you are in luck. Command `git reflog`
+enables you to *recall* detached local commits by referencing or applying them
+via commit-id. Although, do not expect to see really old commits in reflog, because
+Git regularly [cleans the commits which are *unreachable* by branches or tags][git-autoclean-ref].
+
+To view repository history and to track older commits you can use below command:
+
+```shell
+$ git reflog show
+
+# Example output:
+b673187 HEAD@{4}: merge 6e43d5987921bde189640cc1e37661f7f75c9c0b: Merge made by the 'recursive' strategy.
+eb37e74 HEAD@{5}: rebase -i (finish): returning to refs/heads/master
+eb37e74 HEAD@{6}: rebase -i (pick): Commit C
+97436c6 HEAD@{7}: rebase -i (start): checkout 97436c6eec6396c63856c19b6a96372705b08b1b
+...
+88f1867 HEAD@{12}: commit: Commit D
+97436c6 HEAD@{13}: checkout: moving from 97436c6eec6396c63856c19b6a96372705b08b1b to test
+97436c6 HEAD@{14}: checkout: moving from master to 97436c6
+05cc326 HEAD@{15}: commit: Commit C
+6e43d59 HEAD@{16}: commit: Commit B
+```
+
+Output of command shows repository history. In first column there is commit-id,
+in following column, number next to `HEAD` indicates how many commits ago something
+was made, after that indicator of action that was made (commit, rebase, merge, ...)
+and then on end description of that action.
+
+## Undo remote changes without changing history
+
+This topic is roughly same as modifying committed local changes without modifying
+history. **It should be the preferred way of undoing changes on any remote repository
+or public branch.** Keep in mind that branching is the best solution when you want
+to retain the history of faulty development, yet start anew from certain point. Branching
+enables you to include the existing changes in new development (by merging) and
+it also provides a clear timeline and development structure.
+
+![Use revert to keep branch flowing](img/revert.png)
+
+If you want to revert changes introduced in certain `commit-id` you can simply
+revert that `commit-id` (swap additions and deletions) in newly created commit:
+You can do this with
+
+```shell
+git revert commit-id
+```
+
+or creating a new branch:
+
+```shell
+git checkout commit-id
+git checkout -b new-path-of-feature
+```
+
+## Undo remote changes with modifying history
+
+This is useful when you want to *hide* certain things - like secret keys,
+passwords, SSH keys, etc. It is and should not be used to hide mistakes, as
+it will make it harder to debug in case there are some other bugs. The main
+reason for this is that you loose the real development progress. **Also keep in
+mind that, even with modified history, commits are just detached and can still be
+accessed through commit-id** - at least until all repositories perform
+the cleanup of detached commits (happens automatically).
+
+![Modifying history causes problems on remote branch](img/rebase_reset.png)
+
+### Where modifying history is generally acceptable
+
+Modified history breaks the development chain of other developers, as changed
+history does not have matching commits'ids. For that reason it should not
+be used on any public branch or on branch that *might* be used by other
+developers. When contributing to big open source repositories (e.g. [GitLab CE][gitlab-ce]),
+it is acceptable to *squash* commits into a single one, to present
+a nicer history of your contribution.
+Keep in mind that this also removes the comments attached to certain commits
+in merge requests, so if you need to retain traceability in GitLab, then
+modifying history is not acceptable.
+A feature-branch of a merge request is a public branch and might be used by
+other developers, but project process and rules might allow or require
+you to use `git rebase` (command that changes history) to reduce number of
+displayed commits on target branch after reviews are done (for example
+GitLab). There is a `git merge --squash` command which does exactly that
+(squashes commits on feature-branch to a single commit on target branch
+at merge).
+
+>**Note:**
+Never modify the commit history of `master` or shared branch
+
+### How modifying history is done
+
+After you know what you want to modify (how far in history or how which range of
+old commits), use `git rebase -i commit-id`. This command will then display all the commits from
+current version to chosen commit-id and allow modification, squashing, deletion
+of that commits.
+
+```shell
+$ git rebase -i commit1-id..commit3-id
+pick <commit1-id> <commit1-commit-message>
+pick <commit2-id> <commit2-commit-message>
+pick <commit3-id> <commit3-commit-message>
+
+# Rebase commit1-id..commit3-id onto <commit4-id> (3 command(s))
+#
+# Commands:
+# p, pick = use commit
+# r, reword = use commit, but edit the commit message
+# e, edit = use commit, but stop for amending
+# s, squash = use commit, but meld into previous commit
+# f, fixup = like "squash", but discard this commit's log message
+# x, exec = run command (the rest of the line) using shell
+# d, drop = remove commit
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+#
+# However, if you remove everything, the rebase will be aborted.
+#
+# Note that empty commits are commented out
+```
+
+>**Note:**
+It is important to notice that comment from the output clearly states that, if
+you decide to abort, then do not just close your editor (as that will in-fact
+modify history), but remove all uncommented lines and save.
+
+That is one of the reasons why `git rebase` should be used carefully on
+shared and remote branches. But don't worry, there will be nothing broken until
+you push back to the remote repository (so you can freely explore the
+different outcomes locally).
+
+```shell
+# Modify history from commit-id to HEAD (current commit)
+git rebase -i commit-id
+```
+
+### Deleting sensitive information from commits
+
+Git also enables you to delete sensitive information from your past commits and
+it does modify history in the progress. That is why we have included it in this
+section and not as a standalone topic. To do so, you should run the
+`git filter-branch`, which enables you to rewrite history with
+[certain filters][git-filters-manual].
+This command uses rebase to modify history and if you want to remove certain
+file from history altogether use:
+
+```shell
+git filter-branch --tree-filter 'rm filename' HEAD
+```
+
+Since `git filter-branch` command might be slow on big repositories, there are
+tools that can use some of Git specifics to enable faster execution of common
+tasks (which is exactly what removing sensitive information file is about).
+An alternative is [BFG Repo-cleaner][bfg-repo-cleaner]. Keep in mind that these
+tools are faster because they do not provide a same fully feature set as `git filter-branch`
+does, but focus on specific usecases.
+
+## Conclusion
+
+There are various options of undoing your work with any version control system, but
+because of de-centralized nature of Git, these options are multiplied (or limited)
+depending on the stage of your process. Git also enables rewriting history, but that
+should be avoided as it might cause problems when multiple developers are
+contributing to the same codebase.
+
+<!-- Identifiers, in alphabetical order -->
+
+[bfg-repo-cleaner]: https://rtyley.github.io/bfg-repo-cleaner/
+[git-autoclean-ref]: https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery
+[git-basics]: https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository
+[git-debug]: https://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git
+[git-distributed]: https://git-scm.com/about/distributed
+[git-filters-manual]: https://git-scm.com/docs/git-filter-branch#_options
+[git-official]: https://git-scm.com/
+[gitlab-ce]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#contribution-acceptance-criteria
+[gitlab-flow]: https://about.gitlab.com/2014/09/29/gitlab-flow/
+[gitlab-git-tips-n-tricks]: https://about.gitlab.com/2016/12/08/git-tips-and-tricks/
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index d3433594eb7..dc5313c5597 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -117,7 +117,7 @@ following these rules:
created (requires GitLab Runner v1.1.0 or higher)
To override the default behavior, you can
-[specify a service alias](#available-settings-for-services-entry).
+[specify a service alias](#available-settings-for-services).
## Define `image` and `services` from `.gitlab-ci.yml`
@@ -183,8 +183,7 @@ test:
## Extended Docker configuration options
-> **Note:**
-This feature requires GitLab 9.4 and GitLab Runner 9.4 or higher.
+> Introduced in GitLab and GitLab Runner 9.4.
When configuring the `image` or `services` entries, you can use a string or a map as
options:
@@ -221,28 +220,29 @@ For example, the following two definitions are equal:
### Available settings for `image`
-> **Note:**
-This feature requires GitLab 9.4 and GitLab Runner 9.4 or higher.
+> Introduced in GitLab and GitLab Runner 9.4.
-| Setting | Required | Description |
-|------------|----------|-------------|
-| `name` | yes, when used with any other option | Full name of the image that should be used. It should contain the Registry part if needed. |
-| `entrypoint` | no | Command or script that should be executed as the container's entrypoint. It will be translated to Docker's `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`][entrypoint] directive, where each shell token is a separate string in the array. |
+| Setting | Required | GitLab version | Description |
+|------------|----------|----------------| ----------- |
+| `name` | yes, when used with any other option | 9.4 |Full name of the image that should be used. It should contain the Registry part if needed. |
+| `entrypoint` | no | 9.4 |Command or script that should be executed as the container's entrypoint. It will be translated to Docker's `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`][entrypoint] directive, where each shell token is a separate string in the array. |
### Available settings for `services`
-> **Note:**
-This feature requires GitLab 9.4 and GitLab Runner 9.4 or higher.
+> Introduced in GitLab and GitLab Runner 9.4.
-| Setting | Required | Description |
-|------------|----------|-------------|
-| `name` | yes, when used with any other option | Full name of the image that should be used. It should contain the Registry part if needed. |
-| `entrypoint` | no | Command or script that should be executed as the container's entrypoint. It will be translated to Docker's `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`][entrypoint] directive, where each shell token is a separate string in the array. |
-| `command` | no | Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to [`Dockerfile`'s `CMD`][cmd] directive, where each shell token is a separate string in the array. |
-| `alias` | no | Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
+| Setting | Required | GitLab version | Description |
+|------------|----------|----------------| ----------- |
+| `name` | yes, when used with any other option | 9.4 | Full name of the image that should be used. It should contain the Registry part if needed. |
+| `entrypoint` | no | 9.4 |Command or script that should be executed as the container's entrypoint. It will be translated to Docker's `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`][entrypoint] directive, where each shell token is a separate string in the array. |
+| `command` | no | 9.4 |Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to [`Dockerfile`'s `CMD`][cmd] directive, where each shell token is a separate string in the array. |
+| `alias` | no | 9.4 |Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
### Starting multiple services from the same image
+> Introduced in GitLab and GitLab Runner 9.4. Read more about the [extended
+configuration options](#extended-docker-configuration-options).
+
Before the new extended Docker configuration options, the following configuration
would not work properly:
@@ -274,6 +274,9 @@ in `.gitlab-ci.yml` file.
### Setting a command for the service
+> Introduced in GitLab and GitLab Runner 9.4. Read more about the [extended
+configuration options](#extended-docker-configuration-options).
+
Let's assume you have a `super/sql:latest` image with some SQL database
inside it and you would like to use it as a service for your job. Let's also
assume that this image doesn't start the database process while starting
@@ -313,6 +316,9 @@ As you can see, the syntax of `command` is similar to [Dockerfile's `CMD`][cmd].
### Overriding the entrypoint of an image
+> Introduced in GitLab and GitLab Runner 9.4. Read more about the [extended
+configuration options](#extended-docker-configuration-options).
+
Let's assume you have a `super/sql:experimental` image with some SQL database
inside it and you would like to use it as a base image for your job because you
want to execute some tests with this database binary. Let's also assume that
diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md
index 2513f4b420a..b4b77a2f94b 100644
--- a/doc/gitlab-basics/create-project.md
+++ b/doc/gitlab-basics/create-project.md
@@ -1,5 +1,9 @@
# How to create a project in GitLab
+>**Notes:**
+- For a list of words that are not allowed to be used as project names see the
+ [reserved names][reserved].
+
1. In your dashboard, click the green **New project** button or use the plus
icon in the upper right corner of the navigation bar.
@@ -25,4 +29,12 @@
1. Click **Create project**.
+## From a template
+
+To kickstart your development GitLab projects can be started from a template.
+For example, one of the templates included is Ruby on Rails. When filling out the
+form for new projects, click the 'Ruby on Rails' button. During project creation,
+this will import a Ruby on Rails template with GitLab CI preconfigured.
+
[import it]: ../workflow/importing/README.md
+[reserved]: ../user/reserved_names.md
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index 604f9375714..df56f031970 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -22,6 +22,7 @@ We've gathered some resources to help you to get the best from Git with GitLab.
- [Cherry-picking a commit](../../user/project/merge_requests/cherry_pick_changes.md#cherry-picking-a-commit)
- [Squashing commits](../../workflow/gitlab_flow.md#squashing-commits-with-rebase)
- **Articles:**
+ - [Numerous _undo_ possibilities in Git](../../articles/numerous_undo_possibilities_in_git/index.md)
- [How to install Git](../../articles/how_to_install_git/index.md)
- [Git Tips & Tricks](https://about.gitlab.com/2016/12/08/git-tips-and-tricks/)
- [Eight Tips to help you work better with Git](https://about.gitlab.com/2015/02/19/8-tips-to-help-you-work-better-with-git/)
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index ceec8b74373..9e168e830e5 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -57,6 +57,10 @@ By doing so:
## Create a new group
+> **Notes:**
+- For a list of words that are not allowed to be used as group names see the
+ [reserved names][reserved].
+
You can create a group in GitLab from:
1. The Groups page: expand the left menu, click **Groups**, and click the green button **New group**:
@@ -213,4 +217,5 @@ for the group (GitLab admins only, available in [GitLab Enterprise Edition Start
- **Pipelines quota**: keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group
[permissions]: ../permissions.md#permissions
-[ee]: https://about.gitlab.com/products/ \ No newline at end of file
+[ee]: https://about.gitlab.com/products/
+[reserved]: ../reserved_names.md
diff --git a/doc/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md
index 5724dcfab48..d2478aea4bd 100644
--- a/doc/user/group/subgroups/index.md
+++ b/doc/user/group/subgroups/index.md
@@ -83,10 +83,7 @@ structure.
- You need to be an Owner of a group in order to be able to create
a subgroup. For more information check the [permissions table][permissions].
- For a list of words that are not allowed to be used as group names see the
- [`path_regex.rb` file][reserved] under the `TOP_LEVEL_ROUTES`, `PROJECT_WILDCARD_ROUTES` and `GROUP_ROUTES` lists:
- - `TOP_LEVEL_ROUTES`: are names that are reserved as usernames or top level groups
- - `PROJECT_WILDCARD_ROUTES`: are names that are reserved for child groups or projects.
- - `GROUP_ROUTES`: are names that are reserved for all groups or projects.
+ [reserved names][reserved].
To create a subgroup:
@@ -175,5 +172,5 @@ Here's a list of what you can't do with subgroups:
[ce-2772]: https://gitlab.com/gitlab-org/gitlab-ce/issues/2772
[permissions]: ../../permissions.md#group
-[reserved]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/path_regex.rb
+[reserved]: ../../reserved_names.md
[issue]: https://gitlab.com/gitlab-org/gitlab-ce/issues/30472#note_27747600
diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md
new file mode 100644
index 00000000000..b22c7db0047
--- /dev/null
+++ b/doc/user/project/import/bitbucket.md
@@ -0,0 +1,62 @@
+# Import your project from Bitbucket to GitLab
+
+Import your projects from Bitbucket to GitLab with minimal effort.
+
+## Overview
+
+>**Note:**
+The [Bitbucket integration][bb-import] must be first enabled in order to be
+able to import your projects from Bitbucket. Ask your GitLab administrator
+to enable this if not already.
+
+- At its current state, the Bitbucket importer can import:
+ - the repository description (GitLab 7.7+)
+ - the Git repository data (GitLab 7.7+)
+ - the issues (GitLab 7.7+)
+ - the issue comments (GitLab 8.15+)
+ - the pull requests (GitLab 8.4+)
+ - the pull request comments (GitLab 8.15+)
+ - the milestones (GitLab 8.15+)
+ - the wiki (GitLab 8.15+)
+- References to pull requests and issues are preserved (GitLab 8.7+)
+- Repository public access is retained. If a repository is private in Bitbucket
+ it will be created as private in GitLab as well.
+
+
+## How it works
+
+When issues/pull requests are being imported, the Bitbucket importer tries to find
+the Bitbucket author/assignee in GitLab's database using the Bitbucket ID. For this
+to work, the Bitbucket author/assignee should have signed in beforehand in GitLab
+and **associated their Bitbucket account**. If the user is not
+found in GitLab's database, the project creator (most of the times the current
+user that started the import process) is set as the author, but a reference on
+the issue about the original Bitbucket author is kept.
+
+The importer will create any new namespaces (groups) if they don't exist or in
+the case the namespace is taken, the repository will be imported under the user's
+namespace that started the import process.
+
+## Importing your Bitbucket repositories
+
+1. Sign in to GitLab and go to your dashboard.
+1. Click on **New project**.
+
+ ![New project in GitLab](img/bitbucket_import_new_project.png)
+
+1. Click on the "Bitbucket" button
+
+ ![Bitbucket](img/import_projects_from_new_project_page.png)
+
+1. Grant GitLab access to your Bitbucket account
+
+ ![Grant access](img/bitbucket_import_grant_access.png)
+
+1. Click on the projects that you'd like to import or **Import all projects**.
+ You can also select the namespace under which each project will be
+ imported.
+
+ ![Import projects](img/bitbucket_import_select_project.png)
+
+[bb-import]: ../../../integration/bitbucket.md
+[social sign-in]: ../../profile/account/social_sign_in.md
diff --git a/doc/user/project/import/fogbugz.md b/doc/user/project/import/fogbugz.md
new file mode 100644
index 00000000000..17222c53675
--- /dev/null
+++ b/doc/user/project/import/fogbugz.md
@@ -0,0 +1,28 @@
+# Import your project from FogBugz to GitLab
+
+It only takes a few simple steps to import your project from FogBugz.
+The importer will import all of your cases and comments with original case
+numbers and timestamps. You will also have the opportunity to map FogBugz
+users to GitLab users.
+
+1. From your GitLab dashboard click 'New project'
+1. Click on the 'FogBugz' button
+
+ ![FogBugz](img/fogbugz_import_select_fogbogz.png)
+
+1. Enter your FogBugz URL, email address, and password.
+
+ ![Login](img/fogbugz_import_login.png)
+
+1. Create mapping from FogBugz users to GitLab users.
+
+ ![User Map](img/fogbugz_import_user_map.png)
+
+1. Select the projects you wish to import by clicking the Import buttons
+
+ ![Import Project](img/fogbugz_import_select_project.png)
+
+1. Once the import has finished click the link to take you to the project
+dashboard. Follow the directions to push your existing repository.
+
+ ![Finished](img/fogbugz_import_finished.png)
diff --git a/doc/user/project/import/gitea.md b/doc/user/project/import/gitea.md
new file mode 100644
index 00000000000..f5746a0fb31
--- /dev/null
+++ b/doc/user/project/import/gitea.md
@@ -0,0 +1,77 @@
+# Import your project from Gitea to GitLab
+
+Import your projects from Gitea to GitLab with minimal effort.
+
+## Overview
+
+>**Note:**
+This requires Gitea `v1.0.0` or newer.
+
+- At its current state, Gitea importer can import:
+ - the repository description (GitLab 8.15+)
+ - the Git repository data (GitLab 8.15+)
+ - the issues (GitLab 8.15+)
+ - the pull requests (GitLab 8.15+)
+ - the milestones (GitLab 8.15+)
+ - the labels (GitLab 8.15+)
+- Repository public access is retained. If a repository is private in Gitea
+ it will be created as private in GitLab as well.
+
+## How it works
+
+Since Gitea is currently not an OAuth provider, author/assignee cannot be mapped
+to users in your GitLab's instance. This means that the project creator (most of
+the times the current user that started the import process) is set as the author,
+but a reference on the issue about the original Gitea author is kept.
+
+The importer will create any new namespaces (groups) if they don't exist or in
+the case the namespace is taken, the repository will be imported under the user's
+namespace that started the import process.
+
+## Importing your Gitea repositories
+
+The importer page is visible when you create a new project.
+
+![New project page on GitLab](img/import_projects_from_new_project_page.png)
+
+Click on the **Gitea** link and the import authorization process will start.
+
+![New Gitea project import](img/import_projects_from_gitea_new_import.png)
+
+### Authorize access to your repositories using a personal access token
+
+With this method, you will perform a one-off authorization with Gitea to grant
+GitLab access your repositories:
+
+1. Go to <https://you-gitea-instance/user/settings/applications> (replace
+ `you-gitea-instance` with the host of your Gitea instance).
+1. Click **Generate New Token**.
+1. Enter a token description.
+1. Click **Generate Token**.
+1. Copy the token hash.
+1. Go back to GitLab and provide the token to the Gitea importer.
+1. Hit the **List Your Gitea Repositories** button and wait while GitLab reads
+ your repositories' information. Once done, you'll be taken to the importer
+ page to select the repositories to import.
+
+### Select which repositories to import
+
+After you've authorized access to your Gitea repositories, you will be
+redirected to the Gitea importer page.
+
+From there, you can see the import statuses of your Gitea repositories.
+
+- Those that are being imported will show a _started_ status,
+- those already successfully imported will be green with a _done_ status,
+- whereas those that are not yet imported will have an **Import** button on the
+ right side of the table.
+
+If you want, you can import all your Gitea projects in one go by hitting
+**Import all projects** in the upper left corner.
+
+![Gitea importer page](img/import_projects_from_github_importer.png)
+
+---
+
+You can also choose a different name for the project and a different namespace,
+if you have the privileges to do so.
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
new file mode 100644
index 00000000000..016f98966e3
--- /dev/null
+++ b/doc/user/project/import/github.md
@@ -0,0 +1,122 @@
+# Import your project from GitHub to GitLab
+
+Import your projects from GitHub to GitLab with minimal effort.
+
+## Overview
+
+>**Note:**
+If you are an administrator you can enable the [GitHub integration][gh-import]
+in your GitLab instance sitewide. This configuration is optional, users will
+still be able to import their GitHub repositories with a
+[personal access token][gh-token].
+
+>**Note:**
+Administrators of a GitLab instance (Community or Enterprise Edition) can also
+use the [GitHub rake task][gh-rake] to import projects from GitHub without the
+constrains of a Sidekiq worker.
+
+- At its current state, GitHub importer can import:
+ - the repository description (GitLab 7.7+)
+ - the Git repository data (GitLab 7.7+)
+ - the issues (GitLab 7.7+)
+ - the pull requests (GitLab 8.4+)
+ - the wiki pages (GitLab 8.4+)
+ - the milestones (GitLab 8.7+)
+ - the labels (GitLab 8.7+)
+ - the release note descriptions (GitLab 8.12+)
+- References to pull requests and issues are preserved (GitLab 8.7+)
+- Repository public access is retained. If a repository is private in GitHub
+ it will be created as private in GitLab as well.
+
+## How it works
+
+When issues/pull requests are being imported, the GitHub importer tries to find
+the GitHub author/assignee in GitLab's database using the GitHub ID. For this
+to work, the GitHub author/assignee should have signed in beforehand in GitLab
+and **associated their GitHub account**. If the user is not
+found in GitLab's database, the project creator (most of the times the current
+user that started the import process) is set as the author, but a reference on
+the issue about the original GitHub author is kept.
+
+The importer will create any new namespaces (groups) if they don't exist or in
+the case the namespace is taken, the repository will be imported under the user's
+namespace that started the import process.
+
+## Importing your GitHub repositories
+
+The importer page is visible when you create a new project.
+
+![New project page on GitLab](img/import_projects_from_new_project_page.png)
+
+Click on the **GitHub** link and the import authorization process will start.
+There are two ways to authorize access to your GitHub repositories:
+
+1. [Using the GitHub integration][gh-integration] (if it's enabled by your
+ GitLab administrator). This is the preferred way as it's possible to
+ preserve the GitHub authors/assignees. Read more in the [How it works](#how-it-works)
+ section.
+1. [Using a personal access token][gh-token] provided by GitHub.
+
+![Select authentication method](img/import_projects_from_github_select_auth_method.png)
+
+### Authorize access to your repositories using the GitHub integration
+
+If the [GitHub integration][gh-import] is enabled by your GitLab administrator,
+you can use it instead of the personal access token.
+
+1. First you may want to connect your GitHub account to GitLab in order for
+ the username mapping to be correct.
+1. Once you connect GitHub, click the **List your GitHub repositories** button
+ and you will be redirected to GitHub for permission to access your projects.
+1. After accepting, you'll be automatically redirected to the importer.
+
+You can now go on and [select which repositories to import](#select-which-repositories-to-import).
+
+### Authorize access to your repositories using a personal access token
+
+>**Note:**
+For a proper author/assignee mapping for issues and pull requests, the
+[GitHub integration][gh-integration] should be used instead of the
+[personal access token][gh-token]. If the GitHub integration is enabled by your
+GitLab administrator, it should be the preferred method to import your repositories.
+Read more in the [How it works](#how-it-works) section.
+
+If you are not using the GitHub integration, you can still perform a one-off
+authorization with GitHub to grant GitLab access your repositories:
+
+1. Go to <https://github.com/settings/tokens/new>.
+1. Enter a token description.
+1. Check the `repo` scope.
+1. Click **Generate token**.
+1. Copy the token hash.
+1. Go back to GitLab and provide the token to the GitHub importer.
+1. Hit the **List Your GitHub Repositories** button and wait while GitLab reads
+ your repositories' information. Once done, you'll be taken to the importer
+ page to select the repositories to import.
+
+### Select which repositories to import
+
+After you've authorized access to your GitHub repositories, you will be
+redirected to the GitHub importer page.
+
+From there, you can see the import statuses of your GitHub repositories.
+
+- Those that are being imported will show a _started_ status,
+- those already successfully imported will be green with a _done_ status,
+- whereas those that are not yet imported will have an **Import** button on the
+ right side of the table.
+
+If you want, you can import all your GitHub projects in one go by hitting
+**Import all projects** in the upper left corner.
+
+![GitHub importer page](img/import_projects_from_github_importer.png)
+
+---
+
+You can also choose a different name for the project and a different namespace,
+if you have the privileges to do so.
+
+[gh-import]: ../../../integration/github.md "GitHub integration"
+[gh-rake]: ../../../administration/raketasks/github_import.md "GitHub rake task"
+[gh-integration]: #authorize-access-to-your-repositories-using-the-github-integration
+[gh-token]: #authorize-access-to-your-repositories-using-a-personal-access-token
diff --git a/doc/user/project/import/gitlab_com.md b/doc/user/project/import/gitlab_com.md
new file mode 100644
index 00000000000..3b37da67a5b
--- /dev/null
+++ b/doc/user/project/import/gitlab_com.md
@@ -0,0 +1,20 @@
+# Project importing from GitLab.com to your private GitLab instance
+
+You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if
+GitLab support is enabled on your GitLab instance.
+You can read more about GitLab support [here](http://docs.gitlab.com/ce/integration/gitlab.html)
+To get to the importer page you need to go to "New project" page.
+
+>**Note:**
+If you are interested in importing Wiki and Merge Request data to your new
+instance, you'll need to follow the instructions for [project export](../settings/import_export.md)
+
+![New project page](img/gitlab_new_project_page.png)
+
+Click on the "Import projects from GitLab.com" link and you will be redirected to GitLab.com
+for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
+
+![Importer page](img/gitlab_importer.png)
+
+To import a project, you can simple click "Import". The importer will import your repository and issues.
+Once the importer is done, a new GitLab project will be created with your imported data.
diff --git a/doc/workflow/importing/img/bitbucket_import_grant_access.png b/doc/user/project/import/img/bitbucket_import_grant_access.png
index 429904e621d..429904e621d 100644
--- a/doc/workflow/importing/img/bitbucket_import_grant_access.png
+++ b/doc/user/project/import/img/bitbucket_import_grant_access.png
Binary files differ
diff --git a/doc/workflow/importing/img/bitbucket_import_new_project.png b/doc/user/project/import/img/bitbucket_import_new_project.png
index 8ed528c2f09..8ed528c2f09 100644
--- a/doc/workflow/importing/img/bitbucket_import_new_project.png
+++ b/doc/user/project/import/img/bitbucket_import_new_project.png
Binary files differ
diff --git a/doc/workflow/importing/img/bitbucket_import_select_project.png b/doc/user/project/import/img/bitbucket_import_select_project.png
index 1bca6166ec8..1bca6166ec8 100644
--- a/doc/workflow/importing/img/bitbucket_import_select_project.png
+++ b/doc/user/project/import/img/bitbucket_import_select_project.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png b/doc/user/project/import/img/fogbugz_import_finished.png
index 62c5c86c9b3..62c5c86c9b3 100644
--- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png
+++ b/doc/user/project/import/img/fogbugz_import_finished.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png b/doc/user/project/import/img/fogbugz_import_login.png
index 96bce70b74d..96bce70b74d 100644
--- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png
+++ b/doc/user/project/import/img/fogbugz_import_login.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png b/doc/user/project/import/img/fogbugz_import_select_fogbogz.png
index b26c652e382..b26c652e382 100644
--- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png
+++ b/doc/user/project/import/img/fogbugz_import_select_fogbogz.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png b/doc/user/project/import/img/fogbugz_import_select_project.png
index ccc82f9d4cd..ccc82f9d4cd 100644
--- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png
+++ b/doc/user/project/import/img/fogbugz_import_select_project.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png b/doc/user/project/import/img/fogbugz_import_user_map.png
index 28ff55a8d89..28ff55a8d89 100644
--- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png
+++ b/doc/user/project/import/img/fogbugz_import_user_map.png
Binary files differ
diff --git a/doc/workflow/importing/gitlab_importer/importer.png b/doc/user/project/import/img/gitlab_importer.png
index 27d42eb492e..27d42eb492e 100644
--- a/doc/workflow/importing/gitlab_importer/importer.png
+++ b/doc/user/project/import/img/gitlab_importer.png
Binary files differ
diff --git a/doc/workflow/importing/gitlab_importer/new_project_page.png b/doc/user/project/import/img/gitlab_new_project_page.png
index c673724f436..c673724f436 100644
--- a/doc/workflow/importing/gitlab_importer/new_project_page.png
+++ b/doc/user/project/import/img/gitlab_new_project_page.png
Binary files differ
diff --git a/doc/workflow/importing/img/import_projects_from_gitea_new_import.png b/doc/user/project/import/img/import_projects_from_gitea_new_import.png
index a3f603cbd0a..a3f603cbd0a 100644
--- a/doc/workflow/importing/img/import_projects_from_gitea_new_import.png
+++ b/doc/user/project/import/img/import_projects_from_gitea_new_import.png
Binary files differ
diff --git a/doc/workflow/importing/img/import_projects_from_github_importer.png b/doc/user/project/import/img/import_projects_from_github_importer.png
index d8effaf6075..d8effaf6075 100644
--- a/doc/workflow/importing/img/import_projects_from_github_importer.png
+++ b/doc/user/project/import/img/import_projects_from_github_importer.png
Binary files differ
diff --git a/doc/workflow/importing/img/import_projects_from_github_select_auth_method.png b/doc/user/project/import/img/import_projects_from_github_select_auth_method.png
index 1ccb38a815e..1ccb38a815e 100644
--- a/doc/workflow/importing/img/import_projects_from_github_select_auth_method.png
+++ b/doc/user/project/import/img/import_projects_from_github_select_auth_method.png
Binary files differ
diff --git a/doc/workflow/importing/img/import_projects_from_new_project_page.png b/doc/user/project/import/img/import_projects_from_new_project_page.png
index 97ca30b2087..97ca30b2087 100644
--- a/doc/workflow/importing/img/import_projects_from_new_project_page.png
+++ b/doc/user/project/import/img/import_projects_from_new_project_page.png
Binary files differ
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
new file mode 100644
index 00000000000..06e8c81ef06
--- /dev/null
+++ b/doc/user/project/import/index.md
@@ -0,0 +1,20 @@
+# Migrating projects to a GitLab instance
+
+1. [From Bitbucket.org](bitbucket.md)
+1. [From GitHub.com of GitHub Enterprise](github.md)
+1. [From GitLab.com](gitlab_com.md)
+1. [From FogBugz](fogbugz.md)
+1. [From Gitea](gitea.md)
+1. [From SVN](svn.md)
+
+In addition to the specific migration documentation above, you can import any
+Git repository via HTTP from the New Project page. Be aware that if the
+repository is too large the import can timeout.
+
+## Migrating from self-hosted GitLab to GitLab.com
+
+You can copy your repos by changing the remote and pushing to the new server,
+but issues and merge requests can't be imported.
+
+If you want to retain all metadata like issues and merge requests, you can use
+the [import/export feature](../settings/import_export.md).
diff --git a/doc/user/project/import/svn.md b/doc/user/project/import/svn.md
new file mode 100644
index 00000000000..7a3628a39d7
--- /dev/null
+++ b/doc/user/project/import/svn.md
@@ -0,0 +1,183 @@
+# Migrating from SVN to GitLab
+
+Subversion (SVN) is a central version control system (VCS) while
+Git is a distributed version control system. There are some major differences
+between the two, for more information consult your favorite search engine.
+
+## Overview
+
+There are two approaches to SVN to Git migration:
+
+1. [Git/SVN Mirror](#smooth-migration-with-a-gitsvn-mirror-using-subgit) which:
+ - Makes the GitLab repository to mirror the SVN project.
+ - Git and SVN repositories are kept in sync; you can use either one.
+ - Smoothens the migration process and allows to manage migration risks.
+
+1. [Cut over migration](#cut-over-migration-with-svn2git) which:
+ - Translates and imports the existing data and history from SVN to Git.
+ - Is a fire and forget approach, good for smaller teams.
+
+## Smooth migration with a Git/SVN mirror using SubGit
+
+[SubGit](https://subgit.com) is a tool for a smooth, stress-free SVN to Git
+migration. It creates a writable Git mirror of a local or remote Subversion
+repository and that way you can use both Subversion and Git as long as you like.
+It requires access to your GitLab server as it talks with the Git repositories
+directly in a filesystem level.
+
+### SubGit prerequisites
+
+1. Install Oracle JRE 1.8 or newer. On Debian-based Linux distributions you can
+ follow [this article](http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html).
+1. Download SubGit from https://subgit.com/download/.
+1. Unpack the downloaded SubGit zip archive to the `/opt` directory. The `subgit`
+ command will be available at `/opt/subgit-VERSION/bin/subgit`.
+
+### SubGit configuration
+
+The first step to mirror you SVN repository in GitLab is to create a new empty
+project which will be used as a mirror. For Omnibus installations the path to
+the repository will be located at
+`/var/opt/gitlab/git-data/repositories/USER/REPO.git` by default. For
+installations from source, the default repository directory will be
+`/home/git/repositories/USER/REPO.git`. For convenience, assign this path to a
+variable:
+
+```
+GIT_REPO_PATH=/var/opt/gitlab/git-data/repositories/USER/REPOS.git
+```
+
+SubGit will keep this repository in sync with a remote SVN project. For
+convenience, assign your remote SVN project URL to a variable:
+
+```
+SVN_PROJECT_URL=http://svn.company.com/repos/project
+```
+
+Next you need to run SubGit to set up a Git/SVN mirror. Make sure the following
+`subgit` command is ran on behalf of the same user that keeps ownership of
+GitLab Git repositories (by default `git`):
+
+```
+subgit configure --layout auto $SVN_PROJECT_URL $GIT_REPO_PATH
+```
+
+Adjust authors and branches mappings, if necessary. Open with your favorite
+text editor:
+
+```
+edit $GIT_REPO_PATH/subgit/authors.txt
+edit $GIT_REPO_PATH/subgit/config
+```
+
+For more information regarding the SubGit configuration options, refer to
+[SubGit's documentation](https://subgit.com/documentation.html) website.
+
+### Initial translation
+
+Now that SubGit has configured the Git/SVN repos, run `subgit` to perform the
+initial translation of existing SVN revisions into the Git repository:
+
+```
+subgit install $GIT_REPO_PATH
+```
+
+After the initial translation is completed, the Git repository and the SVN
+project will be kept in sync by `subgit` - new Git commits will be translated to
+SVN revisions and new SVN revisions will be translated to Git commits. Mirror
+works transparently and does not require any special commands.
+
+If you would prefer to perform one-time cut over migration with `subgit`, use
+the `import` command instead of `install`:
+
+```
+subgit import $GIT_REPO_PATH
+```
+
+### SubGit licensing
+
+Running SubGit in a mirror mode requires a
+[registration](https://subgit.com/pricing.html). Registration is free for open
+source, academic and startup projects.
+
+We're currently working on deeper GitLab/SubGit integration. You may track our
+progress at [this issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/990).
+
+### SubGit support
+
+For any questions related to SVN to GitLab migration with SubGit, you can
+contact the SubGit team directly at [support@subgit.com](mailto:support@subgit.com).
+
+## Cut over migration with svn2git
+
+If you are currently using an SVN repository, you can migrate the repository
+to Git and GitLab. We recommend a hard cut over - run the migration command once
+and then have all developers start using the new GitLab repository immediately.
+Otherwise, it's hard to keep changing in sync in both directions. The conversion
+process should be run on a local workstation.
+
+Install `svn2git`. On all systems you can install as a Ruby gem if you already
+have Ruby and Git installed.
+
+```bash
+sudo gem install svn2git
+```
+
+On Debian-based Linux distributions you can install the native packages:
+
+```bash
+sudo apt-get install git-core git-svn ruby
+```
+
+Optionally, prepare an authors file so `svn2git` can map SVN authors to Git authors.
+If you choose not to create the authors file then commits will not be attributed
+to the correct GitLab user. Some users may not consider this a big issue while
+others will want to ensure they complete this step. If you choose to map authors
+you will be required to map every author that is present on changes in the SVN
+repository. If you don't, the conversion will fail and you will have to update
+the author file accordingly. The following command will search through the
+repository and output a list of authors.
+
+```bash
+svn log --quiet | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq
+```
+
+Use the output from the last command to construct the authors file.
+Create a file called `authors.txt` and add one mapping per line.
+
+```
+janedoe = Jane Doe <janedoe@example.com>
+johndoe = John Doe <johndoe@example.com>
+```
+
+If your SVN repository is in the standard format (trunk, branches, tags,
+not nested) the conversion is simple. For a non-standard repository see
+[svn2git documentation](https://github.com/nirvdrum/svn2git). The following
+command will checkout the repository and do the conversion in the current
+working directory. Be sure to create a new directory for each repository before
+running the `svn2git` command. The conversion process will take some time.
+
+```bash
+svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt
+```
+
+If your SVN repository requires a username and password add the
+`--username <username>` and `--password <password` flags to the above command.
+`svn2git` also supports excluding certain file paths, branches, tags, etc. See
+[svn2git documentation](https://github.com/nirvdrum/svn2git) or run
+`svn2git --help` for full documentation on all of the available options.
+
+Create a new GitLab project, where you will eventually push your converted code.
+Copy the SSH or HTTP(S) repository URL from the project page. Add the GitLab
+repository as a Git remote and push all the changes. This will push all commits,
+branches and tags.
+
+```bash
+git remote add origin git@gitlab.com:<group>/<project>.git
+git push --all origin
+git push --tags origin
+```
+
+## Contribute to this guide
+We welcome all contributions that would expand this guide with instructions on
+how to migrate from SVN and other version control systems.
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 0dd0faf35e9..ba6ac2797b3 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -90,11 +90,11 @@ from your fork to the upstream project
## Import or export a project
-- Import a project from:
- - [GitHub to GitLab](../../workflow/importing/import_projects_from_github.md)
- - [BitBucket to GitLab](../../workflow/importing/import_projects_from_bitbucket.md)
- - [Gitea to GitLab](../../workflow/importing/import_projects_from_gitea.md)
- - [FogBugz to GitLab](../../workflow/importing/import_projects_from_fogbugz.md)
+- [Import a project](import/index.md) from:
+ - [GitHub to GitLab](import/github.md)
+ - [BitBucket to GitLab](import/bitbucket.md)
+ - [Gitea to GitLab](import/gitea.md)
+ - [FogBugz to GitLab](import/fogbugz.md)
- [Export a project from GitLab](settings/import_export.md#exporting-a-project-and-its-data)
- [Importing and exporting projects between GitLab instances](settings/import_export.md)
diff --git a/doc/user/reserved_names.md b/doc/user/reserved_names.md
new file mode 100644
index 00000000000..50ec99be48b
--- /dev/null
+++ b/doc/user/reserved_names.md
@@ -0,0 +1,109 @@
+# Reserved project and group names
+
+Not all project & group names are allowed because they would conflict with
+existing routes used by GitLab.
+
+For a list of words that are not allowed to be used as group or project names, see the
+[`path_regex.rb` file][reserved] under the `TOP_LEVEL_ROUTES`, `PROJECT_WILDCARD_ROUTES` and `GROUP_ROUTES` lists:
+- `TOP_LEVEL_ROUTES`: are names that are reserved as usernames or top level groups
+- `PROJECT_WILDCARD_ROUTES`: are names that are reserved for child groups or projects.
+- `GROUP_ROUTES`: are names that are reserved for all groups or projects.
+
+## Reserved project names
+
+It is currently not possible to create a project with the following names:
+
+- -
+- badges
+- blame
+- blob
+- builds
+- commits
+- create
+- create_dir
+- edit
+- environments/folders
+- files
+- find_file
+- gitlab-lfs/objects
+- info/lfs/objects
+- new
+- preview
+- raw
+- refs
+- tree
+- update
+- wikis
+
+## Reserved group names
+
+Currently the following names are reserved as top level groups:
+
+- 503.html
+- -
+- .well-known
+- 404.html
+- 422.html
+- 500.html
+- 502.html
+- abuse_reports
+- admin
+- api
+- apple-touch-icon-precomposed.png
+- apple-touch-icon.png
+- files
+- assets
+- autocomplete
+- ci
+- dashboard
+- deploy.html
+- explore
+- favicon.ico
+- groups
+- header_logo_dark.png
+- header_logo_light.png
+- health_check
+- help
+- import
+- invites
+- jwt
+- koding
+- notification_settings
+- oauth
+- profile
+- projects
+- public
+- robots.txt
+- s
+- search
+- sent_notifications
+- slash-command-logo.png
+- snippets
+- u
+- unicorn_test
+- unsubscribes
+- uploads
+- users
+
+These group names are unavailable as subgroup names:
+
+- -
+- activity
+- analytics
+- audit_events
+- avatar
+- edit
+- group_members
+- hooks
+- issues
+- labels
+- ldap
+- ldap_group_links
+- merge_requests
+- milestones
+- notification_setting
+- pipeline_quota
+- projects
+- subgroups
+
+[reserved]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/path_regex.rb
diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md
index 2d91bee0e94..f753708ad89 100644
--- a/doc/workflow/importing/README.md
+++ b/doc/workflow/importing/README.md
@@ -1,17 +1 @@
-# Migrating projects to a GitLab instance
-
-1. [Bitbucket](import_projects_from_bitbucket.md)
-1. [GitHub](import_projects_from_github.md)
-1. [GitLab.com](import_projects_from_gitlab_com.md)
-1. [FogBugz](import_projects_from_fogbugz.md)
-1. [Gitea](import_projects_from_gitea.md)
-1. [SVN](migrating_from_svn.md)
-
-In addition to the specific migration documentation above, you can import any
-Git repository via HTTP from the New Project page. Be aware that if the
-repository is too large the import can timeout.
-
-### Migrating from self-hosted GitLab to GitLab.com
-
-You can copy your repos by changing the remote and pushing to the new server;
-but issues and merge requests can't be imported.
+This document was moved to a [new location](../../user/project/import/index.md).
diff --git a/doc/workflow/importing/import_projects_from_bitbucket.md b/doc/workflow/importing/import_projects_from_bitbucket.md
index f3c636ed1d5..248c3990372 100644
--- a/doc/workflow/importing/import_projects_from_bitbucket.md
+++ b/doc/workflow/importing/import_projects_from_bitbucket.md
@@ -1,62 +1 @@
-# Import your project from Bitbucket to GitLab
-
-Import your projects from Bitbucket to GitLab with minimal effort.
-
-## Overview
-
->**Note:**
-The [Bitbucket integration][bb-import] must be first enabled in order to be
-able to import your projects from Bitbucket. Ask your GitLab administrator
-to enable this if not already.
-
-- At its current state, the Bitbucket importer can import:
- - the repository description (GitLab 7.7+)
- - the Git repository data (GitLab 7.7+)
- - the issues (GitLab 7.7+)
- - the issue comments (GitLab 8.15+)
- - the pull requests (GitLab 8.4+)
- - the pull request comments (GitLab 8.15+)
- - the milestones (GitLab 8.15+)
- - the wiki (GitLab 8.15+)
-- References to pull requests and issues are preserved (GitLab 8.7+)
-- Repository public access is retained. If a repository is private in Bitbucket
- it will be created as private in GitLab as well.
-
-
-## How it works
-
-When issues/pull requests are being imported, the Bitbucket importer tries to find
-the Bitbucket author/assignee in GitLab's database using the Bitbucket ID. For this
-to work, the Bitbucket author/assignee should have signed in beforehand in GitLab
-and **associated their Bitbucket account**. If the user is not
-found in GitLab's database, the project creator (most of the times the current
-user that started the import process) is set as the author, but a reference on
-the issue about the original Bitbucket author is kept.
-
-The importer will create any new namespaces (groups) if they don't exist or in
-the case the namespace is taken, the repository will be imported under the user's
-namespace that started the import process.
-
-## Importing your Bitbucket repositories
-
-1. Sign in to GitLab and go to your dashboard.
-1. Click on **New project**.
-
- ![New project in GitLab](img/bitbucket_import_new_project.png)
-
-1. Click on the "Bitbucket" button
-
- ![Bitbucket](img/import_projects_from_new_project_page.png)
-
-1. Grant GitLab access to your Bitbucket account
-
- ![Grant access](img/bitbucket_import_grant_access.png)
-
-1. Click on the projects that you'd like to import or **Import all projects**.
- You can also select the namespace under which each project will be
- imported.
-
- ![Import projects](img/bitbucket_import_select_project.png)
-
-[bb-import]: ../../integration/bitbucket.md
-[social sign-in]: ../../user/profile/account/social_sign_in.md
+This document was moved to a [new location](../../user/project/import/bitbucket.md).
diff --git a/doc/workflow/importing/import_projects_from_fogbugz.md b/doc/workflow/importing/import_projects_from_fogbugz.md
index 71af0f9ea44..050746e2b4d 100644
--- a/doc/workflow/importing/import_projects_from_fogbugz.md
+++ b/doc/workflow/importing/import_projects_from_fogbugz.md
@@ -1,29 +1 @@
-# Import your project from FogBugz to GitLab
-
-It only takes a few simple steps to import your project from FogBugz.
-The importer will import all of your cases and comments with original case
-numbers and timestamps. You will also have the opportunity to map FogBugz
-users to GitLab users.
-
-* From your GitLab dashboard click 'New project'
-
-* Click on the 'FogBugz' button
-
-![FogBugz](fogbugz_importer/fogbugz_import_select_fogbogz.png)
-
-* Enter your FogBugz URL, email address, and password.
-
-![Login](fogbugz_importer/fogbugz_import_login.png)
-
-* Create mapping from FogBugz users to GitLab users.
-
-![User Map](fogbugz_importer/fogbugz_import_user_map.png)
-
-* Select the projects you wish to import by clicking the Import buttons
-
-![Import Project](fogbugz_importer/fogbugz_import_select_project.png)
-
-* Once the import has finished click the link to take you to the project
-dashboard. Follow the directions to push your existing repository.
-
-![Finished](fogbugz_importer/fogbugz_import_finished.png)
+This document was moved to a [new location](../../user/project/import/fogbugz.md).
diff --git a/doc/workflow/importing/import_projects_from_gitea.md b/doc/workflow/importing/import_projects_from_gitea.md
index f5746a0fb31..cb90c490b0f 100644
--- a/doc/workflow/importing/import_projects_from_gitea.md
+++ b/doc/workflow/importing/import_projects_from_gitea.md
@@ -1,77 +1 @@
-# Import your project from Gitea to GitLab
-
-Import your projects from Gitea to GitLab with minimal effort.
-
-## Overview
-
->**Note:**
-This requires Gitea `v1.0.0` or newer.
-
-- At its current state, Gitea importer can import:
- - the repository description (GitLab 8.15+)
- - the Git repository data (GitLab 8.15+)
- - the issues (GitLab 8.15+)
- - the pull requests (GitLab 8.15+)
- - the milestones (GitLab 8.15+)
- - the labels (GitLab 8.15+)
-- Repository public access is retained. If a repository is private in Gitea
- it will be created as private in GitLab as well.
-
-## How it works
-
-Since Gitea is currently not an OAuth provider, author/assignee cannot be mapped
-to users in your GitLab's instance. This means that the project creator (most of
-the times the current user that started the import process) is set as the author,
-but a reference on the issue about the original Gitea author is kept.
-
-The importer will create any new namespaces (groups) if they don't exist or in
-the case the namespace is taken, the repository will be imported under the user's
-namespace that started the import process.
-
-## Importing your Gitea repositories
-
-The importer page is visible when you create a new project.
-
-![New project page on GitLab](img/import_projects_from_new_project_page.png)
-
-Click on the **Gitea** link and the import authorization process will start.
-
-![New Gitea project import](img/import_projects_from_gitea_new_import.png)
-
-### Authorize access to your repositories using a personal access token
-
-With this method, you will perform a one-off authorization with Gitea to grant
-GitLab access your repositories:
-
-1. Go to <https://you-gitea-instance/user/settings/applications> (replace
- `you-gitea-instance` with the host of your Gitea instance).
-1. Click **Generate New Token**.
-1. Enter a token description.
-1. Click **Generate Token**.
-1. Copy the token hash.
-1. Go back to GitLab and provide the token to the Gitea importer.
-1. Hit the **List Your Gitea Repositories** button and wait while GitLab reads
- your repositories' information. Once done, you'll be taken to the importer
- page to select the repositories to import.
-
-### Select which repositories to import
-
-After you've authorized access to your Gitea repositories, you will be
-redirected to the Gitea importer page.
-
-From there, you can see the import statuses of your Gitea repositories.
-
-- Those that are being imported will show a _started_ status,
-- those already successfully imported will be green with a _done_ status,
-- whereas those that are not yet imported will have an **Import** button on the
- right side of the table.
-
-If you want, you can import all your Gitea projects in one go by hitting
-**Import all projects** in the upper left corner.
-
-![Gitea importer page](img/import_projects_from_github_importer.png)
-
----
-
-You can also choose a different name for the project and a different namespace,
-if you have the privileges to do so.
+This document was moved to a [new location](../../user/project/import/gitea.md).
diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md
index 8ed1d98d05b..13639feaa04 100644
--- a/doc/workflow/importing/import_projects_from_github.md
+++ b/doc/workflow/importing/import_projects_from_github.md
@@ -1,122 +1 @@
-# Import your project from GitHub to GitLab
-
-Import your projects from GitHub to GitLab with minimal effort.
-
-## Overview
-
->**Note:**
-If you are an administrator you can enable the [GitHub integration][gh-import]
-in your GitLab instance sitewide. This configuration is optional, users will
-still be able to import their GitHub repositories with a
-[personal access token][gh-token].
-
->**Note:**
-Administrators of a GitLab instance (Community or Enterprise Edition) can also
-use the [GitHub rake task][gh-rake] to import projects from GitHub without the
-constrains of a Sidekiq worker.
-
-- At its current state, GitHub importer can import:
- - the repository description (GitLab 7.7+)
- - the Git repository data (GitLab 7.7+)
- - the issues (GitLab 7.7+)
- - the pull requests (GitLab 8.4+)
- - the wiki pages (GitLab 8.4+)
- - the milestones (GitLab 8.7+)
- - the labels (GitLab 8.7+)
- - the release note descriptions (GitLab 8.12+)
-- References to pull requests and issues are preserved (GitLab 8.7+)
-- Repository public access is retained. If a repository is private in GitHub
- it will be created as private in GitLab as well.
-
-## How it works
-
-When issues/pull requests are being imported, the GitHub importer tries to find
-the GitHub author/assignee in GitLab's database using the GitHub ID. For this
-to work, the GitHub author/assignee should have signed in beforehand in GitLab
-and **associated their GitHub account**. If the user is not
-found in GitLab's database, the project creator (most of the times the current
-user that started the import process) is set as the author, but a reference on
-the issue about the original GitHub author is kept.
-
-The importer will create any new namespaces (groups) if they don't exist or in
-the case the namespace is taken, the repository will be imported under the user's
-namespace that started the import process.
-
-## Importing your GitHub repositories
-
-The importer page is visible when you create a new project.
-
-![New project page on GitLab](img/import_projects_from_new_project_page.png)
-
-Click on the **GitHub** link and the import authorization process will start.
-There are two ways to authorize access to your GitHub repositories:
-
-1. [Using the GitHub integration][gh-integration] (if it's enabled by your
- GitLab administrator). This is the preferred way as it's possible to
- preserve the GitHub authors/assignees. Read more in the [How it works](#how-it-works)
- section.
-1. [Using a personal access token][gh-token] provided by GitHub.
-
-![Select authentication method](img/import_projects_from_github_select_auth_method.png)
-
-### Authorize access to your repositories using the GitHub integration
-
-If the [GitHub integration][gh-import] is enabled by your GitLab administrator,
-you can use it instead of the personal access token.
-
-1. First you may want to connect your GitHub account to GitLab in order for
- the username mapping to be correct.
-1. Once you connect GitHub, click the **List your GitHub repositories** button
- and you will be redirected to GitHub for permission to access your projects.
-1. After accepting, you'll be automatically redirected to the importer.
-
-You can now go on and [select which repositories to import](#select-which-repositories-to-import).
-
-### Authorize access to your repositories using a personal access token
-
->**Note:**
-For a proper author/assignee mapping for issues and pull requests, the
-[GitHub integration][gh-integration] should be used instead of the
-[personal access token][gh-token]. If the GitHub integration is enabled by your
-GitLab administrator, it should be the preferred method to import your repositories.
-Read more in the [How it works](#how-it-works) section.
-
-If you are not using the GitHub integration, you can still perform a one-off
-authorization with GitHub to grant GitLab access your repositories:
-
-1. Go to <https://github.com/settings/tokens/new>.
-1. Enter a token description.
-1. Check the `repo` scope.
-1. Click **Generate token**.
-1. Copy the token hash.
-1. Go back to GitLab and provide the token to the GitHub importer.
-1. Hit the **List Your GitHub Repositories** button and wait while GitLab reads
- your repositories' information. Once done, you'll be taken to the importer
- page to select the repositories to import.
-
-### Select which repositories to import
-
-After you've authorized access to your GitHub repositories, you will be
-redirected to the GitHub importer page.
-
-From there, you can see the import statuses of your GitHub repositories.
-
-- Those that are being imported will show a _started_ status,
-- those already successfully imported will be green with a _done_ status,
-- whereas those that are not yet imported will have an **Import** button on the
- right side of the table.
-
-If you want, you can import all your GitHub projects in one go by hitting
-**Import all projects** in the upper left corner.
-
-![GitHub importer page](img/import_projects_from_github_importer.png)
-
----
-
-You can also choose a different name for the project and a different namespace,
-if you have the privileges to do so.
-
-[gh-import]: ../../integration/github.md "GitHub integration"
-[gh-rake]: ../../administration/raketasks/github_import.md "GitHub rake task"
-[gh-integration]: #authorize-access-to-your-repositories-using-the-github-integration
-[gh-token]: #authorize-access-to-your-repositories-using-a-personal-access-token
+This document was moved to a [new location](../../user/project/import/github.md).
diff --git a/doc/workflow/importing/import_projects_from_gitlab_com.md b/doc/workflow/importing/import_projects_from_gitlab_com.md
index b27125a44de..df4c180919a 100644
--- a/doc/workflow/importing/import_projects_from_gitlab_com.md
+++ b/doc/workflow/importing/import_projects_from_gitlab_com.md
@@ -1,21 +1 @@
-# Project importing from GitLab.com to your private GitLab instance
-
-You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if
-GitLab support is enabled on your GitLab instance.
-You can read more about GitLab support [here](http://docs.gitlab.com/ce/integration/gitlab.html)
-To get to the importer page you need to go to "New project" page.
-
->**Note:**
-If you are interested in importing Wiki and Merge Request data to your new instance, you'll need to follow the instructions for [project export](../../user/project/settings/import_export.md)
-
-![New project page](gitlab_importer/new_project_page.png)
-
-Click on the "Import projects from GitLab.com" link and you will be redirected to GitLab.com
-for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
-
-
-![Importer page](gitlab_importer/importer.png)
-
-
-To import a project, you can simple click "Import". The importer will import your repository and issues.
-Once the importer is done, a new GitLab project will be created with your imported data. \ No newline at end of file
+This document was moved to a [new location](../../user/project/import/gitlab_com.md).
diff --git a/doc/workflow/importing/migrating_from_svn.md b/doc/workflow/importing/migrating_from_svn.md
index 7a3628a39d7..81df3fbcdbb 100644
--- a/doc/workflow/importing/migrating_from_svn.md
+++ b/doc/workflow/importing/migrating_from_svn.md
@@ -1,183 +1 @@
-# Migrating from SVN to GitLab
-
-Subversion (SVN) is a central version control system (VCS) while
-Git is a distributed version control system. There are some major differences
-between the two, for more information consult your favorite search engine.
-
-## Overview
-
-There are two approaches to SVN to Git migration:
-
-1. [Git/SVN Mirror](#smooth-migration-with-a-gitsvn-mirror-using-subgit) which:
- - Makes the GitLab repository to mirror the SVN project.
- - Git and SVN repositories are kept in sync; you can use either one.
- - Smoothens the migration process and allows to manage migration risks.
-
-1. [Cut over migration](#cut-over-migration-with-svn2git) which:
- - Translates and imports the existing data and history from SVN to Git.
- - Is a fire and forget approach, good for smaller teams.
-
-## Smooth migration with a Git/SVN mirror using SubGit
-
-[SubGit](https://subgit.com) is a tool for a smooth, stress-free SVN to Git
-migration. It creates a writable Git mirror of a local or remote Subversion
-repository and that way you can use both Subversion and Git as long as you like.
-It requires access to your GitLab server as it talks with the Git repositories
-directly in a filesystem level.
-
-### SubGit prerequisites
-
-1. Install Oracle JRE 1.8 or newer. On Debian-based Linux distributions you can
- follow [this article](http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html).
-1. Download SubGit from https://subgit.com/download/.
-1. Unpack the downloaded SubGit zip archive to the `/opt` directory. The `subgit`
- command will be available at `/opt/subgit-VERSION/bin/subgit`.
-
-### SubGit configuration
-
-The first step to mirror you SVN repository in GitLab is to create a new empty
-project which will be used as a mirror. For Omnibus installations the path to
-the repository will be located at
-`/var/opt/gitlab/git-data/repositories/USER/REPO.git` by default. For
-installations from source, the default repository directory will be
-`/home/git/repositories/USER/REPO.git`. For convenience, assign this path to a
-variable:
-
-```
-GIT_REPO_PATH=/var/opt/gitlab/git-data/repositories/USER/REPOS.git
-```
-
-SubGit will keep this repository in sync with a remote SVN project. For
-convenience, assign your remote SVN project URL to a variable:
-
-```
-SVN_PROJECT_URL=http://svn.company.com/repos/project
-```
-
-Next you need to run SubGit to set up a Git/SVN mirror. Make sure the following
-`subgit` command is ran on behalf of the same user that keeps ownership of
-GitLab Git repositories (by default `git`):
-
-```
-subgit configure --layout auto $SVN_PROJECT_URL $GIT_REPO_PATH
-```
-
-Adjust authors and branches mappings, if necessary. Open with your favorite
-text editor:
-
-```
-edit $GIT_REPO_PATH/subgit/authors.txt
-edit $GIT_REPO_PATH/subgit/config
-```
-
-For more information regarding the SubGit configuration options, refer to
-[SubGit's documentation](https://subgit.com/documentation.html) website.
-
-### Initial translation
-
-Now that SubGit has configured the Git/SVN repos, run `subgit` to perform the
-initial translation of existing SVN revisions into the Git repository:
-
-```
-subgit install $GIT_REPO_PATH
-```
-
-After the initial translation is completed, the Git repository and the SVN
-project will be kept in sync by `subgit` - new Git commits will be translated to
-SVN revisions and new SVN revisions will be translated to Git commits. Mirror
-works transparently and does not require any special commands.
-
-If you would prefer to perform one-time cut over migration with `subgit`, use
-the `import` command instead of `install`:
-
-```
-subgit import $GIT_REPO_PATH
-```
-
-### SubGit licensing
-
-Running SubGit in a mirror mode requires a
-[registration](https://subgit.com/pricing.html). Registration is free for open
-source, academic and startup projects.
-
-We're currently working on deeper GitLab/SubGit integration. You may track our
-progress at [this issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/990).
-
-### SubGit support
-
-For any questions related to SVN to GitLab migration with SubGit, you can
-contact the SubGit team directly at [support@subgit.com](mailto:support@subgit.com).
-
-## Cut over migration with svn2git
-
-If you are currently using an SVN repository, you can migrate the repository
-to Git and GitLab. We recommend a hard cut over - run the migration command once
-and then have all developers start using the new GitLab repository immediately.
-Otherwise, it's hard to keep changing in sync in both directions. The conversion
-process should be run on a local workstation.
-
-Install `svn2git`. On all systems you can install as a Ruby gem if you already
-have Ruby and Git installed.
-
-```bash
-sudo gem install svn2git
-```
-
-On Debian-based Linux distributions you can install the native packages:
-
-```bash
-sudo apt-get install git-core git-svn ruby
-```
-
-Optionally, prepare an authors file so `svn2git` can map SVN authors to Git authors.
-If you choose not to create the authors file then commits will not be attributed
-to the correct GitLab user. Some users may not consider this a big issue while
-others will want to ensure they complete this step. If you choose to map authors
-you will be required to map every author that is present on changes in the SVN
-repository. If you don't, the conversion will fail and you will have to update
-the author file accordingly. The following command will search through the
-repository and output a list of authors.
-
-```bash
-svn log --quiet | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq
-```
-
-Use the output from the last command to construct the authors file.
-Create a file called `authors.txt` and add one mapping per line.
-
-```
-janedoe = Jane Doe <janedoe@example.com>
-johndoe = John Doe <johndoe@example.com>
-```
-
-If your SVN repository is in the standard format (trunk, branches, tags,
-not nested) the conversion is simple. For a non-standard repository see
-[svn2git documentation](https://github.com/nirvdrum/svn2git). The following
-command will checkout the repository and do the conversion in the current
-working directory. Be sure to create a new directory for each repository before
-running the `svn2git` command. The conversion process will take some time.
-
-```bash
-svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt
-```
-
-If your SVN repository requires a username and password add the
-`--username <username>` and `--password <password` flags to the above command.
-`svn2git` also supports excluding certain file paths, branches, tags, etc. See
-[svn2git documentation](https://github.com/nirvdrum/svn2git) or run
-`svn2git --help` for full documentation on all of the available options.
-
-Create a new GitLab project, where you will eventually push your converted code.
-Copy the SSH or HTTP(S) repository URL from the project page. Add the GitLab
-repository as a Git remote and push all the changes. This will push all commits,
-branches and tags.
-
-```bash
-git remote add origin git@gitlab.com:<group>/<project>.git
-git push --all origin
-git push --tags origin
-```
-
-## Contribute to this guide
-We welcome all contributions that would expand this guide with instructions on
-how to migrate from SVN and other version control systems.
+This document was moved to a [new location](../../user/project/import/svn.md).
diff --git a/lib/after_commit_queue.rb b/lib/after_commit_queue.rb
new file mode 100644
index 00000000000..b67575a3ac2
--- /dev/null
+++ b/lib/after_commit_queue.rb
@@ -0,0 +1,30 @@
+module AfterCommitQueue
+ extend ActiveSupport::Concern
+
+ included do
+ after_commit :_run_after_commit_queue
+ after_rollback :_clear_after_commit_queue
+ end
+
+ def run_after_commit(method = nil, &block)
+ _after_commit_queue << proc { self.send(method) } if method
+ _after_commit_queue << block if block
+ true
+ end
+
+ protected
+
+ def _run_after_commit_queue
+ while action = _after_commit_queue.pop
+ self.instance_eval(&action)
+ end
+ end
+
+ def _after_commit_queue
+ @after_commit_queue ||= []
+ end
+
+ def _clear_after_commit_queue
+ _after_commit_queue.clear
+ end
+end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 3582ed81b0f..b56fd2388b3 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -290,7 +290,7 @@ module API
def uploaded_file(field, uploads_path)
if params[field]
- bad_request!("#{field} is not a file") unless params[field].respond_to?(:filename)
+ bad_request!("#{field} is not a file") unless params[field][:filename]
return params[field]
end
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index 8a67de10bca..a40018b214e 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -16,9 +16,9 @@ module API
case scope
when String
[scope]
- when Hashie::Mash
+ when ::Hash
scope.values
- when Hashie::Array
+ when ::Array
scope
else
['unknown']
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index 0fc13b35d5b..f70bc0622b7 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -57,7 +57,7 @@ module API
end
get "templates/licenses" do
options = {
- featured: declared(params).popular.present? ? true : nil
+ featured: declared(params)[:popular].present? ? true : nil
}
licences = ::Kaminari.paginate_array(Licensee::License.all(options))
present paginate(licences), with: Entities::RepoLicense
@@ -71,7 +71,7 @@ module API
requires :name, type: String, desc: 'The name of the template'
end
get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do
- not_found!('License') unless Licensee::License.find(declared(params).name)
+ not_found!('License') unless Licensee::License.find(declared(params)[:name])
template = parsed_license_template
@@ -102,7 +102,7 @@ module API
requires :name, type: String, desc: 'The name of the template'
end
get "templates/#{template_type}/:name" do
- new_template = klass.find(declared(params).name)
+ new_template = klass.find(declared(params)[:name])
render_response(template_type, new_template)
end
diff --git a/lib/api/v3/builds.rb b/lib/api/v3/builds.rb
index 93ad9eb26b8..c189d486f50 100644
--- a/lib/api/v3/builds.rb
+++ b/lib/api/v3/builds.rb
@@ -16,7 +16,7 @@ module API
coerce_with: ->(scope) {
if scope.is_a?(String)
[scope]
- elsif scope.is_a?(Hashie::Mash)
+ elsif scope.is_a?(::Hash)
scope.values
else
['unknown']
diff --git a/lib/api/v3/templates.rb b/lib/api/v3/templates.rb
index 4c577a8d2b7..2a2fb59045c 100644
--- a/lib/api/v3/templates.rb
+++ b/lib/api/v3/templates.rb
@@ -59,7 +59,7 @@ module API
end
get route do
options = {
- featured: declared(params).popular.present? ? true : nil
+ featured: declared(params)[:popular].present? ? true : nil
}
present Licensee::License.all(options), with: ::API::Entities::RepoLicense
end
@@ -76,7 +76,7 @@ module API
requires :name, type: String, desc: 'The name of the template'
end
get route, requirements: { name: /[\w\.-]+/ } do
- not_found!('License') unless Licensee::License.find(declared(params).name)
+ not_found!('License') unless Licensee::License.find(declared(params)[:name])
template = parsed_license_template
@@ -111,7 +111,7 @@ module API
requires :name, type: String, desc: 'The name of the template'
end
get route do
- new_template = klass.find(declared(params).name)
+ new_template = klass.find(declared(params)[:name])
render_response(template_type, new_template)
end
diff --git a/lib/gitlab/gitaly_client/blob_service.rb b/lib/gitlab/gitaly_client/blob_service.rb
index 7ea8e8d0857..a250eb75bd4 100644
--- a/lib/gitlab/gitaly_client/blob_service.rb
+++ b/lib/gitlab/gitaly_client/blob_service.rb
@@ -13,10 +13,17 @@ module Gitlab
)
response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_blob, request)
- blob = response.first
- return unless blob.oid.present?
+ data = ''
+ blob = nil
+ response.each do |msg|
+ if blob.nil?
+ blob = msg
+ end
- data = response.reduce(blob.data.dup) { |memo, msg| memo << msg.data.dup }
+ data << msg.data
+ end
+
+ return nil if blob.oid.blank?
Gitlab::Git::Blob.new(
id: blob.oid,
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 93268d9f33c..b36e81278d6 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -60,15 +60,21 @@ module Gitlab
)
response = GitalyClient.call(@repository.storage, :commit_service, :tree_entry, request)
- entry = response.first
- return unless entry.oid.present?
- if entry.type == :BLOB
- rest_of_data = response.reduce("") { |memo, msg| memo << msg.data }
- entry.data += rest_of_data
+ entry = nil
+ data = ''
+ response.each do |msg|
+ if entry.nil?
+ entry = msg
+
+ break unless entry.type == :BLOB
+ end
+
+ data << msg.data
end
+ entry.data = data
- entry
+ entry unless entry.oid.blank?
end
def tree_entries(repository, revision, path)
diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb
index 84ab1977dfa..cbc8d170936 100644
--- a/lib/gitlab/import_export/project_tree_restorer.rb
+++ b/lib/gitlab/import_export/project_tree_restorer.rb
@@ -1,6 +1,9 @@
module Gitlab
module ImportExport
class ProjectTreeRestorer
+ # Relations which cannot have both group_id and project_id at the same time
+ RESTRICT_PROJECT_AND_GROUP = %i(milestones).freeze
+
def initialize(user:, shared:, project:)
@path = File.join(shared.export_path, 'project.json')
@user = user
@@ -118,9 +121,11 @@ module Gitlab
end
def create_relation(relation, relation_hash_list)
+ relation_type = relation.to_sym
+
relation_array = [relation_hash_list].flatten.map do |relation_hash|
- Gitlab::ImportExport::RelationFactory.create(relation_sym: relation.to_sym,
- relation_hash: parsed_relation_hash(relation_hash),
+ Gitlab::ImportExport::RelationFactory.create(relation_sym: relation_type,
+ relation_hash: parsed_relation_hash(relation_hash, relation_type),
members_mapper: members_mapper,
user: @user,
project: restored_project)
@@ -129,8 +134,16 @@ module Gitlab
relation_hash_list.is_a?(Array) ? relation_array : relation_array.first
end
- def parsed_relation_hash(relation_hash)
- relation_hash.merge!('group_id' => restored_project.group.try(:id), 'project_id' => restored_project.id)
+ def parsed_relation_hash(relation_hash, relation_type)
+ if RESTRICT_PROJECT_AND_GROUP.include?(relation_type)
+ params = {}
+ params['group_id'] = restored_project.group.try(:id) if relation_hash['group_id']
+ params['project_id'] = restored_project.id if relation_hash['project_id']
+ else
+ params = { 'group_id' => restored_project.group.try(:id), 'project_id' => restored_project.id }
+ end
+
+ relation_hash.merge(params)
end
end
end
diff --git a/lib/gitlab/sidekiq_status.rb b/lib/gitlab/sidekiq_status.rb
index ca8d3271541..a0a2769cf9e 100644
--- a/lib/gitlab/sidekiq_status.rb
+++ b/lib/gitlab/sidekiq_status.rb
@@ -90,9 +90,14 @@ module Gitlab
#
# Returns an array of completed JIDs
def self.completed_jids(job_ids)
- Sidekiq.redis do |redis|
- job_ids.reject { |jid| redis.exists(key_for(jid)) }
+ statuses = job_status(job_ids)
+
+ completed = []
+ job_ids.zip(statuses).each do |job_id, status|
+ completed << job_id unless status
end
+
+ completed
end
def self.key_for(jid)
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index bd4f233cba9..93be3b066ee 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -50,7 +50,7 @@ describe 'Help Pages' do
it 'hides the version check image if the image request fails' do
# We use '--load-images=yes' with poltergeist so the image fails to load
- expect(find('.js-version-status-badge', visible: false)).not_to be_visible
+ expect(page).to have_selector('.js-version-status-badge', visible: false)
end
end
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index 672022304da..f183dd8cb75 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -7,9 +7,8 @@ describe 'Profile account page' do
sign_in(user)
end
- describe 'when signup is enabled' do
+ describe 'when I delete my account' do
before do
- stub_application_setting(signup_enabled: true)
visit profile_account_path
end
@@ -21,18 +20,6 @@ describe 'Profile account page' do
end
end
- describe 'when signup is disabled' do
- before do
- stub_application_setting(signup_enabled: false)
- visit profile_account_path
- end
-
- it 'does not have option to remove account' do
- expect(page).not_to have_content('Remove account')
- expect(current_path).to eq(profile_account_path)
- end
- end
-
describe 'when I reset private token' do
before do
visit profile_account_path
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index d3d7915bebf..baf3d29e6c5 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -18,7 +18,7 @@ feature 'Project' do
click_button "Create project"
end
- expect(page).to have_content 'This project Loading..'
+ expect(page).to have_content template.name
end
end
diff --git a/spec/lib/after_commit_queue_spec.rb b/spec/lib/after_commit_queue_spec.rb
new file mode 100644
index 00000000000..6e7c2ec2363
--- /dev/null
+++ b/spec/lib/after_commit_queue_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe AfterCommitQueue do
+ it 'runs after transaction is committed' do
+ called = false
+ test_proc = proc { called = true }
+
+ project = build(:project)
+ project.run_after_commit(&test_proc)
+
+ project.save
+
+ expect(called).to be true
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
index 87f45619e7a..0d5fffa38ff 100644
--- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
@@ -210,7 +210,11 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads::Event do
end
end
-describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads do
+##
+# The background migration relies on a temporary table, hence we're migrating
+# to a specific version of the database where said table is still present.
+#
+describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migration, schema: 20170608152748 do
let(:migration) { described_class.new }
let(:project) { create(:project_empty_repo) }
let(:author) { create(:user) }
@@ -229,21 +233,6 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads do
)
end
- # The background migration relies on a temporary table, hence we're migrating
- # to a specific version of the database where said table is still present.
- before :all do
- ActiveRecord::Migration.verbose = false
-
- ActiveRecord::Migrator
- .migrate(ActiveRecord::Migrator.migrations_paths, 20170608152748)
- end
-
- after :all do
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths)
-
- ActiveRecord::Migration.verbose = true
- end
-
describe '#perform' do
it 'returns if data should not be migrated' do
allow(migration).to receive(:migrate?).and_return(false)
diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json
index a78836c3c34..2d8f3d4a566 100644
--- a/spec/lib/gitlab/import_export/project.light.json
+++ b/spec/lib/gitlab/import_export/project.light.json
@@ -2,6 +2,20 @@
"description": "Nisi et repellendus ut enim quo accusamus vel magnam.",
"visibility_level": 10,
"archived": false,
+ "milestones": [
+ {
+ "id": 1,
+ "title": "test milestone",
+ "project_id": 8,
+ "description": "test milestone",
+ "due_date": null,
+ "created_at": "2016-06-14T15:02:04.415Z",
+ "updated_at": "2016-06-14T15:02:04.415Z",
+ "state": "active",
+ "iid": 1,
+ "group_id": null
+ }
+ ],
"labels": [
{
"id": 2,
@@ -14,20 +28,6 @@
"description": "",
"type": "ProjectLabel",
"priorities": [
- ]
- },
- {
- "id": 3,
- "title": "test3",
- "color": "#428bca",
- "group_id": 8,
- "created_at": "2016-07-22T08:55:44.161Z",
- "updated_at": "2016-07-22T08:55:44.161Z",
- "template": false,
- "description": "",
- "project_id": null,
- "type": "GroupLabel",
- "priorities": [
{
"id": 1,
"project_id": 5,
@@ -39,10 +39,80 @@
]
}
],
+ "issues": [
+ {
+ "id": 1,
+ "title": "Fugiat est minima quae maxime non similique.",
+ "assignee_id": null,
+ "project_id": 8,
+ "author_id": 1,
+ "created_at": "2017-07-07T18:13:01.138Z",
+ "updated_at": "2017-08-15T18:37:40.807Z",
+ "branch_name": null,
+ "description": "Quam totam fuga numquam in eveniet.",
+ "state": "opened",
+ "iid": 20,
+ "updated_by_id": 1,
+ "confidential": false,
+ "deleted_at": null,
+ "due_date": null,
+ "moved_to_id": null,
+ "lock_version": null,
+ "time_estimate": 0,
+ "closed_at": null,
+ "last_edited_at": null,
+ "last_edited_by_id": null,
+ "group_milestone_id": null,
+ "label_links": [
+ {
+ "id": 11,
+ "label_id": 6,
+ "target_id": 1,
+ "target_type": "Issue",
+ "created_at": "2017-08-15T18:37:40.795Z",
+ "updated_at": "2017-08-15T18:37:40.795Z",
+ "label": {
+ "id": 6,
+ "title": "group label",
+ "color": "#A8D695",
+ "project_id": null,
+ "created_at": "2017-08-15T18:37:19.698Z",
+ "updated_at": "2017-08-15T18:37:19.698Z",
+ "template": false,
+ "description": "",
+ "group_id": 5,
+ "type": "GroupLabel",
+ "priorities": []
+ }
+ },
+ {
+ "id": 11,
+ "label_id": 2,
+ "target_id": 1,
+ "target_type": "Issue",
+ "created_at": "2017-08-15T18:37:40.795Z",
+ "updated_at": "2017-08-15T18:37:40.795Z",
+ "label": {
+ "id": 6,
+ "title": "project label",
+ "color": "#A8D695",
+ "project_id": null,
+ "created_at": "2017-08-15T18:37:19.698Z",
+ "updated_at": "2017-08-15T18:37:19.698Z",
+ "template": false,
+ "description": "",
+ "group_id": 5,
+ "type": "ProjectLabel",
+ "priorities": []
+ }
+ }
+ ]
+ }
+ ],
"snippets": [
],
"hooks": [
]
-} \ No newline at end of file
+}
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 7ee0e22f28d..956f1d56eb4 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -183,7 +183,8 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
let(:restored_project_json) { project_tree_restorer.restore }
before do
- allow(ImportExport).to receive(:project_filename).and_return('project.light.json')
+ project_tree_restorer.instance_variable_set(:@path, "spec/lib/gitlab/import_export/project.light.json")
+
allow(shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
end
@@ -195,7 +196,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
restored_project_json
- expect(shared.errors.first).not_to include('test')
+ expect(shared.errors.first).to be_nil
end
end
end
@@ -219,15 +220,42 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
before do
+ project_tree_restorer.instance_variable_set(:@path, "spec/lib/gitlab/import_export/project.light.json")
+
restored_project_json
end
- it 'has group labels' do
- expect(GroupLabel.count).to eq(1)
+ it 'correctly restores project' do
+ expect(restored_project_json).to be_truthy
+ expect(shared.errors).to be_empty
+ end
+
+ it 'has labels' do
+ expect(project.labels.count).to eq(2)
+ end
+
+ it 'creates group label' do
+ expect(project.group.labels.count).to eq(1)
end
it 'has label priorities' do
- expect(GroupLabel.first.priorities).not_to be_empty
+ expect(project.labels.first.priorities).not_to be_empty
+ end
+
+ it 'has milestones' do
+ expect(project.milestones.count).to eq(1)
+ end
+
+ it 'has issue' do
+ expect(project.issues.count).to eq(1)
+ expect(project.issues.first.labels.count).to eq(2)
+ end
+
+ it 'has issue with group label and project label' do
+ labels = project.issues.first.labels
+
+ expect(labels.where(type: "GroupLabel").count).to eq(1)
+ expect(labels.where(type: "ProjectLabel").count).to eq(1)
end
end
end
diff --git a/spec/migrations/README.md b/spec/migrations/README.md
index 05d4f35db72..45cf25b96de 100644
--- a/spec/migrations/README.md
+++ b/spec/migrations/README.md
@@ -28,6 +28,14 @@ The `after` hook will migrate the database **up** and reinstitutes the latest
schema version, so that the process does not affect subsequent specs and
ensures proper isolation.
+## Testing a class that is not an ActiveRecord::Migration
+
+In order to test a class that is not a migration itself, you will need to
+manually provide a required schema version. Please add a `schema` tag to a
+context that you want to switch the database schema within.
+
+Example: `describe SomeClass, :migration, schema: 20170608152748`.
+
## Available helpers
Use `table` helper to create a temporary `ActiveRecord::Base` derived model
@@ -80,8 +88,6 @@ end
## Best practices
-1. Use only one test example per migration unless there is a good reason to
-use more.
1. Note that this type of tests do not run within the transaction, we use
a truncation database cleanup strategy. Do not depend on transaction being
present.
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index eba71ba2f72..5e60511f3a8 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1610,8 +1610,7 @@ describe Project do
it 'imports a project' do
expect_any_instance_of(RepositoryImportWorker).to receive(:perform).and_call_original
- project.import_schedule
-
+ expect { project.import_schedule }.to change { project.import_jid }
expect(project.reload.import_status).to eq('finished')
end
end
@@ -1624,6 +1623,13 @@ describe Project do
allow(Projects::HousekeepingService).to receive(:new) { housekeeping_service }
end
+ it 'resets project import_error' do
+ error_message = 'Some error'
+ mirror = create(:project_empty_repo, :import_started, import_error: error_message)
+
+ expect { mirror.import_finish }.to change { mirror.import_error }.from(error_message).to(nil)
+ end
+
it 'performs housekeeping when an import of a fresh project is completed' do
project = create(:project_empty_repo, :import_started, import_type: :github)
@@ -1730,17 +1736,21 @@ describe Project do
end
describe '#add_import_job' do
+ let(:import_jid) { '123' }
+
context 'forked' do
let(:forked_project_link) { create(:forked_project_link, :forked_to_empty_project) }
let(:forked_from_project) { forked_project_link.forked_from_project }
let(:project) { forked_project_link.forked_to_project }
it 'schedules a RepositoryForkWorker job' do
- expect(RepositoryForkWorker).to receive(:perform_async)
- .with(project.id, forked_from_project.repository_storage_path,
- forked_from_project.disk_path, project.namespace.full_path)
+ expect(RepositoryForkWorker).to receive(:perform_async).with(
+ project.id,
+ forked_from_project.repository_storage_path,
+ forked_from_project.disk_path,
+ project.namespace.full_path).and_return(import_jid)
- project.add_import_job
+ expect(project.add_import_job).to eq(import_jid)
end
end
@@ -1748,9 +1758,8 @@ describe Project do
it 'schedules a RepositoryImportWorker job' do
project = create(:project, import_url: generate(:url))
- expect(RepositoryImportWorker).to receive(:perform_async).with(project.id)
-
- project.add_import_job
+ expect(RepositoryImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid)
+ expect(project.add_import_job).to eq(import_jid)
end
end
end
@@ -2311,6 +2320,44 @@ describe Project do
end
end
+ describe '#remove_pages' do
+ let(:project) { create(:project) }
+ let(:namespace) { project.namespace }
+ let(:pages_path) { project.pages_path }
+
+ around do |example|
+ FileUtils.mkdir_p(pages_path)
+ begin
+ example.run
+ ensure
+ FileUtils.rm_rf(pages_path)
+ end
+ end
+
+ it 'removes the pages directory' do
+ expect_any_instance_of(Projects::UpdatePagesConfigurationService).to receive(:execute)
+ expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project).and_return(true)
+ expect(PagesWorker).to receive(:perform_in).with(5.minutes, :remove, namespace.full_path, anything)
+
+ project.remove_pages
+ end
+
+ it 'is a no-op when there is no namespace' do
+ project.update_column(:namespace_id, nil)
+
+ expect_any_instance_of(Projects::UpdatePagesConfigurationService).not_to receive(:execute)
+ expect_any_instance_of(Gitlab::PagesTransfer).not_to receive(:rename_project)
+
+ project.remove_pages
+ end
+
+ it 'is run when the project is destroyed' do
+ expect(project).to receive(:remove_pages).and_call_original
+
+ project.destroy
+ end
+ end
+
describe '#forks_count' do
it 'returns the number of forks' do
project = build(:project)
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 3eea39d4bf4..c10197ff651 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -132,17 +132,12 @@ RSpec.configure do |config|
Sidekiq.redis(&:flushall)
end
- config.before(:example, :migration) do
- ActiveRecord::Migrator
- .migrate(migrations_paths, previous_migration.version)
-
- reset_column_in_migration_models
+ config.before(:each, :migration) do
+ schema_migrate_down!
end
- config.after(:example, :migration) do
- ActiveRecord::Migrator.migrate(migrations_paths)
-
- reset_column_in_migration_models
+ config.after(:context, :migration) do
+ schema_migrate_up!
end
config.around(:each, :nested_groups) do |example|
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 7f5769209bb..b0f520d08e8 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -20,7 +20,7 @@ RSpec.configure do |config|
end
config.before(:each, :migration) do
- DatabaseCleaner.strategy = :truncation
+ DatabaseCleaner.strategy = :truncation, { cache_tables: false }
end
config.before(:each) do
diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb
index aabdad13047..255b3d96a62 100644
--- a/spec/support/migrations_helpers.rb
+++ b/spec/support/migrations_helpers.rb
@@ -31,6 +31,35 @@ module MigrationsHelpers
end
end
+ def migration_schema_version
+ self.class.metadata[:schema] || previous_migration.version
+ end
+
+ def schema_migrate_down!
+ disable_migrations_output do
+ ActiveRecord::Migrator.migrate(migrations_paths,
+ migration_schema_version)
+ end
+
+ reset_column_in_migration_models
+ end
+
+ def schema_migrate_up!
+ disable_migrations_output do
+ ActiveRecord::Migrator.migrate(migrations_paths)
+ end
+
+ reset_column_in_migration_models
+ end
+
+ def disable_migrations_output
+ ActiveRecord::Migration.verbose = false
+
+ yield
+ ensure
+ ActiveRecord::Migration.verbose = true
+ end
+
def migrate!
ActiveRecord::Migrator.up(migrations_paths) do |migration|
migration.name == described_class.name
diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb
index ca904e512ac..100dfc32bbe 100644
--- a/spec/workers/repository_import_worker_spec.rb
+++ b/spec/workers/repository_import_worker_spec.rb
@@ -22,8 +22,8 @@ describe RepositoryImportWorker do
it 'hide the credentials that were used in the import URL' do
error = %q{remote: Not Found fatal: repository 'https://user:pass@test.com/root/repoC.git/' not found }
+ project.update_attributes(import_jid: '123')
expect_any_instance_of(Projects::ImportService).to receive(:execute).and_return({ status: :error, message: error })
- allow(subject).to receive(:jid).and_return('123')
expect do
subject.perform(project.id)
diff --git a/spec/workers/stuck_import_jobs_worker_spec.rb b/spec/workers/stuck_import_jobs_worker_spec.rb
index 2f5b685a332..a82eb54ffe4 100644
--- a/spec/workers/stuck_import_jobs_worker_spec.rb
+++ b/spec/workers/stuck_import_jobs_worker_spec.rb
@@ -8,29 +8,29 @@ describe StuckImportJobsWorker do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(exclusive_lease_uuid)
end
- describe 'long running import' do
- let(:project) { create(:project, import_jid: '123', import_status: 'started') }
+ describe 'with started import_status' do
+ let(:project) { create(:project, :import_started, import_jid: '123') }
- before do
- allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return(['123'])
- end
+ describe 'long running import' do
+ it 'marks the project as failed' do
+ allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return(['123'])
- it 'marks the project as failed' do
- expect { worker.perform }.to change { project.reload.import_status }.to('failed')
+ expect { worker.perform }.to change { project.reload.import_status }.to('failed')
+ end
end
- end
- describe 'running import' do
- let(:project) { create(:project, import_jid: '123', import_status: 'started') }
-
- before do
- allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return([])
- end
+ describe 'running import' do
+ it 'does not mark the project as failed' do
+ allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return([])
- it 'does not mark the project as failed' do
- worker.perform
+ expect { worker.perform }.not_to change { project.reload.import_status }
+ end
- expect(project.reload.import_status).to eq('started')
+ describe 'import without import_jid' do
+ it 'marks the project as failed' do
+ expect { worker.perform }.to change { project.reload.import_status }.to('failed')
+ end
+ end
end
end
end