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.
- data/README.markdown +7 -0
- data/Rakefile +77 -124
- data/config/config.ru +29 -0
- data/config/config.sample.ru +6 -16
- data/config/config.sample.yml +15 -12
- data/config/config.yml +34 -0
- data/lib/integrity.rb +13 -13
- data/lib/integrity/app.rb +138 -0
- data/lib/integrity/author.rb +39 -0
- data/lib/integrity/build.rb +54 -31
- data/lib/integrity/commit.rb +71 -0
- data/lib/integrity/helpers.rb +3 -3
- data/lib/integrity/helpers/authorization.rb +2 -2
- data/lib/integrity/helpers/forms.rb +3 -3
- data/lib/integrity/helpers/pretty_output.rb +1 -1
- data/lib/integrity/helpers/rendering.rb +6 -1
- data/lib/integrity/helpers/resources.rb +9 -3
- data/lib/integrity/helpers/urls.rb +15 -13
- data/lib/integrity/installer.rb +43 -60
- data/lib/integrity/migrations.rb +31 -48
- data/lib/integrity/notifier.rb +14 -16
- data/lib/integrity/notifier/base.rb +29 -19
- data/lib/integrity/notifier/test_helpers.rb +100 -0
- data/lib/integrity/project.rb +69 -33
- data/lib/integrity/project_builder.rb +23 -14
- data/lib/integrity/scm/git.rb +15 -14
- data/lib/integrity/scm/git/uri.rb +9 -9
- data/test/acceptance/api_test.rb +97 -0
- data/test/acceptance/browse_project_builds_test.rb +65 -0
- data/test/acceptance/browse_project_test.rb +95 -0
- data/test/acceptance/build_notifications_test.rb +42 -0
- data/test/acceptance/create_project_test.rb +97 -0
- data/test/acceptance/delete_project_test.rb +53 -0
- data/test/acceptance/edit_project_test.rb +117 -0
- data/test/acceptance/error_page_test.rb +18 -0
- data/test/acceptance/helpers.rb +2 -0
- data/test/acceptance/installer_test.rb +62 -0
- data/test/acceptance/manual_build_project_test.rb +82 -0
- data/test/acceptance/notifier_test.rb +109 -0
- data/test/acceptance/project_syndication_test.rb +30 -0
- data/test/acceptance/stylesheet_test.rb +18 -0
- data/test/helpers.rb +59 -26
- data/test/helpers/acceptance.rb +19 -65
- data/test/helpers/acceptance/email_notifier.rb +55 -0
- data/test/helpers/acceptance/git_helper.rb +15 -15
- data/test/helpers/acceptance/textfile_notifier.rb +3 -3
- data/test/helpers/expectations.rb +0 -1
- data/test/helpers/expectations/be_a.rb +4 -4
- data/test/helpers/expectations/change.rb +5 -5
- data/test/helpers/expectations/have.rb +4 -4
- data/test/helpers/expectations/predicates.rb +4 -4
- data/test/helpers/fixtures.rb +44 -18
- data/test/helpers/initial_migration_fixture.sql +44 -0
- data/test/unit/build_test.rb +51 -0
- data/test/unit/commit_test.rb +83 -0
- data/test/unit/helpers_test.rb +56 -0
- data/test/unit/integrity_test.rb +18 -0
- data/test/unit/migrations_test.rb +56 -0
- data/test/unit/notifier_test.rb +123 -0
- data/test/unit/project_builder_test.rb +108 -0
- data/test/unit/project_test.rb +282 -0
- data/test/unit/scm_test.rb +54 -0
- data/views/_commit_info.haml +24 -0
- data/views/build.haml +2 -2
- data/views/error.haml +4 -3
- data/views/home.haml +3 -5
- data/views/integrity.sass +19 -6
- data/views/new.haml +6 -6
- data/views/project.builder +9 -9
- data/views/project.haml +14 -12
- metadata +89 -122
- data/VERSION.yml +0 -4
- data/app.rb +0 -138
- data/integrity.gemspec +0 -76
- data/lib/integrity/core_ext/string.rb +0 -5
- data/test/helpers/expectations/have_tag.rb +0 -128
- data/views/_build_info.haml +0 -18
data/lib/integrity/project.rb
CHANGED
@@ -2,7 +2,7 @@ module Integrity
|
|
2
2
|
class Project
|
3
3
|
include DataMapper::Resource
|
4
4
|
|
5
|
-
property :id,
|
5
|
+
property :id, Integer, :serial => true
|
6
6
|
property :name, String, :nullable => false
|
7
7
|
property :permalink, String
|
8
8
|
property :uri, URI, :nullable => false, :length => 255
|
@@ -13,7 +13,7 @@ module Integrity
|
|
13
13
|
property :created_at, DateTime
|
14
14
|
property :updated_at, DateTime
|
15
15
|
|
16
|
-
has n, :
|
16
|
+
has n, :commits, :class_name => "Integrity::Commit"
|
17
17
|
has n, :notifiers, :class_name => "Integrity::Notifier"
|
18
18
|
|
19
19
|
before :save, :set_permalink
|
@@ -30,36 +30,52 @@ module Integrity
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def build(commit_identifier="HEAD")
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
ensure
|
37
|
-
update_attributes(:building => false)
|
38
|
-
send_notifications
|
33
|
+
commit_identifier = head_of_remote_repo if commit_identifier == "HEAD"
|
34
|
+
commit = find_or_create_commit_with_identifier(commit_identifier)
|
35
|
+
commit.queue_build
|
39
36
|
end
|
40
37
|
|
41
38
|
def push(payload)
|
42
|
-
payload =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
payload = parse_payload(payload)
|
40
|
+
raise ArgumentError unless valid_payload?(payload)
|
41
|
+
|
42
|
+
commits =
|
43
|
+
if Integrity.config[:build_all_commits]
|
44
|
+
payload["commits"]
|
45
|
+
else
|
46
|
+
[ payload["commits"].first ]
|
47
47
|
end
|
48
|
-
|
49
|
-
|
48
|
+
|
49
|
+
commits.each do |commit_data|
|
50
|
+
create_commit_from(commit_data)
|
51
|
+
build(commit_data["id"])
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
55
|
+
def last_commit
|
56
|
+
commits.first(:project_id => id, :order => [:committed_at.desc])
|
57
|
+
end
|
58
|
+
|
53
59
|
def last_build
|
54
|
-
|
60
|
+
warn "Project#last_build is deprecated, use Project#last_commit"
|
61
|
+
last_commit
|
62
|
+
end
|
63
|
+
|
64
|
+
def previous_commits
|
65
|
+
commits.all(:project_id => id, :order => [:committed_at.desc]).tap {|commits| commits.shift }
|
55
66
|
end
|
56
67
|
|
57
68
|
def previous_builds
|
58
|
-
|
69
|
+
warn "Project#previous_builds is deprecated, use Project#previous_commits"
|
70
|
+
previous_commits
|
59
71
|
end
|
60
72
|
|
61
73
|
def status
|
62
|
-
|
74
|
+
last_commit && last_commit.status
|
75
|
+
end
|
76
|
+
|
77
|
+
def human_readable_status
|
78
|
+
last_commit && last_commit.human_readable_status
|
63
79
|
end
|
64
80
|
|
65
81
|
def public=(flag)
|
@@ -70,12 +86,12 @@ module Integrity
|
|
70
86
|
end
|
71
87
|
|
72
88
|
def config_for(notifier)
|
73
|
-
notifier = notifiers.first(:name => notifier.to_s.split(/::/).last)
|
89
|
+
notifier = notifiers.first(:name => notifier.to_s.split(/::/).last, :project_id => id)
|
74
90
|
notifier.blank? ? {} : notifier.config
|
75
91
|
end
|
76
92
|
|
77
93
|
def notifies?(notifier)
|
78
|
-
!notifiers.first(:name => notifier.to_s.split(/::/).last).blank?
|
94
|
+
!notifiers.first(:name => notifier.to_s.split(/::/).last, :project_id => id).blank?
|
79
95
|
end
|
80
96
|
|
81
97
|
def enable_notifiers(*args)
|
@@ -83,6 +99,30 @@ module Integrity
|
|
83
99
|
end
|
84
100
|
|
85
101
|
private
|
102
|
+
def find_or_create_commit_with_identifier(commit_identifier)
|
103
|
+
# We abuse +committed_at+ here setting it to Time.now because we use it
|
104
|
+
# to sort (for last_commit and previous_commits). I don't like this
|
105
|
+
# very much, but for now it's the only solution I can find.
|
106
|
+
#
|
107
|
+
# This also creates a dependency, as now we *always* have to update the
|
108
|
+
# +committed_at+ field after building to ensure the date is correct :(
|
109
|
+
#
|
110
|
+
# This might also make your commit listings a little jumpy, if some
|
111
|
+
# commits change place every time a build finishes =\
|
112
|
+
commits.first_or_create({ :identifier => commit_identifier, :project_id => id }, :committed_at => Time.now)
|
113
|
+
end
|
114
|
+
|
115
|
+
def head_of_remote_repo
|
116
|
+
SCM.new(uri, branch).head
|
117
|
+
end
|
118
|
+
|
119
|
+
def create_commit_from(data)
|
120
|
+
commits.create(:identifier => data["id"],
|
121
|
+
:author => "#{data["author"]["name"]} <#{data["author"]["email"]}>",
|
122
|
+
:message => data["message"],
|
123
|
+
:committed_at => data["timestamp"])
|
124
|
+
end
|
125
|
+
|
86
126
|
def set_permalink
|
87
127
|
self.permalink = (name || "").downcase.
|
88
128
|
gsub(/'s/, "s").
|
@@ -92,26 +132,22 @@ module Integrity
|
|
92
132
|
end
|
93
133
|
|
94
134
|
def delete_code
|
95
|
-
|
135
|
+
commits.all(:project_id => id).destroy!
|
96
136
|
ProjectBuilder.new(self).delete_code
|
97
137
|
rescue SCM::SCMUnknownError => error
|
98
138
|
Integrity.log "Problem while trying to deleting code: #{error}"
|
99
139
|
end
|
100
140
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
notifier.notify_of_build last_build
|
106
|
-
rescue Timeout::Error
|
107
|
-
Integrity.log "#{notifier.name} notifier timed out"
|
108
|
-
next
|
109
|
-
end
|
110
|
-
end
|
141
|
+
def valid_payload?(payload)
|
142
|
+
payload && payload["ref"].to_s.include?(branch) &&
|
143
|
+
!payload["commits"].nil? &&
|
144
|
+
!payload["commits"].to_a.empty?
|
111
145
|
end
|
112
146
|
|
113
|
-
def
|
114
|
-
|
147
|
+
def parse_payload(payload)
|
148
|
+
JSON.parse(payload.to_s)
|
149
|
+
rescue JSON::ParserError
|
150
|
+
false
|
115
151
|
end
|
116
152
|
end
|
117
153
|
end
|
@@ -1,23 +1,24 @@
|
|
1
1
|
module Integrity
|
2
2
|
class ProjectBuilder
|
3
|
-
attr_reader :build_script
|
4
|
-
|
5
3
|
def initialize(project)
|
4
|
+
@project = project
|
6
5
|
@uri = project.uri
|
7
6
|
@build_script = project.command
|
8
7
|
@branch = project.branch
|
9
8
|
@scm = SCM.new(@uri, @branch, export_directory)
|
10
|
-
@build = Build.new(:project => project)
|
11
9
|
end
|
12
10
|
|
13
11
|
def build(commit)
|
14
|
-
|
15
|
-
@
|
12
|
+
@commit = commit
|
13
|
+
@build = commit.build
|
14
|
+
@build.start!
|
15
|
+
Integrity.log "Building #{commit.identifier} (#{@branch}) of #{@project.name} in #{export_directory} using #{@scm.name}"
|
16
|
+
@scm.with_revision(commit.identifier) { run_build_script }
|
16
17
|
@build
|
17
18
|
ensure
|
18
|
-
@build.
|
19
|
-
@
|
20
|
-
|
19
|
+
@build.complete!
|
20
|
+
@commit.update_attributes(@scm.info(commit.identifier))
|
21
|
+
send_notifications
|
21
22
|
end
|
22
23
|
|
23
24
|
def delete_code
|
@@ -27,18 +28,26 @@ module Integrity
|
|
27
28
|
end
|
28
29
|
|
29
30
|
private
|
30
|
-
def
|
31
|
-
|
31
|
+
def send_notifications
|
32
|
+
@project.notifiers.each do |notifier|
|
33
|
+
begin
|
34
|
+
Integrity.log "Notifying of build #{@commit.short_identifier} using the #{notifier.name} notifier"
|
35
|
+
notifier.notify_of_build @commit
|
36
|
+
rescue Timeout::Error
|
37
|
+
Integrity.log "#{notifier.name} notifier timed out"
|
38
|
+
next
|
39
|
+
end
|
40
|
+
end
|
32
41
|
end
|
33
42
|
|
34
|
-
def
|
35
|
-
@
|
43
|
+
def export_directory
|
44
|
+
Integrity.config[:export_directory] / "#{SCM.working_tree_path(@uri)}-#{@branch}"
|
36
45
|
end
|
37
46
|
|
38
47
|
def run_build_script
|
39
|
-
Integrity.log "Running `#{build_script}` in #{@scm.working_directory}"
|
48
|
+
Integrity.log "Running `#{@build_script}` in #{@scm.working_directory}"
|
40
49
|
|
41
|
-
IO.popen "(cd #{@scm.working_directory} && #{build_script}) 2>&1", "r" do |pipe|
|
50
|
+
IO.popen "(cd #{@scm.working_directory} && #{@build_script}) 2>&1", "r" do |pipe|
|
42
51
|
@build.output = pipe.read
|
43
52
|
end
|
44
53
|
@build.successful = $?.success?
|
data/lib/integrity/scm/git.rb
CHANGED
@@ -9,8 +9,8 @@ module Integrity
|
|
9
9
|
Git::URI.new(uri).working_tree_path
|
10
10
|
end
|
11
11
|
|
12
|
-
def initialize(uri, branch, working_directory)
|
13
|
-
@uri
|
12
|
+
def initialize(uri, branch, working_directory=nil)
|
13
|
+
@uri = uri.to_s
|
14
14
|
@branch = branch.to_s
|
15
15
|
@working_directory = working_directory
|
16
16
|
end
|
@@ -21,27 +21,28 @@ module Integrity
|
|
21
21
|
yield
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
|
24
|
+
def name
|
25
|
+
self.class.name.split("::").last
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
28
|
+
def head
|
29
|
+
log "Getting the HEAD of '#{uri}' at '#{branch}'"
|
30
|
+
`git ls-remote --heads #{uri} #{branch} | awk '{print $1}'`.chomp
|
31
31
|
end
|
32
|
-
|
33
|
-
def
|
34
|
-
|
32
|
+
|
33
|
+
def info(revision)
|
34
|
+
format = %Q(---%n:author: %an <%ae>%n:message: >-%n %s%n:committed_at: %ci%n)
|
35
|
+
YAML.load(`cd #{working_directory} && git show -s --pretty=format:"#{format}" #{revision}`)
|
35
36
|
end
|
36
37
|
|
37
38
|
private
|
38
39
|
|
39
40
|
def fetch_code
|
40
|
-
clone
|
41
|
+
clone unless cloned?
|
41
42
|
checkout unless on_branch?
|
42
43
|
pull
|
43
44
|
end
|
44
|
-
|
45
|
+
|
45
46
|
def clone
|
46
47
|
log "Cloning #{uri} to #{working_directory}"
|
47
48
|
`git clone #{uri} #{working_directory} &>/dev/null`
|
@@ -51,11 +52,11 @@ module Integrity
|
|
51
52
|
strategy = case
|
52
53
|
when treeish then treeish
|
53
54
|
when local_branches.include?(branch) then branch
|
54
|
-
else "
|
55
|
+
else "origin/#{branch}"
|
55
56
|
end
|
56
57
|
|
57
58
|
log "Checking-out #{strategy}"
|
58
|
-
`cd #{working_directory} && git
|
59
|
+
`cd #{working_directory} && git reset --hard #{strategy} &>/dev/null`
|
59
60
|
end
|
60
61
|
|
61
62
|
def pull
|
@@ -13,13 +13,13 @@ module Integrity
|
|
13
13
|
# ssh://[user@]host.xz/path/to/repo.git/
|
14
14
|
# ssh://[user@]host.xz/~user/path/to/repo.git/
|
15
15
|
# ssh://[user@]host.xz/~/path/to/repo.git
|
16
|
-
#
|
17
|
-
# SSH is the default transport protocol over the network. You can optionally
|
18
|
-
# specify which user to log-in as, and an alternate, scp-like syntax is also
|
16
|
+
#
|
17
|
+
# SSH is the default transport protocol over the network. You can optionally
|
18
|
+
# specify which user to log-in as, and an alternate, scp-like syntax is also
|
19
19
|
# supported
|
20
20
|
#
|
21
|
-
# Both syntaxes support username expansion, as does the native git protocol,
|
22
|
-
# but only the former supports port specification. The following three are
|
21
|
+
# Both syntaxes support username expansion, as does the native git protocol,
|
22
|
+
# but only the former supports port specification. The following three are
|
23
23
|
# identical to the last three above, respectively:
|
24
24
|
#
|
25
25
|
# [user@]host.xz:/path/to/repo.git/
|
@@ -30,13 +30,13 @@ module Integrity
|
|
30
30
|
def initialize(uri_string)
|
31
31
|
@uri = Addressable::URI.parse(uri_string)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def working_tree_path
|
35
35
|
strip_extension(path).gsub("/", "-")
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
private
|
39
|
-
|
39
|
+
|
40
40
|
def strip_extension(string)
|
41
41
|
uri = Pathname.new(string)
|
42
42
|
if uri.extname.any?
|
@@ -46,7 +46,7 @@ module Integrity
|
|
46
46
|
string
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def path
|
51
51
|
path = @uri.path
|
52
52
|
path.gsub(/\~[a-zA-Z0-9]*\//, "").gsub(/^\//, "")
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helpers"
|
2
|
+
|
3
|
+
class ApiTest < Test::Unit::AcceptanceTestCase
|
4
|
+
story <<-EOF
|
5
|
+
As a project owner,
|
6
|
+
I want to be able to use GitHub as a build triggerer
|
7
|
+
So that my project is built everytime I push to the Holy Hub
|
8
|
+
EOF
|
9
|
+
|
10
|
+
def payload(after, branch="master", commits=[])
|
11
|
+
payload = { "after" => "#{after}", "ref" => "refs/heads/#{branch}" }
|
12
|
+
payload["commits"] = commits if commits.any?
|
13
|
+
payload.to_json
|
14
|
+
end
|
15
|
+
|
16
|
+
def post(path, data)
|
17
|
+
request_page(path, "post", data)
|
18
|
+
end
|
19
|
+
|
20
|
+
scenario "it only build commits for the branch being monitored" do
|
21
|
+
repo = git_repo(:my_test_project) # initial commit && successful commit
|
22
|
+
Project.gen(:my_test_project, :uri => repo.path, :branch => "my-branch")
|
23
|
+
|
24
|
+
basic_auth "admin", "test"
|
25
|
+
|
26
|
+
lambda do
|
27
|
+
post "/my-test-project/push", :payload => payload(repo.head, "master", repo.commits)
|
28
|
+
response_code.should == 422
|
29
|
+
end.should_not change(Build, :count)
|
30
|
+
|
31
|
+
visit "/my-test-project"
|
32
|
+
|
33
|
+
assert_contain("No builds for this project")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "receiving a build request with build_all_commits *enabled* builds all commits, most recent first" do
|
37
|
+
Integrity.config[:build_all_commits] = true
|
38
|
+
|
39
|
+
repo = git_repo(:my_test_project) # initial commit && successful commit
|
40
|
+
3.times do |i|
|
41
|
+
repo.add_commit("commit #{i}") do
|
42
|
+
system "echo commit_#{i} >> test-file"
|
43
|
+
system "git add test-file &>/dev/null"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Project.gen(:my_test_project, :uri => repo.path, :command => "echo successful", :branch => "master")
|
48
|
+
|
49
|
+
basic_auth "admin", "test"
|
50
|
+
post "/my-test-project/push", :payload => payload(repo.head, "master", repo.commits)
|
51
|
+
|
52
|
+
visit "/my-test-project"
|
53
|
+
|
54
|
+
assert_have_tag("h1", :content => "Built #{git_repo(:my_test_project).short_head} successfully")
|
55
|
+
assert_have_tag(".attribution", :content => "by John Doe")
|
56
|
+
|
57
|
+
assert_have_tag("#previous_builds li", :count => 4)
|
58
|
+
end
|
59
|
+
|
60
|
+
scenario "receiving a build request with build_all_commits *disabled* only builds the last commit passed" do
|
61
|
+
Integrity.config[:build_all_commits] = false
|
62
|
+
|
63
|
+
Project.gen(:my_test_project, :uri => git_repo(:my_test_project).path)
|
64
|
+
|
65
|
+
git_repo(:my_test_project).add_failing_commit
|
66
|
+
git_repo(:my_test_project).add_successful_commit
|
67
|
+
head = git_repo(:my_test_project).head
|
68
|
+
|
69
|
+
basic_auth "admin", "test"
|
70
|
+
post "/my-test-project/push", :payload => payload(head, "master", git_repo(:my_test_project).commits)
|
71
|
+
|
72
|
+
response_code.should == 201
|
73
|
+
|
74
|
+
visit "/my-test-project"
|
75
|
+
|
76
|
+
assert_have_tag("h1", :content => "Built #{git_repo(:my_test_project).short_head} successfully")
|
77
|
+
|
78
|
+
assert_have_no_tag("#previous_builds li")
|
79
|
+
end
|
80
|
+
|
81
|
+
scenario "an unauthenticated request returns a 401" do
|
82
|
+
Project.gen(:my_test_project, :uri => git_repo(:my_test_project).path)
|
83
|
+
head = git_repo(:my_test_project).head
|
84
|
+
post "/my-test-project/push", :payload => payload(head, "master")
|
85
|
+
|
86
|
+
response_code.should == 401
|
87
|
+
end
|
88
|
+
|
89
|
+
scenario "receiving a build request with an invalid payload returns an Invalid Request error" do
|
90
|
+
Project.gen(:my_test_project, :uri => git_repo(:my_test_project).path)
|
91
|
+
|
92
|
+
basic_auth "admin", "test"
|
93
|
+
|
94
|
+
post "/my-test-project/push", :payload => "foo"
|
95
|
+
response_code.should == 422
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helpers"
|
2
|
+
|
3
|
+
class BrowseProjectBuildsTest < Test::Unit::AcceptanceTestCase
|
4
|
+
story <<-EOS
|
5
|
+
As a user,
|
6
|
+
I want to browse the builds of a project in Integrity
|
7
|
+
So I can see the history of a project
|
8
|
+
EOS
|
9
|
+
|
10
|
+
scenario "a project with no builds should say so in a friendly manner" do
|
11
|
+
Project.gen(:integrity, :public => true, :commits => [])
|
12
|
+
|
13
|
+
visit "/integrity"
|
14
|
+
|
15
|
+
assert_have_no_tag("#last_build")
|
16
|
+
assert_have_no_tag("#previous_builds")
|
17
|
+
assert_contain("No builds for this project, buddy")
|
18
|
+
end
|
19
|
+
|
20
|
+
scenario "a user can see the last build and the list of previous builds on a project page" do
|
21
|
+
Project.gen(:integrity, :public => true, :commits => \
|
22
|
+
3.of { Commit.gen(:successful) } +
|
23
|
+
2.of { Commit.gen(:failed) } +
|
24
|
+
2.of { Commit.gen(:pending) })
|
25
|
+
|
26
|
+
visit "/integrity"
|
27
|
+
|
28
|
+
assert_have_tag("#last_build")
|
29
|
+
|
30
|
+
within("ul#previous_builds") do
|
31
|
+
assert_have_tag("li.pending", :count => 2)
|
32
|
+
assert_have_tag("li.failed", :count => 2)
|
33
|
+
assert_have_tag("li.success", :count => 2)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
scenario "a user can see details about the last build on the project page" do
|
38
|
+
commit = Commit.gen(:successful, :identifier => "7fee3f0014b529e2b76d591a8085d76eab0ff923",
|
39
|
+
:author => "Nicolas Sanguinetti <contacto@nicolassanguinetti.info>",
|
40
|
+
:message => "No more pending tests :)",
|
41
|
+
:committed_at => Time.mktime(2008, 12, 15, 18))
|
42
|
+
commit.build.update_attributes(:output => "This is the build output")
|
43
|
+
Project.gen(:integrity, :public => true, :commits => [commit])
|
44
|
+
|
45
|
+
visit "/integrity"
|
46
|
+
|
47
|
+
assert_have_tag("h1", :content => "Built 7fee3f0 successfully")
|
48
|
+
assert_have_tag("blockquote p", :content => "No more pending tests")
|
49
|
+
assert_have_tag("span.who", :content => "by: Nicolas Sanguinetti")
|
50
|
+
assert_have_tag("span.when", :content => "Dec 15th")
|
51
|
+
assert_have_tag("pre.output", :content => "This is the build output")
|
52
|
+
end
|
53
|
+
|
54
|
+
scenario "a user can browse to individual build pages" do
|
55
|
+
Project.gen(:integrity, :public => true, :commits => [
|
56
|
+
Commit.gen(:successful, :identifier => "7fee3f0014b529e2b76d591a8085d76eab0ff923"),
|
57
|
+
Commit.gen(:successful, :identifier => "87e673a83d273ecde121624a3fcfae57a04f2b76")
|
58
|
+
])
|
59
|
+
|
60
|
+
visit "/integrity"
|
61
|
+
click_link(/Build 87e673a/)
|
62
|
+
|
63
|
+
assert_have_tag("h1", :content => "Built 87e673a successfully")
|
64
|
+
end
|
65
|
+
end
|