integrity 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +66 -0
- data/Rakefile +165 -0
- data/VERSION.yml +4 -0
- data/app.rb +138 -0
- data/bin/integrity +4 -0
- data/config/config.sample.ru +31 -0
- data/config/config.sample.yml +38 -0
- data/config/thin.sample.yml +13 -0
- data/integrity.gemspec +76 -0
- data/lib/integrity.rb +80 -0
- data/lib/integrity/build.rb +61 -0
- data/lib/integrity/core_ext/object.rb +6 -0
- data/lib/integrity/core_ext/string.rb +5 -0
- data/lib/integrity/helpers.rb +16 -0
- data/lib/integrity/helpers/authorization.rb +33 -0
- data/lib/integrity/helpers/breadcrumbs.rb +20 -0
- data/lib/integrity/helpers/forms.rb +28 -0
- data/lib/integrity/helpers/pretty_output.rb +45 -0
- data/lib/integrity/helpers/rendering.rb +14 -0
- data/lib/integrity/helpers/resources.rb +13 -0
- data/lib/integrity/helpers/urls.rb +47 -0
- data/lib/integrity/installer.rb +132 -0
- data/lib/integrity/migrations.rb +157 -0
- data/lib/integrity/notifier.rb +50 -0
- data/lib/integrity/notifier/base.rb +55 -0
- data/lib/integrity/project.rb +117 -0
- data/lib/integrity/project_builder.rb +47 -0
- data/lib/integrity/scm.rb +19 -0
- data/lib/integrity/scm/git.rb +83 -0
- data/lib/integrity/scm/git/uri.rb +57 -0
- data/public/buttons.css +82 -0
- data/public/reset.css +7 -0
- data/public/spinner.gif +0 -0
- data/test/helpers.rb +47 -0
- data/test/helpers/acceptance.rb +127 -0
- data/test/helpers/acceptance/git_helper.rb +99 -0
- data/test/helpers/acceptance/textfile_notifier.rb +26 -0
- data/test/helpers/expectations.rb +5 -0
- data/test/helpers/expectations/be_a.rb +23 -0
- data/test/helpers/expectations/change.rb +90 -0
- data/test/helpers/expectations/have.rb +105 -0
- data/test/helpers/expectations/have_tag.rb +128 -0
- data/test/helpers/expectations/predicates.rb +37 -0
- data/test/helpers/fixtures.rb +83 -0
- data/views/_build_info.haml +18 -0
- data/views/build.haml +2 -0
- data/views/error.haml +36 -0
- data/views/home.haml +23 -0
- data/views/integrity.sass +387 -0
- data/views/layout.haml +28 -0
- data/views/new.haml +51 -0
- data/views/not_found.haml +31 -0
- data/views/notifier.haml +7 -0
- data/views/project.builder +21 -0
- data/views/project.haml +28 -0
- data/views/unauthorized.haml +38 -0
- metadata +258 -0
data/README.markdown
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
Integrity
|
2
|
+
=========
|
3
|
+
|
4
|
+
[Integrity][website] is your friendly automated Continuous Integration server.
|
5
|
+
|
6
|
+
* See our [website][] for documentation and a [live demo][demo]
|
7
|
+
* Report bugs and submit features request on our [Lighthouse account][lighthouse]
|
8
|
+
* Join us on [#integrity][irc-channel] for ideas, help, patches or something
|
9
|
+
* Get the code on [GitHub][repo]
|
10
|
+
|
11
|
+
Thanks
|
12
|
+
------
|
13
|
+
|
14
|
+
Thanks to the fellowing people for their feedbacks, ideas and patches :
|
15
|
+
|
16
|
+
* [James Adam][james]
|
17
|
+
* [Elliott Cable][ec]
|
18
|
+
* [Corey Donohoe][atmos]
|
19
|
+
* [Kyle Hargraves][kyle]
|
20
|
+
* [Pier-Hugues Pellerin][ph]
|
21
|
+
* [Simon Rozet][sr]
|
22
|
+
* [Scott Taylor][scott]
|
23
|
+
|
24
|
+
License
|
25
|
+
-------
|
26
|
+
|
27
|
+
(The MIT License)
|
28
|
+
|
29
|
+
Copyright (c) 2008 [Nicolás Sanguinetti][foca], [entp][]
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
32
|
+
a copy of this software and associated documentation files (the
|
33
|
+
'Software'), to deal in the Software without restriction, including
|
34
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
35
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
36
|
+
permit persons to whom the Software is furnished to do so, subject to
|
37
|
+
the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be
|
40
|
+
included in all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
43
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
44
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
45
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
46
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
47
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
48
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
49
|
+
|
50
|
+
[website]: http://integrityapp.com
|
51
|
+
[demo]: http://builder.integrityapp.com
|
52
|
+
[repo]: http://github.com/foca/integrity
|
53
|
+
[lighthouse]: http://integrity.lighthouseapp.com/projects/14308-integrity
|
54
|
+
[irc-channel]: irc://irc.freenode.net/integrity
|
55
|
+
|
56
|
+
[foca]: http://nicolassanguinetti.info/
|
57
|
+
[entp]: http://entp.com
|
58
|
+
|
59
|
+
[james]: http://github.com/lazyatom
|
60
|
+
[ec]: http://github.com/elliotcabble
|
61
|
+
[atmos]: http://github.com/atmos
|
62
|
+
[kyle]: http://github.com/pd
|
63
|
+
[ph]: http://github.com/ph
|
64
|
+
[sr]: http://purl.org/net/sr/
|
65
|
+
[scott]: http://github.com/smtlaissezfaire
|
66
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rcov/rcovtask"
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + "/lib/integrity"
|
6
|
+
|
7
|
+
desc "Run all tests and check test coverage"
|
8
|
+
task :default => "test:coverage:verify"
|
9
|
+
|
10
|
+
desc "Run tests"
|
11
|
+
task :test => %w(test:units test:acceptance)
|
12
|
+
|
13
|
+
namespace :test do
|
14
|
+
Rake::TestTask.new(:units) do |t|
|
15
|
+
t.test_files = FileList["test/unit/*_test.rb"]
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::TestTask.new(:acceptance) do |t|
|
19
|
+
t.test_files = FileList["test/acceptance/*_test.rb"]
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Measure test coverage"
|
23
|
+
task :coverage => %w(test:coverage:units test:coverage:acceptance)
|
24
|
+
|
25
|
+
namespace :coverage do
|
26
|
+
desc "Measure test coverage of unit tests"
|
27
|
+
Rcov::RcovTask.new(:units) do |rcov|
|
28
|
+
rcov.pattern = "test/unit/*_test.rb"
|
29
|
+
rcov.rcov_opts = %w(--html --aggregate .aggregated_coverage_report)
|
30
|
+
rcov.rcov_opts << ENV["RCOV_OPTS"] if ENV["RCOV_OPTS"]
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Measure test coverage of acceptance tests"
|
34
|
+
Rcov::RcovTask.new(:acceptance) do |rcov|
|
35
|
+
rcov.pattern = "test/acceptance/*_test.rb"
|
36
|
+
rcov.rcov_opts = %w(--html --aggregate .aggregated_coverage_report)
|
37
|
+
rcov.rcov_opts << ENV["RCOV_OPTS"] if ENV["RCOV_OPTS"]
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Verify test coverage"
|
41
|
+
task :verify => "test:coverage" do
|
42
|
+
File.read("coverage/index.html") =~ /<tt class='coverage_total'>\s*(\d+\.\d+)%\s*<\/tt>/
|
43
|
+
coverage = $1.to_f
|
44
|
+
|
45
|
+
puts
|
46
|
+
if coverage == 100
|
47
|
+
puts "\e[32m100% coverage! Awesome!\e[0m"
|
48
|
+
else
|
49
|
+
puts "\e[31mOnly #{coverage}% code coverage. You can do better ;)\e[0m"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Install all gems on which the tests depend on"
|
55
|
+
task :install_dependencies do
|
56
|
+
system 'gem install redgreen rr mocha ruby-debug dm-sweatshop webrat'
|
57
|
+
system 'gem install -s http://gems.github.com jeremymcanally-context jeremymcanally-matchy jeremymcanally-pending foca-storyteller'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
namespace :db do
|
62
|
+
desc "Setup connection."
|
63
|
+
task :connect do
|
64
|
+
config = File.expand_path(ENV['CONFIG']) if ENV['CONFIG']
|
65
|
+
config = Integrity.root / 'config.yml' if File.exists?(Integrity.root / 'config.yml')
|
66
|
+
Integrity.new(config)
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "Automigrate the database"
|
70
|
+
task :migrate => :connect do
|
71
|
+
require "project"
|
72
|
+
require "build"
|
73
|
+
require "notifier"
|
74
|
+
DataMapper.auto_migrate!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# tx RMT :)
|
79
|
+
namespace :rubyforge do
|
80
|
+
def package(ext="")
|
81
|
+
"dist/integrity-#{Integrity.version}" + ext
|
82
|
+
end
|
83
|
+
|
84
|
+
directory "dist/"
|
85
|
+
CLOBBER.include("dist")
|
86
|
+
|
87
|
+
desc "Build packages"
|
88
|
+
task :package => %w[.gem .tar.gz].map { |ext| package(ext) } << :changelog
|
89
|
+
|
90
|
+
desc "Build and install as local gem"
|
91
|
+
task :install => package(".gem") do
|
92
|
+
sh "gem install #{package(".gem")}"
|
93
|
+
end
|
94
|
+
|
95
|
+
file package(".gem") => %w[dist/ integrity.gemspec] do |f|
|
96
|
+
sh "gem build integrity.gemspec"
|
97
|
+
mv File.basename(f.name), f.name
|
98
|
+
end
|
99
|
+
|
100
|
+
file package('.tar.gz') => %w[dist/] do |f|
|
101
|
+
sh <<-SH
|
102
|
+
git archive \
|
103
|
+
--prefix=integrity-#{Integrity.version}/ \
|
104
|
+
--format=tar \
|
105
|
+
HEAD | gzip > #{f.name}
|
106
|
+
SH
|
107
|
+
end
|
108
|
+
|
109
|
+
desc "Publish gem and tarball to rubyforge"
|
110
|
+
task "publish:gem" => [package(".gem"), package(".tar.gz")] do |t|
|
111
|
+
sh <<-end
|
112
|
+
rubyforge add_release integrity integrity #{Integrity.version} #{package('.gem')} &&
|
113
|
+
rubyforge add_file integrity integrity #{Integrity.version} #{package('.tar.gz')}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
file "dist/git-changelog.py" => %w[dist/] do
|
118
|
+
sh "cd dist && wget http://gist.github.com/raw/62837/bc6d2c6102933c3eac5fa33afd3effd7ab97edb7/git-changelog.py"
|
119
|
+
end
|
120
|
+
|
121
|
+
task :changelog => ["dist/git-changelog.py"] do
|
122
|
+
sh "python git-changelog.py"
|
123
|
+
sh "git add ChangeLog"
|
124
|
+
sh 'git commit -m "Regenerated ChangeLog"'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
begin
|
129
|
+
require "jeweler"
|
130
|
+
|
131
|
+
namespace :jeweler do
|
132
|
+
Jeweler::Tasks.new do |s|
|
133
|
+
files = `git ls-files`.split("\n").reject {|f| f =~ %r(^test/acceptance) || f =~ %r(^test/unit) || f =~ /^\.git/ }
|
134
|
+
|
135
|
+
s.name = 'integrity'
|
136
|
+
s.summary = 'The easy and fun Continuous Integration server'
|
137
|
+
s.description = 'Your Friendly Continuous Integration server. Easy, fun and painless!'
|
138
|
+
s.homepage = 'http://integrityapp.com'
|
139
|
+
s.rubyforge_project = 'integrity'
|
140
|
+
s.email = 'contacto@nicolassanguinetti.info'
|
141
|
+
s.authors = ['Nicolás Sanguinetti', 'Simon Rozet']
|
142
|
+
s.files = files
|
143
|
+
s.executables = ['integrity']
|
144
|
+
s.post_install_message = 'Run `integrity help` for information on how to setup Integrity.'
|
145
|
+
|
146
|
+
s.add_dependency 'sinatra', ['>= 0.9.0.3']
|
147
|
+
s.add_dependency 'haml', ['>= 2.0.0']
|
148
|
+
s.add_dependency 'dm-core', ['>= 0.9.5']
|
149
|
+
s.add_dependency 'dm-validations', ['>= 0.9.5']
|
150
|
+
s.add_dependency 'dm-types', ['>= 0.9.5']
|
151
|
+
s.add_dependency 'dm-timestamps', ['>= 0.9.5']
|
152
|
+
s.add_dependency 'dm-aggregates', ['>= 0.9.5']
|
153
|
+
s.add_dependency 'dm-migrations', ['>= 0.9.5']
|
154
|
+
s.add_dependency 'data_objects', ['>= 0.9.5']
|
155
|
+
s.add_dependency 'do_sqlite3', ['>= 0.9.5']
|
156
|
+
s.add_dependency 'json'
|
157
|
+
s.add_dependency 'foca-sinatra-diddies', ['>= 0.0.2']
|
158
|
+
s.add_dependency 'thor'
|
159
|
+
s.add_dependency 'uuidtools' # required by dm-types
|
160
|
+
s.add_dependency 'bcrypt-ruby' # required by dm-types
|
161
|
+
end
|
162
|
+
end
|
163
|
+
rescue LoadError
|
164
|
+
end
|
165
|
+
|
data/VERSION.yml
ADDED
data/app.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require "sinatra"
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + "/lib/integrity"
|
4
|
+
require "integrity/helpers"
|
5
|
+
|
6
|
+
set :root, Integrity.root
|
7
|
+
set :public, Integrity.root / "public"
|
8
|
+
set :views, Integrity.root / "views"
|
9
|
+
|
10
|
+
enable :sessions
|
11
|
+
|
12
|
+
include Integrity
|
13
|
+
|
14
|
+
configure :development do
|
15
|
+
config = Integrity.root / "config" / "config.yml"
|
16
|
+
Integrity.config = config if File.exists? config
|
17
|
+
end
|
18
|
+
|
19
|
+
configure do
|
20
|
+
Integrity.new
|
21
|
+
end
|
22
|
+
|
23
|
+
not_found do
|
24
|
+
status 404
|
25
|
+
show :not_found, :title => "lost, are we?"
|
26
|
+
end
|
27
|
+
|
28
|
+
error do
|
29
|
+
@error = request.env['sinatra.error']
|
30
|
+
status 500
|
31
|
+
show :error, :title => "something has gone terribly wrong"
|
32
|
+
end
|
33
|
+
|
34
|
+
before do
|
35
|
+
# The browser only sends http auth data for requests that are explicitly
|
36
|
+
# required to do so. This way we get the real values of +#logged_in?+ and
|
37
|
+
# +#current_user+
|
38
|
+
login_required if session[:user]
|
39
|
+
end
|
40
|
+
|
41
|
+
get "/" do
|
42
|
+
@projects = Project.only_public_unless(authorized?)
|
43
|
+
show :home, :title => "projects"
|
44
|
+
end
|
45
|
+
|
46
|
+
get "/login" do
|
47
|
+
login_required
|
48
|
+
session[:user] = current_user
|
49
|
+
redirect root_url
|
50
|
+
end
|
51
|
+
|
52
|
+
get "/new" do
|
53
|
+
login_required
|
54
|
+
|
55
|
+
@project = Project.new
|
56
|
+
show :new, :title => ["projects", "new project"]
|
57
|
+
end
|
58
|
+
|
59
|
+
post "/" do
|
60
|
+
login_required
|
61
|
+
|
62
|
+
@project = Project.new(params[:project_data])
|
63
|
+
if @project.save
|
64
|
+
@project.enable_notifiers(params["enabled_notifiers[]"], params["notifiers"])
|
65
|
+
redirect project_url(@project)
|
66
|
+
else
|
67
|
+
show :new, :title => ["projects", "new project"]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
get "/:project" do
|
72
|
+
login_required unless current_project.public?
|
73
|
+
show :project, :title => ["projects", current_project.name]
|
74
|
+
end
|
75
|
+
|
76
|
+
get "/:project.atom" do
|
77
|
+
login_required unless current_project.public?
|
78
|
+
response["Content-Type"] = "application/rss+xml; charset=utf-8"
|
79
|
+
builder :project
|
80
|
+
end
|
81
|
+
|
82
|
+
put "/:project" do
|
83
|
+
login_required
|
84
|
+
|
85
|
+
if current_project.update_attributes(params[:project_data])
|
86
|
+
current_project.enable_notifiers(params["enabled_notifiers"], params["notifiers"])
|
87
|
+
redirect project_url(current_project)
|
88
|
+
else
|
89
|
+
show :new, :title => ["projects", current_project.permalink, "edit"]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
delete "/:project" do
|
94
|
+
login_required
|
95
|
+
|
96
|
+
current_project.destroy
|
97
|
+
redirect root_url
|
98
|
+
end
|
99
|
+
|
100
|
+
get "/:project/edit" do
|
101
|
+
login_required
|
102
|
+
|
103
|
+
show :new, :title => ["projects", current_project.permalink, "edit"]
|
104
|
+
end
|
105
|
+
|
106
|
+
post "/:project/push" do
|
107
|
+
login_required
|
108
|
+
|
109
|
+
content_type "text/plain"
|
110
|
+
|
111
|
+
begin
|
112
|
+
current_project.push(params[:payload])
|
113
|
+
"Thanks, build started."
|
114
|
+
rescue JSON::ParserError => exception
|
115
|
+
throw :halt, [422, exception.to_s]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
post "/:project/builds" do
|
120
|
+
login_required
|
121
|
+
|
122
|
+
current_project.build
|
123
|
+
redirect project_url(@project)
|
124
|
+
end
|
125
|
+
|
126
|
+
get "/:project/builds/:build" do
|
127
|
+
login_required unless current_project.public?
|
128
|
+
show :build, :title => ["projects", current_project.permalink, current_build.short_commit_identifier]
|
129
|
+
end
|
130
|
+
|
131
|
+
get "/integrity.css" do
|
132
|
+
response["Content-Type"] = "text/css; charset=utf-8"
|
133
|
+
sass :integrity
|
134
|
+
end
|
135
|
+
|
136
|
+
helpers do
|
137
|
+
include Helpers
|
138
|
+
end
|
data/bin/integrity
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "rubygems"
|
3
|
+
require "integrity"
|
4
|
+
|
5
|
+
# If you want to add any notifiers, install the gems and then require them here
|
6
|
+
# For example, to enable the Email notifier: install the gem (from github:
|
7
|
+
#
|
8
|
+
# sudo gem install -s http://gems.github.com foca-integrity-email
|
9
|
+
#
|
10
|
+
# And then uncomment the following line:
|
11
|
+
#
|
12
|
+
# require "notifier/email"
|
13
|
+
|
14
|
+
# Load integrity's configuration.
|
15
|
+
Integrity.config = File.expand_path("./config.yml")
|
16
|
+
|
17
|
+
#######################################################################
|
18
|
+
## ##
|
19
|
+
## == DON'T EDIT ANYTHING BELOW UNLESS YOU KNOW WHAT YOU'RE DOING == ##
|
20
|
+
## ##
|
21
|
+
#######################################################################
|
22
|
+
require Integrity.root / "app"
|
23
|
+
|
24
|
+
set :environment, ENV["RACK_ENV"] || :production
|
25
|
+
set :public, Integrity.root / "public"
|
26
|
+
set :views, Integrity.root / "views"
|
27
|
+
set :port, 8910
|
28
|
+
disable :run, :reload
|
29
|
+
|
30
|
+
use Rack::CommonLogger, Integrity.logger if Integrity.config[:log_debug_info]
|
31
|
+
run Sinatra::Application
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Domain where integrity will be running from. This is used to have
|
2
|
+
# nice URLs in your notifications.
|
3
|
+
# For example:
|
4
|
+
# http://builder.integrityapp.com
|
5
|
+
:base_uri: http://integrity.domain.tld
|
6
|
+
|
7
|
+
# This should be a complete connection string to your database. For example
|
8
|
+
# `mysql://user@localhost/integrity` (you need an `integrity` db created in
|
9
|
+
# localhost, of course).
|
10
|
+
:database_uri: sqlite3:///var/integrity.db
|
11
|
+
|
12
|
+
# This is where your project's code will be checked out to. Make sure it's
|
13
|
+
# writable by the user that runs Integrity.
|
14
|
+
:export_directory: /path/to/scm/exports
|
15
|
+
|
16
|
+
# Path to the integrity log file
|
17
|
+
:log: /var/log/integrity.log
|
18
|
+
|
19
|
+
# Enable/Disable debug logging. Turning this on will log queries made to the
|
20
|
+
# database and web requests (if using the provided rackup file)
|
21
|
+
:log_debug_info: false
|
22
|
+
|
23
|
+
# Enable or disable HTTP authentication for the app. BE AWARE that if you
|
24
|
+
# disable this anyone can delete and alter projects, so do it only if your
|
25
|
+
# app is running in a controlled environment (ie, behind your company's
|
26
|
+
# firewall.)
|
27
|
+
:use_basic_auth: false
|
28
|
+
|
29
|
+
# When `use_basic_auth` is true, the admin's username for HTTP authentication.
|
30
|
+
:admin_username: username
|
31
|
+
|
32
|
+
# When `use_basic_auth` is true, the admin's password. Usually saved as a
|
33
|
+
# SHA1 hash. See the next option.
|
34
|
+
:admin_password: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
|
35
|
+
|
36
|
+
# If this is true, then whenever we authenticate the admin user, will hash
|
37
|
+
# it using SHA1. If not, we'll assume the provided password is in plain text.
|
38
|
+
:hash_admin_password: true
|