foca-integrity 0.1.4 → 0.1.6
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.markdown +19 -106
- data/Rakefile +53 -25
- data/VERSION.yml +1 -1
- data/app.rb +24 -153
- data/bin/integrity +2 -80
- data/config/config.sample.ru +2 -1
- data/config/config.sample.yml +4 -0
- data/integrity.gemspec +16 -11
- data/lib/integrity/build.rb +10 -5
- 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/helpers.rb +16 -0
- data/lib/integrity/installer.rb +133 -0
- data/lib/integrity/migrations.rb +50 -0
- data/lib/integrity/notifier/base.rb +1 -1
- data/lib/integrity/notifier.rb +2 -2
- data/lib/integrity/project.rb +40 -13
- data/lib/integrity/{builder.rb → project_builder.rb} +1 -3
- data/lib/integrity/scm/git.rb +4 -4
- data/lib/integrity/scm.rb +5 -8
- data/lib/integrity.rb +37 -26
- data/test/helpers/acceptance/git_helper.rb +99 -0
- data/test/helpers/acceptance/textfile_notifier.rb +26 -0
- data/test/helpers/acceptance.rb +126 -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/expectations.rb +5 -0
- data/test/helpers/fixtures.rb +83 -0
- data/test/helpers.rb +48 -0
- data/views/_build_info.haml +18 -0
- data/views/build.haml +1 -1
- data/views/error.haml +10 -3
- data/views/home.haml +3 -2
- data/views/integrity.sass +1 -1
- data/views/layout.haml +3 -0
- data/views/new.haml +10 -13
- data/views/notifier.haml +1 -1
- data/views/project.builder +21 -0
- data/views/project.haml +9 -13
- metadata +38 -11
- data/lib/integrity/core_ext/time.rb +0 -13
- data/spec/form_field_matchers.rb +0 -91
- data/spec/spec_helper.rb +0 -135
- data/vendor/sinatra-hacks/lib/hacks.rb +0 -49
- data/views/build_info.haml +0 -22
data/integrity.gemspec
CHANGED
@@ -1,71 +1,76 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = %q{integrity}
|
3
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.6"
|
4
6
|
|
5
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
8
|
s.authors = ["Nicol\303\241s Sanguinetti", "Simon Rozet"]
|
7
|
-
s.date = %q{
|
9
|
+
s.date = %q{2009-01-29}
|
8
10
|
s.default_executable = %q{integrity}
|
9
11
|
s.description = %q{Your Friendly Continuous Integration server. Easy, fun and painless!}
|
10
12
|
s.email = %q{contacto@nicolassanguinetti.info}
|
11
13
|
s.executables = ["integrity"]
|
12
|
-
s.files = ["README.markdown", "Rakefile", "VERSION.yml", "app.rb", "bin/integrity", "config/config.sample.ru", "config/config.sample.yml", "config/thin.sample.yml", "integrity.gemspec", "lib/integrity.rb", "lib/integrity/build.rb", "lib/integrity/
|
14
|
+
s.files = ["README.markdown", "Rakefile", "VERSION.yml", "app.rb", "bin/integrity", "config/config.sample.ru", "config/config.sample.yml", "config/thin.sample.yml", "integrity.gemspec", "lib/integrity.rb", "lib/integrity/build.rb", "lib/integrity/core_ext/object.rb", "lib/integrity/core_ext/string.rb", "lib/integrity/helpers.rb", "lib/integrity/helpers/authorization.rb", "lib/integrity/helpers/breadcrumbs.rb", "lib/integrity/helpers/forms.rb", "lib/integrity/helpers/pretty_output.rb", "lib/integrity/helpers/rendering.rb", "lib/integrity/helpers/resources.rb", "lib/integrity/helpers/urls.rb", "lib/integrity/installer.rb", "lib/integrity/migrations.rb", "lib/integrity/notifier.rb", "lib/integrity/notifier/base.rb", "lib/integrity/project.rb", "lib/integrity/project_builder.rb", "lib/integrity/scm.rb", "lib/integrity/scm/git.rb", "lib/integrity/scm/git/uri.rb", "public/buttons.css", "public/reset.css", "public/spinner.gif", "test/helpers.rb", "test/helpers/acceptance.rb", "test/helpers/acceptance/git_helper.rb", "test/helpers/acceptance/textfile_notifier.rb", "test/helpers/expectations.rb", "test/helpers/expectations/be_a.rb", "test/helpers/expectations/change.rb", "test/helpers/expectations/have.rb", "test/helpers/expectations/have_tag.rb", "test/helpers/expectations/predicates.rb", "test/helpers/fixtures.rb", "views/_build_info.haml", "views/build.haml", "views/error.haml", "views/home.haml", "views/integrity.sass", "views/layout.haml", "views/new.haml", "views/not_found.haml", "views/notifier.haml", "views/project.builder", "views/project.haml", "views/unauthorized.haml"]
|
13
15
|
s.homepage = %q{http://integrityapp.com}
|
14
16
|
s.post_install_message = %q{Run `integrity help` for information on how to setup Integrity.}
|
15
17
|
s.require_paths = ["lib"]
|
16
18
|
s.rubyforge_project = %q{integrity}
|
17
|
-
s.rubygems_version = %q{1.
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
18
20
|
s.summary = %q{The easy and fun Continuous Integration server}
|
19
21
|
|
20
22
|
if s.respond_to? :specification_version then
|
21
23
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
24
|
s.specification_version = 2
|
23
25
|
|
24
|
-
if
|
25
|
-
s.add_runtime_dependency(%q<sinatra>, [">= 0.3
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<sinatra>, [">= 0.9.0.3"])
|
26
28
|
s.add_runtime_dependency(%q<haml>, [">= 0"])
|
27
29
|
s.add_runtime_dependency(%q<dm-core>, [">= 0.9.5"])
|
28
30
|
s.add_runtime_dependency(%q<dm-validations>, [">= 0.9.5"])
|
29
31
|
s.add_runtime_dependency(%q<dm-types>, [">= 0.9.5"])
|
30
32
|
s.add_runtime_dependency(%q<dm-timestamps>, [">= 0.9.5"])
|
31
33
|
s.add_runtime_dependency(%q<dm-aggregates>, [">= 0.9.5"])
|
34
|
+
s.add_runtime_dependency(%q<dm-migrations>, [">= 0.9.5"])
|
32
35
|
s.add_runtime_dependency(%q<data_objects>, [">= 0.9.5"])
|
33
36
|
s.add_runtime_dependency(%q<do_sqlite3>, [">= 0.9.5"])
|
34
37
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
35
38
|
s.add_runtime_dependency(%q<foca-sinatra-diddies>, [">= 0.0.2"])
|
36
|
-
s.add_runtime_dependency(%q<rspec_hpricot_matchers>, [">= 0"])
|
37
39
|
s.add_runtime_dependency(%q<thor>, [">= 0"])
|
40
|
+
s.add_runtime_dependency(%q<uuidtools>, [">= 0"])
|
38
41
|
s.add_runtime_dependency(%q<bcrypt-ruby>, [">= 0"])
|
39
42
|
else
|
40
|
-
s.add_dependency(%q<sinatra>, [">= 0.3
|
43
|
+
s.add_dependency(%q<sinatra>, [">= 0.9.0.3"])
|
41
44
|
s.add_dependency(%q<haml>, [">= 0"])
|
42
45
|
s.add_dependency(%q<dm-core>, [">= 0.9.5"])
|
43
46
|
s.add_dependency(%q<dm-validations>, [">= 0.9.5"])
|
44
47
|
s.add_dependency(%q<dm-types>, [">= 0.9.5"])
|
45
48
|
s.add_dependency(%q<dm-timestamps>, [">= 0.9.5"])
|
46
49
|
s.add_dependency(%q<dm-aggregates>, [">= 0.9.5"])
|
50
|
+
s.add_dependency(%q<dm-migrations>, [">= 0.9.5"])
|
47
51
|
s.add_dependency(%q<data_objects>, [">= 0.9.5"])
|
48
52
|
s.add_dependency(%q<do_sqlite3>, [">= 0.9.5"])
|
49
53
|
s.add_dependency(%q<json>, [">= 0"])
|
50
54
|
s.add_dependency(%q<foca-sinatra-diddies>, [">= 0.0.2"])
|
51
|
-
s.add_dependency(%q<rspec_hpricot_matchers>, [">= 0"])
|
52
55
|
s.add_dependency(%q<thor>, [">= 0"])
|
56
|
+
s.add_dependency(%q<uuidtools>, [">= 0"])
|
53
57
|
s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
|
54
58
|
end
|
55
59
|
else
|
56
|
-
s.add_dependency(%q<sinatra>, [">= 0.3
|
60
|
+
s.add_dependency(%q<sinatra>, [">= 0.9.0.3"])
|
57
61
|
s.add_dependency(%q<haml>, [">= 0"])
|
58
62
|
s.add_dependency(%q<dm-core>, [">= 0.9.5"])
|
59
63
|
s.add_dependency(%q<dm-validations>, [">= 0.9.5"])
|
60
64
|
s.add_dependency(%q<dm-types>, [">= 0.9.5"])
|
61
65
|
s.add_dependency(%q<dm-timestamps>, [">= 0.9.5"])
|
62
66
|
s.add_dependency(%q<dm-aggregates>, [">= 0.9.5"])
|
67
|
+
s.add_dependency(%q<dm-migrations>, [">= 0.9.5"])
|
63
68
|
s.add_dependency(%q<data_objects>, [">= 0.9.5"])
|
64
69
|
s.add_dependency(%q<do_sqlite3>, [">= 0.9.5"])
|
65
70
|
s.add_dependency(%q<json>, [">= 0"])
|
66
71
|
s.add_dependency(%q<foca-sinatra-diddies>, [">= 0.0.2"])
|
67
|
-
s.add_dependency(%q<rspec_hpricot_matchers>, [">= 0"])
|
68
72
|
s.add_dependency(%q<thor>, [">= 0"])
|
73
|
+
s.add_dependency(%q<uuidtools>, [">= 0"])
|
69
74
|
s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
|
70
75
|
end
|
71
76
|
end
|
data/lib/integrity/build.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
|
3
1
|
module Integrity
|
4
2
|
class Build
|
5
3
|
include DataMapper::Resource
|
6
4
|
|
7
|
-
property :id,
|
8
|
-
property :output, Text, :nullable => false, :default =>
|
5
|
+
property :id, Serial
|
6
|
+
property :output, Text, :nullable => false, :default => ""
|
9
7
|
property :successful, Boolean, :nullable => false, :default => false
|
10
8
|
property :commit_identifier, String, :nullable => false
|
11
9
|
property :commit_metadata, Yaml, :nullable => false, :lazy => false
|
@@ -23,12 +21,19 @@ module Integrity
|
|
23
21
|
end
|
24
22
|
|
25
23
|
def human_readable_status
|
26
|
-
successful? ?
|
24
|
+
successful? ? "Build Successful" : "Build Failed"
|
27
25
|
end
|
28
26
|
|
29
27
|
def short_commit_identifier
|
30
28
|
sha1?(commit_identifier) ? commit_identifier[0..6] : commit_identifier
|
31
29
|
end
|
30
|
+
|
31
|
+
def commit_metadata
|
32
|
+
case data = attribute_get(:commit_metadata)
|
33
|
+
when String; YAML.load(data)
|
34
|
+
else data
|
35
|
+
end
|
36
|
+
end
|
32
37
|
|
33
38
|
def commit_author
|
34
39
|
@author ||= begin
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "diddies"
|
2
|
+
|
3
|
+
module Integrity
|
4
|
+
module Helpers
|
5
|
+
module Authorization
|
6
|
+
include Sinatra::Authorization
|
7
|
+
|
8
|
+
def authorization_realm
|
9
|
+
"Integrity"
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorized?
|
13
|
+
return true unless Integrity.config[:use_basic_auth]
|
14
|
+
!!request.env["REMOTE_USER"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def authorize(user, password)
|
18
|
+
if Integrity.config[:hash_admin_password]
|
19
|
+
password = Digest::SHA1.hexdigest(password)
|
20
|
+
end
|
21
|
+
|
22
|
+
!Integrity.config[:use_basic_auth] ||
|
23
|
+
(Integrity.config[:admin_username] == user &&
|
24
|
+
Integrity.config[:admin_password] == password)
|
25
|
+
end
|
26
|
+
|
27
|
+
def unauthorized!(realm=authorization_realm)
|
28
|
+
response["WWW-Authenticate"] = %(Basic realm="#{realm}")
|
29
|
+
throw :halt, [401, show(:unauthorized, :title => "incorrect credentials")]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Integrity
|
2
|
+
module Helpers
|
3
|
+
module Breadcrumbs
|
4
|
+
def pages
|
5
|
+
@pages ||= [["projects", "/"], ["new project", "/new"]]
|
6
|
+
end
|
7
|
+
|
8
|
+
def breadcrumbs(*crumbs)
|
9
|
+
crumbs[0..-2].map do |crumb|
|
10
|
+
if page_data = pages.detect {|c| c.first == crumb }
|
11
|
+
%Q(<a href="#{page_data.last}">#{page_data.first}</a>)
|
12
|
+
elsif @project && @project.permalink == crumb
|
13
|
+
%Q(<a href="#{project_url(@project)}">#{@project.permalink}</a>)
|
14
|
+
end
|
15
|
+
end + [crumbs.last]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Integrity
|
2
|
+
module Helpers
|
3
|
+
module Forms
|
4
|
+
def errors_on(object, field)
|
5
|
+
return "" unless errors = object.errors.on(field)
|
6
|
+
errors.map {|e| e.gsub(/#{field} /i, "") }.join(", ")
|
7
|
+
end
|
8
|
+
|
9
|
+
def error_class(object, field)
|
10
|
+
object.errors.on(field).nil? ? "" : "with_errors"
|
11
|
+
end
|
12
|
+
|
13
|
+
def checkbox(name, condition, extras={})
|
14
|
+
attrs = { :name => name, :type => "checkbox", :value => "1" }
|
15
|
+
attrs.merge(condition ? { :checked => "checked" } : {})
|
16
|
+
attrs.merge(extras)
|
17
|
+
end
|
18
|
+
|
19
|
+
def notifier_form(notifier)
|
20
|
+
haml(notifier.to_haml, :layout => :notifier, :locals => {
|
21
|
+
:config => current_project.config_for(notifier),
|
22
|
+
:notifier => "#{notifier.to_s.split(/::/).last}",
|
23
|
+
:enabled => current_project.notifies?(notifier)
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Integrity
|
2
|
+
module Helpers
|
3
|
+
module PrettyOutput
|
4
|
+
def cycle(*values)
|
5
|
+
@cycles ||= {}
|
6
|
+
@cycles[values] ||= -1 # first value returned is 0
|
7
|
+
next_value = @cycles[values] = (@cycles[values] + 1) % values.size
|
8
|
+
values[next_value]
|
9
|
+
end
|
10
|
+
|
11
|
+
def bash_color_codes(string)
|
12
|
+
string.gsub("\e[0m", '</span>').
|
13
|
+
gsub("\e[31m", '<span class="color31">').
|
14
|
+
gsub("\e[32m", '<span class="color32">').
|
15
|
+
gsub("\e[33m", '<span class="color33">').
|
16
|
+
gsub("\e[34m", '<span class="color34">').
|
17
|
+
gsub("\e[35m", '<span class="color35">').
|
18
|
+
gsub("\e[36m", '<span class="color36">').
|
19
|
+
gsub("\e[37m", '<span class="color37">')
|
20
|
+
end
|
21
|
+
|
22
|
+
def pretty_date(date_time)
|
23
|
+
today = Date.today
|
24
|
+
if date_time.day == today.day && date_time.month == today.month && date_time.year == today.year
|
25
|
+
"today"
|
26
|
+
elsif date_time.day == today.day - 1 && date_time.month == today.month && date_time.year == today.year
|
27
|
+
"yesterday"
|
28
|
+
else
|
29
|
+
strftime_with_ordinal(date_time, "on %b %d%o")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def strftime_with_ordinal(date_time, format_string)
|
34
|
+
ordinal = case date_time.day
|
35
|
+
when 1, 21, 31 then "st"
|
36
|
+
when 2, 22 then "nd"
|
37
|
+
when 3, 23 then "rd"
|
38
|
+
else "th"
|
39
|
+
end
|
40
|
+
|
41
|
+
date_time.strftime(format_string.gsub("%o", ordinal))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Integrity
|
2
|
+
module Helpers
|
3
|
+
module Rendering
|
4
|
+
def show(view, options={})
|
5
|
+
@title = breadcrumbs(*options[:title])
|
6
|
+
haml view
|
7
|
+
end
|
8
|
+
|
9
|
+
def partial(template, locals={})
|
10
|
+
haml("_#{template}".to_sym, :locals => locals, :layout => false)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Integrity
|
2
|
+
module Helpers
|
3
|
+
module Resources
|
4
|
+
def current_project
|
5
|
+
@project ||= Project.first(:permalink => params[:project]) or raise Sinatra::NotFound
|
6
|
+
end
|
7
|
+
|
8
|
+
def current_build
|
9
|
+
@build ||= current_project.builds.first(:commit_identifier => params[:build]) or raise Sinatra::NotFound
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Integrity
|
2
|
+
module Helpers
|
3
|
+
module Urls
|
4
|
+
def url(path)
|
5
|
+
url = "#{request.scheme}://#{request.host}"
|
6
|
+
|
7
|
+
if request.scheme == "https" && request.port != 443 ||
|
8
|
+
request.scheme == "http" && request.port != 80
|
9
|
+
url << ":#{request.port}"
|
10
|
+
end
|
11
|
+
|
12
|
+
url << "/" unless path.index("/").zero?
|
13
|
+
url << path
|
14
|
+
end
|
15
|
+
|
16
|
+
def root_url
|
17
|
+
url("/")
|
18
|
+
end
|
19
|
+
|
20
|
+
def project_path(project, *path)
|
21
|
+
"/" << [project.permalink, *path].join("/")
|
22
|
+
end
|
23
|
+
|
24
|
+
def project_url(project, *path)
|
25
|
+
url project_path(project, *path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def push_url_for(project)
|
29
|
+
Addressable::URI.parse(project_url(project, "push")).tap do |url|
|
30
|
+
if Integrity.config[:use_basic_auth]
|
31
|
+
url.user = Integrity.config[:admin_username]
|
32
|
+
url.password = Integrity.config[:hash_admin_password] ?
|
33
|
+
"<password>" : Integrity.config[:admin_password]
|
34
|
+
end
|
35
|
+
end.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_path(build)
|
39
|
+
"/#{build.project.permalink}/builds/#{build.commit_identifier}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_url(build)
|
43
|
+
url build_path(build)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Dir["#{File.dirname(__FILE__)}/helpers/*.rb"].each &method(:require)
|
2
|
+
|
3
|
+
module Integrity
|
4
|
+
module Helpers
|
5
|
+
include Authorization
|
6
|
+
include Breadcrumbs
|
7
|
+
include Forms
|
8
|
+
include PrettyOutput
|
9
|
+
include Rendering
|
10
|
+
include Resources
|
11
|
+
include Urls
|
12
|
+
|
13
|
+
include Rack::Utils
|
14
|
+
alias :h :escape_html
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../integrity"
|
2
|
+
require "thor"
|
3
|
+
|
4
|
+
module Integrity
|
5
|
+
class Installer < Thor
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
desc "install [PATH]",
|
9
|
+
"Copy template files to PATH. Next, go there and edit them."
|
10
|
+
def install(path)
|
11
|
+
@root = File.expand_path(path)
|
12
|
+
|
13
|
+
create_dir_structure
|
14
|
+
copy_template_files
|
15
|
+
edit_template_files
|
16
|
+
create_db(root / "config.yml")
|
17
|
+
after_setup_message
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "create_db [CONFIG]",
|
21
|
+
"Checks the `database_uri` in CONFIG and creates and bootstraps a database for integrity"
|
22
|
+
def create_db(config, direction="up")
|
23
|
+
Integrity.new(config)
|
24
|
+
migrate_db(direction)
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "version",
|
28
|
+
"Print the current integrity version"
|
29
|
+
def version
|
30
|
+
puts Integrity.version
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
attr_reader :root
|
35
|
+
|
36
|
+
def migrate_db(direction="up")
|
37
|
+
require "dm-core"
|
38
|
+
require "migrations"
|
39
|
+
|
40
|
+
set_up_migrations unless migrations_already_set_up?
|
41
|
+
add_initial_migration if tables_from_before_migrations_exist?
|
42
|
+
|
43
|
+
case direction.to_s
|
44
|
+
when "up" then migrate_up!
|
45
|
+
when "down" then migrate_down!
|
46
|
+
else raise ArgumentError, "DIRECTION must be either up or down"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_dir_structure
|
51
|
+
mkdir_p root
|
52
|
+
mkdir_p root / "builds"
|
53
|
+
mkdir_p root / "log"
|
54
|
+
mkdir_p root / "public" # this one is to play nice with Passenger
|
55
|
+
mkdir_p root / "tmp" # this one is to play nice with Passenger
|
56
|
+
end
|
57
|
+
|
58
|
+
def copy_template_files
|
59
|
+
cp Integrity.root / "config" / "config.sample.ru", root / "config.ru"
|
60
|
+
cp Integrity.root / "config" / "config.sample.yml", root / "config.yml"
|
61
|
+
cp Integrity.root / "config" / "thin.sample.yml", root / "thin.yml"
|
62
|
+
end
|
63
|
+
|
64
|
+
def edit_template_files
|
65
|
+
edit_integrity_configuration
|
66
|
+
edit_thin_configuration
|
67
|
+
end
|
68
|
+
|
69
|
+
def edit_integrity_configuration
|
70
|
+
config = File.read(root / "config.yml")
|
71
|
+
config.gsub! %r(sqlite3:///var/integrity.db), "sqlite3://#{root}/integrity.db"
|
72
|
+
config.gsub! %r(/path/to/scm/exports), "#{root}/builds"
|
73
|
+
config.gsub! %r(/var/log), "#{root}/log"
|
74
|
+
File.open(root / "config.yml", "w") { |f| f.puts config }
|
75
|
+
end
|
76
|
+
|
77
|
+
def edit_thin_configuration
|
78
|
+
config = File.read(root / "thin.yml")
|
79
|
+
config.gsub! %r(/apps/integrity), root
|
80
|
+
File.open(root / "thin.yml", 'w') { |f| f.puts config }
|
81
|
+
end
|
82
|
+
|
83
|
+
def after_setup_message
|
84
|
+
puts
|
85
|
+
puts %Q(Awesome! Integrity was installed successfully!)
|
86
|
+
puts
|
87
|
+
puts %Q(If you want to enable notifiers, install the gems and then require them)
|
88
|
+
puts %Q(in #{root}/config.ru)
|
89
|
+
puts
|
90
|
+
puts %Q(For example:)
|
91
|
+
puts
|
92
|
+
puts %Q( sudo gem install -s http://gems.github.com foca-integrity-email)
|
93
|
+
puts
|
94
|
+
puts %Q(And then in #{root}/config.ru add:)
|
95
|
+
puts
|
96
|
+
puts %Q( require "notifier/email")
|
97
|
+
puts
|
98
|
+
puts %Q(Don't forget to tweak #{root / "config.yml"} to your needs.)
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_up_migrations
|
102
|
+
database_adapter.execute %q(CREATE TABLE "migration_info" ("migration_name" VARCHAR(255));)
|
103
|
+
end
|
104
|
+
|
105
|
+
def add_initial_migration
|
106
|
+
database_adapter.execute %q(INSERT INTO "migration_info" ("migration_name") VALUES ("initial"))
|
107
|
+
end
|
108
|
+
|
109
|
+
def tables_from_before_migrations_exist?
|
110
|
+
table_exists?("integrity_projects") &&
|
111
|
+
table_exists?("integrity_builds") &&
|
112
|
+
table_exists?("integrity_notifiers")
|
113
|
+
end
|
114
|
+
|
115
|
+
def migrations_already_set_up?
|
116
|
+
table_exists?("migration_info")
|
117
|
+
end
|
118
|
+
|
119
|
+
def without_pluralizing_table_names
|
120
|
+
database_adapter.resource_naming_convention = DataMapper::NamingConventions::Resource::Underscored
|
121
|
+
yield
|
122
|
+
database_adapter.resource_naming_convention = DataMapper::NamingConventions::Resource::UnderscoredAndPluralized
|
123
|
+
end
|
124
|
+
|
125
|
+
def table_exists?(table_name)
|
126
|
+
database_adapter.storage_exists?(table_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
def database_adapter
|
130
|
+
DataMapper.repository(:default).adapter
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "dm-migrations"
|
2
|
+
require "migration_runner"
|
3
|
+
|
4
|
+
include DataMapper::Types
|
5
|
+
|
6
|
+
migration 1, :initial do
|
7
|
+
up do
|
8
|
+
create_table :integrity_projects do
|
9
|
+
column :id, Serial
|
10
|
+
column :name, String, :nullable => false
|
11
|
+
column :permalink, String
|
12
|
+
column :uri, URI, :nullable => false
|
13
|
+
column :branch, String, :nullable => false, :default => "master"
|
14
|
+
column :command, String, :nullable => false, :default => "rake"
|
15
|
+
column :public, Boolean, :default => true
|
16
|
+
column :building, Boolean, :default => false
|
17
|
+
column :created_at, DateTime
|
18
|
+
column :updated_at, DateTime
|
19
|
+
|
20
|
+
column :build_id, Serial
|
21
|
+
column :notifier_id,Serial
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :integrity_builds do
|
25
|
+
column :id, Serial
|
26
|
+
column :output, Text, :nullable => false, :default => ""
|
27
|
+
column :successful, Boolean, :nullable => false, :default => false
|
28
|
+
column :commit_identifier, String, :nullable => false
|
29
|
+
column :commit_metadata, Yaml, :nullable => false
|
30
|
+
column :created_at, DateTime
|
31
|
+
column :updated_at, DateTime
|
32
|
+
|
33
|
+
column :project_id, Serial
|
34
|
+
end
|
35
|
+
|
36
|
+
create_table :integrity_notifiers do
|
37
|
+
column :id, Serial
|
38
|
+
column :name, String, :nullable => false
|
39
|
+
column :config, Yaml, :nullable => false
|
40
|
+
|
41
|
+
column :project_id, Serial
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
down do
|
46
|
+
drop_table :integrity_notifiers
|
47
|
+
drop_table :integrity_projects
|
48
|
+
drop_table :integrity_builds
|
49
|
+
end
|
50
|
+
end
|
data/lib/integrity/notifier.rb
CHANGED
@@ -2,7 +2,7 @@ module Integrity
|
|
2
2
|
class Notifier
|
3
3
|
include DataMapper::Resource
|
4
4
|
|
5
|
-
property :id,
|
5
|
+
property :id, Serial
|
6
6
|
property :name, String, :nullable => false
|
7
7
|
property :config, Yaml, :nullable => false, :lazy => false
|
8
8
|
|
@@ -45,6 +45,6 @@ module Integrity
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
require File.dirname(__FILE__) /
|
48
|
+
require File.dirname(__FILE__) / "notifier" / "base"
|
49
49
|
|
50
50
|
Dir["#{File.dirname(__FILE__)}/notifier/*.rb"].each &method(:require)
|
data/lib/integrity/project.rb
CHANGED
@@ -2,7 +2,7 @@ module Integrity
|
|
2
2
|
class Project
|
3
3
|
include DataMapper::Resource
|
4
4
|
|
5
|
-
property :id,
|
5
|
+
property :id, Serial
|
6
6
|
property :name, String, :nullable => false
|
7
7
|
property :permalink, String
|
8
8
|
property :uri, URI, :nullable => false, :length => 255
|
@@ -21,23 +21,41 @@ module Integrity
|
|
21
21
|
|
22
22
|
validates_is_unique :name
|
23
23
|
|
24
|
+
def self.only_public_unless(condition)
|
25
|
+
if condition
|
26
|
+
all
|
27
|
+
else
|
28
|
+
all(:public => true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
24
32
|
def build(commit_identifier="HEAD")
|
25
33
|
return if building?
|
26
34
|
update_attributes(:building => true)
|
27
|
-
|
35
|
+
ProjectBuilder.new(self).build(commit_identifier)
|
28
36
|
ensure
|
29
37
|
update_attributes(:building => false)
|
30
38
|
send_notifications
|
31
39
|
end
|
32
40
|
|
41
|
+
def push(payload)
|
42
|
+
payload = JSON.parse(payload || "")
|
43
|
+
|
44
|
+
if Integrity.config[:build_all_commits]
|
45
|
+
payload["commits"].sort_by { |commit| Time.parse(commit["timestamp"]) }.each do |commit|
|
46
|
+
build(commit["id"]) if payload["ref"] =~ /#{branch}/
|
47
|
+
end
|
48
|
+
else
|
49
|
+
build(payload["after"]) if payload["ref"] =~ /#{branch}/
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
33
53
|
def last_build
|
34
|
-
|
54
|
+
all_builds.first
|
35
55
|
end
|
36
56
|
|
37
57
|
def previous_builds
|
38
|
-
|
39
|
-
builds.shift
|
40
|
-
end
|
58
|
+
all_builds.tap {|builds| builds.shift }
|
41
59
|
end
|
42
60
|
|
43
61
|
def status
|
@@ -45,22 +63,25 @@ module Integrity
|
|
45
63
|
end
|
46
64
|
|
47
65
|
def public=(flag)
|
48
|
-
attribute_set(:public,
|
66
|
+
attribute_set(:public, case flag
|
67
|
+
when "1", "0" then flag == "1"
|
68
|
+
else !!flag
|
69
|
+
end)
|
49
70
|
end
|
50
|
-
|
71
|
+
|
51
72
|
def config_for(notifier)
|
52
73
|
notifier = notifiers.first(:name => notifier.to_s.split(/::/).last)
|
53
74
|
notifier.blank? ? {} : notifier.config
|
54
75
|
end
|
55
|
-
|
76
|
+
|
56
77
|
def notifies?(notifier)
|
57
78
|
!notifiers.first(:name => notifier.to_s.split(/::/).last).blank?
|
58
79
|
end
|
59
|
-
|
80
|
+
|
60
81
|
def enable_notifiers(*args)
|
61
82
|
Notifier.enable_notifiers(id, *args)
|
62
83
|
end
|
63
|
-
|
84
|
+
|
64
85
|
private
|
65
86
|
def set_permalink
|
66
87
|
self.permalink = (name || "").downcase.
|
@@ -72,9 +93,11 @@ module Integrity
|
|
72
93
|
|
73
94
|
def delete_code
|
74
95
|
builds.destroy!
|
75
|
-
|
96
|
+
ProjectBuilder.new(self).delete_code
|
97
|
+
rescue SCM::SCMUnknownError => error
|
98
|
+
Integrity.log "Problem while trying to deleting code: #{error}"
|
76
99
|
end
|
77
|
-
|
100
|
+
|
78
101
|
def send_notifications
|
79
102
|
notifiers.each do |notifier|
|
80
103
|
begin
|
@@ -86,5 +109,9 @@ module Integrity
|
|
86
109
|
end
|
87
110
|
end
|
88
111
|
end
|
112
|
+
|
113
|
+
def all_builds
|
114
|
+
builds.all.sort_by {|b| b.commited_at }.reverse
|
115
|
+
end
|
89
116
|
end
|
90
117
|
end
|