##// END OF EJS Templates
scm: git: add the model method whether reporting last commit in repository tree (#7047)....
Toshi MARUYAMA -
r5536:03fb61a782a3
parent child
Show More
@@ -1,163 +1,167
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 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
3 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
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 require 'redmine/scm/adapters/git_adapter'
18 require 'redmine/scm/adapters/git_adapter'
19
19
20 class Repository::Git < Repository
20 class Repository::Git < Repository
21 attr_protected :root_url
21 attr_protected :root_url
22 validates_presence_of :url
22 validates_presence_of :url
23
23
24 def self.human_attribute_name(attribute_key_name)
24 def self.human_attribute_name(attribute_key_name)
25 attr_name = attribute_key_name
25 attr_name = attribute_key_name
26 if attr_name == "url"
26 if attr_name == "url"
27 attr_name = "path_to_repository"
27 attr_name = "path_to_repository"
28 end
28 end
29 super(attr_name)
29 super(attr_name)
30 end
30 end
31
31
32 def self.scm_adapter_class
32 def self.scm_adapter_class
33 Redmine::Scm::Adapters::GitAdapter
33 Redmine::Scm::Adapters::GitAdapter
34 end
34 end
35
35
36 def self.scm_name
36 def self.scm_name
37 'Git'
37 'Git'
38 end
38 end
39
39
40 def report_last_commit
41 true
42 end
43
40 def supports_directory_revisions?
44 def supports_directory_revisions?
41 true
45 true
42 end
46 end
43
47
44 def repo_log_encoding
48 def repo_log_encoding
45 'UTF-8'
49 'UTF-8'
46 end
50 end
47
51
48 # Returns the identifier for the given git changeset
52 # Returns the identifier for the given git changeset
49 def self.changeset_identifier(changeset)
53 def self.changeset_identifier(changeset)
50 changeset.scmid
54 changeset.scmid
51 end
55 end
52
56
53 # Returns the readable identifier for the given git changeset
57 # Returns the readable identifier for the given git changeset
54 def self.format_changeset_identifier(changeset)
58 def self.format_changeset_identifier(changeset)
55 changeset.revision[0, 8]
59 changeset.revision[0, 8]
56 end
60 end
57
61
58 def branches
62 def branches
59 scm.branches
63 scm.branches
60 end
64 end
61
65
62 def tags
66 def tags
63 scm.tags
67 scm.tags
64 end
68 end
65
69
66 def find_changeset_by_name(name)
70 def find_changeset_by_name(name)
67 return nil if name.nil? || name.empty?
71 return nil if name.nil? || name.empty?
68 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
72 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
69 return e if e
73 return e if e
70 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
74 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
71 end
75 end
72
76
73 def entries(path=nil, identifier=nil)
77 def entries(path=nil, identifier=nil)
74 scm.entries(path, identifier)
78 scm.entries(path, identifier)
75 end
79 end
76
80
77 # In Git and Mercurial, revisions are not in date order.
81 # In Git and Mercurial, revisions are not in date order.
78 # Mercurial fixed issues.
82 # Mercurial fixed issues.
79 # * Redmine Takes Too Long On Large Mercurial Repository
83 # * Redmine Takes Too Long On Large Mercurial Repository
80 # http://www.redmine.org/issues/3449
84 # http://www.redmine.org/issues/3449
81 # * Sorting for changesets might go wrong on Mercurial repos
85 # * Sorting for changesets might go wrong on Mercurial repos
82 # http://www.redmine.org/issues/3567
86 # http://www.redmine.org/issues/3567
83 # Database revision column is text, so Redmine can not sort by revision.
87 # Database revision column is text, so Redmine can not sort by revision.
84 # Mercurial has revision number, and revision number guarantees revision order.
88 # Mercurial has revision number, and revision number guarantees revision order.
85 # Mercurial adapter uses "hg log -r 0:tip --limit 10"
89 # Mercurial adapter uses "hg log -r 0:tip --limit 10"
86 # to get limited revisions from old to new.
90 # to get limited revisions from old to new.
87 # And Mercurial model stored revisions ordered by database id in database.
91 # And Mercurial model stored revisions ordered by database id in database.
88 # So, Mercurial can use correct order revisions.
92 # So, Mercurial can use correct order revisions.
89 #
93 #
90 # But, Git 1.7.3.4 does not support --reverse with -n or --skip.
94 # But, Git 1.7.3.4 does not support --reverse with -n or --skip.
91 #
95 #
92 # With SCM's that have a sequential commit numbering, redmine is able to be
96 # With SCM's that have a sequential commit numbering, redmine is able to be
93 # clever and only fetch changesets going forward from the most recent one
97 # clever and only fetch changesets going forward from the most recent one
94 # it knows about.
98 # it knows about.
95 # However, with git, you never know if people have merged
99 # However, with git, you never know if people have merged
96 # commits into the middle of the repository history, so we should parse
100 # commits into the middle of the repository history, so we should parse
97 # the entire log.
101 # the entire log.
98 #
102 #
99 # Since it's way too slow for large repositories,
103 # Since it's way too slow for large repositories,
100 # we only parse 1 week before the last known commit.
104 # we only parse 1 week before the last known commit.
101 #
105 #
102 # The repository can still be fully reloaded by calling #clear_changesets
106 # The repository can still be fully reloaded by calling #clear_changesets
103 # before fetching changesets (eg. for offline resync)
107 # before fetching changesets (eg. for offline resync)
104 def fetch_changesets
108 def fetch_changesets
105 c = changesets.find(:first, :order => 'committed_on DESC')
109 c = changesets.find(:first, :order => 'committed_on DESC')
106 since = (c ? c.committed_on - 7.days : nil)
110 since = (c ? c.committed_on - 7.days : nil)
107
111
108 revisions = scm.revisions('', nil, nil, {:all => true, :since => since, :reverse => true})
112 revisions = scm.revisions('', nil, nil, {:all => true, :since => since, :reverse => true})
109 return if revisions.nil? || revisions.empty?
113 return if revisions.nil? || revisions.empty?
110
114
111 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
115 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
112
116
113 # Clean out revisions that are no longer in git
117 # Clean out revisions that are no longer in git
114 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
118 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
115
119
116 # Subtract revisions that redmine already knows about
120 # Subtract revisions that redmine already knows about
117 recent_revisions = recent_changesets.map{|c| c.scmid}
121 recent_revisions = recent_changesets.map{|c| c.scmid}
118 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
122 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
119
123
120 # Save the remaining ones to the database
124 # Save the remaining ones to the database
121 unless revisions.nil?
125 unless revisions.nil?
122 revisions.each do |rev|
126 revisions.each do |rev|
123 transaction do
127 transaction do
124 save_revision(rev)
128 save_revision(rev)
125 end
129 end
126 end
130 end
127 end
131 end
128 end
132 end
129
133
130 def save_revision(rev)
134 def save_revision(rev)
131 changeset = Changeset.new(
135 changeset = Changeset.new(
132 :repository => self,
136 :repository => self,
133 :revision => rev.identifier,
137 :revision => rev.identifier,
134 :scmid => rev.scmid,
138 :scmid => rev.scmid,
135 :committer => rev.author,
139 :committer => rev.author,
136 :committed_on => rev.time,
140 :committed_on => rev.time,
137 :comments => rev.message
141 :comments => rev.message
138 )
142 )
139 if changeset.save
143 if changeset.save
140 rev.paths.each do |file|
144 rev.paths.each do |file|
141 Change.create(
145 Change.create(
142 :changeset => changeset,
146 :changeset => changeset,
143 :action => file[:action],
147 :action => file[:action],
144 :path => file[:path])
148 :path => file[:path])
145 end
149 end
146 end
150 end
147 end
151 end
148 private :save_revision
152 private :save_revision
149
153
150 def latest_changesets(path,rev,limit=10)
154 def latest_changesets(path,rev,limit=10)
151 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
155 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
152 return [] if revisions.nil? || revisions.empty?
156 return [] if revisions.nil? || revisions.empty?
153
157
154 changesets.find(
158 changesets.find(
155 :all,
159 :all,
156 :conditions => [
160 :conditions => [
157 "scmid IN (?)",
161 "scmid IN (?)",
158 revisions.map!{|c| c.scmid}
162 revisions.map!{|c| c.scmid}
159 ],
163 ],
160 :order => 'committed_on DESC'
164 :order => 'committed_on DESC'
161 )
165 )
162 end
166 end
163 end
167 end
General Comments 0
You need to be logged in to leave comments. Login now