annotate app/models/.svn/text-base/repository.rb.svn-base @ 45:65d9e2cabaa3 luisf

Added tipoftheday to the config/settings in order to correct previous issues. Tip of the day is now working correctly. Added the heading strings to the locales files.
author luisf
date Tue, 23 Nov 2010 11:50:01 +0000
parents 513646585e45
children af80e5618e9b 8661b858af72
rev   line source
Chris@0 1 # redMine - project management software
Chris@0 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
Chris@0 3 #
Chris@0 4 # This program is free software; you can redistribute it and/or
Chris@0 5 # modify it under the terms of the GNU General Public License
Chris@0 6 # as published by the Free Software Foundation; either version 2
Chris@0 7 # of the License, or (at your option) any later version.
Chris@0 8 #
Chris@0 9 # This program is distributed in the hope that it will be useful,
Chris@0 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 12 # GNU General Public License for more details.
Chris@0 13 #
Chris@0 14 # You should have received a copy of the GNU General Public License
Chris@0 15 # along with this program; if not, write to the Free Software
Chris@0 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 17
Chris@0 18 class Repository < ActiveRecord::Base
Chris@0 19 belongs_to :project
Chris@0 20 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
Chris@0 21 has_many :changes, :through => :changesets
Chris@0 22
Chris@0 23 # Raw SQL to delete changesets and changes in the database
Chris@0 24 # has_many :changesets, :dependent => :destroy is too slow for big repositories
Chris@0 25 before_destroy :clear_changesets
Chris@0 26
Chris@0 27 # Checks if the SCM is enabled when creating a repository
Chris@0 28 validate_on_create { |r| r.errors.add(:type, :invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) }
Chris@0 29
Chris@0 30 # Removes leading and trailing whitespace
Chris@0 31 def url=(arg)
Chris@0 32 write_attribute(:url, arg ? arg.to_s.strip : nil)
Chris@0 33 end
Chris@0 34
Chris@0 35 # Removes leading and trailing whitespace
Chris@0 36 def root_url=(arg)
Chris@0 37 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
Chris@0 38 end
Chris@0 39
Chris@0 40 def scm
Chris@0 41 @scm ||= self.scm_adapter.new url, root_url, login, password
Chris@0 42 update_attribute(:root_url, @scm.root_url) if root_url.blank?
Chris@0 43 @scm
Chris@0 44 end
Chris@0 45
Chris@0 46 def scm_name
Chris@0 47 self.class.scm_name
Chris@0 48 end
Chris@0 49
Chris@0 50 def supports_cat?
Chris@0 51 scm.supports_cat?
Chris@0 52 end
Chris@0 53
Chris@0 54 def supports_annotate?
Chris@0 55 scm.supports_annotate?
Chris@0 56 end
Chris@0 57
Chris@0 58 def entry(path=nil, identifier=nil)
Chris@0 59 scm.entry(path, identifier)
Chris@0 60 end
Chris@0 61
Chris@0 62 def entries(path=nil, identifier=nil)
Chris@0 63 scm.entries(path, identifier)
Chris@0 64 end
Chris@0 65
Chris@0 66 def branches
Chris@0 67 scm.branches
Chris@0 68 end
Chris@0 69
Chris@0 70 def tags
Chris@0 71 scm.tags
Chris@0 72 end
Chris@0 73
Chris@0 74 def default_branch
Chris@0 75 scm.default_branch
Chris@0 76 end
Chris@0 77
Chris@0 78 def properties(path, identifier=nil)
Chris@0 79 scm.properties(path, identifier)
Chris@0 80 end
Chris@0 81
Chris@0 82 def cat(path, identifier=nil)
Chris@0 83 scm.cat(path, identifier)
Chris@0 84 end
Chris@0 85
Chris@0 86 def diff(path, rev, rev_to)
Chris@0 87 scm.diff(path, rev, rev_to)
Chris@0 88 end
Chris@0 89
Chris@0 90 # Returns a path relative to the url of the repository
Chris@0 91 def relative_path(path)
Chris@0 92 path
Chris@0 93 end
Chris@0 94
Chris@0 95 # Finds and returns a revision with a number or the beginning of a hash
Chris@0 96 def find_changeset_by_name(name)
Chris@0 97 changesets.find(:first, :conditions => (name.match(/^\d*$/) ? ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%']))
Chris@0 98 end
Chris@0 99
Chris@0 100 def latest_changeset
Chris@0 101 @latest_changeset ||= changesets.find(:first)
Chris@0 102 end
Chris@0 103
Chris@0 104 # Returns the latest changesets for +path+
Chris@0 105 # Default behaviour is to search in cached changesets
Chris@0 106 def latest_changesets(path, rev, limit=10)
Chris@0 107 if path.blank?
Chris@0 108 changesets.find(:all, :include => :user,
Chris@0 109 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
Chris@0 110 :limit => limit)
Chris@0 111 else
Chris@0 112 changes.find(:all, :include => {:changeset => :user},
Chris@0 113 :conditions => ["path = ?", path.with_leading_slash],
Chris@0 114 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
Chris@0 115 :limit => limit).collect(&:changeset)
Chris@0 116 end
Chris@0 117 end
Chris@0 118
Chris@0 119 def scan_changesets_for_issue_ids
Chris@0 120 self.changesets.each(&:scan_comment_for_issue_ids)
Chris@0 121 end
Chris@0 122
Chris@0 123 # Returns an array of committers usernames and associated user_id
Chris@0 124 def committers
Chris@0 125 @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
Chris@0 126 end
Chris@0 127
Chris@0 128 # Maps committers username to a user ids
Chris@0 129 def committer_ids=(h)
Chris@0 130 if h.is_a?(Hash)
Chris@0 131 committers.each do |committer, user_id|
Chris@0 132 new_user_id = h[committer]
Chris@0 133 if new_user_id && (new_user_id.to_i != user_id.to_i)
Chris@0 134 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
Chris@0 135 Changeset.update_all("user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", ["repository_id = ? AND committer = ?", id, committer])
Chris@0 136 end
Chris@0 137 end
Chris@0 138 @committers = nil
Chris@0 139 @found_committer_users = nil
Chris@0 140 true
Chris@0 141 else
Chris@0 142 false
Chris@0 143 end
Chris@0 144 end
Chris@0 145
Chris@0 146 # Returns the Redmine User corresponding to the given +committer+
Chris@0 147 # It will return nil if the committer is not yet mapped and if no User
Chris@0 148 # with the same username or email was found
Chris@0 149 def find_committer_user(committer)
Chris@0 150 unless committer.blank?
Chris@0 151 @found_committer_users ||= {}
Chris@0 152 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
Chris@0 153
Chris@0 154 user = nil
Chris@0 155 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
Chris@0 156 if c && c.user
Chris@0 157 user = c.user
Chris@0 158 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
Chris@0 159 username, email = $1.strip, $3
Chris@0 160 u = User.find_by_login(username)
Chris@0 161 u ||= User.find_by_mail(email) unless email.blank?
Chris@0 162 user = u
Chris@0 163 end
Chris@0 164 @found_committer_users[committer] = user
Chris@0 165 user
Chris@0 166 end
Chris@0 167 end
Chris@0 168
Chris@0 169 # Fetches new changesets for all repositories of active projects
Chris@0 170 # Can be called periodically by an external script
Chris@0 171 # eg. ruby script/runner "Repository.fetch_changesets"
Chris@0 172 def self.fetch_changesets
Chris@0 173 Project.active.has_module(:repository).find(:all, :include => :repository).each do |project|
Chris@0 174 if project.repository
Chris@0 175 project.repository.fetch_changesets
Chris@0 176 end
Chris@0 177 end
Chris@0 178 end
Chris@0 179
Chris@0 180 # scan changeset comments to find related and fixed issues for all repositories
Chris@0 181 def self.scan_changesets_for_issue_ids
Chris@0 182 find(:all).each(&:scan_changesets_for_issue_ids)
Chris@0 183 end
Chris@0 184
Chris@0 185 def self.scm_name
Chris@0 186 'Abstract'
Chris@0 187 end
Chris@0 188
Chris@0 189 def self.available_scm
Chris@0 190 subclasses.collect {|klass| [klass.scm_name, klass.name]}
Chris@0 191 end
Chris@0 192
Chris@0 193 def self.factory(klass_name, *args)
Chris@0 194 klass = "Repository::#{klass_name}".constantize
Chris@0 195 klass.new(*args)
Chris@0 196 rescue
Chris@0 197 nil
Chris@0 198 end
Chris@0 199
Chris@0 200 private
Chris@0 201
Chris@0 202 def before_save
Chris@0 203 # Strips url and root_url
Chris@0 204 url.strip!
Chris@0 205 root_url.strip!
Chris@0 206 true
Chris@0 207 end
Chris@0 208
Chris@0 209 def clear_changesets
Chris@0 210 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}"
Chris@0 211 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
Chris@0 212 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
Chris@0 213 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
Chris@0 214 end
Chris@0 215 end