summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb1
-rw-r--r--app/controllers/groups/group_members_controller.rb1
-rwxr-xr-xapp/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/controllers/projects/milestones_controller.rb2
-rw-r--r--app/controllers/registrations_controller.rb4
-rw-r--r--app/services/users/destroy_service.rb4
-rw-r--r--changelogs/unreleased/29541-fix-github-importer-deleted-fork.yml4
-rw-r--r--changelogs/unreleased/sh-fix-destroy-user-race.yml5
-rw-r--r--lib/api/users.rb2
-rw-r--r--lib/gitlab/github_import/branch_formatter.rb8
-rw-r--r--lib/gitlab/github_import/pull_request_formatter.rb33
-rw-r--r--spec/controllers/registrations_controller_spec.rb16
-rw-r--r--spec/finders/issues_finder_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer_spec.rb4
-rw-r--r--spec/lib/gitlab/github_import/pull_request_formatter_spec.rb47
-rw-r--r--spec/requests/api/users_spec.rb10
-rw-r--r--spec/services/users/destroy_spec.rb19
-rw-r--r--spec/support/test_env.rb6
18 files changed, 130 insertions, 39 deletions
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 5055c318a5f..dc9a6df5f75 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -1,6 +1,7 @@
class Admin::AbuseReportsController < Admin::ApplicationController
def index
@abuse_reports = AbuseReport.order(id: :desc).page(params[:page])
+ @abuse_reports.includes(:reporter, :user)
end
def destroy
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 0cbf3eb58a3..00c50f9d0ad 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -14,6 +14,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
@members = @members.search(params[:search]) if params[:search].present?
@members = @members.sort(@sort)
@members = @members.page(params[:page]).per(50)
+ @members.includes(:user)
@requesters = AccessRequestsFinder.new(@group).execute(current_user)
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 9621b30b251..37e3ac05916 100755
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -39,6 +39,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@collection_type = "MergeRequest"
@merge_requests = merge_requests_collection
@merge_requests = @merge_requests.page(params[:page])
+ @merge_requests = @merge_requests.includes(merge_request_diff: :merge_request)
@issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type)
if @merge_requests.out_of_range? && @merge_requests.total_pages != 0
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 5922e686cd0..408c0c60cb0 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -21,9 +21,9 @@ class Projects::MilestonesController < Projects::ApplicationController
@sort = params[:sort] || 'due_date_asc'
@milestones = @milestones.sort(@sort)
- @milestones = @milestones.includes(:project)
respond_to do |format|
format.html do
+ @milestones = @milestones.includes(:project)
@milestones = @milestones.page(params[:page])
end
format.json do
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index a49a1f50a81..8109427a45f 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -25,12 +25,12 @@ class RegistrationsController < Devise::RegistrationsController
end
def destroy
- Users::DestroyService.new(current_user).execute(current_user)
+ DeleteUserWorker.perform_async(current_user.id, current_user.id)
respond_to do |format|
format.html do
session.try(:destroy)
- redirect_to new_user_session_path, notice: "Account successfully removed."
+ redirect_to new_user_session_path, notice: "Account scheduled for removal."
end
end
end
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index 833da5bc5d1..a3b32a71a64 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -20,10 +20,10 @@ module Users
Groups::DestroyService.new(group, current_user).execute
end
- user.personal_projects.each do |project|
+ user.personal_projects.with_deleted.each do |project|
# Skip repository removal because we remove directory with namespace
# that contain all this repositories
- ::Projects::DestroyService.new(project, current_user, skip_repo: true).async_execute
+ ::Projects::DestroyService.new(project, current_user, skip_repo: true).execute
end
move_issues_to_ghost_user(user)
diff --git a/changelogs/unreleased/29541-fix-github-importer-deleted-fork.yml b/changelogs/unreleased/29541-fix-github-importer-deleted-fork.yml
new file mode 100644
index 00000000000..fcb5798a619
--- /dev/null
+++ b/changelogs/unreleased/29541-fix-github-importer-deleted-fork.yml
@@ -0,0 +1,4 @@
+---
+title: Fix GitHub Importer for PRs of deleted forked repositories
+merge_request: 9992
+author:
diff --git a/changelogs/unreleased/sh-fix-destroy-user-race.yml b/changelogs/unreleased/sh-fix-destroy-user-race.yml
new file mode 100644
index 00000000000..4d650b51ada
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-destroy-user-race.yml
@@ -0,0 +1,5 @@
+---
+title: Fix race condition where a namespace would be deleted before a project was
+ deleted
+merge_request:
+author:
diff --git a/lib/api/users.rb b/lib/api/users.rb
index a4201fe6fed..530ca0b5235 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -293,7 +293,7 @@ module API
user = User.find_by(id: params[:id])
not_found!('User') unless user
- ::Users::DestroyService.new(current_user).execute(user)
+ DeleteUserWorker.perform_async(current_user.id, user.id)
end
desc 'Block a user. Available only for admins.'
diff --git a/lib/gitlab/github_import/branch_formatter.rb b/lib/gitlab/github_import/branch_formatter.rb
index 5d29e698b27..8aa885fb811 100644
--- a/lib/gitlab/github_import/branch_formatter.rb
+++ b/lib/gitlab/github_import/branch_formatter.rb
@@ -11,6 +11,14 @@ module Gitlab
sha.present? && ref.present?
end
+ def user
+ raw_data.user&.login || 'unknown'
+ end
+
+ def short_sha
+ Commit.truncate_sha(sha)
+ end
+
private
def branch_exists?
diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb
index add7236e339..38660a7ccca 100644
--- a/lib/gitlab/github_import/pull_request_formatter.rb
+++ b/lib/gitlab/github_import/pull_request_formatter.rb
@@ -1,8 +1,8 @@
module Gitlab
module GithubImport
class PullRequestFormatter < IssuableFormatter
- delegate :exists?, :project, :ref, :repo, :sha, to: :source_branch, prefix: true
- delegate :exists?, :project, :ref, :repo, :sha, to: :target_branch, prefix: true
+ delegate :user, :project, :ref, :repo, :sha, to: :source_branch, prefix: true
+ delegate :user, :exists?, :project, :ref, :repo, :sha, :short_sha, to: :target_branch, prefix: true
def attributes
{
@@ -37,13 +37,20 @@ module Gitlab
end
def source_branch_name
- @source_branch_name ||= begin
- if cross_project?
- "pull/#{number}/#{source_branch_repo.full_name}/#{source_branch_ref}"
+ @source_branch_name ||=
+ if cross_project? || !source_branch_exists?
+ source_branch_name_prefixed
else
- source_branch_exists? ? source_branch_ref : "pull/#{number}/#{source_branch_ref}"
+ source_branch_ref
end
- end
+ end
+
+ def source_branch_name_prefixed
+ "gh-#{target_branch_short_sha}/#{number}/#{source_branch_user}/#{source_branch_ref}"
+ end
+
+ def source_branch_exists?
+ !cross_project? && source_branch.exists?
end
def target_branch
@@ -51,13 +58,17 @@ module Gitlab
end
def target_branch_name
- @target_branch_name ||= begin
- target_branch_exists? ? target_branch_ref : "pull/#{number}/#{target_branch_ref}"
- end
+ @target_branch_name ||= target_branch_exists? ? target_branch_ref : target_branch_name_prefixed
+ end
+
+ def target_branch_name_prefixed
+ "gl-#{target_branch_short_sha}/#{number}/#{target_branch_user}/#{target_branch_ref}"
end
def cross_project?
- source_branch.repo.id != target_branch.repo.id
+ return true if source_branch_repo.nil?
+
+ source_branch_repo.id != target_branch_repo.id
end
def opened?
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 902911071c4..71dd9ef3eb4 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -68,4 +68,20 @@ describe RegistrationsController do
end
end
end
+
+ describe '#destroy' do
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'schedules the user for destruction' do
+ expect(DeleteUserWorker).to receive(:perform_async).with(user.id, user.id)
+
+ post(:destroy)
+
+ expect(response.status).to eq(302)
+ end
+ end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index ee52dc65175..231fd85c464 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -9,7 +9,7 @@ describe IssuesFinder do
let(:label) { create(:label, project: project2) }
let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone, title: 'gitlab') }
let(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'gitlab') }
- let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) }
+ let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2, title: 'tanuki', description: 'tanuki') }
describe '#execute' do
let(:closed_issue) { create(:issue, author: user2, assignee: user2, project: project2, state: 'closed') }
diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb
index 8b867fbe322..9d5e20841b5 100644
--- a/spec/lib/gitlab/github_import/importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer_spec.rb
@@ -215,9 +215,9 @@ describe Gitlab::GithubImport::Importer, lib: true do
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
let(:repository) { double(id: 1, fork: false) }
let(:source_sha) { create(:commit, project: project).id }
- let(:source_branch) { double(ref: 'branch-merged', repo: repository, sha: source_sha) }
+ let(:source_branch) { double(ref: 'branch-merged', repo: repository, sha: source_sha, user: octocat) }
let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
- let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) }
+ let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha, user: octocat) }
let(:pull_request) do
double(
number: 1347,
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index 44423917944..9b9f7e4d34e 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -4,15 +4,18 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
let(:client) { double }
let(:project) { create(:project, :repository) }
let(:source_sha) { create(:commit, project: project).id }
- let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
+ let(:target_commit) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit) }
+ let(:target_sha) { target_commit.id }
+ let(:target_short_sha) { target_commit.id.to_s[0..7] }
let(:repository) { double(id: 1, fork: false) }
let(:source_repo) { repository }
let(:source_branch) { double(ref: 'branch-merged', repo: source_repo, sha: source_sha) }
let(:forked_source_repo) { double(id: 2, fork: true, name: 'otherproject', full_name: 'company/otherproject') }
let(:target_repo) { repository }
- let(:target_branch) { double(ref: 'master', repo: target_repo, sha: target_sha) }
- let(:removed_branch) { double(ref: 'removed-branch', repo: source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b') }
- let(:forked_branch) { double(ref: 'master', repo: forked_source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b') }
+ let(:target_branch) { double(ref: 'master', repo: target_repo, sha: target_sha, user: octocat) }
+ let(:removed_branch) { double(ref: 'removed-branch', repo: source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) }
+ let(:forked_branch) { double(ref: 'master', repo: forked_source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) }
+ let(:branch_deleted_repo) { double(ref: 'master', repo: nil, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) }
let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
@@ -203,16 +206,24 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
context 'when source branch does not exist' do
let(:raw_data) { double(base_data.merge(head: removed_branch)) }
- it 'prefixes branch name with pull request number' do
- expect(pull_request.source_branch_name).to eq 'pull/1347/removed-branch'
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/removed-branch"
end
end
context 'when source branch is from a fork' do
let(:raw_data) { double(base_data.merge(head: forked_branch)) }
- it 'prefixes branch name with pull request number and project with namespace to avoid collision' do
- expect(pull_request.source_branch_name).to eq 'pull/1347/company/otherproject/master'
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/master"
+ end
+ end
+
+ context 'when source branch is from a deleted fork' do
+ let(:raw_data) { double(base_data.merge(head: branch_deleted_repo)) }
+
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/master"
end
end
end
@@ -229,8 +240,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
context 'when target branch does not exist' do
let(:raw_data) { double(base_data.merge(base: removed_branch)) }
- it 'prefixes branch name with pull request number' do
- expect(pull_request.target_branch_name).to eq 'pull/1347/removed-branch'
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.target_branch_name).to eq 'gl-2e5d3239/1347/octocat/removed-branch'
end
end
end
@@ -290,6 +301,14 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end
end
+ context 'when source repository does not exist anymore' do
+ let(:raw_data) { double(base_data.merge(head: branch_deleted_repo)) }
+
+ it 'returns true' do
+ expect(pull_request.cross_project?).to eq true
+ end
+ end
+
context 'when source and target repositories are the same' do
let(:raw_data) { double(base_data.merge(head: source_branch)) }
@@ -299,6 +318,14 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end
end
+ describe '#source_branch_exists?' do
+ let(:raw_data) { double(base_data.merge(head: forked_branch)) }
+
+ it 'returns false when is a cross_project' do
+ expect(pull_request.source_branch_exists?).to eq false
+ end
+ end
+
describe '#url' do
let(:raw_data) { double(base_data) }
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 04e7837fd7a..f793c0db2f3 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -676,7 +676,7 @@ describe API::Users, api: true do
before { admin }
it "deletes user" do
- delete api("/users/#{user.id}", admin)
+ Sidekiq::Testing.inline! { delete api("/users/#{user.id}", admin) }
expect(response).to have_http_status(204)
expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
@@ -684,23 +684,23 @@ describe API::Users, api: true do
end
it "does not delete for unauthenticated user" do
- delete api("/users/#{user.id}")
+ Sidekiq::Testing.inline! { delete api("/users/#{user.id}") }
expect(response).to have_http_status(401)
end
it "is not available for non admin users" do
- delete api("/users/#{user.id}", user)
+ Sidekiq::Testing.inline! { delete api("/users/#{user.id}", user) }
expect(response).to have_http_status(403)
end
it "returns 404 for non-existing user" do
- delete api("/users/999999", admin)
+ Sidekiq::Testing.inline! { delete api("/users/999999", admin) }
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 User Not Found')
end
it "returns a 404 for invalid ID" do
- delete api("/users/ASDF", admin)
+ Sidekiq::Testing.inline! { delete api("/users/ASDF", admin) }
expect(response).to have_http_status(404)
end
diff --git a/spec/services/users/destroy_spec.rb b/spec/services/users/destroy_spec.rb
index 9a28c03d968..66c61b7f8ff 100644
--- a/spec/services/users/destroy_spec.rb
+++ b/spec/services/users/destroy_spec.rb
@@ -17,13 +17,28 @@ describe Users::DestroyService, services: true do
expect { Namespace.with_deleted.find(user.namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
- it 'will delete the project in the near future' do
- expect_any_instance_of(Projects::DestroyService).to receive(:async_execute).once
+ it 'will delete the project' do
+ expect_any_instance_of(Projects::DestroyService).to receive(:execute).once
service.execute(user)
end
end
+ context 'projects in pending_delete' do
+ before do
+ project.pending_delete = true
+ project.save
+ end
+
+ it 'destroys a project in pending_delete' do
+ expect_any_instance_of(Projects::DestroyService).to receive(:execute).once
+
+ service.execute(user)
+
+ expect { Project.find(project.id) }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
context "a deleted user's issues" do
let(:project) { create(:project) }
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index a19a35c2c0d..1b5cb71a6b0 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -131,8 +131,10 @@ module TestEnv
set_repo_refs(repo_path, branch_sha)
- # We must copy bare repositories because we will push to them.
- system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare}))
+ unless File.directory?(repo_path_bare)
+ # We must copy bare repositories because we will push to them.
+ system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare}))
+ end
end
def copy_repo(project)