##// END OF EJS Templates
SVN integration: reposman.rb can now register created repositories in Redmine, so that the administrator doesn't have to enter the repository url in Redmine once it's created....
Jean-Philippe Lang -
r847:cedca57620e3
parent child
Show More
@@ -1,25 +1,25
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 SysApi < ActionWebService::API::Base
18 class SysApi < ActionWebService::API::Base
19 api_method :projects,
19 api_method :projects,
20 :expects => [],
20 :expects => [],
21 :returns => [[Project]]
21 :returns => [[Project]]
22 api_method :repository_created,
22 api_method :repository_created,
23 :expects => [:int, :string],
23 :expects => [:string, :string],
24 :returns => [:int]
24 :returns => [:int]
25 end
25 end
@@ -1,44 +1,47
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 SysController < ActionController::Base
18 class SysController < ActionController::Base
19 wsdl_service_name 'Sys'
19 wsdl_service_name 'Sys'
20 web_service_api SysApi
20 web_service_api SysApi
21 web_service_scaffold :invoke
21 web_service_scaffold :invoke
22
22
23 before_invocation :check_enabled
23 before_invocation :check_enabled
24
24
25 # Returns the projects list, with their repositories
25 def projects
26 def projects
26 Project.find(:all, :include => :repository)
27 Project.find(:all, :include => :repository)
27 end
28 end
28
29
29 def repository_created(project_id, url)
30 # Registers a repository for the given project identifier
30 project = Project.find_by_id(project_id)
31 # (Subversion specific)
32 def repository_created(identifier, url)
33 project = Project.find_by_identifier(identifier)
34 # Do not create the repository if the project has already one
31 return 0 unless project && project.repository.nil?
35 return 0 unless project && project.repository.nil?
32 logger.debug "Repository for #{project.name} created"
36 logger.debug "Repository for #{project.name} was created"
33 repository = Repository.new(:project => project, :url => url)
37 repository = Repository.factory('Subversion', :project => project, :url => url)
34 repository.root_url = url
35 repository.save
38 repository.save
36 repository.id
39 repository.id || 0
37 end
40 end
38
41
39 protected
42 protected
40
43
41 def check_enabled(name, args)
44 def check_enabled(name, args)
42 Setting.sys_api_enabled?
45 Setting.sys_api_enabled?
43 end
46 end
44 end
47 end
@@ -1,157 +1,213
1 #!/usr/bin/ruby
1 #!/usr/bin/ruby
2
2
3 # == Synopsis
3 # == Synopsis
4 #
4 #
5 # reposman: manages your svn repositories with redMine
5 # reposman: manages your svn repositories with Redmine
6 #
6 #
7 # == Usage
7 # == Usage
8 #
8 #
9 # reposman [ -h | --help ] [ -v | --verbose ] [ -V | --version ] [ -q | --quiet ] -s /var/svn -r redmine.host.org
9 # reposman [ -h | --help ] [ -v | --verbose ] [ -V | --version ] [ -q | --quiet ] -s /var/svn -r redmine.host.org
10 # example: reposman --svn-dir=/var/svn --redmine-host=redmine.mydomain.foo
10 # example: reposman --svn-dir=/var/svn --redmine-host=redmine.mydomain.foo
11 # reposman -s /var/svn -r redmine.mydomain.foo
11 # reposman -s /var/svn -r redmine.mydomain.foo
12 #
12 #
13 # == Arguments (mandatory)
13 # == Arguments (mandatory)
14 #
14 #
15 # -s, --svn-dir=DIR
15 # -s, --svn-dir=DIR
16 # use DIR as base directory for svn repositories
16 # use DIR as base directory for svn repositories
17 #
17 #
18 # -r, --redmine-host=HOST
18 # -r, --redmine-host=HOST
19 # assume redMine is hosted on HOST.
19 # assume Redmine is hosted on HOST.
20 # you can use :
20 # you can use :
21 # * -r redmine.mydomain.foo (will add http://)
21 # * -r redmine.mydomain.foo (will add http://)
22 # * -r http://redmine.mydomain.foo
22 # * -r http://redmine.mydomain.foo
23 # * -r https://mydomain.foo/redmine
23 # * -r https://mydomain.foo/redmine
24 #
24 #
25 # == Options
25 # == Options
26 #
26 #
27 # -o, --owner=OWNER
28 # owner of the repository. using the rails login allow user to browse
29 # the repository in Redmine even for private project
30 #
31 # -u, --url=URL
32 # the base url Redmine will use to access your repositories. This
33 # will be used to register the repository in Redmine so that user
34 # doesn't need to do anything. reposman will add the identifier to this url :
35 #
36 # -u https://my.svn.server/my/reposity/root # if the repository can be access by http
37 # -u file:///var/svn/ # if the repository is local
38 # if this option isn't set, reposman won't register the repository
39 #
40 #
27 # -h, --help:
41 # -h, --help:
28 # show help and exit
42 # show help and exit
29 #
43 #
30 # -v, --verbose
44 # -v, --verbose
31 # verbose
45 # verbose
32 #
46 #
33 # -V, --version
47 # -V, --version
34 # print version and exit
48 # print version and exit
35 #
49 #
36 # -q, --quiet
50 # -q, --quiet
37 # no log
51 # no log
38 #
52 #
39
53
40 require 'getoptlong'
54 require 'getoptlong'
41 require 'rdoc/usage'
55 require 'rdoc/usage'
42 require 'soap/wsdlDriver'
56 require 'soap/wsdlDriver'
43 require 'find'
57 require 'find'
44 require 'etc'
58 require 'etc'
45
59
46 Version = "1.0"
60 Version = "1.0"
47
61
48 opts = GetoptLong.new(
62 opts = GetoptLong.new(
49 ['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT],
63 ['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT],
50 ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
64 ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
65 ['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT],
66 ['--url', '-u', GetoptLong::REQUIRED_ARGUMENT],
51 ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
67 ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
52 ['--version', '-V', GetoptLong::NO_ARGUMENT],
68 ['--version', '-V', GetoptLong::NO_ARGUMENT],
53 ['--help' , '-h', GetoptLong::NO_ARGUMENT],
69 ['--help' , '-h', GetoptLong::NO_ARGUMENT],
54 ['--quiet' , '-q', GetoptLong::NO_ARGUMENT]
70 ['--quiet' , '-q', GetoptLong::NO_ARGUMENT]
55 )
71 )
56
72
57 $verbose = 0
73 $verbose = 0
58 $quiet = false
74 $quiet = false
59 $redmine_host = ''
75 $redmine_host = ''
60 $repos_base = ''
76 $repos_base = ''
77 $svn_owner = 'root'
78 $svn_url = false
61
79
62 def log(text,level=0, exit=false)
80 def log(text,level=0, exit=false)
63 return if $quiet or level > $verbose
81 return if $quiet or level > $verbose
64 puts text
82 puts text
65 exit 1 if exit
83 exit 1 if exit
66 end
84 end
67
85
68 begin
86 begin
69 opts.each do |opt, arg|
87 opts.each do |opt, arg|
70 case opt
88 case opt
71 when '--svn-dir'; $repos_base = arg.dup
89 when '--svn-dir'; $repos_base = arg.dup
72 when '--redmine-host'; $redmine_host = arg.dup
90 when '--redmine-host'; $redmine_host = arg.dup
91 when '--owner'; $svn_owner = arg.dup
92 when '--url'; $svn_url = arg.dup
73 when '--verbose'; $verbose += 1
93 when '--verbose'; $verbose += 1
74 when '--version'; puts Version; exit
94 when '--version'; puts Version; exit
75 when '--help'; RDoc::usage
95 when '--help'; RDoc::usage
76 when '--quiet'; $quiet = true
96 when '--quiet'; $quiet = true
77 end
97 end
78 end
98 end
79 rescue
99 rescue
80 exit 1
100 exit 1
81 end
101 end
82
102
103 $svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
104
83 if ($redmine_host.empty? or $repos_base.empty?)
105 if ($redmine_host.empty? or $repos_base.empty?)
84 RDoc::usage
106 RDoc::usage
85 end
107 end
86
108
87 unless File.directory?($repos_base)
109 unless File.directory?($repos_base)
88 log("directory '#{$repos_base}' doesn't exists", 0, true)
110 log("directory '#{$repos_base}' doesn't exists", 0, true)
89 end
111 end
90
112
91 log("querying redMine for projects...", 1);
113 log("querying Redmine for projects...", 1);
92
114
93 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
115 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
94 $redmine_host.gsub!(/\/$/, '')
116 $redmine_host.gsub!(/\/$/, '')
95
117
96 wsdl_url = "#{$redmine_host}/sys/service.wsdl";
118 wsdl_url = "#{$redmine_host}/sys/service.wsdl";
97
119
98 begin
120 begin
99 soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
121 soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
100 rescue => e
122 rescue => e
101 log("Unable to connect to #{wsdl_url} : #{e}", 0, true)
123 log("Unable to connect to #{wsdl_url} : #{e}", 0, true)
102 end
124 end
103
125
104 projects = soap.Projects
126 projects = soap.Projects
105
127
106 if projects.nil?
128 if projects.nil?
107 log('no project found, perhaps you forgot to "Enable WS for repository management"', 0, true)
129 log('no project found, perhaps you forgot to "Enable WS for repository management"', 0, true)
108 end
130 end
109
131
110 log("retrieved #{projects.size} projects", 1)
132 log("retrieved #{projects.size} projects", 1)
111
133
112 projects.each do |p|
134 def set_owner_and_rights(project, repos_path, &block)
113 log("treating project #{p.name}", 1)
135 if RUBY_PLATFORM =~ /mswin/
136 yield if block_given?
137 else
138 uid, gid = Etc.getpwnam($svn_owner).uid, Etc.getgrnam(project.identifier).gid
139 right = project.is_public ? 0575 : 0570
140 yield if block_given?
141 Find.find(repos_path) do |f|
142 File.chmod right, f
143 File.chown uid, gid, f
144 end
145 end
146 end
147
148 def other_read_right?(file)
149 (File.stat(file).mode & 0007).zero? ? false : true
150 end
151
152 def owner_name(file)
153 RUBY_PLATFORM =~ /mswin/ ?
154 $svn_owner :
155 Etc.getpwuid( File.stat(file).uid ).name
156 end
114
157
115 if p.identifier.empty?
158 projects.each do |project|
116 log("\tno identifier for project #{p.name}")
159 log("treating project #{project.name}", 1)
160
161 if project.identifier.empty?
162 log("\tno identifier for project #{project.name}")
117 next
163 next
118 elsif not p.identifier.match(/^[a-z0-9\-]+$/)
164 elsif not project.identifier.match(/^[a-z0-9\-]+$/)
119 log("\tinvalid identifier for project #{p.name} : #{p.identifier}");
165 log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
120 next;
166 next;
121 end
167 end
122
168
123 repos_path = $repos_base + "/" + p.identifier
169 repos_path = $repos_base + "/" + project.identifier
124
170
125 if File.directory?(repos_path)
171 if File.directory?(repos_path)
126
172
127 other_read = (File.stat(repos_path).mode & 0007).zero? ? false : true
173 # we must verify that repository has the good owner and the good
128 next if p.is_public == other_read
174 # rights before leaving
129
175 other_read = other_read_right?(repos_path)
130 right = p.is_public ? 0775 : 0770
176 owner = owner_name(repos_path)
177 next if project.is_public == other_read and owner == $svn_owner
131
178
132 begin
179 begin
133 Find.find(repos_path) { |f| File.chmod right, f }
180 set_owner_and_rights(project, repos_path)
134 rescue Errno::EPERM => e
181 rescue Errno::EPERM => e
135 log("\tunable to change mode on #{repos_path} : #{e}\n")
182 log("\tunable to change mode on #{repos_path} : #{e}\n")
136 next
183 next
137 end
184 end
138
185
139 log("\tmode change on #{repos_path}");
186 log("\tmode change on #{repos_path}");
140
187
141 else
188 else
142 p.is_public ? File.umask(0002) : File.umask(0007)
189 project.is_public ? File.umask(0202) : File.umask(0207)
143
190
144 begin
191 begin
145 uid, gid = Etc.getpwnam("root").uid, Etc.getgrnam(p.identifier).gid
192 set_owner_and_rights(project, repos_path) do
146 raise "svnadmin create #{repos_path} failed" unless system("svnadmin", "create", repos_path)
193 raise "svnadmin create #{repos_path} failed" unless system("svnadmin", "create", repos_path)
147 Find.find(repos_path) { |f| File.chown uid, gid, f }
194 end
148 rescue => e
195 rescue => e
149 log("\tunable to create #{repos_path} : #{e}\n")
196 log("\tunable to create #{repos_path} : #{e}\n")
150 next
197 next
151 end
198 end
152
199
200 if $svn_url
201 ret = soap.RepositoryCreated project.identifier, "#{$svn_url}#{project.identifier}"
202 if ret > 0
203 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}");
204 else
205 log("\trepository #{repos_path} not registered in Redmine. Look in your log to find why.");
206 end
207 end
208
153 log("\trepository #{repos_path} created");
209 log("\trepository #{repos_path} created");
154 end
210 end
155
211
156 end
212 end
157
213
General Comments 0
You need to be logged in to leave comments. Login now