damagecontrol 0.5.0
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.
- 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
|