heidi 0.3.1 → 0.4.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 (72) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +3 -0
  3. data/README.rdoc +20 -0
  4. data/VERSION +1 -1
  5. data/bin/heidi +8 -82
  6. data/heidi.gemspec +49 -10
  7. data/lib/heidi.rb +4 -0
  8. data/lib/heidi/build.rb +42 -10
  9. data/lib/heidi/builder.rb +7 -2
  10. data/lib/heidi/hook.rb +2 -0
  11. data/lib/heidi/integrator.rb +11 -5
  12. data/lib/heidi/project.rb +37 -24
  13. data/lib/heidi/shell.rb +119 -0
  14. data/lib/heidi/tester.rb +6 -5
  15. data/lib/heidi/web.rb +65 -4
  16. data/lib/heidi/web/assets/css/bootstrap-responsive.css +643 -0
  17. data/lib/heidi/web/assets/css/bootstrap.css +3682 -0
  18. data/lib/heidi/web/{public/css/screen.css → assets/css/colors.css} +1 -75
  19. data/lib/heidi/web/assets/css/docs.css +772 -0
  20. data/lib/heidi/web/{public → assets}/images/HeidiBlue-480.png +0 -0
  21. data/lib/heidi/web/{public → assets}/images/HeidiBlue.gif +0 -0
  22. data/lib/heidi/web/{public → assets}/images/OrganisedMinds.png +0 -0
  23. data/lib/heidi/web/{public → assets}/images/heidi.jpeg +0 -0
  24. data/lib/heidi/web/assets/img/glyphicons-halflings-white.png +0 -0
  25. data/lib/heidi/web/assets/img/glyphicons-halflings.png +0 -0
  26. data/lib/heidi/web/assets/img/glyphicons/glyphicons_009_magic.png +0 -0
  27. data/lib/heidi/web/assets/img/glyphicons/glyphicons_042_group.png +0 -0
  28. data/lib/heidi/web/assets/img/glyphicons/glyphicons_079_podium.png +0 -0
  29. data/lib/heidi/web/assets/img/glyphicons/glyphicons_082_roundabout.png +0 -0
  30. data/lib/heidi/web/assets/img/glyphicons/glyphicons_155_show_thumbnails.png +0 -0
  31. data/lib/heidi/web/assets/img/glyphicons/glyphicons_163_iphone.png +0 -0
  32. data/lib/heidi/web/assets/img/glyphicons/glyphicons_214_resize_small.png +0 -0
  33. data/lib/heidi/web/assets/img/glyphicons/glyphicons_266_book_open.png +0 -0
  34. data/lib/heidi/web/assets/js/README.md +106 -0
  35. data/lib/heidi/web/assets/js/application.js +180 -0
  36. data/lib/heidi/web/assets/js/bootstrap-alert.js +94 -0
  37. data/lib/heidi/web/assets/js/bootstrap-button.js +100 -0
  38. data/lib/heidi/web/assets/js/bootstrap-carousel.js +157 -0
  39. data/lib/heidi/web/assets/js/bootstrap-collapse.js +136 -0
  40. data/lib/heidi/web/assets/js/bootstrap-dropdown.js +92 -0
  41. data/lib/heidi/web/assets/js/bootstrap-modal.js +210 -0
  42. data/lib/heidi/web/assets/js/bootstrap-popover.js +95 -0
  43. data/lib/heidi/web/assets/js/bootstrap-scrollspy.js +125 -0
  44. data/lib/heidi/web/assets/js/bootstrap-tab.js +130 -0
  45. data/lib/heidi/web/assets/js/bootstrap-tooltip.js +270 -0
  46. data/lib/heidi/web/assets/js/bootstrap-transition.js +51 -0
  47. data/lib/heidi/web/assets/js/bootstrap-typeahead.js +271 -0
  48. data/lib/heidi/web/assets/js/google-code-prettify/prettify.css +30 -0
  49. data/lib/heidi/web/assets/js/google-code-prettify/prettify.js +28 -0
  50. data/lib/heidi/web/assets/js/jquery.js +9252 -0
  51. data/lib/heidi/web/views/build.erb +40 -24
  52. data/lib/heidi/web/views/commit.erb +10 -7
  53. data/lib/heidi/web/views/config.erb +34 -18
  54. data/lib/heidi/web/views/home.erb +44 -25
  55. data/lib/heidi/web/views/layout.erb +57 -4
  56. data/lib/heidi/web/views/new_project.erb +56 -0
  57. data/lib/heidi/web/views/project.erb +114 -32
  58. data/lib/heidi/web/views/project_header.erb +20 -0
  59. data/spec/heidi/build_spec.rb +163 -2
  60. data/spec/heidi/builder_spec.rb +61 -1
  61. data/spec/heidi/hook_spec.rb +47 -1
  62. data/spec/heidi/integrator_spec.rb +96 -1
  63. data/spec/heidi/project_spec.rb +177 -2
  64. data/spec/heidi/shell_spec.rb +67 -0
  65. data/spec/heidi/web_spec.rb +78 -2
  66. data/spec/heidi_spec.rb +16 -5
  67. data/spec/spec_helper.rb +1 -1
  68. data/spec/support/01_rworld.rb +9 -0
  69. data/spec/support/mock_project.rb +39 -0
  70. data/spec/support/survivable.rb +10 -0
  71. metadata +131 -79
  72. data/spec/heidi/tester_spec.rb +0 -5
@@ -0,0 +1,20 @@
1
+ <header>
2
+ <div class="row">
3
+ <div class="span9">
4
+ <h1><%= project.name %></h1>
5
+ </div>
6
+ <div class="span3">
7
+ <ul class="nav nav-list">
8
+ <li>
9
+ <a href="/"><i class="icon-home"></i>Home</a>
10
+ </li>
11
+ <li>
12
+ <a href="/projects/<%= project.basename %>"><i class="icon-book"></i><%= project.name %></a>
13
+ </li>
14
+ <li>
15
+ <a href="/projects/<%= project.basename %>/configure"><i class="icon-cog"></i>Configure</a>
16
+ </li>
17
+ </ul>
18
+ </div>
19
+ </div>
20
+ </header>
@@ -1,5 +1,166 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Heidi::Build do
4
- pending "more tests please!"
5
- end
4
+ before(:all) do
5
+ fake_me_a_heidi
6
+
7
+ @project = @heidi[:heidi_test]
8
+ end
9
+
10
+ after(:all) do
11
+ FileUtils.remove_entry_secure @fake
12
+ end
13
+
14
+ before :each do
15
+ @build = Heidi::Build.new(@project)
16
+ end
17
+
18
+ it "should have a project" do
19
+ @build.project.should == @project
20
+ end
21
+
22
+ it "should be tied to a commit" do
23
+ @build.commit.should == @project.commit
24
+ end
25
+
26
+ it "should have a root" do
27
+ @build.root.should == File.join(@project.root, "logs", @project.commit)
28
+ end
29
+
30
+ it "should have a log root" do
31
+ @build.log_root.should == File.join(@build.root, "logs")
32
+ end
33
+
34
+ it "should have a build root" do
35
+ @build.build_root.should == File.join(@build.root, "build")
36
+ end
37
+
38
+ it "should have an author" do
39
+ @build.author.should_not be_nil
40
+ @build.date.should be_kind_of(String)
41
+ end
42
+
43
+ it "should have a date" do
44
+ @build.date.should_not be_nil
45
+ @build.date.should be_kind_of(String)
46
+ end
47
+
48
+ it "should have a time" do
49
+ @build.time.should_not be_nil
50
+ @build.time.should_not == 0
51
+ @build.time.should be_kind_of(Time)
52
+ end
53
+
54
+ it "should load hooks" do
55
+ expect { @build.load_hooks }.to change { @build.hooks }
56
+ end
57
+
58
+ it "should clean up" do
59
+ expect { @build.clean }.to change { Dir[File.join(@build.root, "**", "*")] }
60
+ end
61
+
62
+ describe "Locking" do
63
+ it "should not be locked" do
64
+ @build.should_not be_locked
65
+ end
66
+
67
+ it "should be lockable" do
68
+ @build.lock
69
+ @build.should be_locked
70
+ end
71
+
72
+ it "should be unlockable" do
73
+ @build.unlock
74
+ @build.should_not be_locked
75
+ end
76
+
77
+ it "should be block-lockable" do
78
+ @build.should_not be_locked
79
+ @build.lock do
80
+ @build.should be_locked
81
+ end
82
+ @build.should_not be_locked
83
+ end
84
+
85
+ end
86
+
87
+ describe "Logging" do
88
+ it "should have logs" do
89
+ @build.logs.should be_kind_of(Heidi::Build::Logs)
90
+ end
91
+
92
+ it "should write to a log file" do
93
+ log = "my_new.log"
94
+ file = File.join(@build.log_root, log)
95
+
96
+ File.exists?(file).should_not be_true
97
+
98
+ @build.logs[log].write("the message")
99
+
100
+ File.exists?(file).should be_true
101
+ File.read(file).should =~ /the message/
102
+ end
103
+
104
+ it "should read from a log file" do
105
+ log = "my_new.log"
106
+ @build.logs[log].read.should =~ /the message/
107
+ end
108
+
109
+ it "should have convenience methods for heidi.* logs" do
110
+ @build.log(:info, "my custom message")
111
+ @build.logs["heidi.info"].read.should =~ /my custom message/
112
+ end
113
+ end
114
+
115
+ describe "Records" do
116
+ it "should have a status" do
117
+ survivable do
118
+ File.unlink(File.join(@build.root, Heidi::Build::FAILURE))
119
+ File.unlink(File.join(@build.root, Heidi::Build::SUCCESS))
120
+ end
121
+
122
+ @build.status.should == Heidi::DNF
123
+ end
124
+
125
+ it "should return failed?" do
126
+ survivable do
127
+ File.unlink(File.join(@build.root, Heidi::Build::FAILURE))
128
+ end
129
+
130
+ @build.should_not be_failed
131
+ @build.status.should_not == Heidi::FAILED
132
+ end
133
+
134
+ it "should return success?" do
135
+ survivable do
136
+ File.unlink(File.join(@build.root, Heidi::Build::FAILURE))
137
+ end
138
+
139
+ @build.should_not be_success
140
+ @build.status.should_not == Heidi::PASSED
141
+ end
142
+
143
+ it "should record success" do
144
+ @build.record(:success)
145
+ @build.should be_success
146
+ @build.status.should == Heidi::PASSED
147
+ end
148
+
149
+ it "should record failure" do
150
+ @build.record(:failure)
151
+ @build.should be_failed
152
+ @build.status.should == Heidi::FAILED
153
+ end
154
+
155
+ it "should provide access to the tar-ball" do
156
+ # first 'create' the tar-ball
157
+ File.open(File.join(@build.root, "#{@build.commit}.tar.bz2"), "w") do |f|
158
+ f.puts "I am the tar-ball, see?"
159
+ end
160
+
161
+ @build.tar_ball.should_not be_nil
162
+ @build.tar_ball.should be_kind_of(IO)
163
+ @build.tar_ball.read.should =~ /i am the tar-ball/i
164
+ end
165
+ end
166
+ end
@@ -1,5 +1,65 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Heidi::Builder do
4
- pending "more tests please!"
4
+ before(:all) do
5
+ fake_me_a_heidi
6
+ end
7
+
8
+ after(:all) do
9
+ FileUtils.remove_entry_secure @fake
10
+ end
11
+
12
+ before(:each) do
13
+ @project = @heidi[:heidi_test]
14
+ @build = Heidi::Build.new(@project)
15
+ end
16
+
17
+ it "should create a build dir" do
18
+ builder = Heidi::Builder.new(@build)
19
+ result = builder.build!
20
+ result.should_not be_false
21
+
22
+ File.directory?(File.join(@project.root, "logs", @project.commit))
23
+ end
24
+
25
+ it "should write to the info log" do
26
+ @build.logs["heidi.info"].read.should_not be_empty
27
+ end
28
+
29
+ it "should replace a build dir" do
30
+ File.directory?(File.join(@project.root, "logs", @project.commit))
31
+ prev_logs = @build.logs["heidi.info"].read
32
+
33
+ @build.unlock if @build.locked?
34
+
35
+ builder = Heidi::Builder.new(@build)
36
+ result = builder.build!
37
+ result.should_not be_false
38
+
39
+ File.directory?(File.join(@project.root, "logs", @project.commit))
40
+ build_logs = @build.logs["heidi.info"].read
41
+ build_logs.should_not == prev_logs
42
+
43
+ build_logs.should =~ /removing previous build/i
44
+ end
45
+
46
+ it "should leave the heidi.errors log empty" do
47
+ @build.logs["heidi.errors"].read.should be_empty
48
+ end
49
+
50
+ it "should leave the build directory locked" do
51
+ @build.unlock
52
+
53
+ builder = Heidi::Builder.new(@build)
54
+ result = builder.build!
55
+ result.should_not be_false
56
+ @build.should be_locked
57
+ end
58
+
59
+ it "should not replace a locked build dir" do
60
+ builder = Heidi::Builder.new(@build)
61
+ result = builder.build!
62
+ result.should be_false
63
+ @build.logs["heidi.errors"].read.should =~ /build was locked/i
64
+ end
5
65
  end
@@ -1,5 +1,51 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Heidi::Hook do
4
- pending "more tests please!"
4
+ before(:all) do
5
+ fake_me_a_heidi
6
+ @script = File.join(@fake, "projects/heidi_test/hooks/before/testing_hook.sh")
7
+ File.open(@script, File::CREAT|File::WRONLY) do |f|
8
+ f.puts %Q(#!/bin/sh
9
+
10
+ printenv > #{@fake}/testing_hook.out
11
+ )
12
+ end
13
+
14
+ SimpleShell.new(@fake).chmod %W(+x #{@script})
15
+ end
16
+
17
+ after(:all) do
18
+ FileUtils.remove_entry_secure @fake
19
+ end
20
+
21
+ before(:each) do
22
+ @project = @heidi[:heidi_test]
23
+ @build = Heidi::Build.new(@project)
24
+ @hook = Heidi::Hook.new(@build, @script)
25
+ end
26
+
27
+ it "has a name" do
28
+ @hook.name.should == "before/testing_hook.sh"
29
+ end
30
+
31
+ it "performs" do
32
+ outfile = File.join(@fake, "testing_hook.out")
33
+ File.exists?(outfile).should_not be_true
34
+ @hook.perform
35
+ @hook.should_not be_failed
36
+ File.exists?(outfile).should be_true
37
+ end
38
+
39
+ it "resets the environment" do
40
+ @hook.perform
41
+ @hook.should_not be_failed
42
+ contents = File.read(File.join(@fake, "testing_hook.out"))
43
+
44
+ contents.should_not =~ /RUBYOPT/
45
+ contents.should_not =~ /GEM_HOME/
46
+ contents.should_not =~ /GEM_PATH/
47
+ contents.should_not =~ /BUNDLE_/
48
+ contents.should =~ /HEIDI_BUILD_/
49
+ contents.should =~ /HEIDI_LOG_DIR/
50
+ end
5
51
  end
@@ -1,5 +1,100 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Heidi::Integrator do
4
- pending "more tests please!"
4
+ # not using all, might be slow - but I need clean projects every time
5
+ before(:each) do
6
+ fake_me_a_heidi
7
+ @project = @heidi[:heidi_test]
8
+ @integrator = Heidi::Integrator.new(@project)
9
+ end
10
+
11
+ after(:each) do
12
+ FileUtils.remove_entry_secure @fake
13
+ end
14
+
15
+ it "should create a build" do
16
+ @integrator.build.should_not be_nil
17
+ @integrator.build.should be_kind_of(Heidi::Build)
18
+ end
19
+
20
+ it "should integrate" do
21
+ res = @integrator.integrate
22
+ res.should_not be_kind_of(String)
23
+ res.should_not be_false
24
+ end
25
+
26
+ describe "recording" do
27
+ it "should not have any record files" do
28
+ ( File.exists?(
29
+ File.join(@integrator.build.root, Heidi::Build::FAILURE)
30
+ ) | File.exists?(
31
+ File.join(@integrator.build.root, Heidi::Build::SUCCESS)
32
+ )
33
+ ).should be_false
34
+ end
35
+
36
+ it "should record success on success" do
37
+ expect {
38
+ @integrator.integrate
39
+ }.to change {
40
+ File.exists? File.join(@integrator.build.root, Heidi::Build::SUCCESS)
41
+ }
42
+ end
43
+
44
+ it "should not record anything without test hooks" do
45
+ # remove the test hooks, so the build will fail
46
+ Dir[ File.join(@project.root, "hooks", "tests", "*") ].each do |hook|
47
+ File.unlink hook
48
+ end
49
+
50
+ expect {
51
+ @integrator.integrate
52
+ }.to_not change {
53
+ ( File.exists?(
54
+ File.join(@integrator.build.root, Heidi::Build::FAILURE)
55
+ ) | File.exists?(
56
+ File.join(@integrator.build.root, Heidi::Build::SUCCESS)
57
+ )
58
+ ) == false
59
+ }
60
+ end
61
+
62
+ it "should record failure on failure" do
63
+ # fix the tests so that they exit 1 (and thus fail)
64
+ Dir[ File.join(@project.root, "hooks", "tests", "*") ].each do |hook|
65
+ File.open(hook, File::WRONLY|File::APPEND) do |f|
66
+ f.puts "\n\nexit 1"
67
+ end
68
+ end
69
+
70
+ expect {
71
+ res = @integrator.integrate
72
+ }.to change {
73
+ File.exists? File.join(@integrator.build.root, Heidi::Build::FAILURE)
74
+ }
75
+ end
76
+ end
77
+
78
+ describe "Hooks" do
79
+ it "should run hooks" do
80
+ # see MockProject#fake_me_a_heidi as to why this would work
81
+ expect {
82
+ @integrator.integrate
83
+ }.to change {
84
+ File.exists? File.join(@fake, File.basename(@fake))
85
+ }
86
+ end
87
+
88
+ it "should survive an empty hooks run" do
89
+ @integrator.run_hooks("no such hooks").should be_true
90
+ end
91
+
92
+ it "should keep record of the hooks executed" do
93
+ expect {
94
+ @integrator.integrate
95
+ }.to change {
96
+ @integrator.instance_variable_get :@hooks_ran
97
+ }
98
+ end
99
+ end
5
100
  end
@@ -1,5 +1,180 @@
1
1
  require 'spec_helper'
2
+ require 'fileutils'
2
3
 
3
4
  describe Heidi::Project do
4
- pending "more tests please!"
5
- end
5
+ before(:all) do
6
+ fake_me_a_heidi
7
+ end
8
+
9
+ after(:all) do
10
+ FileUtils.remove_entry_secure @fake
11
+ end
12
+
13
+ before(:each) do
14
+ @project = @heidi[:heidi_test]
15
+ end
16
+
17
+ it "should be available" do
18
+ @project.should_not be_nil
19
+ end
20
+
21
+ describe "Before first fetch" do
22
+ it "should have no builds" do
23
+ @project.builds.count == 0
24
+ end
25
+
26
+ it "should have a base name" do
27
+ @project.basename.should == "heidi_test"
28
+ end
29
+
30
+ it "should have a given name" do
31
+ @project.name.should == "heidi_test"
32
+ end
33
+
34
+ it "should have a settable name" do
35
+ @project.name = "Heidi Test"
36
+ @project.name.should == "Heidi Test"
37
+ end
38
+
39
+ it "should have a current commit" do
40
+ @project.commit.should_not be_empty
41
+ @project.commit.length.should == 8
42
+ end
43
+
44
+ it "should have a current author" do
45
+ @project.author.should_not be_empty
46
+ end
47
+
48
+ it "should have a current date" do
49
+ @project.date.should_not be_empty
50
+ end
51
+
52
+ it "should not have a last commit" do
53
+ @project.last_commit.should be_empty
54
+ end
55
+
56
+ it "should not have a current build" do
57
+ @project.current_build.should be_empty
58
+ end
59
+
60
+ it "should not have a latest build" do
61
+ @project.latest_build.should be_empty
62
+ end
63
+
64
+ it "should not have build status" do
65
+ @project.build_status.should be_empty
66
+ end
67
+ end
68
+
69
+ describe "Fetching" do
70
+ it "should fetch" do
71
+ expect { @project.fetch }.not_to raise_error
72
+ end
73
+
74
+ it "should have a last commit" do
75
+ @project.last_commit.should_not be_empty
76
+ end
77
+ end
78
+
79
+ describe "Integration" do
80
+ it "should integrate" do
81
+ output = ""
82
+ expect { output = @project.integrate }.not_to raise_error
83
+ output.should be_nil
84
+ end
85
+
86
+ it "should have a current build" do
87
+ @project.current_build.should_not be_empty
88
+ end
89
+
90
+ it "should have a latest build" do
91
+ @project.latest_build.should_not be_empty
92
+ end
93
+
94
+ it "should have build status" do
95
+ @project.build_status.should_not be_empty
96
+ @project.build_status.should == Heidi::PASSED
97
+ end
98
+ end
99
+
100
+ describe "Locking" do
101
+ it "should not be locked" do
102
+ @project.should_not be_locked
103
+ end
104
+
105
+ it "should be lockable" do
106
+ @project.lock
107
+ @project.should be_locked
108
+ end
109
+
110
+ it "should have surviving locks" do
111
+ @project.should be_locked
112
+ end
113
+
114
+ it "should be unlockable" do
115
+ @project.unlock
116
+ @project.should_not be_locked
117
+ end
118
+
119
+ it "should be block lockable" do
120
+ @project.should_not be_locked
121
+ @project.lock do
122
+ @project.should be_locked
123
+ end
124
+ @project.should_not be_locked
125
+ end
126
+ end
127
+
128
+ describe "Branches" do
129
+ it "should return a list of integration branches" do
130
+ @project.integration_branches.should_not be_empty
131
+
132
+ if ENV['HEIDI_BUILD_COMMIT']
133
+ # somehow heidi fails on this when integrating
134
+ pending "Can't test this (yet) inside Heidi"
135
+ end
136
+
137
+ @project.integration_branches.should include("origin/master")
138
+ end
139
+
140
+ it "should have no default integration branch" do
141
+ @project.branch.should be_nil
142
+ end
143
+
144
+ it "should allow for the setting of a branch" do
145
+ @project.branch = "foo"
146
+ @project.branch.should == "foo"
147
+ end
148
+
149
+ it "should strip origin from the branch name" do
150
+ @project.branch = "origin/master"
151
+ @project.branch.should == "master"
152
+ end
153
+
154
+ it "should set cached to the integration branch" do
155
+ if ENV['HEIDI_BUILD_COMMIT']
156
+ # somehow heidi fails on this when integrating
157
+ pending "Can't test this (yet) inside Heidi"
158
+ end
159
+
160
+ git = Heidi::Git.new(@project.cached_root)
161
+ git.checkout("something_else", "develop")
162
+ git.branch.should_not == "develop"
163
+
164
+ @project.branch = "origin/develop"
165
+ @project.fetch
166
+
167
+ git.branch.should == @project.branch
168
+ end
169
+ end
170
+
171
+ describe "Commits" do
172
+ it "should return the stat of a commit" do
173
+ @project.stat(@project.HEAD).should_not be_empty
174
+ end
175
+
176
+ it "should return the diff of a commit" do
177
+ @project.diff(@project.HEAD).should_not be_empty
178
+ end
179
+ end
180
+ end