##// END OF EJS Templates
Replaces the repositories management SOAP API with a simple REST API....
Jean-Philippe Lang -
r2374:8cf3d7a4929e
parent child
Show More
@@ -0,0 +1,55
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'sys_controller'
20
21 # Re-raise errors caught by the controller.
22 class SysController; def rescue_action(e) raise e end; end
23
24 class SysControllerTest < Test::Unit::TestCase
25 fixtures :projects, :repositories
26
27 def setup
28 @controller = SysController.new
29 @request = ActionController::TestRequest.new
30 @response = ActionController::TestResponse.new
31 Setting.sys_api_enabled = '1'
32 end
33
34 def test_projects_with_repository_enabled
35 get :projects
36 assert_response :success
37 assert_equal 'application/xml', @response.content_type
38 with_options :tag => 'projects' do |test|
39 test.assert_tag :children => { :count => Project.active.has_module(:repository).count }
40 end
41 end
42
43 def test_create_project_repository
44 assert_nil Project.find(4).repository
45
46 post :create_project_repository, :id => 4,
47 :vendor => 'Subversion',
48 :repository => { :url => 'file:///create/project/repository/subproject2'}
49 assert_response :created
50
51 r = Project.find(4).repository
52 assert r.is_a?(Repository::Subversion)
53 assert_equal 'file:///create/project/repository/subproject2', r.url
54 end
55 end
@@ -1,46 +1,50
1 # redMine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2009 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 before_filter :check_enabled
20 web_service_api SysApi
21 web_service_scaffold :invoke
22
20
23 before_invocation :check_enabled
21 def projects
24
22 p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
25 # Returns the projects list, with their repositories
23 render :xml => p.to_xml(:include => :repository)
26 def projects_with_repository_enabled
27 Project.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
28 end
24 end
29
25
30 # Registers a repository for the given project identifier
26 def create_project_repository
31 def repository_created(identifier, vendor, url)
27 project = Project.find(params[:id])
32 project = Project.find_by_identifier(identifier)
28 if project.repository
33 # Do not create the repository if the project has already one
29 render :nothing => true, :status => 409
34 return 0 unless project && project.repository.nil?
30 else
35 logger.debug "Repository for #{project.name} was created"
31 logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}."
36 repository = Repository.factory(vendor, :project => project, :url => url)
32 project.repository = Repository.factory(params[:vendor], params[:repository])
37 repository.save
33 if project.repository && project.repository.save
38 repository.id || 0
34 render :xml => project.repository, :status => 201
35 else
36 render :nothing => true, :status => 422
37 end
38 end
39 end
39 end
40
40
41 protected
41 protected
42
42
43 def check_enabled(name, args)
43 def check_enabled
44 Setting.sys_api_enabled?
44 User.current = nil
45 unless Setting.sys_api_enabled?
46 render :nothing => 'Access denied. Repository management WS is disabled.', :status => 403
47 return false
48 end
45 end
49 end
46 end
50 end
@@ -1,257 +1,258
1 ActionController::Routing::Routes.draw do |map|
1 ActionController::Routing::Routes.draw do |map|
2 # Add your own custom routes here.
2 # Add your own custom routes here.
3 # The priority is based upon order of creation: first created -> highest priority.
3 # The priority is based upon order of creation: first created -> highest priority.
4
4
5 # Here's a sample route:
5 # Here's a sample route:
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 # Keep in mind you can assign values other than :controller and :action
7 # Keep in mind you can assign values other than :controller and :action
8
8
9 # Allow Redmine plugins to map routes and potentially override them
9 # Allow Redmine plugins to map routes and potentially override them
10 Rails.plugins.each do |plugin|
10 Rails.plugins.each do |plugin|
11 map.from_plugin plugin.name.to_sym
11 map.from_plugin plugin.name.to_sym
12 end
12 end
13
13
14 map.home '', :controller => 'welcome'
14 map.home '', :controller => 'welcome'
15
15
16 map.signin 'login', :controller => 'account', :action => 'login'
16 map.signin 'login', :controller => 'account', :action => 'login'
17 map.signout 'logout', :controller => 'account', :action => 'logout'
17 map.signout 'logout', :controller => 'account', :action => 'logout'
18
18
19 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
19 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
20 map.connect 'help/:ctrl/:page', :controller => 'help'
20 map.connect 'help/:ctrl/:page', :controller => 'help'
21
21
22 map.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog'
22 map.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog'
23 map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog'
23 map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog'
24 map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog'
24 map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog'
25
25
26 map.with_options :controller => 'timelog' do |timelog|
26 map.with_options :controller => 'timelog' do |timelog|
27 timelog.connect 'projects/:project_id/time_entries', :action => 'details'
27 timelog.connect 'projects/:project_id/time_entries', :action => 'details'
28
28
29 timelog.with_options :action => 'details', :conditions => {:method => :get} do |time_details|
29 timelog.with_options :action => 'details', :conditions => {:method => :get} do |time_details|
30 time_details.connect 'time_entries'
30 time_details.connect 'time_entries'
31 time_details.connect 'time_entries.:format'
31 time_details.connect 'time_entries.:format'
32 time_details.connect 'issues/:issue_id/time_entries'
32 time_details.connect 'issues/:issue_id/time_entries'
33 time_details.connect 'issues/:issue_id/time_entries.:format'
33 time_details.connect 'issues/:issue_id/time_entries.:format'
34 time_details.connect 'projects/:project_id/time_entries.:format'
34 time_details.connect 'projects/:project_id/time_entries.:format'
35 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries'
35 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries'
36 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries.:format'
36 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries.:format'
37 end
37 end
38 timelog.connect 'projects/:project_id/time_entries/report', :action => 'report'
38 timelog.connect 'projects/:project_id/time_entries/report', :action => 'report'
39 timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report|
39 timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report|
40 time_report.connect 'time_entries/report'
40 time_report.connect 'time_entries/report'
41 time_report.connect 'time_entries/report.:format'
41 time_report.connect 'time_entries/report.:format'
42 time_report.connect 'projects/:project_id/time_entries/report.:format'
42 time_report.connect 'projects/:project_id/time_entries/report.:format'
43 end
43 end
44
44
45 timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit|
45 timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit|
46 time_edit.connect 'issues/:issue_id/time_entries/new'
46 time_edit.connect 'issues/:issue_id/time_entries/new'
47 end
47 end
48
48
49 timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post}
49 timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post}
50 end
50 end
51
51
52 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
52 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
53 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
53 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
54 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
54 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
55 map.with_options :controller => 'wiki' do |wiki_routes|
55 map.with_options :controller => 'wiki' do |wiki_routes|
56 wiki_routes.with_options :conditions => {:method => :get} do |wiki_views|
56 wiki_routes.with_options :conditions => {:method => :get} do |wiki_views|
57 wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i
57 wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i
58 wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil
58 wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil
59 wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit'
59 wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit'
60 wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename'
60 wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename'
61 wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history'
61 wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history'
62 wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff'
62 wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff'
63 wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate'
63 wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate'
64 end
64 end
65
65
66 wiki_routes.connect 'projects/:id/wiki/:page/:action',
66 wiki_routes.connect 'projects/:id/wiki/:page/:action',
67 :action => /edit|rename|destroy|preview|protect/,
67 :action => /edit|rename|destroy|preview|protect/,
68 :conditions => {:method => :post}
68 :conditions => {:method => :post}
69 end
69 end
70
70
71 map.with_options :controller => 'messages' do |messages_routes|
71 map.with_options :controller => 'messages' do |messages_routes|
72 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
72 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
73 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
73 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
74 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
74 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
75 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
75 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
76 end
76 end
77 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
77 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
78 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
78 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
79 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
79 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
80 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
80 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
81 end
81 end
82 end
82 end
83
83
84 map.with_options :controller => 'boards' do |board_routes|
84 map.with_options :controller => 'boards' do |board_routes|
85 board_routes.with_options :conditions => {:method => :get} do |board_views|
85 board_routes.with_options :conditions => {:method => :get} do |board_views|
86 board_views.connect 'projects/:project_id/boards', :action => 'index'
86 board_views.connect 'projects/:project_id/boards', :action => 'index'
87 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
87 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
88 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
88 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
89 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
89 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
90 end
90 end
91 board_routes.with_options :conditions => {:method => :post} do |board_actions|
91 board_routes.with_options :conditions => {:method => :post} do |board_actions|
92 board_actions.connect 'projects/:project_id/boards', :action => 'new'
92 board_actions.connect 'projects/:project_id/boards', :action => 'new'
93 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
93 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
94 end
94 end
95 end
95 end
96
96
97 map.with_options :controller => 'documents' do |document_routes|
97 map.with_options :controller => 'documents' do |document_routes|
98 document_routes.with_options :conditions => {:method => :get} do |document_views|
98 document_routes.with_options :conditions => {:method => :get} do |document_views|
99 document_views.connect 'projects/:project_id/documents', :action => 'index'
99 document_views.connect 'projects/:project_id/documents', :action => 'index'
100 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
100 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
101 document_views.connect 'documents/:id', :action => 'show'
101 document_views.connect 'documents/:id', :action => 'show'
102 document_views.connect 'documents/:id/edit', :action => 'edit'
102 document_views.connect 'documents/:id/edit', :action => 'edit'
103 end
103 end
104 document_routes.with_options :conditions => {:method => :post} do |document_actions|
104 document_routes.with_options :conditions => {:method => :post} do |document_actions|
105 document_actions.connect 'projects/:project_id/documents', :action => 'new'
105 document_actions.connect 'projects/:project_id/documents', :action => 'new'
106 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
106 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
107 end
107 end
108 end
108 end
109
109
110 map.with_options :controller => 'issues' do |issues_routes|
110 map.with_options :controller => 'issues' do |issues_routes|
111 issues_routes.with_options :conditions => {:method => :get} do |issues_views|
111 issues_routes.with_options :conditions => {:method => :get} do |issues_views|
112 issues_views.connect 'issues', :action => 'index'
112 issues_views.connect 'issues', :action => 'index'
113 issues_views.connect 'issues.:format', :action => 'index'
113 issues_views.connect 'issues.:format', :action => 'index'
114 issues_views.connect 'projects/:project_id/issues', :action => 'index'
114 issues_views.connect 'projects/:project_id/issues', :action => 'index'
115 issues_views.connect 'projects/:project_id/issues.:format', :action => 'index'
115 issues_views.connect 'projects/:project_id/issues.:format', :action => 'index'
116 issues_views.connect 'projects/:project_id/issues/new', :action => 'new'
116 issues_views.connect 'projects/:project_id/issues/new', :action => 'new'
117 issues_views.connect 'projects/:project_id/issues/gantt', :action => 'gantt'
117 issues_views.connect 'projects/:project_id/issues/gantt', :action => 'gantt'
118 issues_views.connect 'projects/:project_id/issues/calendar', :action => 'calendar'
118 issues_views.connect 'projects/:project_id/issues/calendar', :action => 'calendar'
119 issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new'
119 issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new'
120 issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/
120 issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/
121 issues_views.connect 'issues/:id.:format', :action => 'show', :id => /\d+/
121 issues_views.connect 'issues/:id.:format', :action => 'show', :id => /\d+/
122 issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\d+/
122 issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\d+/
123 issues_views.connect 'issues/:id/move', :action => 'move', :id => /\d+/
123 issues_views.connect 'issues/:id/move', :action => 'move', :id => /\d+/
124 end
124 end
125 issues_routes.with_options :conditions => {:method => :post} do |issues_actions|
125 issues_routes.with_options :conditions => {:method => :post} do |issues_actions|
126 issues_actions.connect 'projects/:project_id/issues', :action => 'new'
126 issues_actions.connect 'projects/:project_id/issues', :action => 'new'
127 issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/
127 issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/
128 issues_actions.connect 'issues/:id/:action', :action => /edit|move|destroy/, :id => /\d+/
128 issues_actions.connect 'issues/:id/:action', :action => /edit|move|destroy/, :id => /\d+/
129 end
129 end
130 issues_routes.connect 'issues/:action'
130 issues_routes.connect 'issues/:action'
131 end
131 end
132
132
133 map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations|
133 map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations|
134 relations.connect 'issues/:issue_id/relations/:id', :action => 'new'
134 relations.connect 'issues/:issue_id/relations/:id', :action => 'new'
135 relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy'
135 relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy'
136 end
136 end
137
137
138 map.with_options :controller => 'reports', :action => 'issue_report', :conditions => {:method => :get} do |reports|
138 map.with_options :controller => 'reports', :action => 'issue_report', :conditions => {:method => :get} do |reports|
139 reports.connect 'projects/:id/issues/report'
139 reports.connect 'projects/:id/issues/report'
140 reports.connect 'projects/:id/issues/report/:detail'
140 reports.connect 'projects/:id/issues/report/:detail'
141 end
141 end
142
142
143 map.with_options :controller => 'news' do |news_routes|
143 map.with_options :controller => 'news' do |news_routes|
144 news_routes.with_options :conditions => {:method => :get} do |news_views|
144 news_routes.with_options :conditions => {:method => :get} do |news_views|
145 news_views.connect 'news', :action => 'index'
145 news_views.connect 'news', :action => 'index'
146 news_views.connect 'projects/:project_id/news', :action => 'index'
146 news_views.connect 'projects/:project_id/news', :action => 'index'
147 news_views.connect 'projects/:project_id/news.:format', :action => 'index'
147 news_views.connect 'projects/:project_id/news.:format', :action => 'index'
148 news_views.connect 'news.:format', :action => 'index'
148 news_views.connect 'news.:format', :action => 'index'
149 news_views.connect 'projects/:project_id/news/new', :action => 'new'
149 news_views.connect 'projects/:project_id/news/new', :action => 'new'
150 news_views.connect 'news/:id', :action => 'show'
150 news_views.connect 'news/:id', :action => 'show'
151 news_views.connect 'news/:id/edit', :action => 'edit'
151 news_views.connect 'news/:id/edit', :action => 'edit'
152 end
152 end
153 news_routes.with_options do |news_actions|
153 news_routes.with_options do |news_actions|
154 news_actions.connect 'projects/:project_id/news', :action => 'new'
154 news_actions.connect 'projects/:project_id/news', :action => 'new'
155 news_actions.connect 'news/:id/edit', :action => 'edit'
155 news_actions.connect 'news/:id/edit', :action => 'edit'
156 news_actions.connect 'news/:id/destroy', :action => 'destroy'
156 news_actions.connect 'news/:id/destroy', :action => 'destroy'
157 end
157 end
158 end
158 end
159
159
160 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
160 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
161
161
162 map.with_options :controller => 'users' do |users|
162 map.with_options :controller => 'users' do |users|
163 users.with_options :conditions => {:method => :get} do |user_views|
163 users.with_options :conditions => {:method => :get} do |user_views|
164 user_views.connect 'users', :action => 'list'
164 user_views.connect 'users', :action => 'list'
165 user_views.connect 'users', :action => 'index'
165 user_views.connect 'users', :action => 'index'
166 user_views.connect 'users/new', :action => 'add'
166 user_views.connect 'users/new', :action => 'add'
167 user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil
167 user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil
168 end
168 end
169 users.with_options :conditions => {:method => :post} do |user_actions|
169 users.with_options :conditions => {:method => :post} do |user_actions|
170 user_actions.connect 'users', :action => 'add'
170 user_actions.connect 'users', :action => 'add'
171 user_actions.connect 'users/new', :action => 'add'
171 user_actions.connect 'users/new', :action => 'add'
172 user_actions.connect 'users/:id/edit', :action => 'edit'
172 user_actions.connect 'users/:id/edit', :action => 'edit'
173 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
173 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
174 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
174 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
175 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
175 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
176 end
176 end
177 end
177 end
178
178
179 map.with_options :controller => 'projects' do |projects|
179 map.with_options :controller => 'projects' do |projects|
180 projects.with_options :conditions => {:method => :get} do |project_views|
180 projects.with_options :conditions => {:method => :get} do |project_views|
181 project_views.connect 'projects', :action => 'index'
181 project_views.connect 'projects', :action => 'index'
182 project_views.connect 'projects.:format', :action => 'index'
182 project_views.connect 'projects.:format', :action => 'index'
183 project_views.connect 'projects/new', :action => 'add'
183 project_views.connect 'projects/new', :action => 'add'
184 project_views.connect 'projects/:id', :action => 'show'
184 project_views.connect 'projects/:id', :action => 'show'
185 project_views.connect 'projects/:id/:action', :action => /roadmap|changelog|destroy|settings/
185 project_views.connect 'projects/:id/:action', :action => /roadmap|changelog|destroy|settings/
186 project_views.connect 'projects/:id/files', :action => 'list_files'
186 project_views.connect 'projects/:id/files', :action => 'list_files'
187 project_views.connect 'projects/:id/files/new', :action => 'add_file'
187 project_views.connect 'projects/:id/files/new', :action => 'add_file'
188 project_views.connect 'projects/:id/versions/new', :action => 'add_version'
188 project_views.connect 'projects/:id/versions/new', :action => 'add_version'
189 project_views.connect 'projects/:id/categories/new', :action => 'add_issue_category'
189 project_views.connect 'projects/:id/categories/new', :action => 'add_issue_category'
190 project_views.connect 'projects/:id/settings/:tab', :action => 'settings'
190 project_views.connect 'projects/:id/settings/:tab', :action => 'settings'
191 end
191 end
192
192
193 projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity|
193 projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity|
194 activity.connect 'projects/:id/activity'
194 activity.connect 'projects/:id/activity'
195 activity.connect 'projects/:id/activity.:format'
195 activity.connect 'projects/:id/activity.:format'
196 activity.connect 'activity'
196 activity.connect 'activity'
197 activity.connect 'activity.:format'
197 activity.connect 'activity.:format'
198 end
198 end
199
199
200 projects.with_options :conditions => {:method => :post} do |project_actions|
200 projects.with_options :conditions => {:method => :post} do |project_actions|
201 project_actions.connect 'projects/new', :action => 'add'
201 project_actions.connect 'projects/new', :action => 'add'
202 project_actions.connect 'projects', :action => 'add'
202 project_actions.connect 'projects', :action => 'add'
203 project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/
203 project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/
204 project_actions.connect 'projects/:id/files/new', :action => 'add_file'
204 project_actions.connect 'projects/:id/files/new', :action => 'add_file'
205 project_actions.connect 'projects/:id/versions/new', :action => 'add_version'
205 project_actions.connect 'projects/:id/versions/new', :action => 'add_version'
206 project_actions.connect 'projects/:id/categories/new', :action => 'add_issue_category'
206 project_actions.connect 'projects/:id/categories/new', :action => 'add_issue_category'
207 end
207 end
208 end
208 end
209
209
210 map.with_options :controller => 'repositories' do |repositories|
210 map.with_options :controller => 'repositories' do |repositories|
211 repositories.with_options :conditions => {:method => :get} do |repository_views|
211 repositories.with_options :conditions => {:method => :get} do |repository_views|
212 repositories.connect 'projects/:id/repository', :action => 'show'
212 repositories.connect 'projects/:id/repository', :action => 'show'
213 repositories.connect 'projects/:id/repository/edit', :action => 'edit'
213 repositories.connect 'projects/:id/repository/edit', :action => 'edit'
214 repositories.connect 'projects/:id/repository/statistics', :action => 'stats'
214 repositories.connect 'projects/:id/repository/statistics', :action => 'stats'
215 repositories.connect 'projects/:id/repository/revisions', :action => 'revisions'
215 repositories.connect 'projects/:id/repository/revisions', :action => 'revisions'
216 repositories.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
216 repositories.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
217 repositories.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
217 repositories.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
218 repositories.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
218 repositories.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
219 repositories.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
219 repositories.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
220 repositories.connect 'projects/:id/repository/revisions/:rev/:action/*path'
220 repositories.connect 'projects/:id/repository/revisions/:rev/:action/*path'
221 repositories.connect 'projects/:id/repository/:action/*path'
221 repositories.connect 'projects/:id/repository/:action/*path'
222 end
222 end
223
223
224 repositories.connect 'projects/:id/repository/edit', :action => 'edit', :conditions => {:method => :post}
224 repositories.connect 'projects/:id/repository/edit', :action => 'edit', :conditions => {:method => :post}
225 end
225 end
226
226
227 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
227 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
228 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
228 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
229 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
229 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
230
230
231
231
232 #left old routes at the bottom for backwards compat
232 #left old routes at the bottom for backwards compat
233 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
233 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
234 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
234 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
235 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
235 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
236 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
236 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
237 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
237 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
238 map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations'
238 map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations'
239 map.connect 'projects/:project_id/news/:action', :controller => 'news'
239 map.connect 'projects/:project_id/news/:action', :controller => 'news'
240 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
240 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
241 map.with_options :controller => 'repositories' do |omap|
241 map.with_options :controller => 'repositories' do |omap|
242 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
242 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
243 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
243 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
244 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
244 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
245 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
245 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
246 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
246 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
247 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
247 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
248 end
248 end
249
249
250 # Allow downloading Web Service WSDL as a file with an extension
250 map.with_options :controller => 'sys' do |sys|
251 # instead of a file named 'wsdl'
251 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
252 map.connect ':controller/service.wsdl', :action => 'wsdl'
252 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
253 end
253
254
254 # Install the default route as the lowest priority.
255 # Install the default route as the lowest priority.
255 map.connect ':controller/:action/:id'
256 map.connect ':controller/:action/:id'
256 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
257 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
257 end
258 end
@@ -1,289 +1,295
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 # == Synopsis
3 # == Synopsis
4 #
4 #
5 # reposman: manages your repositories with Redmine
5 # reposman: manages your repositories with Redmine
6 #
6 #
7 # == Usage
7 # == Usage
8 #
8 #
9 # reposman [OPTIONS...] -s [DIR] -r [HOST]
9 # reposman [OPTIONS...] -s [DIR] -r [HOST]
10 #
10 #
11 # Examples:
11 # Examples:
12 # reposman --svn-dir=/var/svn --redmine-host=redmine.example.net --scm subversion
12 # reposman --svn-dir=/var/svn --redmine-host=redmine.example.net --scm subversion
13 # reposman -s /var/git -r redmine.example.net -u http://svn.example.net --scm git
13 # reposman -s /var/git -r redmine.example.net -u http://svn.example.net --scm git
14 #
14 #
15 # == Arguments (mandatory)
15 # == Arguments (mandatory)
16 #
16 #
17 # -s, --svn-dir=DIR use DIR as base directory for svn repositories
17 # -s, --svn-dir=DIR use DIR as base directory for svn repositories
18 # -r, --redmine-host=HOST assume Redmine is hosted on HOST. Examples:
18 # -r, --redmine-host=HOST assume Redmine is hosted on HOST. Examples:
19 # -r redmine.example.net
19 # -r redmine.example.net
20 # -r http://redmine.example.net
20 # -r http://redmine.example.net
21 # -r https://example.net/redmine
21 # -r https://example.net/redmine
22 #
22 #
23 # == Options
23 # == Options
24 #
24 #
25 # -o, --owner=OWNER owner of the repository. using the rails login
25 # -o, --owner=OWNER owner of the repository. using the rails login
26 # allow user to browse the repository within
26 # allow user to browse the repository within
27 # Redmine even for private project. If you want to share repositories
27 # Redmine even for private project. If you want to share repositories
28 # through Redmine.pm, you need to use the apache owner.
28 # through Redmine.pm, you need to use the apache owner.
29 # --scm=SCM the kind of SCM repository you want to create (and register) in
29 # --scm=SCM the kind of SCM repository you want to create (and register) in
30 # Redmine (default: Subversion). reposman is able to create Git
30 # Redmine (default: Subversion). reposman is able to create Git
31 # and Subversion repositories. For all other kind (Bazaar,
31 # and Subversion repositories. For all other kind (Bazaar,
32 # Darcs, Filesystem, Mercurial) you must specify a --command option
32 # Darcs, Filesystem, Mercurial) you must specify a --command option
33 # -u, --url=URL the base url Redmine will use to access your
33 # -u, --url=URL the base url Redmine will use to access your
34 # repositories. This option is used to automatically
34 # repositories. This option is used to automatically
35 # register the repositories in Redmine. The project
35 # register the repositories in Redmine. The project
36 # identifier will be appended to this url. Examples:
36 # identifier will be appended to this url. Examples:
37 # -u https://example.net/svn
37 # -u https://example.net/svn
38 # -u file:///var/svn/
38 # -u file:///var/svn/
39 # if this option isn't set, reposman won't register
39 # if this option isn't set, reposman won't register
40 # the repositories in Redmine
40 # the repositories in Redmine
41 # -c, --command=COMMAND use this command instead of "svnadmin create" to
41 # -c, --command=COMMAND use this command instead of "svnadmin create" to
42 # create a repository. This option can be used to
42 # create a repository. This option can be used to
43 # create repositories other than subversion and git kind.
43 # create repositories other than subversion and git kind.
44 # This command override the default creation for git and subversion.
44 # This command override the default creation for git and subversion.
45 # -f, --force force repository creation even if the project
45 # -f, --force force repository creation even if the project
46 # repository is already declared in Redmine
46 # repository is already declared in Redmine
47 # -t, --test only show what should be done
47 # -t, --test only show what should be done
48 # -h, --help show help and exit
48 # -h, --help show help and exit
49 # -v, --verbose verbose
49 # -v, --verbose verbose
50 # -V, --version print version and exit
50 # -V, --version print version and exit
51 # -q, --quiet no log
51 # -q, --quiet no log
52 #
52 #
53 # == References
53 # == References
54 #
54 #
55 # You can find more information on the redmine's wiki : http://www.redmine.org/wiki/redmine/HowTos
55 # You can find more information on the redmine's wiki : http://www.redmine.org/wiki/redmine/HowTos
56
56
57
57
58 require 'getoptlong'
58 require 'getoptlong'
59 require 'rdoc/usage'
59 require 'rdoc/usage'
60 require 'soap/wsdlDriver'
61 require 'find'
60 require 'find'
62 require 'etc'
61 require 'etc'
63
62
64 Version = "1.1"
63 Version = "1.2"
65 SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem )
64 SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem )
66
65
67 opts = GetoptLong.new(
66 opts = GetoptLong.new(
68 ['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT],
67 ['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT],
69 ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
68 ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
70 ['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT],
69 ['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT],
71 ['--url', '-u', GetoptLong::REQUIRED_ARGUMENT],
70 ['--url', '-u', GetoptLong::REQUIRED_ARGUMENT],
72 ['--command' , '-c', GetoptLong::REQUIRED_ARGUMENT],
71 ['--command' , '-c', GetoptLong::REQUIRED_ARGUMENT],
73 ['--scm', GetoptLong::REQUIRED_ARGUMENT],
72 ['--scm', GetoptLong::REQUIRED_ARGUMENT],
74 ['--test', '-t', GetoptLong::NO_ARGUMENT],
73 ['--test', '-t', GetoptLong::NO_ARGUMENT],
75 ['--force', '-f', GetoptLong::NO_ARGUMENT],
74 ['--force', '-f', GetoptLong::NO_ARGUMENT],
76 ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
75 ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
77 ['--version', '-V', GetoptLong::NO_ARGUMENT],
76 ['--version', '-V', GetoptLong::NO_ARGUMENT],
78 ['--help' , '-h', GetoptLong::NO_ARGUMENT],
77 ['--help' , '-h', GetoptLong::NO_ARGUMENT],
79 ['--quiet' , '-q', GetoptLong::NO_ARGUMENT]
78 ['--quiet' , '-q', GetoptLong::NO_ARGUMENT]
80 )
79 )
81
80
82 $verbose = 0
81 $verbose = 0
83 $quiet = false
82 $quiet = false
84 $redmine_host = ''
83 $redmine_host = ''
85 $repos_base = ''
84 $repos_base = ''
86 $svn_owner = 'root'
85 $svn_owner = 'root'
87 $use_groupid = true
86 $use_groupid = true
88 $svn_url = false
87 $svn_url = false
89 $test = false
88 $test = false
90 $force = false
89 $force = false
91 $scm = 'Subversion'
90 $scm = 'Subversion'
92
91
93 def log(text, options={})
92 def log(text, options={})
94 level = options[:level] || 0
93 level = options[:level] || 0
95 puts text unless $quiet or level > $verbose
94 puts text unless $quiet or level > $verbose
96 exit 1 if options[:exit]
95 exit 1 if options[:exit]
97 end
96 end
98
97
99 def system_or_raise(command)
98 def system_or_raise(command)
100 raise "\"#{command}\" failed" unless system command
99 raise "\"#{command}\" failed" unless system command
101 end
100 end
102
101
103 module SCM
102 module SCM
104
103
105 module Subversion
104 module Subversion
106 def self.create(path)
105 def self.create(path)
107 system_or_raise "svnadmin create #{path}"
106 system_or_raise "svnadmin create #{path}"
108 end
107 end
109 end
108 end
110
109
111 module Git
110 module Git
112 def self.create(path)
111 def self.create(path)
113 Dir.mkdir path
112 Dir.mkdir path
114 Dir.chdir(path) do
113 Dir.chdir(path) do
115 system_or_raise "git --bare init --shared"
114 system_or_raise "git --bare init --shared"
116 system_or_raise "git update-server-info"
115 system_or_raise "git update-server-info"
117 end
116 end
118 end
117 end
119 end
118 end
120
119
121 end
120 end
122
121
123 begin
122 begin
124 opts.each do |opt, arg|
123 opts.each do |opt, arg|
125 case opt
124 case opt
126 when '--svn-dir'; $repos_base = arg.dup
125 when '--svn-dir'; $repos_base = arg.dup
127 when '--redmine-host'; $redmine_host = arg.dup
126 when '--redmine-host'; $redmine_host = arg.dup
128 when '--owner'; $svn_owner = arg.dup; $use_groupid = false;
127 when '--owner'; $svn_owner = arg.dup; $use_groupid = false;
129 when '--url'; $svn_url = arg.dup
128 when '--url'; $svn_url = arg.dup
130 when '--scm'; $scm = arg.dup.capitalize; log("Invalid SCM: #{$scm}", :exit => true) unless SUPPORTED_SCM.include?($scm)
129 when '--scm'; $scm = arg.dup.capitalize; log("Invalid SCM: #{$scm}", :exit => true) unless SUPPORTED_SCM.include?($scm)
131 when '--command'; $command = arg.dup
130 when '--command'; $command = arg.dup
132 when '--verbose'; $verbose += 1
131 when '--verbose'; $verbose += 1
133 when '--test'; $test = true
132 when '--test'; $test = true
134 when '--force'; $force = true
133 when '--force'; $force = true
135 when '--version'; puts Version; exit
134 when '--version'; puts Version; exit
136 when '--help'; RDoc::usage
135 when '--help'; RDoc::usage
137 when '--quiet'; $quiet = true
136 when '--quiet'; $quiet = true
138 end
137 end
139 end
138 end
140 rescue
139 rescue
141 exit 1
140 exit 1
142 end
141 end
143
142
144 if $test
143 if $test
145 log("running in test mode")
144 log("running in test mode")
146 end
145 end
147
146
148 # Make sure command is overridden if SCM vendor is not handled internally (for the moment Subversion and Git)
147 # Make sure command is overridden if SCM vendor is not handled internally (for the moment Subversion and Git)
149 if $command.nil?
148 if $command.nil?
150 begin
149 begin
151 scm_module = SCM.const_get($scm)
150 scm_module = SCM.const_get($scm)
152 rescue
151 rescue
153 log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
152 log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
154 end
153 end
155 end
154 end
156
155
157 $svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
156 $svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
158
157
159 if ($redmine_host.empty? or $repos_base.empty?)
158 if ($redmine_host.empty? or $repos_base.empty?)
160 RDoc::usage
159 RDoc::usage
161 end
160 end
162
161
163 unless File.directory?($repos_base)
162 unless File.directory?($repos_base)
164 log("directory '#{$repos_base}' doesn't exists", :exit => true)
163 log("directory '#{$repos_base}' doesn't exists", :exit => true)
165 end
164 end
166
165
166 begin
167 require 'activeresource'
168 rescue LoadError
169 log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true)
170 end
171
172 class Project < ActiveResource::Base; end
173
167 log("querying Redmine for projects...", :level => 1);
174 log("querying Redmine for projects...", :level => 1);
168
175
169 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
176 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
170 $redmine_host.gsub!(/\/$/, '')
177 $redmine_host.gsub!(/\/$/, '')
171
178
172 wsdl_url = "#{$redmine_host}/sys/service.wsdl";
179 Project.site = "#{$redmine_host}/sys";
173
180
174 begin
181 begin
175 soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
182 # Get all active projects that have the Repository module enabled
183 projects = Project.find(:all)
176 rescue => e
184 rescue => e
177 log("Unable to connect to #{wsdl_url} : #{e}", :exit => true)
185 log("Unable to connect to #{Project.site}: #{e}", :exit => true)
178 end
186 end
179
187
180 projects = soap.ProjectsWithRepositoryEnabled
181
182 if projects.nil?
188 if projects.nil?
183 log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
189 log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
184 end
190 end
185
191
186 log("retrieved #{projects.size} projects", :level => 1)
192 log("retrieved #{projects.size} projects", :level => 1)
187
193
188 def set_owner_and_rights(project, repos_path, &block)
194 def set_owner_and_rights(project, repos_path, &block)
189 if RUBY_PLATFORM =~ /mswin/
195 if RUBY_PLATFORM =~ /mswin/
190 yield if block_given?
196 yield if block_given?
191 else
197 else
192 uid, gid = Etc.getpwnam($svn_owner).uid, ($use_groupid ? Etc.getgrnam(project.identifier).gid : 0)
198 uid, gid = Etc.getpwnam($svn_owner).uid, ($use_groupid ? Etc.getgrnam(project.identifier).gid : 0)
193 right = project.is_public ? 0775 : 0770
199 right = project.is_public ? 0775 : 0770
194 yield if block_given?
200 yield if block_given?
195 Find.find(repos_path) do |f|
201 Find.find(repos_path) do |f|
196 File.chmod right, f
202 File.chmod right, f
197 File.chown uid, gid, f
203 File.chown uid, gid, f
198 end
204 end
199 end
205 end
200 end
206 end
201
207
202 def other_read_right?(file)
208 def other_read_right?(file)
203 (File.stat(file).mode & 0007).zero? ? false : true
209 (File.stat(file).mode & 0007).zero? ? false : true
204 end
210 end
205
211
206 def owner_name(file)
212 def owner_name(file)
207 RUBY_PLATFORM =~ /mswin/ ?
213 RUBY_PLATFORM =~ /mswin/ ?
208 $svn_owner :
214 $svn_owner :
209 Etc.getpwuid( File.stat(file).uid ).name
215 Etc.getpwuid( File.stat(file).uid ).name
210 end
216 end
211
217
212 projects.each do |project|
218 projects.each do |project|
213 log("treating project #{project.name}", :level => 1)
219 log("treating project #{project.name}", :level => 1)
214
220
215 if project.identifier.empty?
221 if project.identifier.empty?
216 log("\tno identifier for project #{project.name}")
222 log("\tno identifier for project #{project.name}")
217 next
223 next
218 elsif not project.identifier.match(/^[a-z0-9\-]+$/)
224 elsif not project.identifier.match(/^[a-z0-9\-]+$/)
219 log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
225 log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
220 next;
226 next;
221 end
227 end
222
228
223 repos_path = File.join($repos_base, project.identifier).gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
229 repos_path = File.join($repos_base, project.identifier).gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
224
230
225 if File.directory?(repos_path)
231 if File.directory?(repos_path)
226
232
227 # we must verify that repository has the good owner and the good
233 # we must verify that repository has the good owner and the good
228 # rights before leaving
234 # rights before leaving
229 other_read = other_read_right?(repos_path)
235 other_read = other_read_right?(repos_path)
230 owner = owner_name(repos_path)
236 owner = owner_name(repos_path)
231 next if project.is_public == other_read and owner == $svn_owner
237 next if project.is_public == other_read and owner == $svn_owner
232
238
233 if $test
239 if $test
234 log("\tchange mode on #{repos_path}")
240 log("\tchange mode on #{repos_path}")
235 next
241 next
236 end
242 end
237
243
238 begin
244 begin
239 set_owner_and_rights(project, repos_path)
245 set_owner_and_rights(project, repos_path)
240 rescue Errno::EPERM => e
246 rescue Errno::EPERM => e
241 log("\tunable to change mode on #{repos_path} : #{e}\n")
247 log("\tunable to change mode on #{repos_path} : #{e}\n")
242 next
248 next
243 end
249 end
244
250
245 log("\tmode change on #{repos_path}");
251 log("\tmode change on #{repos_path}");
246
252
247 else
253 else
248 # if repository is already declared in redmine, we don't create
254 # if repository is already declared in redmine, we don't create
249 # unless user use -f with reposman
255 # unless user use -f with reposman
250 if $force == false and not project.repository.nil?
256 if $force == false and project.respond_to?(:repository)
251 log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
257 log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
252 next
258 next
253 end
259 end
254
260
255 project.is_public ? File.umask(0002) : File.umask(0007)
261 project.is_public ? File.umask(0002) : File.umask(0007)
256
262
257 if $test
263 if $test
258 log("\tcreate repository #{repos_path}")
264 log("\tcreate repository #{repos_path}")
259 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
265 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
260 next
266 next
261 end
267 end
262
268
263 begin
269 begin
264 set_owner_and_rights(project, repos_path) do
270 set_owner_and_rights(project, repos_path) do
265 if scm_module.nil?
271 if scm_module.nil?
266 system_or_raise "#{$command} #{repos_path}"
272 system_or_raise "#{$command} #{repos_path}"
267 else
273 else
268 scm_module.create(repos_path)
274 scm_module.create(repos_path)
269 end
275 end
270 end
276 end
271 rescue => e
277 rescue => e
272 log("\tunable to create #{repos_path} : #{e}\n")
278 log("\tunable to create #{repos_path} : #{e}\n")
273 next
279 next
274 end
280 end
275
281
276 if $svn_url
282 if $svn_url
277 ret = soap.RepositoryCreated project.identifier, $scm, "#{$svn_url}#{project.identifier}"
283 begin
278 if ret > 0
284 project.post(:repository, :vendor => $scm, :repository => {:url => "#{$svn_url}#{project.identifier}"})
279 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}");
285 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}");
280 else
286 rescue => e
281 log("\trepository #{repos_path} not registered in Redmine. Look in your log to find why.");
287 log("\trepository #{repos_path} not registered in Redmine: #{e.message}");
282 end
288 end
283 end
289 end
284
290
285 log("\trepository #{repos_path} created");
291 log("\trepository #{repos_path} created");
286 end
292 end
287
293
288 end
294 end
289
295
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (1379 lines changed) Show them Hide them
General Comments 0
You need to be logged in to leave comments. Login now