damagecontrol 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +75 -0
- data/README.license +5 -0
- data/Rakefile +111 -0
- data/app/controllers/admin_controller.rb +10 -0
- data/app/controllers/application.rb +163 -0
- data/app/controllers/files_controller.rb +19 -0
- data/app/controllers/project_controller.rb +284 -0
- data/app/controllers/scm_controller.rb +49 -0
- data/app/helpers/admin_helper.rb +2 -0
- data/app/helpers/application_helper.rb +3 -0
- data/app/helpers/project_helper.rb +2 -0
- data/app/views/dhtml_sites.txt +6 -0
- data/app/views/files/list.rhtml +4 -0
- data/app/views/layouts/rscm.rhtml +79 -0
- data/app/views/project/_bugzilla.rhtml +13 -0
- data/app/views/project/_changesets_list.rhtml +52 -0
- data/app/views/project/_cvs.rhtml +171 -0
- data/app/views/project/_jira.rhtml +19 -0
- data/app/views/project/_mooky.rhtml +23 -0
- data/app/views/project/_null.rhtml +0 -0
- data/app/views/project/_project.rhtml +36 -0
- data/app/views/project/_rubyforge.rhtml +19 -0
- data/app/views/project/_scarab.rhtml +19 -0
- data/app/views/project/_scms.rhtml +15 -0
- data/app/views/project/_sourceforge.rhtml +19 -0
- data/app/views/project/_starteam.rhtml +43 -0
- data/app/views/project/_svn.rhtml +22 -0
- data/app/views/project/_trac.rhtml +13 -0
- data/app/views/project/_trackers.rhtml +18 -0
- data/app/views/project/changesets.rhtml +31 -0
- data/app/views/project/index.rhtml +23 -0
- data/app/views/project/view.rhtml +70 -0
- data/app/views/scm/checkout_status.rhtml +44 -0
- data/app/views/scm/diff.rhtml +1 -0
- data/app/views/scm/scroll.html +27 -0
- data/bin/damagecontrol +7 -0
- data/bin/damagecontrol-webrick +2 -0
- data/config/database.yml +20 -0
- data/config/environment.rb +60 -0
- data/config/environments/development.rb +3 -0
- data/config/environments/production.rb +2 -0
- data/config/environments/test.rb +3 -0
- data/lib/damagecontrol/app.rb +74 -0
- data/lib/damagecontrol/build.rb +104 -0
- data/lib/damagecontrol/diff_htmlizer.rb +82 -0
- data/lib/damagecontrol/diff_parser.rb +153 -0
- data/lib/damagecontrol/directories.rb +126 -0
- data/lib/damagecontrol/poller.rb +72 -0
- data/lib/damagecontrol/project.rb +213 -0
- data/lib/damagecontrol/project_dependencies.rb +8 -0
- data/lib/damagecontrol/scm_web.rb +50 -0
- data/lib/damagecontrol/standard_persister.rb +49 -0
- data/lib/damagecontrol/tracker.rb +164 -0
- data/lib/damagecontrol/visitor/build_executor.rb +32 -0
- data/lib/damagecontrol/visitor/diff_persister.rb +41 -0
- data/lib/damagecontrol/visitor/rss_writer.rb +43 -0
- data/lib/damagecontrol/visitor/yaml_persister.rb +71 -0
- data/public/404.html +6 -0
- data/public/500.html +6 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +7 -0
- data/public/dispatch.rb +10 -0
- data/public/images/16x16/about.png +0 -0
- data/public/images/16x16/bug_green.png +0 -0
- data/public/images/16x16/bug_red.png +0 -0
- data/public/images/16x16/bug_yellow.png +0 -0
- data/public/images/16x16/component.png +0 -0
- data/public/images/16x16/console.png +0 -0
- data/public/images/16x16/console_error.png +0 -0
- data/public/images/16x16/document_add.png +0 -0
- data/public/images/16x16/document_delete.png +0 -0
- data/public/images/16x16/document_edit.png +0 -0
- data/public/images/16x16/document_exchange.png +0 -0
- data/public/images/16x16/document_new.png +0 -0
- data/public/images/16x16/document_warning.png +0 -0
- data/public/images/16x16/safe.png +0 -0
- data/public/images/16x16/scroll_information.png +0 -0
- data/public/images/16x16/wrench.png +0 -0
- data/public/images/24x24/box_delete.png +0 -0
- data/public/images/24x24/box_into.png +0 -0
- data/public/images/24x24/box_new.png +0 -0
- data/public/images/24x24/console_network.png +0 -0
- data/public/images/24x24/document_edit.png +0 -0
- data/public/images/24x24/find.png +0 -0
- data/public/images/24x24/folders.png +0 -0
- data/public/images/24x24/garbage.png +0 -0
- data/public/images/24x24/gear_connection.png +0 -0
- data/public/images/24x24/gear_delete.png +0 -0
- data/public/images/24x24/gears_run.png +0 -0
- data/public/images/24x24/home.png +0 -0
- data/public/images/24x24/navigate_left.png +0 -0
- data/public/images/24x24/navigate_right.png +0 -0
- data/public/images/24x24/package_new.png +0 -0
- data/public/images/24x24/safe.png +0 -0
- data/public/images/24x24/safe_new.png +0 -0
- data/public/images/24x24/safe_out.png +0 -0
- data/public/images/24x24/scroll_information.png +0 -0
- data/public/images/24x24/stop.png +0 -0
- data/public/images/24x24/wrench.png +0 -0
- data/public/images/README.license +2 -0
- data/public/images/blue-16.gif +0 -0
- data/public/images/blue-32.gif +0 -0
- data/public/images/bugzilla.png +0 -0
- data/public/images/cvs.png +0 -0
- data/public/images/footer.gif +0 -0
- data/public/images/green-128.gif +0 -0
- data/public/images/green-16.gif +0 -0
- data/public/images/green-32.gif +0 -0
- data/public/images/grey-16.gif +0 -0
- data/public/images/grey-32.gif +0 -0
- data/public/images/jira.gif +0 -0
- data/public/images/red-16.gif +0 -0
- data/public/images/red-32.gif +0 -0
- data/public/images/red-pulse-32.gif +0 -0
- data/public/images/rss.gif +0 -0
- data/public/images/rubyforge.png +0 -0
- data/public/images/scarab.gif +0 -0
- data/public/images/sourceforge.gif +0 -0
- data/public/images/starteam.png +0 -0
- data/public/images/svnlogo64.png +0 -0
- data/public/images/trac.png +0 -0
- data/public/index.html +1 -0
- data/public/javascripts/dw_event.js +34 -0
- data/public/javascripts/dw_tooltip.js +86 -0
- data/public/javascripts/dw_viewport.js +55 -0
- data/public/javascripts/pngfix.js +29 -0
- data/public/javascripts/toggle_diff.js +25 -0
- data/public/licenses/DAMAGECONTROL.license +28 -0
- data/public/licenses/INCORS.license +32 -0
- data/public/stylesheets/diff.css +23 -0
- data/public/stylesheets/style.css +307 -0
- data/script/breakpointer +5 -0
- data/script/console +30 -0
- data/script/generate +70 -0
- data/script/server +61 -0
- data/test/damagecontrol/a_program.rb +3 -0
- data/test/damagecontrol/a_slow_program.rb +3 -0
- data/test/damagecontrol/build_test.rb +59 -0
- data/test/damagecontrol/diff_htmlizer_test.rb +31 -0
- data/test/damagecontrol/diff_parser_test.rb +61 -0
- data/test/damagecontrol/file_ext.rb +12 -0
- data/test/damagecontrol/poller_test.rb +56 -0
- data/test/damagecontrol/project_test.rb +144 -0
- data/test/damagecontrol/scm_web_test.rb +22 -0
- data/test/damagecontrol/test.diff +38 -0
- data/test/damagecontrol/test.html +40 -0
- data/test/damagecontrol/tracker_test.rb +48 -0
- data/test/damagecontrol/visitor/changesets.rss +34 -0
- data/test/damagecontrol/visitor/diff_persister_test.rb +49 -0
- data/test/damagecontrol/visitor/rss_writer_test.rb +40 -0
- data/test/damagecontrol/visitor/yaml_persister_test.rb +40 -0
- data/test/functional/admin_controller_test.rb +17 -0
- data/test/functional/project_controller_test.rb +17 -0
- data/test/test_helper.rb +14 -0
- 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
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,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
|