integrity 0.1.8 → 0.1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/README.markdown +7 -0
  2. data/Rakefile +77 -124
  3. data/config/config.ru +29 -0
  4. data/config/config.sample.ru +6 -16
  5. data/config/config.sample.yml +15 -12
  6. data/config/config.yml +34 -0
  7. data/lib/integrity.rb +13 -13
  8. data/lib/integrity/app.rb +138 -0
  9. data/lib/integrity/author.rb +39 -0
  10. data/lib/integrity/build.rb +54 -31
  11. data/lib/integrity/commit.rb +71 -0
  12. data/lib/integrity/helpers.rb +3 -3
  13. data/lib/integrity/helpers/authorization.rb +2 -2
  14. data/lib/integrity/helpers/forms.rb +3 -3
  15. data/lib/integrity/helpers/pretty_output.rb +1 -1
  16. data/lib/integrity/helpers/rendering.rb +6 -1
  17. data/lib/integrity/helpers/resources.rb +9 -3
  18. data/lib/integrity/helpers/urls.rb +15 -13
  19. data/lib/integrity/installer.rb +43 -60
  20. data/lib/integrity/migrations.rb +31 -48
  21. data/lib/integrity/notifier.rb +14 -16
  22. data/lib/integrity/notifier/base.rb +29 -19
  23. data/lib/integrity/notifier/test_helpers.rb +100 -0
  24. data/lib/integrity/project.rb +69 -33
  25. data/lib/integrity/project_builder.rb +23 -14
  26. data/lib/integrity/scm/git.rb +15 -14
  27. data/lib/integrity/scm/git/uri.rb +9 -9
  28. data/test/acceptance/api_test.rb +97 -0
  29. data/test/acceptance/browse_project_builds_test.rb +65 -0
  30. data/test/acceptance/browse_project_test.rb +95 -0
  31. data/test/acceptance/build_notifications_test.rb +42 -0
  32. data/test/acceptance/create_project_test.rb +97 -0
  33. data/test/acceptance/delete_project_test.rb +53 -0
  34. data/test/acceptance/edit_project_test.rb +117 -0
  35. data/test/acceptance/error_page_test.rb +18 -0
  36. data/test/acceptance/helpers.rb +2 -0
  37. data/test/acceptance/installer_test.rb +62 -0
  38. data/test/acceptance/manual_build_project_test.rb +82 -0
  39. data/test/acceptance/notifier_test.rb +109 -0
  40. data/test/acceptance/project_syndication_test.rb +30 -0
  41. data/test/acceptance/stylesheet_test.rb +18 -0
  42. data/test/helpers.rb +59 -26
  43. data/test/helpers/acceptance.rb +19 -65
  44. data/test/helpers/acceptance/email_notifier.rb +55 -0
  45. data/test/helpers/acceptance/git_helper.rb +15 -15
  46. data/test/helpers/acceptance/textfile_notifier.rb +3 -3
  47. data/test/helpers/expectations.rb +0 -1
  48. data/test/helpers/expectations/be_a.rb +4 -4
  49. data/test/helpers/expectations/change.rb +5 -5
  50. data/test/helpers/expectations/have.rb +4 -4
  51. data/test/helpers/expectations/predicates.rb +4 -4
  52. data/test/helpers/fixtures.rb +44 -18
  53. data/test/helpers/initial_migration_fixture.sql +44 -0
  54. data/test/unit/build_test.rb +51 -0
  55. data/test/unit/commit_test.rb +83 -0
  56. data/test/unit/helpers_test.rb +56 -0
  57. data/test/unit/integrity_test.rb +18 -0
  58. data/test/unit/migrations_test.rb +56 -0
  59. data/test/unit/notifier_test.rb +123 -0
  60. data/test/unit/project_builder_test.rb +108 -0
  61. data/test/unit/project_test.rb +282 -0
  62. data/test/unit/scm_test.rb +54 -0
  63. data/views/_commit_info.haml +24 -0
  64. data/views/build.haml +2 -2
  65. data/views/error.haml +4 -3
  66. data/views/home.haml +3 -5
  67. data/views/integrity.sass +19 -6
  68. data/views/new.haml +6 -6
  69. data/views/project.builder +9 -9
  70. data/views/project.haml +14 -12
  71. metadata +89 -122
  72. data/VERSION.yml +0 -4
  73. data/app.rb +0 -138
  74. data/integrity.gemspec +0 -76
  75. data/lib/integrity/core_ext/string.rb +0 -5
  76. data/test/helpers/expectations/have_tag.rb +0 -128
  77. data/views/_build_info.haml +0 -18
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'integrity'
3
+
4
+ module Integrity
5
+ class Notifier
6
+ class Email < Notifier::Base
7
+ attr_reader :to, :from
8
+
9
+ def self.to_haml
10
+ <<-EOF
11
+ %p.normal
12
+ %label{ :for => "email_notifier_to" } Send to
13
+ %input.text#email_notifier_to{ :name => "notifiers[Email][to]", :type => "text", :value => config["to"] }
14
+
15
+ %p.normal
16
+ %label{ :for => "email_notifier_from" } Send from
17
+ %input.text#email_notifier_from{ :name => "notifiers[Email][from]", :type => "text", :value => config["from"] }
18
+
19
+ %h3 SMTP Server Configuration
20
+
21
+ %p.normal
22
+ %label{ :for => "email_notifier_host" } Host : Port
23
+ = succeed " : " do
24
+ %input.text#email_notifier_host{ :name => "notifiers[Email][host]", :value => config["host"], :style => "width: 24.5em;", :type => "text" }
25
+ %input.text#email_notifier_port{ :name => "notifiers[Email][port]", :value => config["port"], :style => "width: 3.5em;", :type => "text" }
26
+
27
+ %p.normal
28
+ %label{ :for => "email_notifier_user" } User
29
+ %input.text#email_notifier_user{ :name => "notifiers[Email][user]", :value => config["user"], :type => "text" }
30
+
31
+ %p.normal
32
+ %label{ :for => "email_notifier_pass" } Password
33
+ %input.text#email_notifier_pass{ :name => "notifiers[Email][pass]", :value => config["pass"], :type => "text" }
34
+
35
+ %p.normal
36
+ %label{ :for => "email_notifier_auth" } Auth type
37
+ %input.text#email_notifier_auth{ :name => "notifiers[Email][auth]", :value => (config["auth"] || "plain"), :type => "text" }
38
+
39
+ %p.normal
40
+ %label{ :for => "email_notifier_domain" } Domain
41
+ %input.text#email_notifier_domain{ :name => "notifiers[Email][domain]", :value => config["domain"], :type => "text" }
42
+ EOF
43
+ end
44
+
45
+ def initialize(build, config={})
46
+ @to = config.delete("to")
47
+ @from = config.delete("from")
48
+ super
49
+ end
50
+
51
+ def deliver!
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,32 +1,32 @@
1
1
  module GitHelper
2
2
  @@_git_repositories = Hash.new {|h,k| h[k] = Repo.new(k) }
3
-
3
+
4
4
  def git_repo(name)
5
5
  @@_git_repositories[name]
6
6
  end
7
-
7
+
8
8
  def destroy_all_git_repos
9
9
  @@_git_repositories.each {|n,r| r.destroy }
10
10
  @@_git_repositories.clear
11
11
  end
12
-
12
+
13
13
  class Repo
14
14
  attr_reader :path
15
-
15
+
16
16
  def initialize(name)
17
17
  @name = name
18
18
  @path = "/tmp" / @name.to_s
19
19
  create
20
20
  end
21
-
21
+
22
22
  def path
23
23
  @path / ".git"
24
24
  end
25
-
25
+
26
26
  def create
27
27
  destroy
28
28
  FileUtils.mkdir_p @path
29
-
29
+
30
30
  Dir.chdir(@path) do
31
31
  system 'git init &>/dev/null'
32
32
  system 'git config user.name "John Doe"'
@@ -35,7 +35,7 @@ module GitHelper
35
35
  system 'git add README &>/dev/null'
36
36
  system 'git commit -m "First commit" &>/dev/null'
37
37
  end
38
-
38
+
39
39
  add_successful_commit
40
40
  end
41
41
 
@@ -43,7 +43,7 @@ module GitHelper
43
43
  Dir.chdir(@path) do
44
44
  commits = `git log --pretty=oneline`.collect { |line| line.split(" ").first }
45
45
  commits.inject([]) do |commits, sha1|
46
- format = %Q(---%n:message: >-%n %s%n:timestamp: %ci%n:id: #{sha1})
46
+ format = %Q(---%n:message: >-%n %s%n:timestamp: %ci%n:id: %H%n:author: %n :name: %an%n :email: %ae%n)
47
47
  commits << YAML.load(`git show -s --pretty=format:"#{format}" #{sha1}`)
48
48
  end
49
49
  end
@@ -55,7 +55,7 @@ module GitHelper
55
55
  system %Q(git commit -m "#{message}" &>/dev/null)
56
56
  end
57
57
  end
58
-
58
+
59
59
  def add_failing_commit
60
60
  add_commit "This commit will fail" do
61
61
  system %Q(echo '#{build_script(false)}' > test)
@@ -71,23 +71,23 @@ module GitHelper
71
71
  system %Q(git add test &>/dev/null)
72
72
  end
73
73
  end
74
-
74
+
75
75
  def head
76
76
  Dir.chdir(@path) do
77
77
  `git log --pretty=format:%H | head -1`.chomp
78
78
  end
79
79
  end
80
-
80
+
81
81
  def short_head
82
82
  head[0..6]
83
83
  end
84
-
84
+
85
85
  def destroy
86
86
  FileUtils.rm_rf @path if File.directory?(@path)
87
87
  end
88
-
88
+
89
89
  protected
90
-
90
+
91
91
  def build_script(successful=true)
92
92
  <<-script
93
93
  #!/bin/sh
@@ -8,12 +8,12 @@ module Integrity
8
8
  %input.text#textfile_notifier_file{ :name => "notifiers[Textfile][file]", :type => "text", :value => config["file"] }
9
9
  haml
10
10
  end
11
-
11
+
12
12
  def initialize(build, config={})
13
13
  super
14
14
  @file = @config["file"]
15
15
  end
16
-
16
+
17
17
  def deliver!
18
18
  File.open(@file, "a") do |f|
19
19
  f.puts "=== #{short_message} ==="
@@ -23,4 +23,4 @@ module Integrity
23
23
  end
24
24
  end
25
25
  end
26
- end
26
+ end
@@ -2,4 +2,3 @@ require File.dirname(__FILE__) + "/expectations/be_a"
2
2
  require File.dirname(__FILE__) + "/expectations/change"
3
3
  require File.dirname(__FILE__) + "/expectations/have"
4
4
  require File.dirname(__FILE__) + "/expectations/predicates"
5
- require File.dirname(__FILE__) + "/expectations/have_tag"
@@ -4,20 +4,20 @@ module Matchy::Expectations
4
4
  @receiver = receiver
5
5
  @receiver.is_a?(@expected)
6
6
  end
7
-
7
+
8
8
  def failure_message
9
9
  "Expected #{@receiver.inspect} to be a #{@expected.inspect}."
10
10
  end
11
-
11
+
12
12
  def negative_failure_message
13
13
  "Expected #{@receiver.inspect} to not be a #{@expected.inspect}."
14
14
  end
15
15
  end
16
-
16
+
17
17
  module TestCaseExtensions
18
18
  def be_a(obj)
19
19
  Matchy::Expectations::BeAExpectation.new(obj, self)
20
20
  end
21
21
  alias :be_an :be_a
22
22
  end
23
- end
23
+ end
@@ -10,16 +10,16 @@ module Matchy::Expectations
10
10
 
11
11
  def matches?(event_proc)
12
12
  raise_block_syntax_error if block_given?
13
-
13
+
14
14
  @before = evaluate_value_proc
15
15
  event_proc.call
16
16
  @after = evaluate_value_proc
17
-
17
+
18
18
  return false if @from unless @from == @before
19
19
  return false if @to unless @to == @after
20
20
  return (@before + @amount == @after) if @amount
21
21
  return ((@after - @before) >= @minimum) if @minimum
22
- return ((@after - @before) <= @maximum) if @maximum
22
+ return ((@after - @before) <= @maximum) if @maximum
23
23
  return @before != @after
24
24
  end
25
25
 
@@ -68,7 +68,7 @@ module Matchy::Expectations
68
68
  def by_at_most(maximum)
69
69
  @maximum = maximum
70
70
  self
71
- end
71
+ end
72
72
 
73
73
  def to(to)
74
74
  @to = to
@@ -87,4 +87,4 @@ module Matchy::Expectations
87
87
  Matchy::Expectations::ChangeExpectation.new(receiver, message, self, &block)
88
88
  end
89
89
  end
90
- end
90
+ end
@@ -87,19 +87,19 @@ EOF
87
87
  end
88
88
  end
89
89
 
90
-
90
+
91
91
  module TestCaseExtensions
92
92
  def have(n)
93
93
  HaveExpectation.new(n, :exactly, self)
94
94
  end
95
95
  alias :have_exactly :have
96
-
96
+
97
97
  def have_at_least(n)
98
98
  HaveExpectation.new(n, :at_least, self)
99
99
  end
100
-
100
+
101
101
  def have_at_most(n)
102
102
  HaveExpectation.new(n, :at_most, self)
103
103
  end
104
104
  end
105
- end
105
+ end
@@ -5,12 +5,12 @@ module Matchy::Expectations
5
5
  @predicate = predicate
6
6
  @arguments = arguments
7
7
  end
8
-
8
+
9
9
  def matches?(receiver)
10
10
  @receiver = receiver
11
11
  @receiver.send("#{@predicate}?", *@arguments)
12
12
  end
13
-
13
+
14
14
  def failure_message
15
15
  message = "Expected #{@receiver.inspect} to be #{@predicate}"
16
16
  message << " with #{@arguments.map {|e| e.inspect }.join(", ")}" unless @arguments.empty?
@@ -23,7 +23,7 @@ module Matchy::Expectations
23
23
  message
24
24
  end
25
25
  end
26
-
26
+
27
27
  module TestCaseExtensions
28
28
  def method_missing(method, *args, &block)
29
29
  if method.to_s =~ /^be_(.*)/
@@ -34,4 +34,4 @@ module Matchy::Expectations
34
34
  end
35
35
  end
36
36
  end
37
- end
37
+ end
@@ -1,5 +1,4 @@
1
- require 'rubygems'
2
- require 'dm-sweatshop'
1
+ require "dm-sweatshop"
3
2
 
4
3
  include DataMapper::Sweatshop::Unique
5
4
 
@@ -9,16 +8,6 @@ class Array
9
8
  end
10
9
  end
11
10
 
12
- def commit_metadata
13
- meta_data = <<-EOS
14
- ---
15
- :author: #{/\w+ \w+ <\w+@example.org>/.gen}
16
- :message: >-
17
- #{/\w+/.gen}
18
- :date: #{unique {|i| Time.mktime(2008, 12, 15, 18, (59 - i) % 60) }}
19
- EOS
20
- end
21
-
22
11
  def create_notifier!(name)
23
12
  klass = Class.new(Integrity::Notifier::Base) do
24
13
  def self.to_haml; ""; end
@@ -51,19 +40,56 @@ end
51
40
 
52
41
  Integrity::Project.fixture(:my_test_project) do
53
42
  { :name => "My Test Project",
54
- :uri => Integrity.root / "my-test-project",
43
+ :uri => File.dirname(__FILE__) + "/../../",
55
44
  :branch => "master",
56
45
  :command => "./test",
57
46
  :public => true,
58
47
  :building => false }
59
48
  end
60
49
 
50
+ Integrity::Commit.fixture do
51
+ project = Integrity::Project.first || Integrity::Project.gen
52
+
53
+ { :identifier => Digest::SHA1.hexdigest(/[:paragraph:]/.gen),
54
+ :message => /[:sentence:]/.gen,
55
+ :author => /\w+ \w+ <\w+@example.org>/.gen,
56
+ :committed_at => unique {|i| Time.mktime(2008, 12, 15, 18, (59 - i) % 60) },
57
+ :project_id => project.id }
58
+ end
59
+
60
+ Integrity::Commit.fixture(:successful) do
61
+ Integrity::Commit.generate_attributes.update(:build => Integrity::Build.gen(:successful))
62
+ end
63
+
64
+ Integrity::Commit.fixture(:failed) do
65
+ Integrity::Commit.generate_attributes.update(:build => Integrity::Build.gen(:failed))
66
+ end
67
+
68
+ Integrity::Commit.fixture(:pending) do
69
+ Integrity::Commit.generate_attributes.update(:build => Integrity::Build.gen(:pending))
70
+ end
71
+
61
72
  Integrity::Build.fixture do
62
- { :output => /[:paragraph:]/.gen,
63
- :successful => true,
64
- :created_at => unique {|i| Time.mktime(2008, 12, 15, 18, (59 - i) % 60) },
65
- :commit_identifier => Digest::SHA1.hexdigest(/[:paragraph:]/.gen),
66
- :commit_metadata => commit_metadata }
73
+ commit = Integrity::Commit.first || Integrity::Commit.gen
74
+
75
+ { :output => /[:paragraph:]/.gen,
76
+ :successful => true,
77
+ :started_at => unique {|i| Time.mktime(2008, 12, 15, 18, i % 60) },
78
+ :created_at => unique {|i| Time.mktime(2008, 12, 15, 18, i % 60) },
79
+ :completed_at => unique {|i| Time.mktime(2008, 12, 15, 18, i % 60) },
80
+ :commit_id => commit.id }
81
+ end
82
+
83
+ Integrity::Build.fixture(:successful) do
84
+ Integrity::Build.generate_attributes.update(:successful => true)
85
+ end
86
+
87
+ Integrity::Build.fixture(:failed) do
88
+ Integrity::Build.generate_attributes.update(:successful => false)
89
+ end
90
+
91
+ Integrity::Build.fixture(:pending) do
92
+ Integrity::Build.generate_attributes.update(:successful => nil, :started_at => nil, :completed_at => nil)
67
93
  end
68
94
 
69
95
  Integrity::Notifier.fixture(:irc) do
@@ -0,0 +1,44 @@
1
+ CREATE TABLE "integrity_builds" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "output" TEXT NOT NULL DEFAULT '', "successful" BOOLEAN NOT NULL DEFAULT 'f', "commit_identifier" VARCHAR(50) NOT NULL, "commit_metadata" TEXT NOT NULL, "created_at" DATETIME, "updated_at" DATETIME, "project_id" INTEGER);
2
+ INSERT INTO "integrity_builds" VALUES(1,'rake aborted!
3
+ Don''t know how to build task ''default''
4
+ /home/simon/.gems/gems/rake-0.8.3/lib/rake.rb:1706:in `[]''
5
+ (See full trace by running task with --trace)
6
+ (in /home/simon/bar/builds/sr-shout-bot-master)
7
+ ','f','348e9e27fa72645518fc539b77f1c37fcc20ab11','---
8
+ :message: had to allow for registration time
9
+ :date: 2009-01-04 06:19:30 +0800
10
+ :author: syd <syd@teh.magicha.us>
11
+ ','2009-02-17T19:48:31+01:00','2009-02-17T19:48:31+01:00',1);
12
+ INSERT INTO "integrity_builds" VALUES(2,'....*...........
13
+
14
+ Pending:
15
+ ShoutBot When using Shouter.shout passes given block to join (TODO)
16
+ Called from shout-bot.rb:113
17
+
18
+ Finished in 10.222458 seconds
19
+
20
+ 16 examples, 0 failures, 1 pending
21
+ ','t','348e9e27fa72645518fc539b77f1c37fcc20ab11','---
22
+ :message: had to allow for registration time
23
+ :date: 2009-01-04 06:19:30 +0800
24
+ :author: syd <syd@teh.magicha.us>
25
+ ','2009-02-17T19:49:05+01:00','2009-02-17T19:49:05+01:00',1);
26
+ INSERT INTO "integrity_builds" VALUES(3,'(in /home/simon/bar/builds/sinatra-sinatra-master)
27
+ Loaded suite /home/simon/.gems/gems/rake-0.8.3/lib/rake/rake_test_loader
28
+ Started
29
+ .......................................................................................................................................................................................................................................
30
+ Finished in 1.097704 seconds.
31
+
32
+ 231 tests, 437 assertions, 0 failures, 0 errors
33
+ ','t','a2f5803ec642c43ece86ad96676c45f44fe3746e','---
34
+ :message: Allow dot in named param capture [#153]
35
+ :date: 2009-02-17 09:32:58 -0800
36
+ :author: Ryan Tomayko <rtomayko@gmail.com>
37
+ ','2009-02-17T19:50:11+01:00','2009-02-17T19:50:11+01:00',2);
38
+ DELETE FROM sqlite_sequence;
39
+ INSERT INTO "sqlite_sequence" VALUES('integrity_projects',2);
40
+ INSERT INTO "sqlite_sequence" VALUES('integrity_builds',3);
41
+ CREATE TABLE "integrity_notifiers" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50) NOT NULL, "config" TEXT NOT NULL, "project_id" INTEGER);
42
+ CREATE TABLE "integrity_projects" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50) NOT NULL, "permalink" VARCHAR(50), "uri" VARCHAR(255) NOT NULL, "branch" VARCHAR(50) NOT NULL DEFAULT 'master', "command" VARCHAR(255) NOT NULL DEFAULT 'rake', "public" BOOLEAN DEFAULT 't', "building" BOOLEAN DEFAULT 'f', "created_at" DATETIME, "updated_at" DATETIME);
43
+ INSERT INTO "integrity_projects" VALUES(1,'Shout Bot','shout-bot','git://github.com/sr/shout-bot.git','master','ruby shout-bot.rb','t','f','2009-02-17T19:48:23+01:00','2009-02-17T19:49:05+01:00');
44
+ INSERT INTO "integrity_projects" VALUES(2,'Sinatra','sinatra','git://github.com/sinatra/sinatra.git','master','rake compat test','t','f','2009-02-17T19:49:48+01:00','2009-02-17T19:50:22+01:00');
@@ -0,0 +1,51 @@
1
+ require File.dirname(__FILE__) + '/../helpers'
2
+
3
+ class BuildTest < Test::Unit::TestCase
4
+ before(:each) do
5
+ RR.reset
6
+ end
7
+
8
+ specify "fixture is valid and can be saved" do
9
+ lambda do
10
+ build = Build.gen
11
+ build.save
12
+
13
+ build.should be_valid
14
+ end.should change(Build, :count).by(1)
15
+ end
16
+
17
+ describe "Properties" do
18
+ before(:each) do
19
+ @build = Build.gen
20
+ end
21
+
22
+ it "captures the build's STDOUT/STDERR" do
23
+ @build.output.should_not be_blank
24
+ end
25
+
26
+ it "knows if it failed or not" do
27
+ @build.successful = true
28
+ @build.should be_successful
29
+ @build.successful = false
30
+ @build.should be_failed
31
+ end
32
+
33
+ it "knows it's status" do
34
+ @build.successful = true
35
+ @build.status.should be(:success)
36
+ @build.successful = false
37
+ @build.status.should be(:failed)
38
+ end
39
+ end
40
+
41
+ describe "Pending builds" do
42
+ before(:each) do
43
+ 3.of { Build.gen(:started_at => nil) }
44
+ 2.of { Build.gen(:started_at => Time.mktime(2009, 1, 17, 23, 18)) }
45
+ end
46
+
47
+ it "finds builds that need to be built" do
48
+ Build.should have(3).pending
49
+ end
50
+ end
51
+ end