From ae33fdf297e03866ecc6c31c5470dd5ad72d1328 Mon Sep 17 00:00:00 2001 From: Angus MacArthur Date: Tue, 19 Mar 2013 11:37:50 -0400 Subject: updated fork feature to use gitlab-shell for v5 of gitlab --- app/contexts/projects/fork_context.rb | 37 +++++++++++++++++++++++++++++++ app/controllers/projects_controller.rb | 15 +++++++++++++ app/models/ability.rb | 3 ++- app/models/forked_project_link.rb | 8 +++++++ app/models/project.rb | 7 ++++++ app/observers/project_observer.rb | 12 +++++----- app/views/projects/_clone_panel.html.haml | 3 +++ 7 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 app/contexts/projects/fork_context.rb create mode 100644 app/models/forked_project_link.rb (limited to 'app') diff --git a/app/contexts/projects/fork_context.rb b/app/contexts/projects/fork_context.rb new file mode 100644 index 00000000000..e206a1cdf87 --- /dev/null +++ b/app/contexts/projects/fork_context.rb @@ -0,0 +1,37 @@ +module Projects + class ForkContext < BaseContext + include Gitlab::ShellAdapter + + def initialize(project, user) + @from_project, @current_user = project, user + end + + def execute + project = Project.new + project.initialize_dup(@from_project) + project.name = @from_project.name + project.path = @from_project.path + project.namespace = current_user.namespace + + Project.transaction do + #First save the DB entries as they can be rolled back if the repo fork fails + project.creator = current_user + project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id) + if project.save + project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) + end + #Now fork the repo + unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path) + raise "forking failed in gitlab-shell" + end + project.ensure_satellite_exists + + end + project + rescue => ex + project.errors.add(:base, "Can't fork project. Please try again later") + project.destroy + end + + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 8e55aa01cc9..255baba0ecb 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -78,4 +78,19 @@ class ProjectsController < ProjectResourceController format.html { redirect_to root_path } end end + + def fork + @project = ::Projects::ForkContext.new(project, current_user).execute + + respond_to do |format| + format.html do + if @project.saved? && @project.forked? + redirect_to(@project, notice: 'Project was successfully forked.') + else + render action: "new" + end + end + format.js + end + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 5b49104da8a..0c5fbc2e5e7 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -60,7 +60,8 @@ class Ability :read_note, :write_project, :write_issue, - :write_note + :write_note, + :fork_project ] end diff --git a/app/models/forked_project_link.rb b/app/models/forked_project_link.rb new file mode 100644 index 00000000000..c3199ca264e --- /dev/null +++ b/app/models/forked_project_link.rb @@ -0,0 +1,8 @@ +class ForkedProjectLink < ActiveRecord::Base + attr_accessible :forked_from_project_id, :forked_to_project_id + + # Relations + belongs_to :forked_to_project, class_name: Project + belongs_to :forked_from_project, class_name: Project + +end diff --git a/app/models/project.rb b/app/models/project.rb index cad8f1666d3..1d1b7c1134c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -43,6 +43,8 @@ class Project < ActiveRecord::Base has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id' has_one :gitlab_ci_service, dependent: :destroy + has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" + has_one :forked_from_project, through: :forked_project_link has_many :events, dependent: :destroy has_many :merge_requests, dependent: :destroy @@ -400,4 +402,9 @@ class Project < ActiveRecord::Base def protected_branch? branch_name protected_branches_names.include?(branch_name) end + + def forked? + !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) + end + end diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index 7d7ecdd319f..de9edf41c6d 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -1,11 +1,13 @@ class ProjectObserver < BaseObserver def after_create(project) - GitlabShellWorker.perform_async( - :add_repository, - project.path_with_namespace - ) + unless project.forked? + GitlabShellWorker.perform_async( + :add_repository, + project.path_with_namespace + ) - log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") + log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") + end end def after_update(project) diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml index 9a2be429206..7b90f80985c 100644 --- a/app/views/projects/_clone_panel.html.haml +++ b/app/views/projects/_clone_panel.html.haml @@ -5,6 +5,9 @@ .span4.pull-right .pull-right - unless @project.empty_repo? + - if can? current_user, :fork_project, @project + = link_to fork_project_path(@project), title: "Fork", class: "btn small grouped", method: "POST" do + Fork - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do %i.icon-download-alt -- cgit v1.2.1 From de8df1be1a75cfde02a5a1d3f52a888b770c54e0 Mon Sep 17 00:00:00 2001 From: Angus MacArthur Date: Thu, 2 May 2013 15:30:13 -0400 Subject: Fix bug for repeated fork requests When asking to fork a project and a project with the same name already exists (likely from a previous fork), the recovery from the fork failure would inadvertantly delete the repo of the existing destination project. --- app/contexts/projects/fork_context.rb | 42 +++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'app') diff --git a/app/contexts/projects/fork_context.rb b/app/contexts/projects/fork_context.rb index e206a1cdf87..f2a0684b01c 100644 --- a/app/contexts/projects/fork_context.rb +++ b/app/contexts/projects/fork_context.rb @@ -10,28 +10,36 @@ module Projects project = Project.new project.initialize_dup(@from_project) project.name = @from_project.name - project.path = @from_project.path + project.path = @from_project.path project.namespace = current_user.namespace + project.creator = current_user - Project.transaction do - #First save the DB entries as they can be rolled back if the repo fork fails - project.creator = current_user - project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id) - if project.save - project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) + # If the project cannot save, we do not want to trigger the project destroy + # as this can have the side effect of deleting a repo attached to an existing + # project with the same name and namespace + if project.valid? + begin + Project.transaction do + #First save the DB entries as they can be rolled back if the repo fork fails + project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id) + if project.save + project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) + end + #Now fork the repo + unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path) + raise "forking failed in gitlab-shell" + end + project.ensure_satellite_exists + end + rescue => ex + project.errors.add(:base, "Fork transaction failed.") + project.destroy end - #Now fork the repo - unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path) - raise "forking failed in gitlab-shell" - end - project.ensure_satellite_exists - + else + project.errors.add(:base, "Invalid fork destination") end project - rescue => ex - project.errors.add(:base, "Can't fork project. Please try again later") - project.destroy - end + end end end -- cgit v1.2.1 From ec63804831d1a55171abfb7fc0894af20d4298e8 Mon Sep 17 00:00:00 2001 From: Angus MacArthur Date: Thu, 2 May 2013 16:27:40 -0400 Subject: Made fixes suggested by @randx in pull request See https://github.com/gitlabhq/gitlabhq/pull/3597#discussion-diff-4014638 --- app/models/ability.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/models/ability.rb b/app/models/ability.rb index 0c5fbc2e5e7..eb7f89dcfc1 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -60,15 +60,16 @@ class Ability :read_note, :write_project, :write_issue, - :write_note, - :fork_project + :write_note ] end def project_report_rules project_guest_rules + [ :download_code, - :write_snippet + :write_snippet, + :fork_project + ] end -- cgit v1.2.1