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