polisher 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.rdoc +84 -14
  2. data/Rakefile +21 -19
  3. data/TODO +5 -4
  4. data/bin/server +1 -0
  5. data/config/polisher.yml +0 -15
  6. data/db/connection.rb +13 -10
  7. data/db/migrations/{002_create_managed_gems.rb → 001_create_projects.rb} +4 -5
  8. data/db/migrations/{001_create_sources.rb → 002_create_sources.rb} +1 -3
  9. data/db/migrations/003_create_project_source_versions.rb +28 -0
  10. data/db/migrations/{003_create_events.rb → 004_create_events.rb} +2 -2
  11. data/db/migrations/005_create_project_dependencies.rb +28 -0
  12. data/db/models/event.rb +47 -21
  13. data/db/models/project.rb +110 -0
  14. data/db/models/project_dependency.rb +27 -0
  15. data/db/models/project_source_version.rb +31 -0
  16. data/db/models/source.rb +82 -16
  17. data/lib/common.rb +37 -5
  18. data/lib/dsl.rb +292 -0
  19. data/lib/event_handlers.rb +139 -73
  20. data/lib/gem_adapter.rb +94 -0
  21. data/polisher.rb +302 -50
  22. data/public/stylesheets/style.css +15 -31
  23. data/spec/common_spec.rb +28 -0
  24. data/spec/dsl_spec.rb +357 -0
  25. data/spec/event_handlers_spec.rb +166 -30
  26. data/spec/gem_adapter_spec.rb +89 -0
  27. data/spec/models_spec.rb +635 -107
  28. data/spec/polisher_spec.rb +496 -56
  29. data/views/layout.haml +3 -5
  30. data/views/projects/index.haml +42 -0
  31. data/views/projects/index.html.haml +38 -0
  32. data/views/result.haml +9 -0
  33. data/views/sources/index.haml +24 -41
  34. data/views/sources/index.html.haml +26 -0
  35. metadata +131 -12
  36. data/db/models/managed_gem.rb +0 -111
  37. data/public/javascripts/jquery-1.2.6.min.js +0 -32
  38. data/public/javascripts/polisher.js +0 -15
  39. data/views/gems/index.haml +0 -106
@@ -1,6 +1,12 @@
1
1
  # Gem event handler callbacks,
2
2
  # A method should exist here for every process supported by the system.
3
- # The method should share the same name w/ the corresponding process
3
+ # Once added to this module it will automatically appear in
4
+ # db/models/Event::processes for subsequent use.
5
+ #
6
+ # Each method should take three parameters
7
+ # * the event being run
8
+ # * the version of the project being released
9
+ # * any additional event-specific arguments in an optional hash
4
10
  #
5
11
  # Copyright (C) 2010 Red Hat, Inc.
6
12
  # Written by Mohammed Morsi <mmorsi@redhat.com>
@@ -9,92 +15,152 @@
9
15
  # it under the terms of the GNU Affero General Public License
10
16
  # as published by the Free Software Foundation, either version 3
11
17
  # of the License, or (at your option) any later version.
12
- #
18
+ #
13
19
  # You should have received a copy of the the GNU Affero
14
- # General Public License, along with Polisher. If not, see
20
+ # General Public License, along with Polisher. If not, see
15
21
  # <http://www.gnu.org/licenses/>
16
22
 
23
+ require 'erb'
17
24
  require 'gem2rpm'
18
25
  require 'net/smtp'
19
26
 
20
- # Convert gem into another package format.
21
- # Right now uses gem2rpm to create rpm spec, taking optional template file name
22
- # TODO extend/modify to support any other package format
23
- def create_package(gem, template_file = '')
24
- # d/l gem into artifacts/gems dir, link it into the artifacts/SOURCES dir
25
- gem_file_path = gem.download_to :dir => ARTIFACTS_DIR + "/gems"
26
- gem_file = gem_file_path.split('/').last
27
- File.symlink gem_file_path, ARTIFACTS_DIR + "/SOURCES/" + gem_file
28
-
29
- # spec we are writing
30
- spec_file = ARTIFACTS_DIR + "/SPECS/rubygem-#{gem.name}.spec"
31
- sfh = File.open(spec_file, "wb")
32
-
33
- # coversion template to use, if not specified use gem2rpm default
34
- template = Gem2Rpm::TEMPLATE
35
- File.open(ARTIFACTS_DIR + "/templates/#{template_file}", "rb") { |file|
36
- template = file.read
37
- } unless template_file == '' || template_file.nil?
38
-
39
- # create rpm spec w/ gem2rpm
40
- Gem2Rpm::convert gem_file_path, template, sfh
41
- sfh.close
27
+ # TODO raise some exceptions of our own here (though not neccessary as event.run will rescue everything raised, it might help w/ debugging)
28
+
29
+ module EventHandlers
42
30
 
43
- # run rpmbuild on spec
44
- system("rpmbuild --define '_topdir #{ARTIFACTS_DIR}' -ba #{spec_file}")
31
+ # Download project sources
32
+ def download_sources(event, version, args = {})
33
+ project = event.project
34
+ args.merge!({ :dir => ARTIFACTS_DIR + "/SOURCES", :version => version })
35
+ args = event.process_options.to_h.merge(args) unless event.process_options.nil?
36
+
37
+ # if we've already d/l'd the sources, skip the rest of the event execution (incorporate md5sums in the future)
38
+ downloaded = false
39
+ project.sources_for_version(version).each { |src|
40
+ src.format_uri! args
41
+ downloaded = true if File.exists?(ARTIFACTS_DIR + "/SOURCES/#{src.filename}")
42
+ }
43
+ return if downloaded
44
+
45
+ # d/l projects sources into artifacts/SOURCES dir
46
+ project.download_to args
45
47
  end
46
48
 
47
- # Update specified repository w/ latest gem artifact.
48
- # Right now updates specified yum repo w/ newly created gem rpm
49
- # TODO extend/modify to support other repository formats
50
- def update_repo(gem, repository)
51
- # create the repository dir if it doesn't exist
52
- repo_dir = ARTIFACTS_DIR + "/repos/#{repository}"
53
- Dir.mkdir repo_dir unless File.directory? repo_dir
49
+ # Convert project into rpm package format.
50
+ def create_rpm_package(event, version, args = {})
51
+ project = event.project
52
+ args.merge!({ :version => version })
53
+ template_file = nil
54
+ mock_target = nil
55
+
56
+ unless event.process_options.nil?
57
+ poh = event.process_options.to_h
58
+ template_file = poh["spec"]
59
+ mock_target = poh["mock"]
60
+ end
61
+
62
+ # if the rpm is built, skip the rest of the event execution (really need to check if the sources changed)
63
+ return if !Dir[ARTIFACTS_DIR + "/RPMS/*/#{project.name}-#{version}*.rpm"].empty?
64
+
65
+ # open a handle to the spec file to write
66
+ spec_file = ARTIFACTS_DIR + "/SPECS/#{project.name}.spec"
67
+ sfh = File.open(spec_file, "wb")
68
+
69
+ # read template if specified
70
+ template = (template_file == '' || template_file.nil?) ? nil : File.read_all(template_file)
71
+
72
+ # if primary project source is a gem, process template w/ gem2rpm
73
+ primary_source = project.primary_source_for_version(version)
74
+ if !primary_source.nil? && primary_source.source_type == "gem"
75
+ gem_file_path = ARTIFACTS_DIR + '/SOURCES/' + primary_source.filename
76
+ template = Gem2Rpm::TEMPLATE if template.nil?
77
+ Gem2Rpm::convert gem_file_path, template, sfh
78
+
79
+ # otherwise just process it w/ erb
80
+ else
81
+ # setting local variables to be pulled into erb via binding below
82
+ params_s = ''
83
+ args.each { |k,v| params_s += "#{k} = '#{v}' ; " }
84
+ eval params_s
85
+
86
+ # setting other local variables
87
+ name = project.name
88
+ # version is already set from above
89
+
90
+ # take specified template_file and process it w/ erb,
91
+ # TODO raise exception if we don't have a template
92
+ template = File.read_all(template_file)
93
+ template = ERB.new(template, 0, '<>').result(binding)
94
+
95
+ # write to spec_file
96
+ sfh.write template
97
+
98
+ end
54
99
 
55
- # get the latest built rpm that matches gem name
56
- # FIXME need to incorporate version
57
- gem_file = Dir[ARTIFACTS_DIR + "/RPMS/*/rubygem-#{gem.name}-*.rpm"].
58
- collect { |fn| File.new(fn) }.
59
- sort { |f1,f2| file1.mtime <=> file2.mtime }.last
100
+ sfh.close
60
101
 
61
- # grab the architecture from the directory the file resides in
62
- arch = gem_file.path.split('.')
63
- arch = arch[arch.size-2]
102
+ # run rpmbuild on spec to build srpm
103
+ system("rpmbuild --define '_topdir #{ARTIFACTS_DIR}' -bs #{spec_file}")
64
104
 
65
- # copy gem into repo/arch dir, creating it if it doesn't exist
66
- arch_dir = repo_dir + "/#{arch}"
67
- Dir.mkdir arch_dir unless File.directory? arch_dir
68
- File.open(arch_dir + "/rubygem-#{gem.name}.rpm", 'wb') { |ofile| ofile.write gem_file.read }
105
+ # run mock on srpm to build rpm
106
+ system("mock -r #{mock_target} rebuild #{ARTIFACTS_DIR}/SRPMS/#{project.name}-#{version}-*.src.rpm")
69
107
 
70
- # run createrepo to finalize the repository
71
- system("createrepo #{repo_dir}")
108
+ # copy generated rpms from /var/lib/mock/[mock_root] to ARTIFACTS/RPMS/[arches]
109
+ Dir["/var/lib/mock/#{mock_target}/root/builddir/build/RPMS/*.rpm"].each { |rpm|
110
+ arch = rpm.split(".")
111
+ arch = arch[arch.size-2]
112
+ FileUtils.mkdir_p "#{ARTIFACTS_DIR}/RPMS/#{arch}" unless File.directory? "#{ARTIFACTS_DIR}/RPMS/#{arch}"
113
+ FileUtils.cp rpm, "#{ARTIFACTS_DIR}/RPMS/#{arch}"
114
+ }
72
115
  end
73
116
 
74
- # run gem's test suite against specified repository
75
- def run_test_suite(gem, repository)
76
- end
117
+ # Update specified yum repository w/ latest project artifact for specified version
118
+ def update_yum_repo(event, version, args = {})
119
+ project = event.project
120
+ repository = event.process_options
77
121
 
78
- # notify a list of recipients of gem update
79
- def notify_subscribers(gem, recipients = [])
80
- from = POLISHER_CONFIG['email_from']
81
- subject = POLISHER_CONFIG['email_subject']
82
- body = POLISHER_CONFIG['email_body']
83
- server = POLISHER_CONFIG['email_server']
84
-
85
- # substitute variables into subject / body where appropriate
86
- subject.gsub('#{gem_name}', gem.name)
87
- body.gsub('#{gem_name}', gem.name)
88
-
89
- msg = <<END_OF_MESSAGE
90
- From: #{from}
91
- To: #{recipients.join(',')}
92
- Subject: #{subject}
93
-
94
- #{body}
95
- END_OF_MESSAGE
96
-
97
- Net::SMTP.start(server) do |smtp|
98
- smtp.send_message msg, from, to
99
- end
122
+ # create the repository dir if it doesn't exist
123
+ Dir.mkdir repository unless File.directory? repository
124
+
125
+ packages = [project.name + "-" + version]
126
+
127
+ # XXX real hacky way of getting all the packages corresponding to the project
128
+ # FIXME need a better solution here as any macros in the package names won't get executed properly
129
+ spec_file = ARTIFACTS_DIR + "/SPECS/#{project.name}.spec"
130
+ packages += File.read_all(spec_file).scan(/%package.*/).collect { |p|
131
+ ps = p.split
132
+ prefix = ps[ps.size-2] == "-n" ? "" : (project.name + "-")
133
+ prefix + p.split.last + "-" + version
134
+ }
135
+
136
+ # do not actually generate the repo unless a rpm is copied over
137
+ updated_repo = false
138
+
139
+ # copy the latest built rpms that match the packages
140
+ packages.each { |pkg|
141
+ pkg_file = Dir[ARTIFACTS_DIR + "/RPMS/*/#{pkg}*.rpm"].
142
+ collect { |fn| File.new(fn) }.
143
+ sort { |f1,f2| f1.mtime <=> f2.mtime }.last
144
+
145
+ unless pkg_file.nil?
146
+ # grab the architecture from the directory the src file resides in
147
+ arch = pkg_file.path.split('.')
148
+ arch = arch[arch.size-2]
149
+
150
+ pkg_file_name = pkg_file.path.split('/').last
151
+
152
+ # copy project into repo/arch dir, creating it if it doesn't exist
153
+ arch_dir = repository + "/#{arch}"
154
+ Dir.mkdir arch_dir unless File.directory? arch_dir
155
+ unless File.exists?(arch_dir + "/#{pkg_file_name}") # TODO need to incorporate a md5sum comparison here
156
+ updated_repo = true
157
+ File.write(arch_dir + "/#{pkg_file_name}", File.read_all(pkg_file.path))
158
+ end
159
+ end
160
+ }
161
+
162
+ # run createrepo to finalize the repository
163
+ system("createrepo #{repository}") if updated_repo
100
164
  end
165
+
166
+ end #module EventHandlers
@@ -0,0 +1,94 @@
1
+ # Gem adapter, provides interface to many gem routines
2
+ #
3
+ # Copyright (C) 2010 Red Hat, Inc.
4
+ # Written by Mohammed Morsi <mmorsi@redhat.com>
5
+ #
6
+ # This program is free software, you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation, either version 3
9
+ # of the License, or (at your option) any later version.
10
+ #
11
+ # You should have received a copy of the the GNU Affero
12
+ # General Public License, along with Polisher. If not, see
13
+ # <http://www.gnu.org/licenses/>
14
+
15
+ module Polisher
16
+ module GemAdapter
17
+
18
+ # Subscribe callback_url to gem updates from the specified source.
19
+ def subscribe(source, callback_url, gem_api_key)
20
+ raise ArgumentError, "must specify valid source, callback url, and api key" if source.nil? || callback_url.class != String || gem_api_key.class != String
21
+
22
+ subscribe_path = '/api/v1/web_hooks'
23
+ headers = { 'Authorization' => gem_api_key }
24
+ data = "gem_name=#{source.name}&url=#{callback_url}"
25
+
26
+ begin
27
+ http = Net::HTTP.new(URI.parse(source.uri).host, 80)
28
+ res = http.post(subscribe_path, data, headers)
29
+ raise RuntimeError unless res.is_a?(Net::HTTPSuccess)
30
+ rescue Exception => e
31
+ raise RuntimeError, "could not subscribe to gem #{source.name} at #{source.uri}#{subscribe_path}"
32
+ end
33
+ end
34
+ module_function :subscribe
35
+
36
+ # Determine if we are subscribed to gem specified by source with the specified gem_api_key
37
+ def subscribed?(source, gem_api_key)
38
+ raise ArgumentError, "must specify valid source and api key" if source.nil? || gem_api_key.class != String
39
+
40
+ subscribe_path = '/api/v1/web_hooks.json'
41
+ headers = { 'Authorization' => gem_api_key }
42
+
43
+ begin
44
+ http = Net::HTTP.new(URI.parse(source.uri).host, 80)
45
+ res = http.get(subscribe_path, headers).body
46
+ raise RuntimeError if res.class == Net::HTTPNotFound
47
+ res = JSON.parse(res)
48
+ return res.has_key?(source.name)
49
+
50
+ rescue Exception => e
51
+ raise RuntimeError, "could not connect to gem source at #{source.uri}#{subscribe_path}"
52
+ end
53
+ end
54
+ module_function :subscribed?
55
+
56
+ # Unsubscribe to updates to the gem specified by source w/ the specified callback_url and api_key
57
+ def unsubscribe(source, callback_url, gem_api_key)
58
+ return unless subscribed?(source, gem_api_key)
59
+ raise ArgumentError, "must specify valid source, callback url, and api key" if source.nil? || callback_url.class != String || gem_api_key.class != String
60
+
61
+ subscribe_path = "/api/v1/web_hooks/remove?gem_name=#{source.name}&url=#{callback_url}"
62
+ headers = { 'Authorization' => gem_api_key }
63
+
64
+ begin
65
+ http = Net::HTTP.new(URI.parse(source.uri).host, 80)
66
+ res = http.delete(subscribe_path, headers)
67
+ raise RuntimeError if res.class == Net::HTTPNotFound
68
+ rescue Exception => e
69
+ raise RuntimeError, "could not delete gem #{source.name} via #{source.uri}#{subscribe_path}"
70
+ end
71
+ end
72
+ module_function :unsubscribe
73
+
74
+ # Return hash of gem attributes/values retreived from remote source
75
+ def get_info(source)
76
+ info = nil
77
+ source_uri = URI.parse(source.uri).host
78
+ get_path = "/api/v1/gems/#{source.name}.json"
79
+ begin
80
+ Net::HTTP.start(source_uri, 80) { |http|
81
+ res = http.get(get_path).body
82
+ raise RuntimeError if res.class == Net::HTTPNotFound
83
+ info = JSON.parse(res)
84
+ }
85
+ rescue Exception => e
86
+ raise RuntimeError, "could not get info for gem #{source.name} via #{source.uri}#{get_path}"
87
+ end
88
+
89
+ return info
90
+ end
91
+ module_function :get_info
92
+
93
+ end # module GemAdapter
94
+ end # module Polisher
@@ -7,9 +7,9 @@
7
7
  # it under the terms of the GNU Affero General Public License
8
8
  # as published by the Free Software Foundation, either version 3
9
9
  # of the License, or (at your option) any later version.
10
- #
10
+ #
11
11
  # You should have received a copy of the the GNU Affero
12
- # General Public License, along with Polisher. If not, see
12
+ # General Public License, along with Polisher. If not, see
13
13
  # <http://www.gnu.org/licenses/>
14
14
 
15
15
  # ruby gems
@@ -20,7 +20,7 @@ require 'fileutils'
20
20
 
21
21
  # lib/ modules
22
22
  require 'common'
23
- require 'event_handlers'
23
+ require 'gem_adapter'
24
24
  require 'sinatra/url_for'
25
25
 
26
26
  # db modules
@@ -29,7 +29,7 @@ require 'db/connection'
29
29
  ##################################################################### Config
30
30
 
31
31
  # dir which generated artifacts reside
32
- ARTIFACTS_DIR = Sinatra::Application.artifacts_dir
32
+ ARTIFACTS_DIR = File.expand_path(Sinatra::Application.artifacts_dir)
33
33
 
34
34
  create_missing_polisher_dirs(:artifacts_dir => ARTIFACTS_DIR, :db_data_dir => Sinatra::Application.db_data_dir, :log_dir => Sinatra::Application.log_dir)
35
35
 
@@ -42,79 +42,331 @@ module Polisher::DB
42
42
  end
43
43
 
44
44
  # get polisher config
45
- POLISHER_CONFIG = YAML::load(File.open(Sinatra::Application.polisher_config))[Sinatra::Application.environment.to_s]
45
+ POLISHER_CONFIG = load_polisher_config(Sinatra::Application)
46
+
47
+ ##################################################################### Projects
46
48
 
47
- ##################################################################### Gems
48
-
49
- # Redirect to /gems
50
- get '/' do redirect '/gems'; end
49
+ # Redirect to /projects
50
+ get '/' do redirect '/projects.html'; end
51
51
 
52
- get '/gems' do
52
+ get '/projects.html' do
53
+ @projects = Project.find :all
53
54
  @sources = Source.find :all
54
- @gems = ManagedGem.find :all
55
- @processes = Event.processes
55
+ @processes = Event.processes
56
56
  @version_qualifiers = Event::VERSION_QUALIFIERS
57
+ haml :"projects/index.html"
58
+ end
57
59
 
58
- haml :"gems/index"
60
+ get '/projects' do
61
+ @projects = Project.find :all
62
+ haml :"projects/index", :layout => false
59
63
  end
60
64
 
61
- post '/gems/create' do
62
- @gem = ManagedGem.new :name => params[:name], :source_id => params[:source_id]
63
- @gem.save!
64
- @gem.subscribe
65
- redirect '/gems'
65
+ post '/projects/create' do
66
+ begin
67
+ if params[:name].nil? || params[:name] == ""
68
+ raise ArgumentError, "/projects/create received an invalid name(#{params[:name]})"
69
+ end
70
+
71
+ @project = Project.new :name => params[:name]
72
+ @project.save!
73
+
74
+ @result = {:success => true, :message => "successfully created project #{@project.name}", :errors => []}
75
+
76
+ rescue Exception => e
77
+ @result = {:success => false, :message => "failed to created project due to error #{e}", :errors => [e]}
78
+ @project.errors.each_full { |e| @result[:errors] << e } unless @project.nil?
79
+ end
80
+
81
+ haml :"result", :layout => false
66
82
  end
67
83
 
68
- delete '/gems/destroy/:id' do
69
- ManagedGem.delete params[:id]
70
- redirect '/gems'
84
+ delete '/projects/destroy/:id' do
85
+ begin
86
+ if params[:id].nil?
87
+ raise ArgumentError, "/projects/destroy/:id received an invalid id(#{params[:id]})"
88
+ end
89
+
90
+ project = Project.find(params[:id])
91
+ if project.nil?
92
+ raise ArgumentError, "/projects/destroy/#{params[:id]} could not find project"
93
+ end
94
+
95
+ project_name = project.name
96
+ Project.delete params[:id]
97
+ @result = {:success => true, :message => "successfully deleted project #{project_name}", :errors => []}
98
+
99
+ rescue Exception => e
100
+ @result = {:success => false, :message => "failed to delete project due to error #{e}", :errors => [e]}
101
+ end
102
+
103
+ haml :"result", :layout => false
71
104
  end
72
105
 
73
- post '/gems/updated' do
74
- name = params[:name]
75
- version = params[:version]
76
- source_uri = ManagedGem.uri_to_source_uri(params[:gem_uri])
106
+ post '/projects/released' do
107
+ begin
108
+ if params[:name].nil? || params[:version].nil?
109
+ raise ArgumentError, "/projects/released received an invalid name(#{params[:name]}) or version(#{params[:version]})"
110
+ end
111
+
112
+ name = params[:name]
113
+ version = params[:version]
114
+ project = Project.find(:first, :conditions => ["name = ?", name])
115
+ if project.nil?
116
+ raise ArgumentError, "/projects/released could not find project from name #{name}"
117
+ end
77
118
 
78
- source = Source.find(:first, :conditions => ["uri = ?", source_uri])
79
- gem = source.gems.all.find { |gem| gem.name == name }
80
- events = gem.events.all.find_all { |event| event.applies_to_version?(version) }
81
- events.each { |event| event.run }
119
+ # process project
120
+ project.released_version(version, params)
121
+ @result = {:success => true, :message => "successfully released project #{project.name}", :errors => []}
82
122
 
83
- redirect '/gems'
123
+ rescue Exception => e
124
+ @result = {:success => false, :message => "failed to release project due to error #{e}", :errors => [e]}
125
+ end
126
+
127
+ haml :"result", :layout => false
84
128
  end
85
129
 
86
130
  ##################################################################### Sources
87
131
 
132
+ get '/sources.html' do
133
+ @sources = Source.find :all
134
+ @projects = Project.find :all
135
+ haml :"sources/index.html"
136
+ end
137
+
88
138
  get '/sources' do
89
139
  @sources = Source.find :all
90
- haml :"sources/index"
140
+ haml :"sources/index", :layout => false
91
141
  end
92
142
 
93
143
  post '/sources/create' do
94
- @source = Source.new :name => params[:name], :uri => params[:uri]
95
- @source.save!
96
- redirect '/sources'
144
+ begin
145
+ if params[:uri].nil? || params[:name].nil? || params[:source_type].nil?
146
+ raise ArgumentError, "/sources/create received an invalid uri(#{params[:uri]}), name(#{params[:name]}) or source_type(#{params[:source_type]})"
147
+ end
148
+
149
+ @source = Source.new(:uri => params[:uri], :name => params['name'], :source_type => params[:source_type])
150
+ @source.save!
151
+
152
+ @result = {:success => true, :message => "successfully created source #{@source.uri}", :errors => []}
153
+
154
+ rescue Exception => e
155
+ @result = {:success => false, :message => "failed to create source due to error #{e}", :errors => [e]}
156
+ @source.errors.each_full { |e| @result[:errors] << e } unless @source.nil?
157
+ end
158
+
159
+ haml :"result", :layout => false
160
+ end
161
+
162
+ delete '/sources/destroy/:id' do
163
+ begin
164
+ if params[:id].nil?
165
+ raise ArgumentError, "/sources/destroy/:id received an invalid id(#{params[:id]})"
166
+ end
167
+
168
+ source = Source.find(params[:id])
169
+ if source.nil?
170
+ raise ArgumentError, "/sources/destroy/#{params[:id]} could not find source"
171
+ end
172
+
173
+ source_uri = source.uri
174
+ Source.delete params[:id]
175
+
176
+ @result = {:success => true, :message => "successfully deleted source #{source_uri}", :errors => []}
177
+
178
+ rescue Exception => e
179
+ @result = {:success => false, :message => "failed to delete source due to error #{e}", :errors => [e]}
180
+ end
181
+
182
+ haml :"result", :layout => false
183
+ end
184
+
185
+ post '/sources/released' do
186
+ begin
187
+ if params[:name].nil? || params[:version].nil?
188
+ raise ArgumentError, "/sources/released received an invalid name(#{params[:name]}) or version(#{params[:version]})"
189
+ end
190
+
191
+ name = params[:name]
192
+ version = params[:version]
193
+ # we also have gem_uri for gem sources
194
+
195
+ source = Source.find(:first, :conditions => ["name = ?", name])
196
+ if source.nil?
197
+ raise ArgumentError, "/sources/released could not find source from name #{name}"
198
+ end
199
+
200
+ # find projects which include this source
201
+ source.project_source_versions_for_version(version).each { |ps|
202
+ # if we can't determine project version, use source version
203
+ project_version = ps.project_version.nil? ? version : ps.project_version
204
+
205
+ # invoke a release on the project
206
+ ps.project.released_version(version, params)
207
+ }
208
+
209
+ @result = {:success => true, :message => "successfully released source #{name}", :errors => []}
210
+
211
+ rescue Exception => e
212
+ @result = {:success => false, :message => "failed to release source due to error #{e}", :errors => [e]}
213
+ end
214
+
215
+ haml :"result", :layout => false
216
+ end
217
+
218
+ ##################################################################### ProjectSourceVersions
219
+
220
+ post '/project_source_versions/create' do
221
+ begin
222
+ if params[:project_id].nil? || params[:source_id].nil?
223
+ raise ArgumentError, "/project_source_versions/create received an invalid project_id(#{params[:project_id]}) or source_id(#{params[:source_id]})"
224
+ end
225
+
226
+ project = Project.find(params[:project_id])
227
+ source = Source.find(params[:source_id])
228
+ if project.nil? || source.nil?
229
+ raise ArgumentError, "/project_source_versions/create could not find project or source from ids"
230
+ end
231
+
232
+ ps = ProjectSourceVersion.new :project => project, :source => source,
233
+ :project_version => params[:project_version],
234
+ :source_version => params[:source_version],
235
+ :source_uri_params => params[:source_uri_params],
236
+ :primary_source => params[:primary_source]
237
+
238
+ ps.save!
239
+ @result = {:success => true, :message => "successfully created project source", :errors => []}
240
+
241
+ rescue Exception => e
242
+ @result = {:success => false, :message => "failed to create project source due to error #{e}", :errors => [e]}
243
+ end
244
+
245
+ haml :"result", :layout => false
246
+ end
247
+
248
+ delete '/project_source_versions/destroy/:id' do
249
+ begin
250
+ if params[:id].nil?
251
+ raise ArgumentError, "/project_source_versions/destroy/:id received an invalid id(#{params[:id]})"
252
+ end
253
+
254
+ ps = ProjectSourceVersion.find(params[:id])
255
+ if ps.nil?
256
+ raise ArgumentError, "/project_source_versions/destroy/#{params[:id]} could not find project source"
257
+ end
258
+
259
+ ProjectSourceVersion.delete params[:id]
260
+ @result = {:success => true, :message => "successfully deleted project source", :errors => []}
261
+
262
+ rescue Exception => e
263
+ @result = {:success => false, :message => "failed to delete project source due to error #{e}", :errors => [e]}
264
+ end
265
+
266
+ haml :"result", :layout => false
267
+ end
268
+
269
+ ##################################################################### ProjectDependencies
270
+
271
+ post '/project_dependencies/create' do
272
+ begin
273
+ if params[:project_id].nil? || params[:depends_on_project_id].nil?
274
+ raise ArgumentError, "/project_dependencies/create received an invalid project_id(#{params[:project_id]}) or depends_on_project_id(#{params[:depends_on_project_id]})"
275
+ end
276
+
277
+ project = Project.find(params[:project_id])
278
+ depends_on = Project.find(params[:depends_on_project_id])
279
+ if project.nil? || depends_on.nil?
280
+ raise ArgumentError, "/project_dependencies/create could not find projects w/ specified ids(#{params[:project_id]}/#{params[:depends_on_project_id]})"
281
+ end
282
+
283
+ project_version = (params[:project_version] != '*' ? params[:project_version] : nil)
284
+ depends_on_version = (params[:depends_on_project_version] != '*' ? params[:depends_on_project_version]: nil)
285
+ @pd = ProjectDependency.new :project => project, :depends_on_project => depends_on,
286
+ :project_version => project_version, :depends_on_project_version => depends_on_version,
287
+ :depends_on_project_params => params[:depends_on_project_params]
288
+ @pd.save!
289
+
290
+ @result = {:success => true, :message => "successfully created project dependency", :errors => []}
291
+
292
+ rescue Exception => e
293
+ @result = {:success => false, :message => "failed to created project dependency due to error #{e}", :errors => [e]}
294
+ @pd.errors.each_full { |e| @result[:errors] << e } unless @event.nil?
295
+ end
296
+
297
+ haml :"result", :layout => false
97
298
  end
98
299
 
99
- delete '/sources/destroy/:id' do
100
- Source.delete params[:id]
101
- redirect '/sources'
300
+ delete '/project_dependencies/destroy/:id' do
301
+ begin
302
+ if params[:id].nil?
303
+ raise ArgumentError, "/project_dependencies/destroy/:id received an invalid id(#{params[:id]})"
304
+ end
305
+
306
+ pd = ProjectDependency.find(params[:id])
307
+ if pd.nil?
308
+ raise ArgumentError, "/project_dependencies/destroy/#{params[:id]} could not find project dependency"
309
+ end
310
+
311
+ ProjectDependency.delete params[:id]
312
+ @result = {:success => true, :message => "successfully deleted project dependency", :errors => []}
313
+
314
+ rescue Exception => e
315
+ @result = {:success => false, :message => "failed to delete project dependency due to error #{e}", :errors => [e]}
316
+ end
317
+
318
+ haml :"result", :layout => false
102
319
  end
103
320
 
104
321
  ##################################################################### Events
105
322
 
106
323
  post '/events/create' do
107
- version = (params[:gem_version] != '*' ? params[:gem_version] : '')
108
- @event = Event.new :managed_gem_id => ManagedGem.find(params[:managed_gem_id]),
109
- :process => params[:process],
110
- :gem_version => version,
111
- :version_qualifier => params[:version_qualifier],
112
- :process_options => params[:process_options]
113
- @event.save!
114
- redirect '/gems'
115
- end
116
-
117
- delete '/events/destroy/:id' do
118
- Event.delete params[:id]
119
- redirect '/gems'
324
+ begin
325
+ if params[:project_id].nil? || params[:process].nil?
326
+ raise ArgumentError, "/events/create received an invalid project_id(#{params[:project_id]}) or process(#{params[:process]})"
327
+ end
328
+
329
+ project = Project.find(params[:project_id])
330
+ if project.nil?
331
+ raise ArgumentError, "/events/create could not find project w/ specified id(#{params[:project_id]})"
332
+ end
333
+
334
+ version = (params[:version] != '*' ? params[:version] : nil)
335
+ version_qualifier = (params[:version_qualifier] != '' ? params[:version_qualifier] : nil)
336
+ @event = Event.new :project => project,
337
+ :version => version,
338
+ :version_qualifier => version_qualifier,
339
+ :process => params[:process],
340
+ :process_options => params[:process_options]
341
+ @event.save!
342
+
343
+ @result = {:success => true, :message => "successfully created event", :errors => []}
344
+
345
+ rescue Exception => e
346
+ @result = {:success => false, :message => "failed to created event due to error #{e}", :errors => [e]}
347
+ @event.errors.each_full { |e| @result[:errors] << e } unless @event.nil?
348
+ end
349
+
350
+ haml :"result", :layout => false
351
+ end
352
+
353
+ delete '/events/destroy/:id' do
354
+ begin
355
+ if params[:id].nil?
356
+ raise ArgumentError, "/events/destroy/:id received an invalid id(#{params[:id]})"
357
+ end
358
+
359
+ event = Event.find(params[:id])
360
+ if event.nil?
361
+ raise ArgumentError, "/events/destroy/#{params[:id]} could not find event"
362
+ end
363
+
364
+ Event.delete params[:id]
365
+ @result = {:success => true, :message => "successfully deleted event", :errors => []}
366
+
367
+ rescue Exception => e
368
+ @result = {:success => false, :message => "failed to delete event due to error #{e}", :errors => [e]}
369
+ end
370
+
371
+ haml :"result", :layout => false
120
372
  end