damagecontrol 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/README +75 -0
  2. data/README.license +5 -0
  3. data/Rakefile +111 -0
  4. data/app/controllers/admin_controller.rb +10 -0
  5. data/app/controllers/application.rb +163 -0
  6. data/app/controllers/files_controller.rb +19 -0
  7. data/app/controllers/project_controller.rb +284 -0
  8. data/app/controllers/scm_controller.rb +49 -0
  9. data/app/helpers/admin_helper.rb +2 -0
  10. data/app/helpers/application_helper.rb +3 -0
  11. data/app/helpers/project_helper.rb +2 -0
  12. data/app/views/dhtml_sites.txt +6 -0
  13. data/app/views/files/list.rhtml +4 -0
  14. data/app/views/layouts/rscm.rhtml +79 -0
  15. data/app/views/project/_bugzilla.rhtml +13 -0
  16. data/app/views/project/_changesets_list.rhtml +52 -0
  17. data/app/views/project/_cvs.rhtml +171 -0
  18. data/app/views/project/_jira.rhtml +19 -0
  19. data/app/views/project/_mooky.rhtml +23 -0
  20. data/app/views/project/_null.rhtml +0 -0
  21. data/app/views/project/_project.rhtml +36 -0
  22. data/app/views/project/_rubyforge.rhtml +19 -0
  23. data/app/views/project/_scarab.rhtml +19 -0
  24. data/app/views/project/_scms.rhtml +15 -0
  25. data/app/views/project/_sourceforge.rhtml +19 -0
  26. data/app/views/project/_starteam.rhtml +43 -0
  27. data/app/views/project/_svn.rhtml +22 -0
  28. data/app/views/project/_trac.rhtml +13 -0
  29. data/app/views/project/_trackers.rhtml +18 -0
  30. data/app/views/project/changesets.rhtml +31 -0
  31. data/app/views/project/index.rhtml +23 -0
  32. data/app/views/project/view.rhtml +70 -0
  33. data/app/views/scm/checkout_status.rhtml +44 -0
  34. data/app/views/scm/diff.rhtml +1 -0
  35. data/app/views/scm/scroll.html +27 -0
  36. data/bin/damagecontrol +7 -0
  37. data/bin/damagecontrol-webrick +2 -0
  38. data/config/database.yml +20 -0
  39. data/config/environment.rb +60 -0
  40. data/config/environments/development.rb +3 -0
  41. data/config/environments/production.rb +2 -0
  42. data/config/environments/test.rb +3 -0
  43. data/lib/damagecontrol/app.rb +74 -0
  44. data/lib/damagecontrol/build.rb +104 -0
  45. data/lib/damagecontrol/diff_htmlizer.rb +82 -0
  46. data/lib/damagecontrol/diff_parser.rb +153 -0
  47. data/lib/damagecontrol/directories.rb +126 -0
  48. data/lib/damagecontrol/poller.rb +72 -0
  49. data/lib/damagecontrol/project.rb +213 -0
  50. data/lib/damagecontrol/project_dependencies.rb +8 -0
  51. data/lib/damagecontrol/scm_web.rb +50 -0
  52. data/lib/damagecontrol/standard_persister.rb +49 -0
  53. data/lib/damagecontrol/tracker.rb +164 -0
  54. data/lib/damagecontrol/visitor/build_executor.rb +32 -0
  55. data/lib/damagecontrol/visitor/diff_persister.rb +41 -0
  56. data/lib/damagecontrol/visitor/rss_writer.rb +43 -0
  57. data/lib/damagecontrol/visitor/yaml_persister.rb +71 -0
  58. data/public/404.html +6 -0
  59. data/public/500.html +6 -0
  60. data/public/dispatch.cgi +10 -0
  61. data/public/dispatch.fcgi +7 -0
  62. data/public/dispatch.rb +10 -0
  63. data/public/images/16x16/about.png +0 -0
  64. data/public/images/16x16/bug_green.png +0 -0
  65. data/public/images/16x16/bug_red.png +0 -0
  66. data/public/images/16x16/bug_yellow.png +0 -0
  67. data/public/images/16x16/component.png +0 -0
  68. data/public/images/16x16/console.png +0 -0
  69. data/public/images/16x16/console_error.png +0 -0
  70. data/public/images/16x16/document_add.png +0 -0
  71. data/public/images/16x16/document_delete.png +0 -0
  72. data/public/images/16x16/document_edit.png +0 -0
  73. data/public/images/16x16/document_exchange.png +0 -0
  74. data/public/images/16x16/document_new.png +0 -0
  75. data/public/images/16x16/document_warning.png +0 -0
  76. data/public/images/16x16/safe.png +0 -0
  77. data/public/images/16x16/scroll_information.png +0 -0
  78. data/public/images/16x16/wrench.png +0 -0
  79. data/public/images/24x24/box_delete.png +0 -0
  80. data/public/images/24x24/box_into.png +0 -0
  81. data/public/images/24x24/box_new.png +0 -0
  82. data/public/images/24x24/console_network.png +0 -0
  83. data/public/images/24x24/document_edit.png +0 -0
  84. data/public/images/24x24/find.png +0 -0
  85. data/public/images/24x24/folders.png +0 -0
  86. data/public/images/24x24/garbage.png +0 -0
  87. data/public/images/24x24/gear_connection.png +0 -0
  88. data/public/images/24x24/gear_delete.png +0 -0
  89. data/public/images/24x24/gears_run.png +0 -0
  90. data/public/images/24x24/home.png +0 -0
  91. data/public/images/24x24/navigate_left.png +0 -0
  92. data/public/images/24x24/navigate_right.png +0 -0
  93. data/public/images/24x24/package_new.png +0 -0
  94. data/public/images/24x24/safe.png +0 -0
  95. data/public/images/24x24/safe_new.png +0 -0
  96. data/public/images/24x24/safe_out.png +0 -0
  97. data/public/images/24x24/scroll_information.png +0 -0
  98. data/public/images/24x24/stop.png +0 -0
  99. data/public/images/24x24/wrench.png +0 -0
  100. data/public/images/README.license +2 -0
  101. data/public/images/blue-16.gif +0 -0
  102. data/public/images/blue-32.gif +0 -0
  103. data/public/images/bugzilla.png +0 -0
  104. data/public/images/cvs.png +0 -0
  105. data/public/images/footer.gif +0 -0
  106. data/public/images/green-128.gif +0 -0
  107. data/public/images/green-16.gif +0 -0
  108. data/public/images/green-32.gif +0 -0
  109. data/public/images/grey-16.gif +0 -0
  110. data/public/images/grey-32.gif +0 -0
  111. data/public/images/jira.gif +0 -0
  112. data/public/images/red-16.gif +0 -0
  113. data/public/images/red-32.gif +0 -0
  114. data/public/images/red-pulse-32.gif +0 -0
  115. data/public/images/rss.gif +0 -0
  116. data/public/images/rubyforge.png +0 -0
  117. data/public/images/scarab.gif +0 -0
  118. data/public/images/sourceforge.gif +0 -0
  119. data/public/images/starteam.png +0 -0
  120. data/public/images/svnlogo64.png +0 -0
  121. data/public/images/trac.png +0 -0
  122. data/public/index.html +1 -0
  123. data/public/javascripts/dw_event.js +34 -0
  124. data/public/javascripts/dw_tooltip.js +86 -0
  125. data/public/javascripts/dw_viewport.js +55 -0
  126. data/public/javascripts/pngfix.js +29 -0
  127. data/public/javascripts/toggle_diff.js +25 -0
  128. data/public/licenses/DAMAGECONTROL.license +28 -0
  129. data/public/licenses/INCORS.license +32 -0
  130. data/public/stylesheets/diff.css +23 -0
  131. data/public/stylesheets/style.css +307 -0
  132. data/script/breakpointer +5 -0
  133. data/script/console +30 -0
  134. data/script/generate +70 -0
  135. data/script/server +61 -0
  136. data/test/damagecontrol/a_program.rb +3 -0
  137. data/test/damagecontrol/a_slow_program.rb +3 -0
  138. data/test/damagecontrol/build_test.rb +59 -0
  139. data/test/damagecontrol/diff_htmlizer_test.rb +31 -0
  140. data/test/damagecontrol/diff_parser_test.rb +61 -0
  141. data/test/damagecontrol/file_ext.rb +12 -0
  142. data/test/damagecontrol/poller_test.rb +56 -0
  143. data/test/damagecontrol/project_test.rb +144 -0
  144. data/test/damagecontrol/scm_web_test.rb +22 -0
  145. data/test/damagecontrol/test.diff +38 -0
  146. data/test/damagecontrol/test.html +40 -0
  147. data/test/damagecontrol/tracker_test.rb +48 -0
  148. data/test/damagecontrol/visitor/changesets.rss +34 -0
  149. data/test/damagecontrol/visitor/diff_persister_test.rb +49 -0
  150. data/test/damagecontrol/visitor/rss_writer_test.rb +40 -0
  151. data/test/damagecontrol/visitor/yaml_persister_test.rb +40 -0
  152. data/test/functional/admin_controller_test.rb +17 -0
  153. data/test/functional/project_controller_test.rb +17 -0
  154. data/test/test_helper.rb +14 -0
  155. metadata +245 -0
data/README ADDED
@@ -0,0 +1,75 @@
1
+ = DamageControl - a cross platform continuous integration server.
2
+
3
+ = Feature overview
4
+
5
+ * Supports all SCMs supported by RSCM.
6
+ * Web interface based on RoR (http://www.rubyonrails.org/)
7
+ * Colourised HTML diffs.
8
+ * RSS feeds for changesets and builds.
9
+ * Generation of URL links to diffs for several popular SCM web front-ends.
10
+ * Generation of URL links to bugs/issues for several popular bug/issue trackers.
11
+ * Uses UTC times according to the SCM server's clock, not the machine running RSCM. No NTP needed!
12
+
13
+ == DamageControl Server
14
+
15
+ DamageControl ships with a web app based on Ruby On Rails (which you currently have to install separately). To launch:
16
+
17
+ ruby script/server
18
+
19
+ You also need to launch (in a separate console) the DamageControl daemon process:
20
+
21
+ ruby -Ilib lib/damagecontrol/server.rb
22
+
23
+ The daemon process is the core of DamageContriol that performs SCM access and executes builds. The web app communicates with this process over Drb to display results.
24
+
25
+ The reason why two processes are needed is due to the fact that Dir.chdir may happen in various threads,
26
+ which would confuse the webapp if they ran in the same Ruby process. We tried with forking, but this is not
27
+ supported on Windows. We may support a fork-based one-process alternative for Linux/Cygwin in the future.
28
+
29
+ Once the two servers are started, you can access the web app on:
30
+
31
+ http://localhost:4712/
32
+
33
+ == Colourised HTML diffs
34
+
35
+ The web interface will present changesets as colourised diffs. Even for SCMs you never thought would support
36
+ that kind of feature. (As long as there is an RSCM plugin for it).
37
+
38
+ == RSS Support
39
+
40
+ The DamageControl daemon can generate RSS feeds for all supported SCMs. The RSS feeds will have one item per changeset.
41
+ Each RSS item's description contains the changeset's commit message, optionally with HTML links to
42
+ issue/bug tracker issues (if detected in the changeset's commit message). The item's description
43
+ will also contain a list of all the modified files, optionally with HTML links to a diff page
44
+ in an SCM web front-end.
45
+
46
+ == Supported Issue trackers
47
+
48
+ DamageControl can recognise bug/issue numbers (in commit messages) for a number of popular issue
49
+ tracking systems. It converts the SCM commit message to HTML with links to the issues mentioned in the commit message.
50
+
51
+ * Bugzilla - http://www.bugzilla.org/
52
+ * JIRA - http://www.atlassian.com/software/jira/
53
+ * RubyForge - http://rubyforge.org/
54
+ * Scarab - http://scarab.tigris.org/
55
+ * SourceForge - http://sourceforge.net/
56
+ * Trac - http://www.edgewall.com/trac/
57
+
58
+ Planned:
59
+
60
+ * RT - http://fsck.com/projects/rt/
61
+
62
+ == SCM web front-ends - diffs
63
+
64
+ DamageControl's web interface features colourised diffs for all changes in a changeset.
65
+ It can also generate links to individual diff pages in other SCM web frontends:
66
+
67
+ * RSCM Built-in HTML diffs.
68
+ * Fisheye - http://www.cenqua.com/fisheye/
69
+ * ViewCVS - http://viewcvs.sourceforge.net/
70
+
71
+ Planned:
72
+
73
+ * Trac - http://www.edgewall.com/trac/
74
+ * Chora - http://horde.org/chora/
75
+
data/README.license ADDED
@@ -0,0 +1,5 @@
1
+ This software consists of parts that are covered by different licenses.
2
+ See the following locations for details:
3
+
4
+ * public/licenses directories.
5
+ * public/images/README.license
data/Rakefile ADDED
@@ -0,0 +1,111 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+
9
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
+ PKG_NAME = 'damagecontrol'
11
+ PKG_VERSION = '0.5.0' + PKG_BUILD
12
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
+
14
+ desc "Default Task"
15
+ task :default => [ :all ]
16
+
17
+ # Run the unit tests
18
+ # To run a specific test: rake test TEST=path/to/test
19
+ fl = FileList.new('test/**/*_test.rb')
20
+ # TODO: figure out how to add all the stuff in app.
21
+ Rake::TestTask.new { |t|
22
+ # We need some of the test utils from rscm
23
+ t.libs << "test" << File.expand_path(File.dirname(__FILE__) + "/../rscm/test") << File.expand_path(File.dirname(__FILE__) + "/../rscm/lib")
24
+ t.test_files = fl
25
+ t.verbose = true
26
+ }
27
+
28
+ rd = Rake::RDocTask.new { |rdoc|
29
+ rdoc.rdoc_dir = 'doc'
30
+ rdoc.title = 'DamageControl - Cross platform Continuous Integration server'
31
+ rdoc.options << '--line-numbers' << '--inline-source'
32
+ rdoc.rdoc_files.include('README')
33
+ rdoc.rdoc_files.include('lib/**/*.rb')
34
+ rdoc.rdoc_files.include('docs/**/*.rd')
35
+ }
36
+
37
+ task :all => [:gem]
38
+
39
+ PKG_FILES = FileList[
40
+ '[A-Z]*',
41
+ 'doc/**/*',
42
+ 'bin/**/*',
43
+ 'app/**/*',
44
+ 'config/**/*',
45
+ 'docs/**/*',
46
+ 'lib/**/*',
47
+ 'public/**/*',
48
+ 'script/**/*',
49
+ 'test/**/*'
50
+ ]
51
+
52
+ if ! defined?(Gem)
53
+ puts "Package Target requires RubyGEMs"
54
+ else
55
+ spec = Gem::Specification.new do |s|
56
+
57
+ #### Basic information.
58
+
59
+ s.name = 'damagecontrol'
60
+ s.version = PKG_VERSION
61
+ s.summary = "DamageControl"
62
+ s.description = <<-EOF
63
+ DamageControl.
64
+ EOF
65
+
66
+ #### Dependencies and requirements.
67
+
68
+ s.add_dependency('log4r', '> 1.0.4')
69
+ s.add_dependency('rscm')
70
+ s.add_dependency('needle')
71
+ # s.add_dependency('rgl')
72
+ #s.requirements << ""
73
+
74
+ #### Which files are to be included in this gem? Everything! (Except CVS directories.)
75
+
76
+ s.files = PKG_FILES.to_a
77
+
78
+ #### C code extensions.
79
+
80
+ #s.extensions << "ext/rmagic/extconf.rb"
81
+
82
+ #### Load-time details: library and application (you will need one or both).
83
+
84
+ s.require_path = 'lib' # Use these for libraries.
85
+ s.autorequire = 'damagecontrol/app'
86
+
87
+ s.bindir = "bin" # Use these for applications.
88
+ s.executables = ["damagecontrol", "damagecontrol-webrick"]
89
+ s.default_executable = "damagecontrol"
90
+
91
+ #### Documentation and testing.
92
+
93
+ s.has_rdoc = true
94
+ s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
95
+ rd.options.each do |op|
96
+ s.rdoc_options << op
97
+ end
98
+
99
+ #### Author and project details.
100
+
101
+ s.author = "Aslak Hellesoy"
102
+ s.email = "dev@damagecontrol.codehaus.org"
103
+ s.homepage = "http://damagecontrol.codehaus.org/"
104
+ # s.rubyforge_project = "rscm"
105
+ end
106
+
107
+ Rake::GemPackageTask.new(spec) do |pkg|
108
+ pkg.need_zip = true
109
+ pkg.need_tar = true
110
+ end
111
+ end
@@ -0,0 +1,10 @@
1
+ #require 'rscm'
2
+ #require 'rscm/tracker'
3
+
4
+ class AdminController < ApplicationController
5
+
6
+ def new_project
7
+ redirect_to(:controller => "project", :action => "view")
8
+ end
9
+
10
+ end
@@ -0,0 +1,163 @@
1
+ # The filters added to this controller will be run for all controllers in the application.
2
+ # Likewise will all the methods added be available for all controllers.
3
+
4
+ require 'rubygems'
5
+ require_gem 'rscm'
6
+ require 'damagecontrol/project'
7
+ require 'damagecontrol/build'
8
+ require 'damagecontrol/tracker'
9
+ require 'damagecontrol/scm_web'
10
+
11
+ # Start Drb - this is how we communicate with the daemon.
12
+ DRb.start_service()
13
+ Rscm = DRbObject.new(nil, 'druby://localhost:9000')
14
+
15
+ class ApplicationController < ActionController::Base
16
+
17
+ layout 'rscm'
18
+
19
+ def initialize
20
+ @sidebar_links = [
21
+ {
22
+ :controller => "project",
23
+ :action => "new",
24
+ :image => "/images/24x24/box_new.png",
25
+ :name => "New project"
26
+ }
27
+ ]
28
+ @controller = self
29
+ end
30
+
31
+ # Loads the project specified by the +id+ parameter and places it into the @project variable
32
+ def load_project
33
+ project_name = @params["id"]
34
+ @project = DamageControl::Project.load(project_name)
35
+ end
36
+
37
+ def breadcrumbs
38
+ subpaths = @request.path.split(/\//)
39
+ # subpaths.collect { |p| link_to_unless_current(p) }.links.join(" ")
40
+ end
41
+
42
+ protected
43
+
44
+ # Sets the links to display in the sidebar. Override this method in other controllers
45
+ # To change what to display.
46
+ def set_sidebar_links
47
+
48
+ end
49
+
50
+ end
51
+
52
+ module ActionView
53
+ module Helpers
54
+ module UrlHelper
55
+ # Modify the original behaviour of +link_to+ so that the link
56
+ # includes the client's timezone as URL param +timezone+ in the request.
57
+ # Can be used by server to adjust formatting of UTC dates so they match the client's time zone.
58
+ def convert_confirm_option_to_javascript!(html_options)
59
+ # We're adding this JS call to add the timezone info as a URL param.
60
+ html_options["onclick"] = "intercept(this);"
61
+ if html_options.include?(:confirm)
62
+ html_options["onclick"] += "return confirm('#{html_options[:confirm]}');"
63
+ html_options.delete(:confirm)
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ class Base
70
+ def text_or_input(input, options)
71
+ if(input)
72
+ options[:class] = "setting-input" unless options[:class]
73
+ tag("input", options)
74
+ elsif(options[:value] =~ /^http?:\/\//)
75
+ content_tag("a", options[:value], "href" => options[:value])
76
+ else
77
+ options[:value]
78
+ end
79
+ end
80
+
81
+ def text_or_select(input, options)
82
+ values = options.delete(:values)
83
+ if(input)
84
+ options[:class] = "setting-input" unless options[:class]
85
+
86
+ option_tags = ""
87
+ values.each do |value|
88
+ option_attrs = {:value => value.class.name}
89
+ option_attrs[:selected] = "true" if value.selected?
90
+ option_tag = content_tag("option", value.name, option_attrs)
91
+ option_tags << option_tag
92
+ end
93
+ content_tag("select", option_tags, options)
94
+ else
95
+ values.find {|v| v.selected?}.name
96
+ end
97
+ end
98
+
99
+ # Creates an image with a tooltip that will show on mouseover.
100
+ #
101
+ # Options:
102
+ # * <tt>:txt</tt> - The text to put in the tooltip. Can be HTML.
103
+ # * <tt>:img</tt> - The image to display on the page. Defaults to '/images/16x16/about.png'
104
+ def tip(options)
105
+ tip = options.delete(:txt)
106
+ options[:src] = options.delete(:img) || "/images/16x16/about.png"
107
+ options[:onmouseover] = "Tooltip.show(event,#{tip})"
108
+ options[:onmouseout] = "Tooltip.hide()"
109
+
110
+ tag("img", options)
111
+ end
112
+ end
113
+ end
114
+
115
+ module DamageControl
116
+
117
+ # Add some generic web capabilities to the RSCM classes
118
+ module Web
119
+ module Configuration
120
+
121
+ def selected?
122
+ false
123
+ end
124
+
125
+ # Returns the short lowercase name. Used for javascript and render_partial.
126
+ def short
127
+ $1.downcase if self.class.name =~ /.*::(.*)/
128
+ end
129
+
130
+ end
131
+ end
132
+ end
133
+
134
+ class RSCM::AbstractSCM
135
+ include DamageControl::Web::Configuration
136
+ end
137
+
138
+ class DamageControl::Tracker::Base
139
+ include DamageControl::Web::Configuration
140
+ end
141
+
142
+ class DamageControl::Project
143
+ include DamageControl::Web::Configuration
144
+ end
145
+
146
+ class DamageControl::Build
147
+ def small_image
148
+ exit_code == 0 ? "/images/green-16.gif" : "/images/red-16.gif"
149
+ end
150
+ end
151
+
152
+ class RSCM::Change
153
+ ICONS = {
154
+ MODIFIED => "/images/16x16/document_edit.png",
155
+ DELETED => "/images/16x16/document_delete.png",
156
+ ADDED => "/images/16x16/document_add.png",
157
+ MOVED => "/images/16x16/document_exchange.png",
158
+ }
159
+
160
+ def icon
161
+ ICONS[@status] || "/images/16x16/document_warning.png"
162
+ end
163
+ end
@@ -0,0 +1,19 @@
1
+ require 'rscm/directories'
2
+
3
+ class FilesController < ApplicationController
4
+
5
+ def list
6
+ load_project
7
+
8
+ root = @project.checkout_dir
9
+ relative_path = @params['path']
10
+ absolute_path = relative_path ? "#{root}/#{relative_path}" : root
11
+ if(File.file?(absolute_path))
12
+ # TODO: use http://rubyforge.org/projects/syntax/
13
+ # TODO: the file contents should be rendered within the regular layout
14
+ render_text(File.open(absolute_path).read)
15
+ else
16
+ @relative_paths = Dir["#{absolute_path}/*"].collect {|f| f[root.length+1..-1]}
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,284 @@
1
+ require 'rscm'
2
+ require 'damagecontrol/project'
3
+ require 'damagecontrol/directories'
4
+ require 'damagecontrol/diff_parser'
5
+ require 'damagecontrol/diff_htmlizer'
6
+
7
+ class ProjectController < ApplicationController
8
+
9
+ # TODO: check if the various SCMs are installed and disable them with a warning if not.
10
+ # Each SCM class should have an available? method
11
+
12
+ SCMS = [
13
+ # Uncomment this to see Mooky in action in the web interface!
14
+ # RSCM::Mooky,
15
+ RSCM::CVS,
16
+ RSCM::SVN,
17
+ RSCM::StarTeam
18
+ ]
19
+
20
+ TRACKERS = [
21
+ DamageControl::Tracker::Null,
22
+ DamageControl::Tracker::Bugzilla,
23
+ DamageControl::Tracker::JIRA,
24
+ DamageControl::Tracker::RubyForge,
25
+ DamageControl::Tracker::SourceForge,
26
+ DamageControl::Tracker::Scarab,
27
+ DamageControl::Tracker::Trac
28
+ ]
29
+
30
+ SCM_WEBS = [
31
+ # SCMWeb::Null.new,
32
+ # SCMWeb::ViewCVS.new,
33
+ # SCMWeb::Fisheye.new
34
+ ]
35
+
36
+ def initialize
37
+ super
38
+ @navigation_name = "changesets_list"
39
+ end
40
+
41
+ def index
42
+ @projects = DamageControl::Project.find_all
43
+ @navigation_name = "null"
44
+ end
45
+
46
+ def new
47
+ @project = DamageControl::Project.new
48
+ @scms = SCMS.collect {|o| o.new}
49
+ first_scm = @scms[0]
50
+ def first_scm.selected?
51
+ true
52
+ end
53
+ @trackers = TRACKERS.collect {|o| o.new}
54
+ first_tracker = @trackers[0]
55
+ def first_tracker.selected?
56
+ true
57
+ end
58
+ @edit = true
59
+ @new_project = true
60
+ render_action("view")
61
+ end
62
+
63
+ def view
64
+ return render_text("No project specified") unless @params["id"]
65
+ @edit = false
66
+ load
67
+ end
68
+
69
+ def edit
70
+ @edit = true
71
+ load
72
+ render_action("view")
73
+ end
74
+
75
+ def changesets_rss
76
+ load
77
+ send_file(@project.changesets_rss_file)
78
+ end
79
+
80
+ def delete
81
+ load_project
82
+ begin
83
+ Rscm.delete_project(project)
84
+ rescue => e
85
+ return render_text("Couldn't connect to RSCM server. Please make sure it's running.<br>" + e.message)
86
+ end
87
+ index
88
+ end
89
+
90
+ def save
91
+ project = instantiate_from_params("project")
92
+ project.scm = instantiate_from_params("scm")
93
+ project.tracker = instantiate_from_params("tracker")
94
+
95
+ begin
96
+ Rscm.save_project(project)
97
+ rescue => e
98
+ $stderr.puts(e.backtrace.join("\n"))
99
+ return render_text("Couldn't connect to RSCM server. Please make sure it's running.<br>" + e.message)
100
+ end
101
+
102
+ redirect_to(:action => "view", :id => project.name)
103
+ end
104
+
105
+ def changesets
106
+ load
107
+ last_changeset_identifier = @params["changeset"]
108
+ @changesets = @project.changesets(last_changeset_identifier.to_identifier, 1)
109
+ @changesets.accept(HtmlDiffVisitor.new(@project))
110
+ end
111
+
112
+ protected
113
+
114
+ # Visitor that adds a method called +html_diff+ to each change
115
+ class HtmlDiffVisitor
116
+ def initialize(project)
117
+ @project = project
118
+ end
119
+
120
+ def visit_changesets(changesets)
121
+ end
122
+
123
+ def visit_changeset(changeset)
124
+ @changeset = changeset
125
+ end
126
+
127
+ def visit_change(change)
128
+ def change.html_diff=(html)
129
+ @html = html
130
+ end
131
+
132
+ def change.html_diff
133
+ @html
134
+ end
135
+
136
+ html = ""
137
+ dp = DamageControl::DiffParser.new
138
+ diff_file = DamageControl::Directories.diff_file(@project.name, @changeset, change)
139
+ if(File.exist?(diff_file))
140
+ File.open(diff_file) do |diffs_io|
141
+ diffs = dp.parse_diffs(diffs_io)
142
+ dh = DamageControl::DiffHtmlizer.new(html)
143
+ diffs.accept(dh)
144
+ if(html == "")
145
+ html = "Diff was calculated, but was empty. (This may be a bug - new, moved and binary files and are not supported yet)."
146
+ end
147
+ end
148
+ else
149
+ html = "Diff not calculated yet."
150
+ end
151
+ change.html_diff = html
152
+ end
153
+ end
154
+
155
+ def set_sidebar_links
156
+ if(@project.exists?)
157
+ @sidebar_links << {
158
+ :controller => "project",
159
+ :action => "edit",
160
+ :id => @project.name,
161
+ :image => "/images/24x24/wrench.png",
162
+ :name => "Edit #{@project.name} settings"
163
+ }
164
+ end
165
+
166
+ # if(@project.exists?)
167
+ # @sidebar_links << {
168
+ # :controller => "project",
169
+ # :action => "delete",
170
+ # :id => @project.name,
171
+ # :image => "/images/24x24/box_delete.png",
172
+ # :name => "Delete #{@project.name} project"
173
+ # }
174
+ # end
175
+
176
+ if(@project.exists? && @project.scm && !@project.scm.exists? && @project.scm.can_create?)
177
+ @sidebar_links << {
178
+ :controller => "scm",
179
+ :action => "create",
180
+ :id => @project.name,
181
+ :image => "/images/24x24/safe_new.png",
182
+ :name => "Create #{@project.scm.name} repository"
183
+ }
184
+ end
185
+
186
+ # if(@project.exists? && !@project.checked_out?)
187
+ # @sidebar_links << {
188
+ # :controller => "scm",
189
+ # :action => "checkout",
190
+ # :id => @project.name,
191
+ # :image => "/images/24x24/safe_out.png",
192
+ # :name => "Check out from #{@project.scm.name}"
193
+ # }
194
+ # end
195
+
196
+ if(@project.exists? && @project.checked_out?)
197
+ @sidebar_links << {
198
+ :controller => "files",
199
+ :action => "list",
200
+ :id => @project.name,
201
+ :image => "/images/24x24/folders.png",
202
+ :name => "Browse working copy"
203
+ }
204
+ end
205
+
206
+ if(@project.exists? && @project.checked_out?)
207
+ @sidebar_links << {
208
+ :controller => "scm",
209
+ :action => "delete_working_copy",
210
+ :id => @project.name,
211
+ :image => "/images/24x24/garbage.png",
212
+ :name => "Delete working copy"
213
+ }
214
+ end
215
+
216
+ if(@project.exists?)
217
+ @sidebar_links << {
218
+ :href => @project.tracker.url,
219
+ :image => "/images/24x24/scroll_information.png",
220
+ :name => @project.tracker.name
221
+ }
222
+ end
223
+
224
+ if(@project.exists? && @project.home_page && @project.home_page != "")
225
+ @sidebar_links << {
226
+ :href => @project.home_page,
227
+ :image => "/images/24x24/home.png",
228
+ :name => "#{@project.name} home page"
229
+ }
230
+ end
231
+
232
+ if(@project.changesets_rss_exists?)
233
+ @sidebar_links << {
234
+ :controller => "project",
235
+ :action => "changesets_rss",
236
+ :id => @project.name,
237
+ :image => "/images/rss.gif",
238
+ :name => "Changesets RSS"
239
+ }
240
+ end
241
+
242
+ end
243
+
244
+ private
245
+
246
+ def load
247
+ load_project
248
+
249
+ scm = @project.scm
250
+ def scm.selected?
251
+ true
252
+ end
253
+
254
+ tracker = @project.tracker
255
+ def tracker.selected?
256
+ true
257
+ end
258
+
259
+ # Make a dupe of the scm/tracker lists and substitute with project's value
260
+ @scms = SCMS.collect {|o| o.new}
261
+ @scms.each_index {|i| @scms[i] = @project.scm if @scms[i].class == @project.scm.class}
262
+
263
+ @trackers = TRACKERS.collect {|o| o.new}
264
+ @trackers.each_index {|i| @trackers[i] = @project.tracker if @trackers[i].class == @project.tracker.class}
265
+
266
+ @linkable_changesets = @project.changesets(@project.latest_changeset_identifier, 10)
267
+ @select_changeset_identifiers = @project.changeset_identifiers[0..-(@linkable_changesets.length+1)]
268
+
269
+ set_sidebar_links
270
+ end
271
+
272
+ # Instantiates an object from parameters
273
+ def instantiate_from_params(param)
274
+ class_name = @params[param]
275
+ clazz = eval(class_name)
276
+ ob = clazz.new
277
+ attribs = @params[class_name] || {}
278
+ attribs.each do |k,v|
279
+ ob.send("#{k}=", v)
280
+ end
281
+ ob
282
+ end
283
+
284
+ end