heidi 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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