diff --git a/app/controllers/projects/projects_controller.rb b/app/controllers/projects/projects_controller.rb index 12a183d58..8781bbc47 100644 --- a/app/controllers/projects/projects_controller.rb +++ b/app/controllers/projects/projects_controller.rb @@ -114,7 +114,9 @@ class Projects::ProjectsController < Projects::BaseController def fork owner = (Group.find params[:group] if params[:group].present?) || current_user authorize! :write, owner if owner.class == Group - if forked = @project.fork(owner, params[:fork_name]) and forked.valid? + + is_alias = params[:alias] == 'true' + if forked = @project.fork(owner, params[:fork_name], is_alias) and forked.valid? redirect_to forked, notice: t("flash.project.forked") else flash[:warning] = t("flash.project.fork_error") diff --git a/app/models/concerns/git.rb b/app/models/concerns/git.rb index 5c097374a..d69d0349c 100644 --- a/app/models/concerns/git.rb +++ b/app/models/concerns/git.rb @@ -153,7 +153,20 @@ module Git end def fork_git_repo - dummy = Grit::Repo.new(path) rescue parent.repo.fork_bare(path, shared: false) + dummy = Grit::Repo.new(path) rescue nil + unless dummy + if alias_from_id + aliases_path = File.join(APP_CONFIG['git_path'], 'git_projects', '.aliases') + FileUtils.mkdir_p(aliases_path) + alias_path = File.join(aliases_path, "#{alias_from_id}.git") + if !Dir.exists?(alias_path) && alias_from + FileUtils.mv(alias_from.path, alias_path, force: true) + end + FileUtils.ln_sf alias_path, path + else + parent.repo.fork_bare(path, shared: false) + end + end write_hook end diff --git a/app/models/project.rb b/app/models/project.rb index 3784265d6..45046c66a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -17,6 +17,9 @@ class Project < ActiveRecord::Base belongs_to :owner, polymorphic: true, counter_cache: :own_projects_count belongs_to :maintainer, class_name: 'User' + belongs_to :alias_from, class_name: 'Project' + has_many :aliases, class_name: 'Project', foreign_key: 'alias_from_id' + has_many :issues, dependent: :destroy has_many :pull_requests, dependent: :destroy, foreign_key: 'to_project_id' has_many :labels, dependent: :destroy @@ -216,13 +219,14 @@ class Project < ActiveRecord::Base end end - def fork(new_owner, new_name = name) + def fork(new_owner, new_name = name, is_alias = false) new_name = new_name.presence || name dup.tap do |c| - c.name = new_name - c.parent_id = id - c.owner = new_owner - c.updated_at = nil; c.created_at = nil # :id = nil + c.name = new_name + c.parent_id = id + c.alias_from_id = alias_from_id || id if is_alias + c.owner = new_owner + c.updated_at = nil; c.created_at = nil # :id = nil # Hack to call protected method :) c.send :set_maintainer c.save diff --git a/app/views/projects/git/base/_choose_fork.html.haml b/app/views/projects/git/base/_choose_fork.html.haml deleted file mode 100644 index 4c216ccb6..000000000 --- a/app/views/projects/git/base/_choose_fork.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- is_group = owner.class == Group ? "(#{t 'activerecord.models.group'})" : '' -- full_name = "#{owner.uname}/#{name} #{is_group}" - -- if owner.own_projects.exists? name: name - %p.text-center - =t 'layout.projects.already_exists' - =link_to full_name, project_path("#{owner.uname}/#{name}")#, class: 'center-block' -- else - = form_for @project, url: fork_project_path(@project), html: { class: :form, multipart: true, method: :post } do |f| - = hidden_field_tag :group, owner.id if owner.class == Group - = hidden_field_tag :fork_name, name, name: 'fork_name' - =f.submit t('layout.projects.fork_to', to: full_name), class: 'btn btn-primary center-block', - 'data-loading-text' => t('layout.processing'), id: 'create_fork' diff --git a/app/views/projects/git/base/_choose_fork.html.slim b/app/views/projects/git/base/_choose_fork.html.slim new file mode 100644 index 000000000..68527a2da --- /dev/null +++ b/app/views/projects/git/base/_choose_fork.html.slim @@ -0,0 +1,22 @@ +- is_group = owner.class == Group ? "(#{t 'activerecord.models.group'})" : '' +- full_name = "#{owner.uname}/#{name} #{is_group}" + +- if owner.own_projects.exists? name: name + p.text-center + => t('layout.projects.already_exists') + = link_to full_name, project_path("#{owner.uname}/#{name}") +- else + = form_for @project, url: fork_project_path(@project), html: { class: :form, multipart: true, method: :post } do |f| + = hidden_field_tag :group, owner.id if owner.class == Group + = hidden_field_tag :fork_name, name, name: 'fork_name' + = hidden_field_tag :alias, '{{create_alias}}' + .btn-group.btn-group-justified ng-init='create_alias = false' + .btn-group + = f.submit t('layout.projects.fork_to', to: full_name), + class: 'btn btn-primary center-block', + 'data-loading-text' => t('layout.processing'), id: 'create_fork' + .btn-group + = f.submit t('layout.projects.create_alias_for', for: full_name), + class: 'btn btn-primary center-block', + ng_click: 'create_alias = true', + 'data-loading-text' => t('layout.processing'), id: 'create_fork' \ No newline at end of file diff --git a/app/views/projects/git/base/_forks.html.haml b/app/views/projects/git/base/_forks.html.haml deleted file mode 100644 index 7e32ebc6e..000000000 --- a/app/views/projects/git/base/_forks.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -=render 'projects/git/base/choose_fork', owner: current_user, name: name -%hr -- Group.can_own_project(current_user).each do |group| - =render 'projects/git/base/choose_fork', owner: group, name: name - %hr \ No newline at end of file diff --git a/app/views/projects/git/base/_forks.html.slim b/app/views/projects/git/base/_forks.html.slim new file mode 100644 index 000000000..c75ee407f --- /dev/null +++ b/app/views/projects/git/base/_forks.html.slim @@ -0,0 +1,5 @@ +== render 'projects/git/base/choose_fork', owner: current_user, name: name +hr +- Group.can_own_project(current_user).each do |group| + == render 'projects/git/base/choose_fork', owner: group, name: name + hr \ No newline at end of file diff --git a/config/locales/models/project.en.yml b/config/locales/models/project.en.yml index 7c2ee4368..ea917c94a 100644 --- a/config/locales/models/project.en.yml +++ b/config/locales/models/project.en.yml @@ -21,6 +21,7 @@ en: edit: Settings fork_and_edit: Fork fork_to: Fork to %{to} + create_alias_for: Create alias for %{for} fork_modal_header: Where do you want to fork this project? already_exists: Project already exists unexisted_project: Project not exists diff --git a/config/locales/models/project.ru.yml b/config/locales/models/project.ru.yml index 87a988194..bb3c1a946 100644 --- a/config/locales/models/project.ru.yml +++ b/config/locales/models/project.ru.yml @@ -21,6 +21,7 @@ ru: edit: Настройки fork_and_edit: Клонировать fork_to: Клонировать в %{to} + create_alias_for: Создать ссылку для %{for} fork_modal_header: Куда Вы хотите клонировать проект? already_exists: Проект уже существует unexisted_project: Проект не существует diff --git a/db/migrate/20150112204757_add_alias_from_to_projects.rb b/db/migrate/20150112204757_add_alias_from_to_projects.rb new file mode 100644 index 000000000..a0ebc11ad --- /dev/null +++ b/db/migrate/20150112204757_add_alias_from_to_projects.rb @@ -0,0 +1,6 @@ +class AddAliasFromToProjects < ActiveRecord::Migration + def change + add_column :projects, :alias_from_id, :integer + add_index :projects, :alias_from_id + end +end diff --git a/db/schema.rb b/db/schema.rb index e93e250ca..3a59b0325 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141015193923) do +ActiveRecord::Schema.define(version: 20150112204757) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -173,6 +173,8 @@ ActiveRecord::Schema.define(version: 20141015193923) do t.string "owner_uname", null: false t.boolean "architecture_dependent", default: false, null: false t.integer "autostart_status" + t.integer "alias_from_id" + t.index ["alias_from_id"], :name => "index_projects_on_alias_from_id" t.index ["name", "owner_id", "owner_type"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false end