alphasights-integrity 0.1.9.8 → 0.1.10

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 (47) hide show
  1. data/.gitignore +0 -1
  2. data/AUTHORS +35 -0
  3. data/CHANGES +21 -3
  4. data/LICENSE +20 -0
  5. data/README.md +10 -52
  6. data/config/config.sample.yml +4 -0
  7. data/config/heroku/.gems +1 -1
  8. data/config/heroku/integrity-config.rb +1 -0
  9. data/integrity.gemspec +6 -11
  10. data/lib/integrity.rb +4 -4
  11. data/lib/integrity/app.rb +1 -1
  12. data/lib/integrity/build.rb +8 -18
  13. data/lib/integrity/commit.rb +13 -8
  14. data/lib/integrity/helpers/pretty_output.rb +8 -0
  15. data/lib/integrity/helpers/urls.rb +3 -3
  16. data/lib/integrity/installer.rb +20 -11
  17. data/lib/integrity/migrations.rb +43 -13
  18. data/lib/integrity/notifier.rb +1 -1
  19. data/lib/integrity/notifier/base.rb +2 -2
  20. data/lib/integrity/notifier/test/fixtures.rb +12 -6
  21. data/lib/integrity/project.rb +34 -38
  22. data/lib/integrity/project/push.rb +4 -5
  23. data/test/acceptance/api_test.rb +1 -1
  24. data/test/acceptance/browse_project_test.rb +12 -6
  25. data/test/acceptance/build_notifications_test.rb +26 -2
  26. data/test/acceptance/installer_test.rb +1 -1
  27. data/test/acceptance/manual_build_project_test.rb +2 -2
  28. data/test/acceptance/notifier_test_test.rb +37 -0
  29. data/test/acceptance/stylesheet_test.rb +2 -1
  30. data/test/helpers.rb +3 -2
  31. data/test/unit/build_test.rb +11 -46
  32. data/test/unit/commit_test.rb +37 -28
  33. data/test/unit/helpers_test.rb +16 -0
  34. data/test/unit/migrations_test.rb +6 -4
  35. data/test/unit/project_test.rb +64 -95
  36. data/views/_commit_info.haml +6 -10
  37. data/views/home.haml +3 -2
  38. data/views/integrity.sass +24 -4
  39. data/views/project.haml +5 -4
  40. metadata +6 -20
  41. data/lib/integrity/helpers/gravatar.rb +0 -16
  42. data/lib/integrity/project_builder.rb +0 -56
  43. data/lib/integrity/scm.rb +0 -19
  44. data/lib/integrity/scm/git.rb +0 -84
  45. data/lib/integrity/scm/git/uri.rb +0 -57
  46. data/test/unit/project_builder_test.rb +0 -118
  47. data/test/unit/scm_test.rb +0 -54
@@ -6,6 +6,11 @@ module Integrity
6
6
  class Installer < Thor
7
7
  include FileUtils
8
8
 
9
+ def self.database_path
10
+ File.join(ENV["HOME"], ".integrity.sqlite3")
11
+ end
12
+ private_class_method :database_path
13
+
9
14
  desc "install [PATH]",
10
15
  "Copy template files to PATH for desired deployement strategy
11
16
  (either Thin, Passenger or Heroku). Next, go there and edit them."
@@ -37,22 +42,25 @@ module Integrity
37
42
  end
38
43
 
39
44
  desc "launch [CONFIG]",
40
- "Launch Integrity real quick."
41
- method_options :config => :optional, :port => 4567
45
+ "Launch Integrity real quick. Database is saved in #{database_path}."
46
+ method_options :config => :optional, :port => :optional
42
47
  def launch
43
48
  require "thin"
44
49
  require "do_sqlite3"
45
50
 
46
- File.file?(options[:config].to_s) ?
47
- Integrity.new(options[:config]) : Integrity.new
48
- Integrity.config[:base_uri] = "http://0.0.0.0:#{options[:port]}"
51
+ port = options[:port] || 4567
52
+
53
+ config = { :database_uri => "sqlite3://#{ENV["HOME"]}/.integrity.db",
54
+ :base_uri => "http://0.0.0.0:#{options[:port]}",
55
+ :export_directory => "/tmp/integrity-exports" }
56
+ config.merge!(YAML.load_file(options[:config])) if options[:config]
49
57
 
50
- DataMapper.auto_migrate!
58
+ migrate_db(config)
51
59
 
52
- Thin::Server.start("0.0.0.0", options[:port], Integrity::App)
60
+ Thin::Server.start("0.0.0.0", port, Integrity::App)
53
61
  rescue LoadError => boom
54
- missing_dependency = boom.message.split("--").last.lstrip
55
- puts "Please install #{missing_dependency} to launch Integrity"
62
+ $stderr << "Make sure thin and do_sqlite3 are insatalled\n\n"
63
+ raise
56
64
  end
57
65
 
58
66
  private
@@ -101,8 +109,9 @@ Your Integrity install is ready to be deployed onto Heroku. Next steps:
101
109
 
102
110
  1. git init && git add . && git commit -am "Initial import"
103
111
  2. heroku create
104
- 3. git push heroku master
105
- 4. heroku rake db:migrate
112
+ 3. Add heroku-given domain as :base_uri in integrity-config.rb
113
+ 4. git push heroku master
114
+ 5. heroku rake db:migrate
106
115
  EOF
107
116
  end
108
117
 
@@ -39,9 +39,9 @@ module Integrity
39
39
  column :id, Integer, :serial => true
40
40
  column :name, String, :nullable => false
41
41
  column :permalink, String
42
- column :uri, Text, :nullable => false
42
+ column :uri, URI, :nullable => false
43
43
  column :branch, String, :nullable => false, :default => "master"
44
- column :command, Text, :nullable => false, :default => "rake"
44
+ column :command, String, :nullable => false, :default => "rake"
45
45
  column :public, Boolean, :default => true
46
46
  column :building, Boolean, :default => false
47
47
  column :created_at, DateTime
@@ -83,12 +83,12 @@ module Integrity
83
83
 
84
84
  create_table :integrity_commits do
85
85
  column :id, Integer, :serial => true
86
- column :identifier, String, :size => 40, :nullable => false
87
- column :message, Text, :nullable => true
88
- column :author, String, :nullable => true, :length => 255
86
+ column :identifier, String, :nullable => false
87
+ column :message, String, :nullable => false, :length => 255
88
+ column :author, String, :nullable => false, :length => 255
89
89
  column :committed_at, DateTime, :nullable => false
90
- column :created_at, DateTime
91
- column :updated_at, DateTime
90
+ column :created_at, DateTime
91
+ column :updated_at, DateTime
92
92
 
93
93
  column :project_id, Integer
94
94
  end
@@ -124,7 +124,6 @@ module Integrity
124
124
  commit = Commit.create(:identifier => build.commit_identifier,
125
125
  :message => build.commit_metadata[:message],
126
126
  :author => build.commit_metadata[:author],
127
- :url => build.commit_metadata[:url],
128
127
  :committed_at => build.commit_metadata[:date],
129
128
  :project_id => build.project_id)
130
129
  end
@@ -149,14 +148,45 @@ module Integrity
149
148
  end
150
149
  end
151
150
 
152
- migration 4, :add_url_to_commits do
151
+ migration 4, :add_commit_uri_column do
152
+ up do
153
+ modify_table(:integrity_commits) { add_column :uri, URI }
154
+ end
155
+
156
+ down do
157
+ #modify_table(:integrity_commits) { add_column :changeset, String }
158
+ end
159
+ end
160
+ end
161
+
162
+ migration 5, :nil_commit_metadata do
153
163
  up do
154
- modify_table(:integrity_commits) { add_column :url, Text }
164
+ all_commits = Commit.all.collect { |c| c.dup }
165
+ drop_table :integrity_commits
166
+
167
+ create_table :integrity_commits do
168
+ column :id, Integer, :serial => true
169
+ column :identifier, String, :nullable => false
170
+ column :message, String, :nullable => true, :length => 255
171
+ column :author, String, :nullable => true, :length => 255
172
+ column :committed_at, DateTime, :nullable => false
173
+ column :created_at, DateTime
174
+ column :updated_at, DateTime
175
+
176
+ column :project_id, Integer
177
+ end
178
+
179
+ all_commits.each { |commit| Commit.create(commit.attributes) }
155
180
  end
181
+ end
156
182
 
157
- down do
158
- #modify_table(:integrity_commits) { drop_column :url }
183
+ =begin
184
+ TODO: drop the :building column of the project table
185
+
186
+ migration 5, :remove_building_column do
187
+ up do
188
+ modify_table(:integrity_projects) { drop_column :building }
159
189
  end
160
190
  end
161
- end
191
+ =end
162
192
  end
@@ -33,7 +33,7 @@ module Integrity
33
33
  private_class_method :valid?
34
34
 
35
35
  def notify_of_build(build)
36
- to_const.notify_of_build(build, config)
36
+ to_const.notify_of_build(build, config) if to_const
37
37
  end
38
38
 
39
39
  private
@@ -2,10 +2,10 @@ module Integrity
2
2
  class Notifier
3
3
  class Base
4
4
  def self.notify_of_build(build, config)
5
- Integrity.log "Notifying of build #{build.commit.short_identifier} using the #{self} notifier"
5
+ Integrity.log "Notifying of build #{build.commit.short_identifier} using the #{to_s} notifier"
6
6
  Timeout.timeout(8) { new(build.commit, config).deliver! }
7
7
  rescue Timeout::Error
8
- Integrity.log "#{self} notifier timed out"
8
+ Integrity.log "#{notifier.name} notifier timed out"
9
9
  false
10
10
  end
11
11
 
@@ -24,8 +24,7 @@ Integrity::Project.fixture do
24
24
  :uri => "git://github.com/#{/\w+/.gen}/#{name}.git",
25
25
  :branch => ["master", "test-refactoring", "lh-34"].pick,
26
26
  :command => ["rake", "make", "ant -buildfile test.xml"].pick,
27
- :public => [true, false].pick,
28
- :building => [true, false].pick }
27
+ :public => [true, false].pick }
29
28
  end
30
29
 
31
30
  Integrity::Project.fixture(:integrity) do
@@ -33,8 +32,7 @@ Integrity::Project.fixture(:integrity) do
33
32
  :uri => "git://github.com/foca/integrity.git",
34
33
  :branch => "master",
35
34
  :command => "rake",
36
- :public => true,
37
- :building => false }
35
+ :public => true }
38
36
  end
39
37
 
40
38
  Integrity::Project.fixture(:my_test_project) do
@@ -42,8 +40,7 @@ Integrity::Project.fixture(:my_test_project) do
42
40
  :uri => File.dirname(__FILE__) + "/../../",
43
41
  :branch => "master",
44
42
  :command => "./test",
45
- :public => true,
46
- :building => false }
43
+ :public => true }
47
44
  end
48
45
 
49
46
  Integrity::Commit.fixture do
@@ -68,6 +65,10 @@ Integrity::Commit.fixture(:pending) do
68
65
  Integrity::Commit.generate_attributes.update(:build => Integrity::Build.gen(:pending))
69
66
  end
70
67
 
68
+ Integrity::Commit.fixture(:building) do
69
+ Integrity::Commit.generate_attributes.update(:build => Integrity::Build.gen(:building))
70
+ end
71
+
71
72
  Integrity::Build.fixture do
72
73
  commit = Integrity::Commit.first || Integrity::Commit.gen
73
74
 
@@ -91,6 +92,11 @@ Integrity::Build.fixture(:pending) do
91
92
  Integrity::Build.generate_attributes.update(:successful => nil, :started_at => nil, :completed_at => nil)
92
93
  end
93
94
 
95
+ Integrity::Build.fixture(:building) do
96
+ Integrity::Build.generate_attributes.update(:completed_at => nil,
97
+ :successful => nil, :output => nil)
98
+ end
99
+
94
100
  Integrity::Notifier.fixture(:irc) do
95
101
  create_notifier! "IRC"
96
102
 
@@ -4,33 +4,50 @@ require "integrity/project/push"
4
4
  module Integrity
5
5
  class Project
6
6
  include DataMapper::Resource
7
+ include Bob::Buildable
7
8
  include Notifiers, Push
8
9
 
9
- property :id, Integer, :serial => true
10
+ property :id, Serial
10
11
  property :name, String, :nullable => false
11
12
  property :permalink, String
12
13
  property :uri, URI, :nullable => false, :length => 255
13
14
  property :branch, String, :nullable => false, :default => "master"
14
- property :command, Text, :nullable => false, :default => "rake"
15
+ property :command, String, :nullable => false, :length => 255, :default => "rake"
15
16
  property :public, Boolean, :default => true
16
- property :building, Boolean, :default => false
17
- property :created_at, DateTime
18
- property :updated_at, DateTime
19
17
 
20
- has n, :commits, :class_name => "Integrity::Commit",
21
- :order => [:committed_at.desc]
18
+ timestamps :at
19
+
20
+ default_scope(:default).update(:order => [:name.asc])
21
+
22
+ has n, :commits, :class_name => "Integrity::Commit"
22
23
  has n, :notifiers, :class_name => "Integrity::Notifier"
23
24
 
24
25
  before :save, :set_permalink
25
- before :destroy, :delete_working_directory
26
+
27
+ before :destroy do
28
+ commits.destroy!
29
+ end
26
30
 
27
31
  validates_is_unique :name
28
32
 
29
- def build(commit_identifier="HEAD")
30
- commit_identifier = head_of_remote_repo if commit_identifier == "HEAD"
31
- commit = find_or_create_commit_with_identifier(commit_identifier)
33
+ def kind
34
+ :git
35
+ end
36
+
37
+ alias_method :build_script, :command
38
+
39
+ def start_building(commit_id, commit_info)
40
+ @commit = commits.first_or_create({:identifier => commit_id},
41
+ commit_info.update(:project_id => id))
42
+ @build = Build.new(:started_at => Time.now)
43
+ @commit.update_attributes(:build => @build)
44
+ end
32
45
 
33
- Build.queue(commit)
46
+ def finish_building(commit_id, status, output)
47
+ @build.update_attributes(
48
+ :successful => status, :output => output,
49
+ :completed_at => Time.now) if @build
50
+ enabled_notifiers.each { |notifier| notifier.notify_of_build(@build) }
34
51
  end
35
52
 
36
53
  def last_commit
@@ -42,8 +59,12 @@ module Integrity
42
59
  tap {|commits| commits.shift }
43
60
  end
44
61
 
62
+ def building?
63
+ commits.any? { |c| c.building? }
64
+ end
65
+
45
66
  def status
46
- last_commit && last_commit.status
67
+ last_commit ? last_commit.status : :blank
47
68
  end
48
69
 
49
70
  def human_readable_status
@@ -58,24 +79,6 @@ module Integrity
58
79
  end
59
80
 
60
81
  private
61
- def find_or_create_commit_with_identifier(identifier)
62
- # We abuse +committed_at+ here setting it to Time.now because we use it
63
- # to sort (for last_commit and previous_commits). I don't like this
64
- # very much, but for now it's the only solution I can find.
65
- #
66
- # This also creates a dependency, as now we *always* have to update the
67
- # +committed_at+ field after building to ensure the date is correct :(
68
- #
69
- # This might also make your commit listings a little jumpy, if some
70
- # commits change place every time a build finishes =\
71
- commits.first_or_create({:identifier => identifier, :project_id => id},
72
- :committed_at => Time.now)
73
- end
74
-
75
- def head_of_remote_repo
76
- SCM.new(uri, branch).head
77
- end
78
-
79
82
  def set_permalink
80
83
  attribute_set(:permalink, (name || "").downcase.
81
84
  gsub(/'s/, "s").
@@ -83,12 +86,5 @@ module Integrity
83
86
  gsub(/[^a-z0-9]+/, "-").
84
87
  gsub(/-*$/, ""))
85
88
  end
86
-
87
- def delete_working_directory
88
- commits.destroy!
89
- ProjectBuilder.delete_working_directory(self)
90
- rescue SCM::SCMUnknownError => error
91
- Integrity.log "Problem while trying to deleting code: #{error}"
92
- end
93
89
  end
94
90
  end
@@ -13,9 +13,8 @@ module Integrity
13
13
  end
14
14
 
15
15
  commits.each { |commit_data|
16
- commit = commit_from(commit_data)
17
- commit.create
18
- build(commit.identifier)
16
+ commit_from(commit_data).create
17
+ build(commit_data["id"])
19
18
  }
20
19
  end
21
20
 
@@ -24,8 +23,8 @@ module Integrity
24
23
  commits.new(:identifier => data["id"],
25
24
  :author => "#{data["author"]["name"]} <#{data["author"]["email"]}>",
26
25
  :message => data["message"],
27
- :url => data["url"],
28
- :committed_at => data["timestamp"])
26
+ :committed_at => data["timestamp"],
27
+ :uri => data["url"])
29
28
  end
30
29
 
31
30
  def valid_payload?(payload)
@@ -33,7 +33,7 @@ class ApiTest < Test::Unit::AcceptanceTestCase
33
33
  assert_contain("No builds for this project")
34
34
  end
35
35
 
36
- it "receiving a build request with build_all_commits *enabled* builds all commits, most recent first" do
36
+ scenario "receiving a build request with build_all_commits *enabled* builds all commits, most recent first" do
37
37
  Integrity.config[:build_all_commits] = true
38
38
 
39
39
  repo = git_repo(:my_test_project) # initial commit && successful commit
@@ -30,15 +30,21 @@ class BrowsePublicProjectsTest < Test::Unit::AcceptanceTestCase
30
30
  scenario "a user can see the projects status on the home page" do
31
31
  integrity = Project.gen(:integrity, :commits => 3.of { Commit.gen(:successful) })
32
32
  test = Project.gen(:my_test_project, :commits => 2.of { Commit.gen(:failed) })
33
- no_build = Project.gen(:public => true, :building => false)
34
- building = Project.gen(:public => true, :building => true)
33
+ no_build = Project.gen(:name => "none yet", :public => true)
34
+ building = Project.gen(:name => "building", :public => true,
35
+ :commits => 1.of{ Commit.gen(:building) })
35
36
 
36
37
  visit "/"
37
38
 
38
- assert_contain("Built #{integrity.last_commit.short_identifier} successfully")
39
- assert_contain("Built #{test.last_commit.short_identifier} and failed")
40
- assert_contain("Never built yet")
41
- assert_contain("Building!")
39
+ assert_have_tag("li[@class~=success]",
40
+ :content => "Built #{integrity.last_commit.short_identifier} successfully")
41
+
42
+ assert_have_tag("li[@class~=failed]",
43
+ :content => "Built #{test.last_commit.short_identifier} and failed")
44
+
45
+ assert_have_tag("li[@class~=blank]", :content => "Never built yet")
46
+
47
+ assert_have_tag("li[@class~=building]", :content => "Building!")
42
48
  end
43
49
 
44
50
  scenario "a user clicking through a link on the home page for a public project arrives at the project page" do
@@ -1,6 +1,5 @@
1
1
  require File.dirname(__FILE__) + "/../helpers/acceptance"
2
2
  require "helpers/acceptance/notifier_helper"
3
- require "helpers/acceptance/textfile_notifier"
4
3
  require "helpers/acceptance/email_notifier"
5
4
 
6
5
  class BuildNotificationsTest < Test::Unit::AcceptanceTestCase
@@ -14,7 +13,11 @@ class BuildNotificationsTest < Test::Unit::AcceptanceTestCase
14
13
 
15
14
  before(:each) do
16
15
  # This is needed before any available notifier is unset
17
- # in the global #before
16
+ # in the global #before.
17
+ # But, we need the reload this one because we remove_const
18
+ # it in a test case. Sigh.
19
+ load "helpers/acceptance/textfile_notifier.rb"
20
+
18
21
  Notifier.register(Integrity::Notifier::Textfile)
19
22
  Notifier.register(Integrity::Notifier::Email)
20
23
  end
@@ -79,6 +82,27 @@ class BuildNotificationsTest < Test::Unit::AcceptanceTestCase
79
82
  assert_have_email_notifier
80
83
  end
81
84
 
85
+ scenario "an admin enables the Textfile notifier and get rid of it later" do
86
+ git_repo(:my_test_project).add_successful_commit
87
+ Project.gen(:my_test_project, :uri => git_repo(:my_test_project).path)
88
+
89
+ login_as "admin", "test"
90
+ visit "/my-test-project"
91
+
92
+ click_link "Edit Project"
93
+ check "enabled_notifiers_textfile"
94
+ fill_in "File", :with => "/tmp/textfile_notifications.txt"
95
+ click_button "Update Project"
96
+
97
+ Notifier.send(:remove_const, :Textfile)
98
+ Notifier.available.clear
99
+ rm_f "/tmp/textfile_notifications.txt"
100
+
101
+ click_button "manual build"
102
+
103
+ assert ! File.file?("/tmp/textfile_notifications.txt")
104
+ end
105
+
82
106
  scenario "an admin configures various notifiers accros multiple projects" do
83
107
  Project.first(:permalink => "integrity").should be_nil
84
108
 
@@ -70,7 +70,7 @@ class InstallerTest < Test::Unit::AcceptanceTestCase
70
70
  scenario "Installing Integrity for Heroku" do
71
71
  message = install("--heroku")
72
72
 
73
- assert_equal "integrity --version 0.1.9.0", root.join(".gems").read.chomp
73
+ assert_equal "integrity --version 0.1.9.3", root.join(".gems").read.chomp
74
74
 
75
75
  assert root.join("Rakefile").file?
76
76
  assert root.join("integrity-config.rb").file?