polisher 0.3 → 0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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