integrity 0.1.8 → 0.1.9.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.
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
data/README.markdown CHANGED
@@ -8,6 +8,13 @@ Integrity
8
8
  * Join us on [#integrity][irc-channel] for ideas, help, patches or something
9
9
  * Get the code on [GitHub][repo]
10
10
 
11
+ Try it!
12
+ -------
13
+
14
+ $ git clone git://github.com/foca/integrity.git
15
+ $ rake launch
16
+ # Navigate to <http://0.0.0.0:4567>
17
+
11
18
  Thanks
12
19
  ------
13
20
 
data/Rakefile CHANGED
@@ -2,14 +2,37 @@ require "rake/testtask"
2
2
  require "rake/clean"
3
3
  require "rcov/rcovtask"
4
4
 
5
- require File.dirname(__FILE__) + "/lib/integrity"
5
+ begin
6
+ require "metric_fu"
7
+ rescue LoadError
8
+ end
9
+
10
+ desc "Default: run all tests"
11
+ task :default => :test
12
+
13
+ desc "Special task for running tests on <http://builder.integrityapp.com>"
14
+ task :ci do
15
+ sh "git submodule update --init"
16
+
17
+ Rake::Task["test"].invoke
6
18
 
7
- desc "Run all tests and check test coverage"
8
- task :default => "test:coverage:verify"
19
+ metrics = %w(flay flog:all reek roodi saikuro)
20
+ metrics.each { |m| Rake::Task["metrics:#{m}"].invoke }
21
+
22
+ rm_rf "/var/www/integrity-metrics"
23
+ mv "tmp/metric_fu", "/var/www/integrity-metrics"
24
+
25
+ File.open("/var/www/integrity-metrics/index.html", "w") { |f|
26
+ f << "<ul>"
27
+ metrics.map { |m| m.split(":").first }.each { |m|
28
+ f << %Q(<li><a href="/#{m}">#{m}</a></li>)
29
+ }
30
+ f << "</ul>"
31
+ }
32
+ end
9
33
 
10
34
  desc "Run tests"
11
35
  task :test => %w(test:units test:acceptance)
12
-
13
36
  namespace :test do
14
37
  Rake::TestTask.new(:units) do |t|
15
38
  t.test_files = FileList["test/unit/*_test.rb"]
@@ -19,147 +42,77 @@ namespace :test do
19
42
  t.test_files = FileList["test/acceptance/*_test.rb"]
20
43
  end
21
44
 
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
45
  desc "Install all gems on which the tests depend on"
55
46
  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'
47
+ system "gem install rr mocha dm-sweatshop ZenTest"
48
+ system "gem install -s http://gems.github.com jeremymcanally-context \
49
+ jeremymcanally-matchy jeremymcanally-pending foca-storyteller"
50
+ system "git submodule update --init"
58
51
  end
59
52
  end
60
53
 
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
54
+ desc "Launch Integrity real quick"
55
+ task :launch do
56
+ ruby "bin/integrity launch"
57
+ end
68
58
 
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
59
+ directory "dist/"
60
+ CLOBBER.include("dist")
61
+
62
+ # Load the gemspec using the same limitations as github
63
+ def spec
64
+ @spec ||=
65
+ begin
66
+ require "rubygems/specification"
67
+ data = File.read("integrity.gemspec")
68
+ spec = nil
69
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
70
+ spec
71
+ end
76
72
  end
77
73
 
78
- # tx RMT :)
79
- namespace :rubyforge do
80
- def package(ext="")
81
- "dist/integrity-#{Integrity.version}" + ext
82
- end
74
+ def package(ext="")
75
+ "dist/integrity-#{spec.version}" + ext
76
+ end
83
77
 
84
- directory "dist/"
85
- CLOBBER.include("dist")
78
+ desc "Build and install as local gem"
79
+ task :install => package('.gem') do
80
+ sh "gem install #{package('.gem')}"
81
+ end
86
82
 
87
- desc "Build packages"
88
- task :package => %w[.gem .tar.gz].map { |ext| package(ext) } << :changelog
83
+ desc "Publish the current release on Rubyforge"
84
+ task :rubyforge => ["rubyforge:gem", "rubyforge:tarball", "rubyforge:git"]
89
85
 
90
- desc "Build and install as local gem"
91
- task :install => package(".gem") do
92
- sh "gem install #{package(".gem")}"
86
+ namespace :rubyforge do
87
+ desc "Publish gem and tarball to rubyforge"
88
+ task :gem => package(".gem") do
89
+ sh "rubyforge add_release integrity integrity #{spec.version} #{package('.gem')}"
93
90
  end
94
91
 
95
- file package(".gem") => %w[dist/ integrity.gemspec] do |f|
96
- sh "gem build integrity.gemspec"
97
- mv File.basename(f.name), f.name
92
+ task :tarball => package(".tar.gz") do
93
+ sh "rubyforge add_file integrity integrity #{spec.version} #{package('.tar.gz')}"
98
94
  end
99
95
 
100
- file package('.tar.gz') => %w[dist/] do |f|
96
+ desc "Push to gitosis@rubyforge.org:integrity.git"
97
+ task :git do
98
+ sh "git push gitosis@rubyforge.org:integrity.git master"
99
+ end
100
+ end
101
+
102
+ desc "Build gem tarball into dist/"
103
+ task :package => %w(.gem .tar.gz).map { |ext| package(ext) }
104
+ namespace :package do
105
+ file package(".tar.gz") => "dist/" do |f|
101
106
  sh <<-SH
102
107
  git archive \
103
- --prefix=integrity-#{Integrity.version}/ \
108
+ --prefix=integrity-#{spec.version}/ \
104
109
  --format=tar \
105
110
  HEAD | gzip > #{f.name}
106
111
  SH
107
112
  end
108
113
 
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
114
+ file package(".gem") => "dist/" do |f|
115
+ sh "gem build integrity.gemspec"
116
+ mv File.basename(f.name), f.name
162
117
  end
163
- rescue LoadError
164
118
  end
165
-
data/config/config.ru ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + "/../lib/integrity"
3
+ require "rack/lobster"
4
+ # If you want to add any notifiers, install the gems and then require them here
5
+ # For example, to enable the Email notifier: install the gem (from github:
6
+ #
7
+ # sudo gem install -s http://gems.github.com foca-integrity-email
8
+ #
9
+ # And then uncomment the following line:
10
+ #
11
+ # require "notifier/email"
12
+
13
+ # Load configuration and initialize Integrity
14
+ Integrity.new#(File.dirname(__FILE__) + "/config.yml")
15
+ DataMapper.auto_migrate!
16
+
17
+ # You probably don't want to edit anything below
18
+ Integrity::App.set :environment, ENV["RACK_ENV"] || :production
19
+ Integrity::App.set :port, 8910
20
+ rack = proc do |env|
21
+ [200, { 'Content-Type' => 'text/html' }, "#{env['rack.session'].inspect}"]
22
+ end
23
+
24
+ map "/foo" do
25
+ run Integrity::App
26
+ end
27
+ map "/" do
28
+ run rack
29
+ end
@@ -11,21 +11,11 @@ require "integrity"
11
11
  #
12
12
  # require "notifier/email"
13
13
 
14
- # Load integrity's configuration.
15
- Integrity.config = File.expand_path("./config.yml")
14
+ # Load configuration and initialize Integrity
15
+ Integrity.new(File.dirname(__FILE__) + "/config.yml")
16
16
 
17
- #######################################################################
18
- ## ##
19
- ## == DON'T EDIT ANYTHING BELOW UNLESS YOU KNOW WHAT YOU'RE DOING == ##
20
- ## ##
21
- #######################################################################
22
- require Integrity.root / "app"
17
+ # You probably don't want to edit anything below
18
+ Integrity::App.set :environment, ENV["RACK_ENV"] || :production
19
+ Integrity::App.set :port, 8910
23
20
 
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
21
+ run Integrity::App
@@ -4,24 +4,27 @@
4
4
  # http://builder.integrityapp.com
5
5
  :base_uri: http://integrity.domain.tld
6
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).
7
+ # This should be a complete connection string to your database.
8
+ #
9
+ # Examples:
10
+ # * `mysql://user:password@localhost/integrity`
11
+ # * `postgres://user:password@localhost/integrity`
12
+ # * `sqlite3:///home/integrity/db/integrity.sqlite`
13
+ #
14
+ # Note:
15
+ # * The appropriate data_objects adapter must be installed (`do_mysql`, etc)
16
+ # * You must create the `integrity` database on localhost, of course.
10
17
  :database_uri: sqlite3:///var/integrity.db
11
18
 
12
- # This is where your project's code will be checked out to. Make sure it's
19
+ # This is where your project's code will be checked out to. Make sure it's
13
20
  # writable by the user that runs Integrity.
14
21
  :export_directory: /path/to/scm/exports
15
22
 
16
23
  # Path to the integrity log file
17
24
  :log: /var/log/integrity.log
18
25
 
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
26
+ # Enable or disable HTTP authentication for the app. BE AWARE that if you
27
+ # disable this anyone can delete and alter projects, so do it only if your
25
28
  # app is running in a controlled environment (ie, behind your company's
26
29
  # firewall.)
27
30
  :use_basic_auth: false
@@ -29,10 +32,10 @@
29
32
  # When `use_basic_auth` is true, the admin's username for HTTP authentication.
30
33
  :admin_username: username
31
34
 
32
- # When `use_basic_auth` is true, the admin's password. Usually saved as a
35
+ # When `use_basic_auth` is true, the admin's password. Usually saved as a
33
36
  # SHA1 hash. See the next option.
34
37
  :admin_password: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
35
38
 
36
- # If this is true, then whenever we authenticate the admin user, will hash
39
+ # If this is true, then whenever we authenticate the admin user, will hash
37
40
  # it using SHA1. If not, we'll assume the provided password is in plain text.
38
41
  :hash_admin_password: true
data/config/config.yml ADDED
@@ -0,0 +1,34 @@
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://0.0.0.0:1234
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:///home/simon/tmp/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: /home/simon/tmp/integrity_exports
15
+
16
+ # Path to the integrity log file
17
+ :log: /tmp/integrity.log
18
+
19
+ # Enable or disable HTTP authentication for the app. BE AWARE that if you
20
+ # disable this anyone can delete and alter projects, so do it only if your
21
+ # app is running in a controlled environment (ie, behind your company's
22
+ # firewall.)
23
+ :use_basic_auth: false
24
+
25
+ # When `use_basic_auth` is true, the admin's username for HTTP authentication.
26
+ :admin_username: username
27
+
28
+ # When `use_basic_auth` is true, the admin's password. Usually saved as a
29
+ # SHA1 hash. See the next option.
30
+ :admin_password: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
31
+
32
+ # If this is true, then whenever we authenticate the admin user, will hash
33
+ # it using SHA1. If not, we'll assume the provided password is in plain text.
34
+ :hash_admin_password: true
data/lib/integrity.rb CHANGED
@@ -6,33 +6,36 @@ require "dm-validations"
6
6
  require "dm-types"
7
7
  require "dm-timestamps"
8
8
  require "dm-aggregates"
9
+ require "sinatra/base"
9
10
 
10
11
  require "yaml"
11
12
  require "logger"
12
13
  require "digest/sha1"
13
14
  require "timeout"
14
15
  require "ostruct"
15
- require "fileutils"
16
+ require "pathname"
16
17
 
17
18
  require "integrity/core_ext/object"
18
- require "integrity/core_ext/string"
19
19
 
20
20
  require "integrity/project"
21
+ require "integrity/author"
22
+ require "integrity/commit"
21
23
  require "integrity/build"
22
24
  require "integrity/project_builder"
23
25
  require "integrity/scm"
24
26
  require "integrity/scm/git"
25
27
  require "integrity/notifier"
28
+ require "integrity/helpers"
29
+ require "integrity/app"
26
30
 
27
31
  module Integrity
28
32
  def self.new(config_file = nil)
29
- self.config = config_file unless config_file.nil?
30
- DataMapper.logger = self.logger if config[:log_debug_info]
33
+ self.config = YAML.load_file(config_file) unless config_file.nil?
31
34
  DataMapper.setup(:default, config[:database_uri])
32
35
  end
33
36
 
34
37
  def self.root
35
- File.expand_path(File.join(File.dirname(__FILE__), ".."))
38
+ Pathname.new(File.dirname(__FILE__)).join("..").expand_path
36
39
  end
37
40
 
38
41
  def self.default_configuration
@@ -42,15 +45,15 @@ module Integrity
42
45
  :base_uri => "http://localhost:8910",
43
46
  :use_basic_auth => false,
44
47
  :build_all_commits => true,
45
- :log_debug_info => false }
48
+ :log_debug_info => false }.dup
46
49
  end
47
50
 
48
51
  def self.config
49
52
  @config ||= default_configuration
50
53
  end
51
54
 
52
- def self.config=(file)
53
- @config = default_configuration.merge(YAML.load_file(file))
55
+ def self.config=(options)
56
+ @config = default_configuration.merge(options)
54
57
  end
55
58
 
56
59
  def self.log(message, &block)
@@ -64,14 +67,11 @@ module Integrity
64
67
  end
65
68
 
66
69
  def self.version
67
- @version ||= begin
68
- file = YAML.load_file(Integrity.root / "VERSION.yml")
69
- "#{file['major']}.#{file['minor']}.#{file['patch']}"
70
- end
70
+ YAML.load_file(File.dirname(__FILE__) + "/../VERSION.yml").
71
+ values.join(".")
71
72
  end
72
73
 
73
74
  private
74
-
75
75
  class LogFormatter < Logger::Formatter
76
76
  def call(severity, time, progname, msg)
77
77
  time.strftime("[%H:%M:%S] ") + msg2str(msg) + "\n"