From cc0d1e2615c39cad7d3d9ab4a1eeb2dde64decb9 Mon Sep 17 00:00:00 2001
From: y.kokubo <y.kokubo@otr-jp.com>
Date: Thu, 6 Jan 2011 16:17:58 +0900
Subject: [PATCH] Multiple SCM per Project

---
 app/controllers/repositories_controller.rb     |   10 ++++---
 app/helpers/application_helper.rb              |    2 +-
 app/helpers/repositories_helper.rb             |   13 ++++++---
 app/models/changeset.rb                        |    7 +++++
 app/models/project.rb                          |    2 +-
 app/views/issues/_changesets.rhtml             |    2 +-
 app/views/projects/settings/_repository.rhtml  |   33 +++++++++++++++++------
 app/views/repositories/_breadcrumbs.rhtml      |    9 ++++--
 app/views/repositories/_dir_list_content.rhtml |    6 ++--
 app/views/repositories/_navigation.rhtml       |    2 +
 app/views/repositories/show.rhtml              |    6 ++++
 lib/redmine.rb                                 |    2 +-
 12 files changed, 66 insertions(+), 28 deletions(-)

diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 6195c64..8366d64 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -35,10 +35,11 @@ class RepositoriesController < ApplicationController
   rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
   
   def edit
+    rid = params[:rid] ? params[:rid].to_i : 0
     @repository = @project.repository
     if !@repository
-      @repository = Repository.factory(params[:repository_scm])
-      @repository.project = @project if @repository
+      @repository[rid] = Repository.factory(params[:repository_scm])
+      @repository[rid].project = @project if @repository[rid]
     end
     if request.post? && @repository
       @repository.attributes = params[:repository]
@@ -46,7 +47,7 @@ class RepositoriesController < ApplicationController
     end
     render(:update) do |page|
       page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'
-      if @repository && !@project.repository
+      if @repository && !@project.repository[rid]
         @project.reload #needed to reload association
         page.replace_html "main-menu", render_main_menu(@project)
       end
@@ -205,7 +206,8 @@ class RepositoriesController < ApplicationController
 
   def find_repository
     @project = Project.find(params[:id])
-    @repository = @project.repository
+    rid = params[:rid] ? params[:rid].to_i : 0
+    @repository = @project.repository[rid]
     (render_404; return false) unless @repository
     @path = params[:path].join('/') unless params[:path].nil?
     @path ||= ''
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3cdd3ad..0d82433 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -106,7 +106,7 @@ module ApplicationHelper
     text = options.delete(:text) || format_revision(revision)
     rev = revision.respond_to?(:identifier) ? revision.identifier : revision
 
-    link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
+    link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev, :rid => params[:rid]},
             :title => l(:label_revision_id, format_revision(revision)))
   end
 
diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb
index 63ea522..99a583b 100644
--- a/app/helpers/repositories_helper.rb
+++ b/app/helpers/repositories_helper.rb
@@ -91,7 +91,8 @@ module RepositoriesHelper
                              :action => 'show',
                              :id => @project,
                              :path => path_param,
-                             :rev => @changeset.identifier)
+                             :rev => @changeset.identifier,
+                             :rid => params[:rid])
         output << "<li class='#{style}'>#{text}</li>"
         output << render_changes_tree(s)
       elsif c = tree[file][:c]
@@ -101,13 +102,15 @@ module RepositoriesHelper
                              :action => 'entry',
                              :id => @project,
                              :path => path_param,
-                             :rev => @changeset.identifier) unless c.action == 'D'
+                             :rev => @changeset.identifier,
+                             :rid => params[:rid]) unless c.action == 'D'
         text << " - #{c.revision}" unless c.revision.blank?
         text << ' (' + link_to('diff', :controller => 'repositories',
                                        :action => 'diff',
                                        :id => @project,
                                        :path => path_param,
-                                       :rev => @changeset.identifier) + ') ' if c.action == 'M'
+                                       :rev => @changeset.identifier,
+                                       :rid => params[:rid]) + ') ' if c.action == 'M'
         text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank?
         output << "<li class='#{style}'>#{text}</li>"
       end
@@ -140,7 +143,7 @@ module RepositoriesHelper
     send(method, form, repository) if repository.is_a?(Repository) && respond_to?(method) && method != 'repository_field_tags'
   end
   
-  def scm_select_tag(repository)
+  def scm_select_tag(repository, rid)
     scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']]
     Redmine::Scm::Base.all.each do |scm|
       scm_options << ["Repository::#{scm}".constantize.scm_name, scm] if Setting.enabled_scm.include?(scm) || (repository && repository.class.name.demodulize == scm)
@@ -149,7 +152,7 @@ module RepositoriesHelper
     select_tag('repository_scm', 
                options_for_select(scm_options, repository.class.name.demodulize),
                :disabled => (repository && !repository.new_record?),
-               :onchange => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)")
+               :onchange => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project, :rid => rid }, :method => :get, :with => "Form.serialize(this.form)")
                )
   end
   
diff --git a/app/models/changeset.rb b/app/models/changeset.rb
index e49113e..3e6591d 100644
--- a/app/models/changeset.rb
+++ b/app/models/changeset.rb
@@ -175,6 +175,13 @@ class Changeset < ActiveRecord::Base
                   :from_revision => change[:from_revision])
   end
   
+  def rid
+    project.repository.each_with_index do |r, i|
+      return i if r.id == repository.id
+    end
+    -1
+  end
+  
   private
 
   # Finds an issue that can be referenced by the commit message
diff --git a/app/models/project.rb b/app/models/project.rb
index 891db8b..806c68f 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -46,7 +46,7 @@ class Project < ActiveRecord::Base
   has_many :news, :dependent => :delete_all, :include => :author
   has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
   has_many :boards, :dependent => :destroy, :order => "position ASC"
-  has_one :repository, :dependent => :destroy
+  has_many :repository, :dependent => :destroy
   has_many :changesets, :through => :repository
   has_one :wiki, :dependent => :destroy
   # Custom field for the project issues
diff --git a/app/views/issues/_changesets.rhtml b/app/views/issues/_changesets.rhtml
index 52cd60f..aa04216 100644
--- a/app/views/issues/_changesets.rhtml
+++ b/app/views/issues/_changesets.rhtml
@@ -1,7 +1,7 @@
 <% changesets.each do |changeset| %>
     <div class="changeset <%= cycle('odd', 'even') %>">
     <p><%= link_to("#{l(:label_revision)} #{changeset.revision}",
-                :controller => 'repositories', :action => 'revision', :id => changeset.project, :rev => changeset.revision) %><br />
+                :controller => 'repositories', :action => 'revision', :id => changeset.project, :rev => changeset.revision, :rid => changeset.rid) %><br />
         <span class="author"><%= authoring(changeset.committed_on, changeset.author) %></span></p>
     <div class="changeset-changes">
         <%= textilizable(changeset, :comments) %>
diff --git a/app/views/projects/settings/_repository.rhtml b/app/views/projects/settings/_repository.rhtml
index 18bb2cd..aafaf1e 100644
--- a/app/views/projects/settings/_repository.rhtml
+++ b/app/views/projects/settings/_repository.rhtml
@@ -1,24 +1,39 @@
-<% remote_form_for :repository, @repository, 
-                   :url => { :controller => 'repositories', :action => 'edit', :id => @project },
+<% @repository.each_with_index do |r, rid| %>
+
+<% remote_form_for :repository, r, r,
+                   :url => { :controller => 'repositories', :action => 'edit', :id => @project, :rid => rid },
                    :builder => TabularFormBuilder,
                    :lang => current_language do |f| %>
 
-<%= error_messages_for 'repository' %>
+<%= error_messages_for 'r' %>
 
 <div class="box tabular">
-<p><%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %></p>
-<%= repository_field_tags(f, @repository) if @repository %>
+<p><%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(r, rid) %></p>
+<%= repository_field_tags(f, r) if r %>
 </div>
 
 <div class="contextual">
-<% if @repository && !@repository.new_record? %>
-<%= link_to(l(:label_user_plural), {:controller => 'repositories', :action => 'committers', :id => @project}, :class => 'icon icon-user') %>
-<%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project},
+<% if @repository[0] && !r.new_record? %>
+<%= link_to(l(:label_user_plural), {:controller => 'repositories', :action => 'committers', :id => @project, :rid => rid}, :class => 'icon icon-user') %>
+<%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project, :rid => rid},
             :confirm => l(:text_are_you_sure),
             :method => :post,
             :class => 'icon icon-del') %>
 <% end %>
 </div>
 
-<%= submit_tag((@repository.nil? || @repository.new_record?) ? l(:button_create) : l(:button_save), :disabled => @repository.nil?) %>
+<%= submit_tag((r.nil? || r.new_record?) ? l(:button_create) : l(:button_save), :disabled => r.nil?) %>
+<% end %>
+<% end %>
+
+<% rid = @repository.size
+  remote_form_for :repository, @repository[rid],
+                  :url => { :controller => 'repositories', :action => 'edit', :id => @project, :rid => rid },
+                  :builder => TabularFormBuilder,
+                  :lang => current_language do |f| %>
+<div class="box tabular">
+<p><%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository[rid], rid) %></p>
+<%= repository_field_tags(f, @repository[rid]) if @repository[rid] %>
+</div>
+<%= submit_tag((@repository[rid].nil? || @repository[rid].new_record?) ? l(:button_create) : l(:button_save), :disabled => @repository[rid].nil?) %>
 <% end %>
diff --git a/app/views/repositories/_breadcrumbs.rhtml b/app/views/repositories/_breadcrumbs.rhtml
index bab0ff3..556b4fd 100644
--- a/app/views/repositories/_breadcrumbs.rhtml
+++ b/app/views/repositories/_breadcrumbs.rhtml
@@ -1,4 +1,7 @@
-<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev %>
+<% if params[:rid] %>
+(<%= @project.repository[params[:rid].to_i].url %>)
+<% end %>
+<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev , :rid => params[:rid]%>
 <% 
 dirs = path.split('/')
 if 'file' == kind
@@ -10,10 +13,10 @@ dirs.each do |dir|
     link_path << '/' unless link_path.empty?
     link_path << "#{dir}" 
     %>
-    / <%= link_to h(dir), :action => 'show', :id => @project, :path => to_path_param(link_path), :rev => @rev %>
+    / <%= link_to h(dir), :action => 'show', :id => @project, :path => to_path_param(link_path), :rev => @rev, :rid => params[:rid] %>
 <% end %>
 <% if filename %>
-    / <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %>
+    / <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev , :rid => params[:rid]%>
 <% end %>
 
 <%= "@ #{h revision}" if revision %>
diff --git a/app/views/repositories/_dir_list_content.rhtml b/app/views/repositories/_dir_list_content.rhtml
index 66574f1..5bc5960 100644
--- a/app/views/repositories/_dir_list_content.rhtml
+++ b/app/views/repositories/_dir_list_content.rhtml
@@ -4,7 +4,7 @@
 <tr id="<%= tr_id %>" class="<%= h params[:parent_id] %> entry <%= entry.kind %>">
 <td style="padding-left: <%=18 * depth%>px;" class="filename">
 <% if entry.is_dir? %>
-<span class="expander" onclick="<%=  remote_function :url => {:action => 'show', :id => @project, :path => to_path_param(entry.path), :rev => @rev, :depth => (depth + 1), :parent_id => tr_id},
+<span class="expander" onclick="<%=  remote_function :url => {:action => 'show', :id => @project, :path => to_path_param(entry.path), :rev => @rev, :depth => (depth + 1), :parent_id => tr_id, :rid => params[:rid]},
 									:method => :get,
                   :update => { :success => tr_id },
                   :position => :after,
@@ -12,11 +12,11 @@
                   :condition => "scmEntryClick('#{tr_id}')"%>">&nbsp</span>
 <% end %>
 <%=  link_to h(entry.name),
-          {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(entry.path), :rev => @rev},
+          {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(entry.path), :rev => @rev, :rid => params[:rid]},
           :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(entry.name)}")%>
 </td>
 <td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td>
-<% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %>
+<% changeset = @project.repository[params[:rid].to_i].changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %>
 <td class="revision"><%= link_to_revision(changeset, @project) if changeset %></td>
 <td class="age"><%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %></td>
 <td class="author"><%= changeset.nil? ? h(entry.lastrev.author.to_s.split('<').first) : changeset.author if entry.lastrev %></td>
diff --git a/app/views/repositories/_navigation.rhtml b/app/views/repositories/_navigation.rhtml
index 5671e29..124a01e 100644
--- a/app/views/repositories/_navigation.rhtml
+++ b/app/views/repositories/_navigation.rhtml
@@ -16,6 +16,8 @@
     <%= select_tag :tag, options_for_select([''] + @repository.tags,@rev), :id => 'tag' %>
   <% end -%>
 
+  <%= hidden_field_tag :rid, params[:rid] %>
+
   | <%= l(:label_revision) %>: 
   <%= text_field_tag 'rev', @rev, :size => 8 %>
 <% end -%>
diff --git a/app/views/repositories/show.rhtml b/app/views/repositories/show.rhtml
index 35106fe..79fc680 100644
--- a/app/views/repositories/show.rhtml
+++ b/app/views/repositories/show.rhtml
@@ -4,6 +4,12 @@
   <%= render :partial => 'navigation' %>
 </div>
 
+<ul>
+<% @project.repository.each_with_index do |r, i| %>
+ <li><%= link_to r.url, :rid => i %></li>
+<% end %>
+</ul>
+
 <h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
 
 <% if !@entries.nil? && authorize_for('repositories', 'browse') %>
diff --git a/lib/redmine.rb b/lib/redmine.rb
index 7fcd764..6930bdf 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -201,7 +201,7 @@ Redmine::MenuManager.map :project_menu do |menu|
               :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
   menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
   menu.push :repository, { :controller => 'repositories', :action => 'show' },
-              :if => Proc.new { |p| p.repository && !p.repository.new_record? }
+              :if => Proc.new { |p| p.repository && p.repository[0] && !p.repository[0].new_record? }
   menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
 end
 
-- 
1.6.5.1.1367.gcd48

