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.
Files changed (53) hide show
  1. data/README.markdown +19 -106
  2. data/Rakefile +53 -25
  3. data/VERSION.yml +1 -1
  4. data/app.rb +24 -153
  5. data/bin/integrity +2 -80
  6. data/config/config.sample.ru +2 -1
  7. data/config/config.sample.yml +4 -0
  8. data/integrity.gemspec +16 -11
  9. data/lib/integrity/build.rb +10 -5
  10. data/lib/integrity/helpers/authorization.rb +33 -0
  11. data/lib/integrity/helpers/breadcrumbs.rb +20 -0
  12. data/lib/integrity/helpers/forms.rb +28 -0
  13. data/lib/integrity/helpers/pretty_output.rb +45 -0
  14. data/lib/integrity/helpers/rendering.rb +14 -0
  15. data/lib/integrity/helpers/resources.rb +13 -0
  16. data/lib/integrity/helpers/urls.rb +47 -0
  17. data/lib/integrity/helpers.rb +16 -0
  18. data/lib/integrity/installer.rb +133 -0
  19. data/lib/integrity/migrations.rb +50 -0
  20. data/lib/integrity/notifier/base.rb +1 -1
  21. data/lib/integrity/notifier.rb +2 -2
  22. data/lib/integrity/project.rb +40 -13
  23. data/lib/integrity/{builder.rb → project_builder.rb} +1 -3
  24. data/lib/integrity/scm/git.rb +4 -4
  25. data/lib/integrity/scm.rb +5 -8
  26. data/lib/integrity.rb +37 -26
  27. data/test/helpers/acceptance/git_helper.rb +99 -0
  28. data/test/helpers/acceptance/textfile_notifier.rb +26 -0
  29. data/test/helpers/acceptance.rb +126 -0
  30. data/test/helpers/expectations/be_a.rb +23 -0
  31. data/test/helpers/expectations/change.rb +90 -0
  32. data/test/helpers/expectations/have.rb +105 -0
  33. data/test/helpers/expectations/have_tag.rb +128 -0
  34. data/test/helpers/expectations/predicates.rb +37 -0
  35. data/test/helpers/expectations.rb +5 -0
  36. data/test/helpers/fixtures.rb +83 -0
  37. data/test/helpers.rb +48 -0
  38. data/views/_build_info.haml +18 -0
  39. data/views/build.haml +1 -1
  40. data/views/error.haml +10 -3
  41. data/views/home.haml +3 -2
  42. data/views/integrity.sass +1 -1
  43. data/views/layout.haml +3 -0
  44. data/views/new.haml +10 -13
  45. data/views/notifier.haml +1 -1
  46. data/views/project.builder +21 -0
  47. data/views/project.haml +9 -13
  48. metadata +38 -11
  49. data/lib/integrity/core_ext/time.rb +0 -13
  50. data/spec/form_field_matchers.rb +0 -91
  51. data/spec/spec_helper.rb +0 -135
  52. data/vendor/sinatra-hacks/lib/hacks.rb +0 -49
  53. 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.4"
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{2008-12-08}
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/builder.rb", "lib/integrity/core_ext/object.rb", "lib/integrity/core_ext/string.rb", "lib/integrity/core_ext/time.rb", "lib/integrity/notifier.rb", "lib/integrity/notifier/base.rb", "lib/integrity/project.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", "vendor/sinatra-hacks/lib/hacks.rb", "views/build.haml", "views/build_info.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.haml", "views/unauthorized.haml", "spec/spec_helper.rb", "spec/form_field_matchers.rb"]
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.2.0}
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 current_version >= 3 then
25
- s.add_runtime_dependency(%q<sinatra>, [">= 0.3.2"])
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.2"])
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.2"])
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
@@ -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, Integer, :serial => true
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? ? 'Build Successful' : 'Build Failed'
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
@@ -48,7 +48,7 @@ EOM
48
48
  private
49
49
 
50
50
  def stripped_build_output
51
- build.output.gsub("\e[0m", '').gsub(/\e\[3[1-7]m/, '')
51
+ build.output.gsub("\e[0m", "").gsub(/\e\[3[1-7]m/, "")
52
52
  end
53
53
  end
54
54
  end
@@ -2,7 +2,7 @@ module Integrity
2
2
  class Notifier
3
3
  include DataMapper::Resource
4
4
 
5
- property :id, Integer, :serial => true
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__) / 'notifier' / 'base'
48
+ require File.dirname(__FILE__) / "notifier" / "base"
49
49
 
50
50
  Dir["#{File.dirname(__FILE__)}/notifier/*.rb"].each &method(:require)
@@ -2,7 +2,7 @@ module Integrity
2
2
  class Project
3
3
  include DataMapper::Resource
4
4
 
5
- property :id, Integer, :serial => true
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
- Builder.new(self).build(commit_identifier)
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
- builds.last
54
+ all_builds.first
35
55
  end
36
56
 
37
57
  def previous_builds
38
- builds.all(:order => [:created_at.desc]).tap do |builds|
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, !!flag)
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
- Builder.new(self).delete_code
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