diff --git a/app/components/jobs-item.coffee b/app/components/jobs-item.coffee
new file mode 100644
index 00000000..ca085418
--- /dev/null
+++ b/app/components/jobs-item.coffee
@@ -0,0 +1,21 @@
+`import Ember from 'ember'`
+`import { colorForState } from 'travis/utils/helpers'`
+`import { languageConfigKeys } from 'travis/utils/keys-map';`
+
+JobsItemComponent = Ember.Component.extend
+ tagName: 'li'
+ classNameBindings: ['job.state']
+ classNames: ['tile', 'tile--jobs', 'row']
+
+ languages: (->
+ output = []
+
+ if config = @get('job.config')
+ for key, languageName of languageConfigKeys
+ if version = config[key]
+ output.push(languageName + ': ' + version)
+
+ output.join(' ')
+ ).property('job.config')
+
+`export default JobsItemComponent`
diff --git a/app/components/jobs-list.coffee b/app/components/jobs-list.coffee
new file mode 100644
index 00000000..65e26d5d
--- /dev/null
+++ b/app/components/jobs-list.coffee
@@ -0,0 +1,11 @@
+`import Ember from 'ember'`
+
+JobsListComponent = Ember.Component.extend
+ jobTableId: Ember.computed(->
+ if @get('required')
+ 'jobs'
+ else
+ 'allowed_failure_jobs'
+ )
+
+`export default JobsListComponent`
diff --git a/app/controllers/build.coffee b/app/controllers/build.coffee
index 1f86f62c..4e868705 100644
--- a/app/controllers/build.coffee
+++ b/app/controllers/build.coffee
@@ -12,6 +12,11 @@ Controller = Ember.Controller.extend GithubUrlPropertievs,
currentItemBinding: 'build'
+ jobsLoaded: (->
+ if jobs = @get('build.jobs')
+ jobs.everyBy('config')
+ ).property('build.jobs.@each.config')
+
loading: (->
@get('build.isLoading')
).property('build.isLoading')
diff --git a/app/styles/app/modules/tooltips.sass b/app/styles/app/modules/tooltips.sass
index 51cd9308..db463507 100644
--- a/app/styles/app/modules/tooltips.sass
+++ b/app/styles/app/modules/tooltips.sass
@@ -32,7 +32,7 @@ $tooltip-grey: #6A6C6D
bottom: -2.5em
@media #{$medium-up}
- width: 25rem
+ width: 18rem
.tooltip-inner
height: 4.1em
diff --git a/app/templates/build.hbs b/app/templates/build.hbs
index cba093f5..bc4998ae 100644
--- a/app/templates/build.hbs
+++ b/app/templates/build.hbs
@@ -76,8 +76,14 @@
{{/unless}}
{{#if build.isMatrix}}
- {{view 'jobs' jobs=build.requiredJobs required="true"}}
- {{view 'jobs' jobs=build.allowedFailureJobs}}
+ {{#if jobsLoaded}}
+ {{jobs-list jobs=build.requiredJobs required="true"}}
+ {{jobs-list jobs=build.allowedFailureJobs}}
+ {{else}}
+
+
+
+ {{/if}}
{{else}}
{{view 'log' job=build.jobs.firstObject}}
{{/if}}
diff --git a/app/templates/components/jobs-item.hbs b/app/templates/components/jobs-item.hbs
new file mode 100644
index 00000000..e6ec8359
--- /dev/null
+++ b/app/templates/components/jobs-item.hbs
@@ -0,0 +1,46 @@
+{{#link-to "job" job.repo job}}
+
+
+
+
+
+
+ {{job.number}}
+
+
+
+
+
+
+ {{#if languages}}
+
+
+ {{languages}}
+
+ {{else}}
+
+
+ no language set
+
+ {{/if}}
+
+
+ {{#if job.config.env}}
+
+
+ {{job.config.env}}
+
+ {{else}}
+
+
+ no environment variables set
+
+ {{/if}}
+
+
+
+ {{format-duration job.duration}}
+
+
+
+{{/link-to}}
diff --git a/app/templates/components/jobs-list.hbs b/app/templates/components/jobs-list.hbs
new file mode 100644
index 00000000..ff8a0243
--- /dev/null
+++ b/app/templates/components/jobs-list.hbs
@@ -0,0 +1,21 @@
+{{#if jobs.length}}
+
+
+ {{#if required}}
+ Build Jobs
+ {{else}}
+ Allowed Failures
+
+
+
+ {{/if}}
+
+
+ {{#each job in jobs}}
+ {{jobs-item job=job}}
+ {{/each}}
+
+
+{{/if}}
diff --git a/app/templates/jobs.hbs b/app/templates/jobs.hbs
index 8c9fc3a2..d443ef2f 100644
--- a/app/templates/jobs.hbs
+++ b/app/templates/jobs.hbs
@@ -7,7 +7,7 @@
Allowed Failures
{{/if}}
diff --git a/app/utils/status-image-formats.coffee b/app/utils/status-image-formats.coffee
index a2faa313..4356464c 100644
--- a/app/utils/status-image-formats.coffee
+++ b/app/utils/status-image-formats.coffee
@@ -28,8 +28,8 @@ podStatusImage = ( (url, slug, branch) ->
"=for HTML
"
)
-ccxmlStatusUrl = ( (slug) ->
- ccXmlUrl(slug)
+ccxmlStatusUrl = ( (slug, branch) ->
+ ccXmlUrl(slug, branch)
)
format = (version, slug, branch) ->
@@ -43,7 +43,7 @@ format = (version, slug, branch) ->
when 'AsciiDoc' then asciidocStatusImage(url, slug, branch)
when 'Rst' then rstStatusImage(url, slug, branch)
when 'Pod' then podStatusImage(url, slug, branch)
- when 'CCTray' then ccxmlStatusUrl(url, slug, branch)
+ when 'CCTray' then ccxmlStatusUrl(slug, branch)
`export default format`
diff --git a/app/utils/urls.coffee b/app/utils/urls.coffee
index 6f91752e..ac3ef3c3 100644
--- a/app/utils/urls.coffee
+++ b/app/utils/urls.coffee
@@ -28,12 +28,17 @@ statusImage = (slug, branch) ->
else
"#{location.protocol}//#{location.host}/#{slug}.svg" + if branch then "?branch=#{encodeURIComponent(branch)}" else ''
-ccXml = (slug) ->
+ccXml = (slug, branch) ->
+ url = "##{config.apiEndpoint}/repos/#{slug}/cc.xml"
+ if branch
+ url = "#{url}?branch=#{branch}"
+
if config.pro
+ delimiter = if url.indexOf('?') == -1 then '?' else '&'
token = Travis.__container__.lookup('controller:currentUser').get('token')
- "##{config.apiEndpoint}/repos/#{slug}/cc.xml?token=#{token}"
- else
- "#{config.apiEndpoint}/repos/#{slug}/cc.xml"
+ url = "#{url}#{delimiter}token=#{token}"
+
+ url
email = (email) ->
"mailto:#{email}"
diff --git a/app/views/jobs-item.coffee b/app/views/jobs-item.coffee
deleted file mode 100644
index df04e841..00000000
--- a/app/views/jobs-item.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-`import BasicView from 'travis/views/basic'`
-`import { colorForState } from 'travis/utils/helpers'`
-`import { languageConfigKeys } from 'travis/utils/keys-map';`
-
-View = BasicView.extend
- tagName: 'div'
- classNameBindings: ['color']
- repoBinding: 'context.repo'
- jobBinding: 'context'
-
- color: (->
- colorForState(@get('job.state'))
- ).property('job.state')
-
- languages: (->
- output = []
-
- if config = @get('job.config')
- for key, languageName of languageConfigKeys
- if version = config[key]
- output.push(languageName + ': ' + version)
-
- output.join(' ')
- ).property()
-
-`export default View`
diff --git a/app/views/jobs.coffee b/app/views/jobs.coffee
deleted file mode 100644
index 241294f9..00000000
--- a/app/views/jobs.coffee
+++ /dev/null
@@ -1,23 +0,0 @@
-`import Ember from 'ember'`
-`import BasicView from 'travis/views/basic'`
-
-View = BasicView.extend
- templateName: 'jobs'
- buildBinding: 'controller.build'
-
- jobTableId: Ember.computed(->
- if @get('required')
- 'jobs'
- else
- 'allowed_failure_jobs'
- )
-
- actions:
- popupClose: ->
- @popupCloseAll()
-
- openHelpPopup: ->
- @popupCloseAll()
- @popup('help-allowed_failures')
-
-`export default View`
diff --git a/testem.json b/testem.json
index 23afdf07..7f180924 100644
--- a/testem.json
+++ b/testem.json
@@ -6,9 +6,6 @@
"SL_firefox"
],
"launch_in_dev": [
- "PhantomJS",
- "Chrome",
- "Firefox"
],
"launchers": {
"SL_chrome": {
diff --git a/tests/index.html b/tests/index.html
index 86513a02..8827643b 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -13,6 +13,15 @@
+
{{content-for 'head-footer'}}
{{content-for 'test-head-footer'}}
diff --git a/tests/unit/components/jobs-item-test.coffee b/tests/unit/components/jobs-item-test.coffee
new file mode 100644
index 00000000..31f0e9aa
--- /dev/null
+++ b/tests/unit/components/jobs-item-test.coffee
@@ -0,0 +1,39 @@
+`import { test, moduleForComponent } from 'ember-qunit'`
+
+moduleForComponent 'jobs-item', 'JobsItemComponent', {
+ # specify the other units that are required for this test
+ needs: ['helper:format-duration']
+}
+
+test 'it renders', ->
+ attributes = {
+ id: 10
+ state: 'passed'
+ number: '2'
+ config: {
+ rvm: '2.1.2'
+ jdk: 'openjdk6'
+ os: 'linux',
+ env: 'TESTS=unit'
+ },
+ duration: 100
+ }
+ job = Ember.Object.create(attributes)
+ component = @subject(job: job)
+ @append()
+
+ ok component.$().hasClass('passed'), 'component should have a state class (passed)'
+ equal component.$('.job-id').text().trim(), '2', 'job number should be displayed'
+ equal component.$('.job-lang').text().trim(), 'JDK: openjdk6 Ruby: 2.1.2', 'langauges list should be displayed'
+ equal component.$('.job-env').text().trim(), 'TESTS=unit', 'env should be displayed'
+ ok component.$('.job-os').hasClass('linux'), 'OS class should be added for OS icon'
+ equal component.$('.job-duration').text().trim(), '1 min 40 sec', 'duration should be displayed'
+
+test 'ouputs info on not set properties', ->
+ job = Ember.Object.create()
+
+ component = @subject(job: job)
+ @append()
+
+ ok component.$('.job-env').text().match(/no environment variables set/), 'a message for no env vars should be displayed'
+ ok component.$('.job-lang').text().match(/no language set/), 'a message about no language being set should be displayed'
diff --git a/tests/unit/components/jobs-list-test.coffee b/tests/unit/components/jobs-list-test.coffee
new file mode 100644
index 00000000..76a40abe
--- /dev/null
+++ b/tests/unit/components/jobs-list-test.coffee
@@ -0,0 +1,25 @@
+`import { test, moduleForComponent } from 'ember-qunit'`
+
+moduleForComponent 'jobs-list', 'JobsListComponent', {
+ needs: ['helper:format-duration', 'component:jobs-item']
+}
+
+test 'it renders a list of jobs', ->
+ jobs = [Ember.Object.create(id: 1, state: 'passed'),
+ Ember.Object.create(id: 1, state: 'failed')]
+
+ component = @subject(jobs: jobs, required: true)
+ @append()
+
+ equal component.$('.build-title').text().trim(), 'Build Jobs'
+ equal component.$('li').length, 2, 'there should be 2 job items'
+ ok component.$('li:nth(0)').hasClass('passed'), 'passed class should be applied to a job'
+ ok component.$('li:nth(1)').hasClass('failed'), 'failed class should be applied to a job'
+
+test 'it renders "Allowed Failures" version without a `required` property', ->
+ jobs = [Ember.Object.create(id: 1)]
+
+ component = @subject(jobs: jobs)
+ @append()
+
+ ok component.$('.build-title').text().match /Allowed Failures/
diff --git a/tests/unit/utils/status-image-formats-test.coffee b/tests/unit/utils/status-image-formats-test.coffee
new file mode 100644
index 00000000..3be2c2cc
--- /dev/null
+++ b/tests/unit/utils/status-image-formats-test.coffee
@@ -0,0 +1,13 @@
+`import Ember from 'ember'`
+`import format from 'travis/utils/status-image-formats'`
+`import config from 'travis/config/environment'`
+
+module 'Status image formats'
+
+test 'it generates CCTray url with a slug', ->
+ url = format('CCTray', 'travis-ci/travis-web')
+ equal url, '#/repos/travis-ci/travis-web/cc.xml'
+
+test 'it generates CCTray url with a slug and a branch', ->
+ url = format('CCTray', 'travis-ci/travis-web', 'development')
+ equal url, '#/repos/travis-ci/travis-web/cc.xml?branch=development'