mirror of
git://git.yoctoproject.org/yocto-autobuilder2.git
synced 2025-07-19 20:59:02 +02:00
yocto_console_view: Add initial version of our customisation buildbot plugin
This commit is contained in:
parent
f08c7d3044
commit
02bcaeb027
17
yocto_console_view/README.txt
Normal file
17
yocto_console_view/README.txt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
This custom buildbot plugin does three things:
|
||||||
|
|
||||||
|
* Replaces the "Console View" with our own "Yocto Console View"
|
||||||
|
* Adds a yoctochangedetails element to customise the information we display about a build
|
||||||
|
(link to the code repository, link to error reporting for the build)
|
||||||
|
* Add a custom field element, ReleaseSelector to the force build scheduler allowing
|
||||||
|
us to customise the form input fields to allow auto population of fields for
|
||||||
|
specific release branch combinations
|
||||||
|
|
||||||
|
The plugin ships in compiled form along with its source code. The generated files are:
|
||||||
|
|
||||||
|
yocto_console_view/static/*
|
||||||
|
yocto_console_view/VERSION
|
||||||
|
|
||||||
|
In order to build this plugin you need a buildbot development environment setup along
|
||||||
|
with its dependencies. FIXME, add more info on building.
|
||||||
|
|
28
yocto_console_view/guanlecoja/config.coffee
Normal file
28
yocto_console_view/guanlecoja/config.coffee
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
### ###############################################################################################
|
||||||
|
#
|
||||||
|
# This module contains all configuration for the build process
|
||||||
|
#
|
||||||
|
### ###############################################################################################
|
||||||
|
ANGULAR_TAG = "~1.5.3"
|
||||||
|
module.exports =
|
||||||
|
|
||||||
|
### ###########################################################################################
|
||||||
|
# Name of the plugin
|
||||||
|
### ###########################################################################################
|
||||||
|
name: 'yocto_console_view'
|
||||||
|
dir: build: 'yocto_console_view/static'
|
||||||
|
bower:
|
||||||
|
testdeps:
|
||||||
|
"guanlecoja-ui":
|
||||||
|
version: '~1.6.0'
|
||||||
|
files: ['vendors.js', 'scripts.js']
|
||||||
|
"angular-mocks":
|
||||||
|
version: ANGULAR_TAG
|
||||||
|
files: "angular-mocks.js"
|
||||||
|
'buildbot-data':
|
||||||
|
version: '~2.1.0'
|
||||||
|
files: 'dist/buildbot-data.js'
|
||||||
|
|
||||||
|
karma:
|
||||||
|
# we put tests first, so that we have angular, and fake app defined
|
||||||
|
files: ["tests.js", "scripts.js", 'fixtures.js']
|
1
yocto_console_view/gulpfile.js
Normal file
1
yocto_console_view/gulpfile.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
require("guanlecoja")(require("gulp"))
|
11
yocto_console_view/package.json
Normal file
11
yocto_console_view/package.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "yocto-console-view",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0",
|
||||||
|
"npm": ">=1.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"guanlecoja": "~0.8.3",
|
||||||
|
"gulp": "3.9.0"
|
||||||
|
}
|
||||||
|
}
|
2
yocto_console_view/setup.cfg
Normal file
2
yocto_console_view/setup.cfg
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[bdist_wheel]
|
||||||
|
universal=1
|
47
yocto_console_view/setup.py
Normal file
47
yocto_console_view/setup.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# This file is part of Buildbot. Buildbot is free software: you can
|
||||||
|
# redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
# License as published by the Free Software Foundation, version 2.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc., 51
|
||||||
|
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# Copyright Buildbot Team Members
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
try:
|
||||||
|
from buildbot_pkg import setup_www_plugin
|
||||||
|
except ImportError:
|
||||||
|
import sys
|
||||||
|
print("Please install buildbot_pkg module in order to install that package, or use the pre-build .whl modules available on pypi", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
setup_www_plugin(
|
||||||
|
name='yocto-console-view',
|
||||||
|
description='Yocto Project Console View plugin.',
|
||||||
|
author=u'Richard Purdie',
|
||||||
|
author_email=u'richard.purdie@linuxfoundation.org',
|
||||||
|
url='http://autobuilder.yoctoproject.org/',
|
||||||
|
license='MIT',
|
||||||
|
packages=['yocto_console_view'],
|
||||||
|
package_data={
|
||||||
|
'': [
|
||||||
|
'VERSION',
|
||||||
|
'static/*'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
entry_points="""
|
||||||
|
[buildbot.www]
|
||||||
|
console_view = yocto_console_view:ep
|
||||||
|
""",
|
||||||
|
)
|
1
yocto_console_view/src/module/builders.fixture.json
Normal file
1
yocto_console_view/src/module/builders.fixture.json
Normal file
File diff suppressed because one or more lines are too long
33
yocto_console_view/src/module/console.tpl.jade
Normal file
33
yocto_console_view/src/module/console.tpl.jade
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
.console.no-select
|
||||||
|
.load-indicator(ng-hide='c.builds.$resolved && c.changes.$resolved && c.buildrequests.$resolved && c.buildsets.$resolved')
|
||||||
|
.spinner
|
||||||
|
i.fa.fa-circle-o-notch.fa-spin.fa-2x
|
||||||
|
p loading
|
||||||
|
div(ng-show="c.changes.$resolved && c.filtered_changes.length==0")
|
||||||
|
p No changes. Console view needs changesource to be setup, and
|
||||||
|
a(href="#changes") changes
|
||||||
|
| to be in the system.
|
||||||
|
|
||||||
|
table.table.table-striped.table-bordered(ng-hide="c.filtered_changes.length==0" ng-class="{'table-fixedwidth': c.isBigTable()}")
|
||||||
|
tr.first-row
|
||||||
|
th.row-header(ng-style="{'width': c.getRowHeaderWidth()}")
|
||||||
|
i.fa.fa-plus-circle.pull-left(ng-click='c.openAll()' uib-tooltip='Open information for all changes' uib-tooltip-placement='right')
|
||||||
|
i.fa.fa-minus-circle.pull-left(ng-click='c.closeAll()' uib-tooltip='Close information for all changes' uib-tooltip-placement='right')
|
||||||
|
th.column(ng-repeat="builder in c.builders")
|
||||||
|
span.builder(ng-style="{'margin-top': c.getColHeaderHeight()}")
|
||||||
|
a(ng-href='#/builders/{{ builder.builderid }}'
|
||||||
|
ng-bind='builder.name')
|
||||||
|
tr.tag_row(ng-repeat="tag_line in c.tag_lines")
|
||||||
|
td.row-header
|
||||||
|
td(ng-repeat="tag in tag_line" colspan="{{tag.colspan}}")
|
||||||
|
span(uib-tooltip='{{ tag.tag }}' ng-style='{width: tag.colspan*50}') {{tag.tag}}
|
||||||
|
tr(ng-repeat="change in c.filtered_changes | orderBy: ['-when_timestamp'] track by change.changeid")
|
||||||
|
td
|
||||||
|
yoctochangedetails(change="change")
|
||||||
|
td.column(ng-repeat="builder in change.builders"
|
||||||
|
title="{{builder.name}}")
|
||||||
|
a(ng-repeat="build in builder.builds | orderBy: ['number']")
|
||||||
|
span.badge-status(ng-if='build.buildid'
|
||||||
|
ng-class="c.results2class(build, 'pulse')"
|
||||||
|
ng-click='c.selectBuild(build)')
|
||||||
|
| {{ build.number }}
|
375
yocto_console_view/src/module/main.module.coffee
Normal file
375
yocto_console_view/src/module/main.module.coffee
Normal file
|
@ -0,0 +1,375 @@
|
||||||
|
# Register new module
|
||||||
|
class App extends App
|
||||||
|
constructor: ->
|
||||||
|
return [
|
||||||
|
'ui.router'
|
||||||
|
'ui.bootstrap'
|
||||||
|
'ngAnimate'
|
||||||
|
'guanlecoja.ui'
|
||||||
|
'bbData'
|
||||||
|
]
|
||||||
|
|
||||||
|
class State extends Config
|
||||||
|
constructor: ($stateProvider, glMenuServiceProvider, bbSettingsServiceProvider) ->
|
||||||
|
|
||||||
|
# Name of the state
|
||||||
|
name = 'console'
|
||||||
|
|
||||||
|
# Menu configuration
|
||||||
|
glMenuServiceProvider.addGroup
|
||||||
|
name: name
|
||||||
|
caption: 'Yocto Console View'
|
||||||
|
icon: 'exclamation-circle'
|
||||||
|
order: 5
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
cfg =
|
||||||
|
group: name
|
||||||
|
caption: 'Yocto Console View'
|
||||||
|
|
||||||
|
# Register new state
|
||||||
|
state =
|
||||||
|
controller: "#{name}Controller"
|
||||||
|
controllerAs: "c"
|
||||||
|
templateUrl: "yocto_console_view/views/#{name}.html"
|
||||||
|
name: name
|
||||||
|
url: "/#{name}"
|
||||||
|
data: cfg
|
||||||
|
|
||||||
|
$stateProvider.state(state)
|
||||||
|
|
||||||
|
bbSettingsServiceProvider.addSettingsGroup
|
||||||
|
name: 'Console'
|
||||||
|
caption: 'Console related settings'
|
||||||
|
items: [
|
||||||
|
type: 'integer'
|
||||||
|
name: 'buildLimit'
|
||||||
|
caption: 'Number of builds to fetch'
|
||||||
|
default_value: 200
|
||||||
|
,
|
||||||
|
type: 'integer'
|
||||||
|
name: 'changeLimit'
|
||||||
|
caption: 'Number of changes to fetch'
|
||||||
|
default_value: 30
|
||||||
|
]
|
||||||
|
|
||||||
|
class Console extends Controller
|
||||||
|
constructor: (@$scope, $q, @$window, dataService, bbSettingsService, resultsService,
|
||||||
|
@$uibModal, @$timeout) ->
|
||||||
|
angular.extend this, resultsService
|
||||||
|
settings = bbSettingsService.getSettingsGroup('Console')
|
||||||
|
@buildLimit = settings.buildLimit.value
|
||||||
|
@changeLimit = settings.changeLimit.value
|
||||||
|
@dataAccessor = dataService.open().closeOnDestroy(@$scope)
|
||||||
|
@_infoIsExpanded = {}
|
||||||
|
@$scope.all_builders = @all_builders = @dataAccessor.getBuilders()
|
||||||
|
@$scope.builders = @builders = []
|
||||||
|
if Intl?
|
||||||
|
collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'})
|
||||||
|
@strcompare = collator.compare
|
||||||
|
else
|
||||||
|
@strcompare = (a, b) ->
|
||||||
|
if a < b
|
||||||
|
return -1
|
||||||
|
if a == b
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@$scope.builds = @builds = @dataAccessor.getBuilds
|
||||||
|
property: ["yp_build_revision"]
|
||||||
|
limit: @buildLimit
|
||||||
|
order: '-started_at'
|
||||||
|
@changes = @dataAccessor.getChanges({limit: @changeLimit, order: '-changeid'})
|
||||||
|
@buildrequests = @dataAccessor.getBuildrequests({limit: @buildLimit, order: '-submitted_at'})
|
||||||
|
@buildsets = @dataAccessor.getBuildsets({limit: @buildLimit, order: '-submitted_at'})
|
||||||
|
|
||||||
|
@builds.onChange = @changes.onChange = @buildrequests.onChange = @buildsets.onChange = @onChange
|
||||||
|
|
||||||
|
onChange: (s) =>
|
||||||
|
# if there is no data, no need to try and build something.
|
||||||
|
if @builds.length == 0 or @all_builders.length == 0 or not @changes.$resolved or
|
||||||
|
@buildsets.length == 0 or @buildrequests == 0
|
||||||
|
return
|
||||||
|
if not @onchange_debounce?
|
||||||
|
@onchange_debounce = @$timeout(@_onChange, 100)
|
||||||
|
|
||||||
|
_onChange: =>
|
||||||
|
@onchange_debounce = undefined
|
||||||
|
# we only display builders who actually have builds
|
||||||
|
for build in @builds
|
||||||
|
@all_builders.get(build.builderid).hasBuild = true
|
||||||
|
|
||||||
|
@sortBuildersByTags(@all_builders)
|
||||||
|
|
||||||
|
@changesBySSID ?= {}
|
||||||
|
@changesByRevision ?= {}
|
||||||
|
for change in @changes
|
||||||
|
@changesBySSID[change.sourcestamp.ssid] = change
|
||||||
|
@changesByRevision[change.revision] = change
|
||||||
|
@populateChange(change)
|
||||||
|
|
||||||
|
|
||||||
|
for build in @builds
|
||||||
|
@matchBuildWithChange(build)
|
||||||
|
|
||||||
|
@filtered_changes = []
|
||||||
|
for ssid, change of @changesBySSID
|
||||||
|
if change.comments
|
||||||
|
change.subject = change.comments.split("\n")[0]
|
||||||
|
for builder in change.builders
|
||||||
|
if builder.builds.length > 0
|
||||||
|
@filtered_changes.push(change)
|
||||||
|
break
|
||||||
|
###
|
||||||
|
# Sort builders by tags
|
||||||
|
# Buildbot eight has the category option, but it was only limited to one category per builder,
|
||||||
|
# which make it easy to sort by category
|
||||||
|
# Here, we have multiple tags per builder, we need to try to group builders with same tags together
|
||||||
|
# The algorithm is rather twisted. It is a first try at the concept of grouping builders by tags..
|
||||||
|
###
|
||||||
|
|
||||||
|
sortBuildersByTags: (all_builders) ->
|
||||||
|
# first we only want builders with builds
|
||||||
|
builders_with_builds = []
|
||||||
|
builderids_with_builds = ""
|
||||||
|
for builder in all_builders
|
||||||
|
if builder.hasBuild
|
||||||
|
builders_with_builds.push(builder)
|
||||||
|
builderids_with_builds += "." + builder.builderid
|
||||||
|
|
||||||
|
if builderids_with_builds == @last_builderids_with_builds
|
||||||
|
# don't recalculate if it hasn't changed!
|
||||||
|
return
|
||||||
|
# we call recursive function, which finds non-overlapping groups
|
||||||
|
tag_line = @_sortBuildersByTags(builders_with_builds)
|
||||||
|
# we get a tree of builders grouped by tags
|
||||||
|
# we now need to flatten the tree, in order to build several lines of tags
|
||||||
|
# (each line is representing a depth in the tag tree)
|
||||||
|
# we walk the tree left to right and build the list of builders in the tree order, and the tag_lines
|
||||||
|
# in the tree, there are groups of remaining builders, which could not be grouped together,
|
||||||
|
# those have the empty tag ''
|
||||||
|
tag_lines = []
|
||||||
|
|
||||||
|
sorted_builders = []
|
||||||
|
set_tag_line = (depth, tag, colspan) ->
|
||||||
|
# we build the tag lines by using a sparse array
|
||||||
|
_tag_line = tag_lines[depth]
|
||||||
|
if not _tag_line?
|
||||||
|
# initialize the sparse array
|
||||||
|
_tag_line = tag_lines[depth] = []
|
||||||
|
else
|
||||||
|
# if we were already initialized, look at the last tag if this is the same
|
||||||
|
# we merge the two entries
|
||||||
|
last_tag = _tag_line[_tag_line.length - 1]
|
||||||
|
if last_tag.tag == tag
|
||||||
|
last_tag.colspan += colspan
|
||||||
|
return
|
||||||
|
_tag_line.push(tag: tag, colspan: colspan)
|
||||||
|
self = @
|
||||||
|
# recursive tree walking
|
||||||
|
walk_tree = (tag, depth) ->
|
||||||
|
set_tag_line(depth, tag.tag, tag.builders.length)
|
||||||
|
if not tag.tag_line? or tag.tag_line.length == 0
|
||||||
|
# this is the leaf of the tree, sort by buildername, and add them to the
|
||||||
|
# list of sorted builders
|
||||||
|
tag.builders.sort (a, b) -> self.strcompare(a.name, b.name)
|
||||||
|
sorted_builders = sorted_builders.concat(tag.builders)
|
||||||
|
for i in [1..100] # set the remaining depth of the tree to the same colspan
|
||||||
|
# (we hardcode the maximum depth for now :/ )
|
||||||
|
set_tag_line(depth + i, '', tag.builders.length)
|
||||||
|
return
|
||||||
|
for _tag in tag.tag_line
|
||||||
|
walk_tree(_tag, depth + 1)
|
||||||
|
|
||||||
|
for tag in tag_line
|
||||||
|
walk_tree(tag, 0)
|
||||||
|
|
||||||
|
@builders = sorted_builders
|
||||||
|
@tag_lines = []
|
||||||
|
# make a new array to avoid it to be sparse, and to remove lines filled with null tags
|
||||||
|
for tag_line in tag_lines
|
||||||
|
if not (tag_line.length == 1 and tag_line[0].tag == "")
|
||||||
|
@tag_lines.push(tag_line)
|
||||||
|
@last_builderids_with_builds = builderids_with_builds
|
||||||
|
###
|
||||||
|
# recursive function which sorts the builders by tags
|
||||||
|
# call recursively with groups of builders smaller and smaller
|
||||||
|
###
|
||||||
|
_sortBuildersByTags: (all_builders) ->
|
||||||
|
|
||||||
|
# first find out how many builders there is by tags in that group
|
||||||
|
builders_by_tags = {}
|
||||||
|
for builder in all_builders
|
||||||
|
if builder.tags?
|
||||||
|
for tag in builder.tags
|
||||||
|
if not builders_by_tags[tag]?
|
||||||
|
builders_by_tags[tag] = []
|
||||||
|
builders_by_tags[tag].push(builder)
|
||||||
|
tags = []
|
||||||
|
for tag, builders of builders_by_tags
|
||||||
|
# we don't want the tags that are on all the builders
|
||||||
|
if builders.length < all_builders.length
|
||||||
|
tags.push(tag: tag, builders: builders)
|
||||||
|
|
||||||
|
# sort the tags to first look at tags with the larger number of builders
|
||||||
|
# @FIXME maybe this is not the best method to find the best groups
|
||||||
|
tags.sort (a, b) -> b.builders.length - a.builders.length
|
||||||
|
|
||||||
|
tag_line = []
|
||||||
|
chosen_builderids = {}
|
||||||
|
# pick the tags one by one, by making sure we make non-overalaping groups
|
||||||
|
for tag in tags
|
||||||
|
excluded = false
|
||||||
|
for builder in tag.builders
|
||||||
|
if chosen_builderids.hasOwnProperty(builder.builderid)
|
||||||
|
excluded = true
|
||||||
|
break
|
||||||
|
if not excluded
|
||||||
|
for builder in tag.builders
|
||||||
|
chosen_builderids[builder.builderid] = tag.tag
|
||||||
|
tag_line.push(tag)
|
||||||
|
|
||||||
|
# some builders do not have tags, we put them in another group
|
||||||
|
remaining_builders = []
|
||||||
|
for builder in all_builders
|
||||||
|
if not chosen_builderids.hasOwnProperty(builder.builderid)
|
||||||
|
remaining_builders.push(builder)
|
||||||
|
|
||||||
|
if remaining_builders.length
|
||||||
|
tag_line.push(tag: "", builders: remaining_builders)
|
||||||
|
|
||||||
|
# if there is more than one tag in this line, we need to recurse
|
||||||
|
if tag_line.length > 1
|
||||||
|
for tag in tag_line
|
||||||
|
tag.tag_line = @_sortBuildersByTags(tag.builders)
|
||||||
|
return tag_line
|
||||||
|
|
||||||
|
###
|
||||||
|
# fill a change with a list of builders
|
||||||
|
###
|
||||||
|
populateChange: (change) ->
|
||||||
|
change.builders = []
|
||||||
|
change.buildersById = {}
|
||||||
|
for builder in @builders
|
||||||
|
builder = builderid: builder.builderid, name: builder.name, builds: []
|
||||||
|
change.builders.push(builder)
|
||||||
|
change.buildersById[builder.builderid] = builder
|
||||||
|
###
|
||||||
|
# Match builds with a change
|
||||||
|
###
|
||||||
|
matchBuildWithChange: (build) =>
|
||||||
|
buildrequest = @buildrequests.get(build.buildrequestid)
|
||||||
|
if not buildrequest?
|
||||||
|
return
|
||||||
|
buildset = @buildsets.get(buildrequest.buildsetid)
|
||||||
|
if not buildset?
|
||||||
|
return
|
||||||
|
if buildset? and buildset.sourcestamps?
|
||||||
|
for sourcestamp in buildset.sourcestamps
|
||||||
|
change = @changesBySSID[sourcestamp.ssid]
|
||||||
|
|
||||||
|
if build.properties?.yp_build_revision?
|
||||||
|
rev = build.properties.yp_build_revision[0]
|
||||||
|
change = @changesByRevision[rev]
|
||||||
|
if not change?
|
||||||
|
change = @changesBySSID[rev]
|
||||||
|
if not change?
|
||||||
|
change = @makeFakeChange(rev, build.started_at, rev)
|
||||||
|
change.caption = "Commit"
|
||||||
|
change.revlink = "http://git.yoctoproject.org/cgit.cgi/poky/commit/?id=" + rev
|
||||||
|
change.errorlink = "http://errors.yoctoproject.org/Errors/Latest/Autobuilder/?filter=" + rev + "&type=commit"
|
||||||
|
|
||||||
|
else
|
||||||
|
rev = "Unresolved"
|
||||||
|
if not change?
|
||||||
|
change = @makeFakeChange("Unresolved #{build.builderid}-#{build.buildid}", build.started_at, "Unresolved #{build.builderid}-#{build.buildid}")
|
||||||
|
change.caption = rev
|
||||||
|
|
||||||
|
change.buildersById[build.builderid].builds.push(build)
|
||||||
|
|
||||||
|
makeFakeChange: (revision, when_timestamp, comments) =>
|
||||||
|
change =
|
||||||
|
revision: revision
|
||||||
|
changeid: revision
|
||||||
|
when_timestamp: when_timestamp
|
||||||
|
comments: comments
|
||||||
|
@changesBySSID[revision] = change
|
||||||
|
@populateChange(change)
|
||||||
|
return change
|
||||||
|
###
|
||||||
|
# Open all change row information
|
||||||
|
###
|
||||||
|
openAll: ->
|
||||||
|
for change in @filtered_changes
|
||||||
|
change.show_details = true
|
||||||
|
|
||||||
|
###
|
||||||
|
# Close all change row information
|
||||||
|
###
|
||||||
|
closeAll: ->
|
||||||
|
for change in @filtered_changes
|
||||||
|
change.show_details = false
|
||||||
|
|
||||||
|
###
|
||||||
|
# Calculate row header (aka first column) width
|
||||||
|
# depending if we display commit comment, we reserve more space
|
||||||
|
###
|
||||||
|
getRowHeaderWidth: ->
|
||||||
|
if @hasExpanded()
|
||||||
|
return 400 # magic value enough to hold 78 characters lines
|
||||||
|
else
|
||||||
|
return 200
|
||||||
|
###
|
||||||
|
# Calculate col header (aka first row) height
|
||||||
|
# It depends on the length of the longest builder
|
||||||
|
###
|
||||||
|
getColHeaderHeight: ->
|
||||||
|
max_buildername = 0
|
||||||
|
for builder in @builders
|
||||||
|
max_buildername = Math.max(builder.name.length, max_buildername)
|
||||||
|
return Math.max(100, max_buildername * 3)
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Determine if we use a 100% width table or if we allow horizontal scrollbar
|
||||||
|
# depending on number of builders, and size of window, we need a fixed column size or a 100% width table
|
||||||
|
#
|
||||||
|
###
|
||||||
|
isBigTable: ->
|
||||||
|
padding = @getRowHeaderWidth()
|
||||||
|
if ((@$window.innerWidth - padding) / @builders.length) < 40
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# do we have at least one change expanded?
|
||||||
|
#
|
||||||
|
###
|
||||||
|
hasExpanded: ->
|
||||||
|
for change in @changes
|
||||||
|
if @infoIsExpanded(change)
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# display build details
|
||||||
|
#
|
||||||
|
###
|
||||||
|
selectBuild: (build) ->
|
||||||
|
modal = @$uibModal.open
|
||||||
|
templateUrl: 'yocto_console_view/views/modal.html'
|
||||||
|
controller: 'consoleModalController as modal'
|
||||||
|
windowClass: 'modal-big'
|
||||||
|
resolve:
|
||||||
|
selectedBuild: -> build
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# toggle display of additional info for that change
|
||||||
|
#
|
||||||
|
###
|
||||||
|
toggleInfo: (change) ->
|
||||||
|
change.show_details = !change.show_details
|
||||||
|
infoIsExpanded: (change) ->
|
||||||
|
return change.show_details
|
177
yocto_console_view/src/module/main.module.spec.coffee
Normal file
177
yocto_console_view/src/module/main.module.spec.coffee
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
beforeEach ->
|
||||||
|
module ($provide) ->
|
||||||
|
$provide.service '$uibModal', -> open: ->
|
||||||
|
null
|
||||||
|
module ($provide) ->
|
||||||
|
$provide.service 'resultsService', -> results2class: ->
|
||||||
|
null
|
||||||
|
|
||||||
|
# Mock bbSettingsProvider
|
||||||
|
module ($provide) ->
|
||||||
|
$provide.provider 'bbSettingsService', class
|
||||||
|
group = {}
|
||||||
|
addSettingsGroup: (g) -> g.items.map (i) ->
|
||||||
|
if i.name is 'lazy_limit_waterfall'
|
||||||
|
i.default_value = 2
|
||||||
|
group[i.name] = value: i.default_value
|
||||||
|
$get: ->
|
||||||
|
getSettingsGroup: ->
|
||||||
|
return group
|
||||||
|
save: ->
|
||||||
|
null
|
||||||
|
module 'yocto_console_view'
|
||||||
|
|
||||||
|
describe 'Console view', ->
|
||||||
|
$state = null
|
||||||
|
beforeEach inject ($injector) ->
|
||||||
|
$state = $injector.get('$state')
|
||||||
|
|
||||||
|
it 'should register a new state with the correct configuration', ->
|
||||||
|
name = 'console'
|
||||||
|
state = $state.get().pop()
|
||||||
|
data = state.data
|
||||||
|
expect(state.controller).toBe("#{name}Controller")
|
||||||
|
expect(state.controllerAs).toBe('c')
|
||||||
|
expect(state.templateUrl).toBe("yocto_console_view/views/#{name}.html")
|
||||||
|
expect(state.url).toBe("/#{name}")
|
||||||
|
|
||||||
|
describe 'Console view controller', ->
|
||||||
|
# Test data
|
||||||
|
|
||||||
|
builders = [
|
||||||
|
builderid: 1
|
||||||
|
masterids: [1]
|
||||||
|
,
|
||||||
|
builderid: 2
|
||||||
|
masterids: [1]
|
||||||
|
,
|
||||||
|
builderid: 3
|
||||||
|
masterids: [1]
|
||||||
|
,
|
||||||
|
builderid: 4
|
||||||
|
masterids: [1]
|
||||||
|
]
|
||||||
|
|
||||||
|
builds1 = [
|
||||||
|
buildid: 1
|
||||||
|
builderid: 1
|
||||||
|
buildrequestid: 1
|
||||||
|
,
|
||||||
|
buildid: 2
|
||||||
|
builderid: 2
|
||||||
|
buildrequestid: 1
|
||||||
|
,
|
||||||
|
buildid: 3
|
||||||
|
builderid: 4
|
||||||
|
buildrequestid: 2
|
||||||
|
,
|
||||||
|
buildid: 4
|
||||||
|
builderid: 3
|
||||||
|
buildrequestid: 2
|
||||||
|
]
|
||||||
|
|
||||||
|
builds2 = [
|
||||||
|
buildid: 5
|
||||||
|
builderid: 2
|
||||||
|
buildrequestid: 3
|
||||||
|
]
|
||||||
|
|
||||||
|
builds = builds1.concat(builds2)
|
||||||
|
|
||||||
|
buildrequests = [
|
||||||
|
builderid: 1
|
||||||
|
buildrequestid: 1
|
||||||
|
buildsetid: 1
|
||||||
|
,
|
||||||
|
builderid: 1
|
||||||
|
buildrequestid: 2
|
||||||
|
buildsetid: 1
|
||||||
|
,
|
||||||
|
builderid: 1
|
||||||
|
buildrequestid: 3
|
||||||
|
buildsetid: 2
|
||||||
|
]
|
||||||
|
|
||||||
|
buildsets = [
|
||||||
|
bsid: 1
|
||||||
|
sourcestamps: [
|
||||||
|
ssid: 1
|
||||||
|
]
|
||||||
|
,
|
||||||
|
bsid: 2
|
||||||
|
sourcestamps: [
|
||||||
|
ssid: 2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
changes = [
|
||||||
|
changeid: 1
|
||||||
|
sourcestamp:
|
||||||
|
ssid: 1
|
||||||
|
]
|
||||||
|
createController = scope = $rootScope = dataService = $window = $timeout = null
|
||||||
|
|
||||||
|
injected = ($injector) ->
|
||||||
|
$q = $injector.get('$q')
|
||||||
|
$rootScope = $injector.get('$rootScope')
|
||||||
|
$window = $injector.get('$window')
|
||||||
|
$timeout = $injector.get('$timeout')
|
||||||
|
dataService = $injector.get('dataService')
|
||||||
|
scope = $rootScope.$new()
|
||||||
|
dataService.when('builds', builds)
|
||||||
|
dataService.when('builders', builders)
|
||||||
|
dataService.when('changes', changes)
|
||||||
|
dataService.when('buildrequests', buildrequests)
|
||||||
|
dataService.when('buildsets', buildsets)
|
||||||
|
|
||||||
|
# Create new controller using controller as syntax
|
||||||
|
$controller = $injector.get('$controller')
|
||||||
|
createController = ->
|
||||||
|
return $controller 'consoleController as c',
|
||||||
|
# Inject controller dependencies
|
||||||
|
$q: $q
|
||||||
|
$window: $window
|
||||||
|
$scope: scope
|
||||||
|
|
||||||
|
beforeEach(inject(injected))
|
||||||
|
|
||||||
|
it 'should be defined', ->
|
||||||
|
createController()
|
||||||
|
expect(scope.c).toBeDefined()
|
||||||
|
|
||||||
|
it 'should bind the builds, builders, changes, buildrequests and buildsets to scope', ->
|
||||||
|
createController()
|
||||||
|
$rootScope.$digest()
|
||||||
|
$timeout.flush()
|
||||||
|
expect(scope.c.builds).toBeDefined()
|
||||||
|
expect(scope.c.builds.length).toBe(builds.length)
|
||||||
|
expect(scope.c.all_builders).toBeDefined()
|
||||||
|
expect(scope.c.all_builders.length).toBe(builders.length)
|
||||||
|
expect(scope.c.changes).toBeDefined()
|
||||||
|
expect(scope.c.changes.length).toBe(changes.length)
|
||||||
|
expect(scope.c.buildrequests).toBeDefined()
|
||||||
|
expect(scope.c.buildrequests.length).toBe(buildrequests.length)
|
||||||
|
expect(scope.c.buildsets).toBeDefined()
|
||||||
|
expect(scope.c.buildsets.length).toBe(buildsets.length)
|
||||||
|
|
||||||
|
it 'should match the builds with the change', ->
|
||||||
|
createController()
|
||||||
|
$timeout.flush()
|
||||||
|
$rootScope.$digest()
|
||||||
|
$timeout.flush()
|
||||||
|
expect(scope.c.changes[0]).toBeDefined()
|
||||||
|
expect(scope.c.changes[0].builders).toBeDefined()
|
||||||
|
builders = scope.c.changes[0].builders
|
||||||
|
expect(builders[0].builds[0].buildid).toBe(1)
|
||||||
|
expect(builders[1].builds[0].buildid).toBe(2)
|
||||||
|
expect(builders[2].builds[0].buildid).toBe(4)
|
||||||
|
expect(builders[3].builds[0].buildid).toBe(3)
|
||||||
|
|
||||||
|
xit 'should match sort the builders by tag groups', ->
|
||||||
|
createController()
|
||||||
|
_builders = FIXTURES['builders.fixture.json'].builders
|
||||||
|
for builder in _builders
|
||||||
|
builder.hasBuild = true
|
||||||
|
scope.c.sortBuildersByTags(_builders)
|
||||||
|
expect(_builders.length).toBe(scope.c.builders.length)
|
||||||
|
expect(scope.c.tag_lines.length).toEqual(5)
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
class Releaseselectorfield extends Directive
|
||||||
|
constructor: ->
|
||||||
|
return {
|
||||||
|
replace: false
|
||||||
|
restrict: 'E'
|
||||||
|
scope: false
|
||||||
|
templateUrl: "yocto_console_view/views/releaseselectorfield.html"
|
||||||
|
controller: '_ReleaseselectorfieldController'
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Releaseselectorfield extends Controller
|
||||||
|
constructor: ($scope, $http) ->
|
||||||
|
# HACK: we find the rootfield by doing $scope.$parent.$parent
|
||||||
|
rootfield = $scope
|
||||||
|
while rootfield? and not rootfield.rootfield?
|
||||||
|
rootfield = rootfield.$parent
|
||||||
|
|
||||||
|
if not rootfield?
|
||||||
|
console.log "rootfield not found!?!?"
|
||||||
|
return
|
||||||
|
|
||||||
|
# copy paste of code in forcedialog, which flatten the fields to be able to find easily
|
||||||
|
fields_ref = {}
|
||||||
|
gatherFields = (fields) ->
|
||||||
|
for field in fields
|
||||||
|
if field.fields?
|
||||||
|
gatherFields(field.fields)
|
||||||
|
else
|
||||||
|
fields_ref[field.fullName] = field
|
||||||
|
|
||||||
|
gatherFields(rootfield.rootfield.fields)
|
||||||
|
|
||||||
|
console.log fields_ref
|
||||||
|
|
||||||
|
# when our field change, we update the fields that we are suppose to
|
||||||
|
$scope.$watch "field.value", (n, o) ->
|
||||||
|
|
||||||
|
selector = $scope.field.selectors[n]
|
||||||
|
if selector?
|
||||||
|
for k, v of selector
|
||||||
|
console.log k
|
||||||
|
fields_ref[k].value = v
|
|
@ -0,0 +1,6 @@
|
||||||
|
basefield
|
||||||
|
label.control-label.col-sm-2(for="{{field.name}}")
|
||||||
|
| {{field.label}}
|
||||||
|
.col-sm-10
|
||||||
|
select.form-control(ng-model="field.value", ng-options="v for v in field.choices")
|
||||||
|
input.select-editable.form-control(type='text', ng-model="field.value")
|
|
@ -0,0 +1,7 @@
|
||||||
|
class ConsoleModal extends Controller
|
||||||
|
constructor: ($scope, @$uibModalInstance, @selectedBuild) ->
|
||||||
|
$scope.$on '$stateChangeStart', =>
|
||||||
|
@close()
|
||||||
|
|
||||||
|
close: ->
|
||||||
|
@$uibModalInstance.close()
|
|
@ -0,0 +1,9 @@
|
||||||
|
.modal-big {
|
||||||
|
.modal-dialog {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
6
yocto_console_view/src/module/view/modal/modal.tpl.jade
Normal file
6
yocto_console_view/src/module/view/modal/modal.tpl.jade
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// Show build summary for the selected build in a modal window
|
||||||
|
.modal-header
|
||||||
|
i.fa.fa-times.pull-right(ng-click='modal.close()')
|
||||||
|
h4.modal-title Build summary
|
||||||
|
.modal-body
|
||||||
|
buildsummary(ng-if='modal.selectedBuild' buildid='modal.selectedBuild.buildid')
|
|
@ -0,0 +1,10 @@
|
||||||
|
class Yoctochangedetails extends Directive('common')
|
||||||
|
constructor: ->
|
||||||
|
return {
|
||||||
|
replace: true
|
||||||
|
restrict: 'E'
|
||||||
|
scope:
|
||||||
|
change: '='
|
||||||
|
compact: '=?'
|
||||||
|
templateUrl: 'yocto_console_view/views/yoctochangedetails.html'
|
||||||
|
}
|
37
yocto_console_view/src/module/yoctochangedetails.tpl.jade
Normal file
37
yocto_console_view/src/module/yoctochangedetails.tpl.jade
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
div.yoctochangedetails(style="width:100%;")
|
||||||
|
div(style="width:100%;", ng-click="change.show_details = !change.show_details")
|
||||||
|
a(ng-if="change.revlink", ng-href="{{change.revlink}}", uib-tooltip="{{change.comments}}")
|
||||||
|
| {{ change.caption }}
|
||||||
|
a(ng-if="change.errorlink", ng-href="{{change.errorlink}}")
|
||||||
|
| {{ "Errors" }}
|
||||||
|
span(ng-if="!change.revlink", uib-tooltip="{{change.comments}}")
|
||||||
|
| {{ change.caption }}
|
||||||
|
span(ng-if="!compact" uib-tooltip="{{change.when_timestamp | dateformat:'LLL'}}")
|
||||||
|
| ({{ change.when_timestamp | timeago }})
|
||||||
|
i.fa.fa-chevron-circle-right.rotate.clickable(ng-class="{'fa-rotate-90':change.show_details}")
|
||||||
|
div.anim-changedetails(ng-show="change.show_details")
|
||||||
|
table.table.table-striped.table-condensed(ng-show="change.show_details")
|
||||||
|
tr(ng-show="change.author")
|
||||||
|
td Author
|
||||||
|
td {{ change.author }}
|
||||||
|
tr
|
||||||
|
td Date
|
||||||
|
td {{ change.when_timestamp | dateformat:'LLL'}} ({{ change.when_timestamp | timeago }})
|
||||||
|
tr(ng-show="change.repository")
|
||||||
|
td Repository
|
||||||
|
td {{ change.repository }}
|
||||||
|
tr(ng-show="change.branch")
|
||||||
|
td Branch
|
||||||
|
td {{ change.branch }}
|
||||||
|
tr
|
||||||
|
td Revision
|
||||||
|
td
|
||||||
|
a(ng-if="change.revlink", ng-href="{{change.revlink}}")
|
||||||
|
| {{ change.revision }}
|
||||||
|
|
||||||
|
h5 Comment
|
||||||
|
pre {{ change.comments }}
|
||||||
|
h5 Changed files
|
||||||
|
ul
|
||||||
|
li(ng-repeat='file in change.files') {{file}}
|
||||||
|
p(ng-hide="change.files.length") No files
|
83
yocto_console_view/src/styles/styles.less
Normal file
83
yocto_console_view/src/styles/styles.less
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
@column-width: 40px;
|
||||||
|
|
||||||
|
.console {
|
||||||
|
.table-fixedwidth {
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
.load-indicator {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 900;
|
||||||
|
background-color: #ffffff;
|
||||||
|
display: table;
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-weight: 300;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
min-width: @column-width;
|
||||||
|
max-width: @column-width;
|
||||||
|
width: @column-width;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.tag_row{
|
||||||
|
td {
|
||||||
|
margin:0px;
|
||||||
|
padding:0px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
font-size: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tr.first-row {
|
||||||
|
background-color: #fff!important;
|
||||||
|
th {
|
||||||
|
border: none;
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
.builder {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
transform: rotate(-25deg) ;
|
||||||
|
transform-origin: 0% 100%;
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.yoctochangedetails > .no-select > * {
|
||||||
|
margin-left: 0.3em;
|
||||||
|
margin-right: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-editable {
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
border:none;
|
||||||
|
margin:2px;
|
||||||
|
width:90%;
|
||||||
|
height:29px;
|
||||||
|
}
|
||||||
|
.select-editable input:focus {
|
||||||
|
outline:none;
|
||||||
|
}
|
2
yocto_console_view/test/main.coffee
Normal file
2
yocto_console_view/test/main.coffee
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# app module is necessary for plugins, but only in the test environment
|
||||||
|
angular.module("app", []).constant("config", {"url": "foourl"})
|
3087
yocto_console_view/yarn.lock
Normal file
3087
yocto_console_view/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
yocto_console_view/yocto_console_view/VERSION
Normal file
1
yocto_console_view/yocto_console_view/VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
1.1.3.dev66
|
11
yocto_console_view/yocto_console_view/__init__.py
Normal file
11
yocto_console_view/yocto_console_view/__init__.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from buildbot.www.plugin import Application
|
||||||
|
from buildbot.schedulers.forcesched import ChoiceStringParameter
|
||||||
|
|
||||||
|
# create the interface for the setuptools entry point
|
||||||
|
ep = Application(__name__, "Yocto Console View UI")
|
||||||
|
|
||||||
|
class ReleaseSelector(ChoiceStringParameter):
|
||||||
|
|
||||||
|
spec_attributes = ["selectors"]
|
||||||
|
type = "releaseselector"
|
||||||
|
selectors = None
|
347
yocto_console_view/yocto_console_view/static/fixtures.js
Normal file
347
yocto_console_view/yocto_console_view/static/fixtures.js
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
window.FIXTURES = {
|
||||||
|
"builders.fixture.json": {
|
||||||
|
"builders": [
|
||||||
|
{
|
||||||
|
"builderid": 1,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"name": "buildbot-job",
|
||||||
|
"tags": [
|
||||||
|
"job",
|
||||||
|
"buildbot"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 2,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"name": "buildbot",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"trunk"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 3,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:pylint TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TESTS:pylint",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 4,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:flake8 TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:flake8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 5,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:isort TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:isort"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 6,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:docs TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:docs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 7,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:coverage TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:coverage"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 8,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:js TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 9,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:smokes TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:smokes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 10,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial TWISTED:14.0.2 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial",
|
||||||
|
"TWISTED:14.0.2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 11,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial TWISTED:15.4.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial",
|
||||||
|
"TWISTED:15.4.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 12,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 13,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot DB_TYPE:sqlite SQLALCHEMY:latest TESTS:trial TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial",
|
||||||
|
"DB_TYPE:sqlite"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 14,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot DB_TYPE:mysql SQLALCHEMY:latest TESTS:trial TWISTED:latest python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial",
|
||||||
|
"DB_TYPE:mysql"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 15,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:0.8.0 TESTS:trial TWISTED:15.5.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial",
|
||||||
|
"SQLALCHEMY:0.8.0",
|
||||||
|
"TWISTED:15.5.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 16,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial TWISTED:15.5.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial",
|
||||||
|
"TWISTED:15.5.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 17,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial_worker TWISTED:10.2.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial_worker",
|
||||||
|
"TWISTED:10.2.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 18,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial_worker TWISTED:11.1.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial_worker",
|
||||||
|
"TWISTED:11.1.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 19,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial_worker TWISTED:12.2.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial_worker",
|
||||||
|
"TWISTED:12.2.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 20,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial_worker TWISTED:13.2.0 python:2.7",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"python:2.7",
|
||||||
|
"TESTS:trial_worker",
|
||||||
|
"TWISTED:13.2.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 21,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial_worker TWISTED:14.0.2 python:2.6",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:14.0.2",
|
||||||
|
"TESTS:trial_worker",
|
||||||
|
"python:2.6"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 22,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial_worker TWISTED:15.4.0 python:2.6",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:15.4.0",
|
||||||
|
"TESTS:trial_worker",
|
||||||
|
"python:2.6"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 23,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:coverage TWISTED:trunk python:3.5",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TESTS:coverage",
|
||||||
|
"TWISTED:trunk",
|
||||||
|
"python:3.5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 24,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:flake8 TWISTED:trunk python:3.5",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TESTS:flake8",
|
||||||
|
"TWISTED:trunk",
|
||||||
|
"python:3.5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 25,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:smokes TWISTED:latest python:3.5",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TWISTED:latest",
|
||||||
|
"TESTS:smokes",
|
||||||
|
"python:3.5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"builderid": 26,
|
||||||
|
"description": null,
|
||||||
|
"masterids": [],
|
||||||
|
"name": "buildbot SQLALCHEMY:latest TESTS:trial TWISTED:trunk python:3.6",
|
||||||
|
"tags": [
|
||||||
|
"buildbot",
|
||||||
|
"SQLALCHEMY:latest",
|
||||||
|
"TESTS:trial",
|
||||||
|
"TWISTED:trunk",
|
||||||
|
"python:3.6"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"total": 26
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
1
yocto_console_view/yocto_console_view/static/scripts.js
Normal file
1
yocto_console_view/yocto_console_view/static/scripts.js
Normal file
File diff suppressed because one or more lines are too long
1
yocto_console_view/yocto_console_view/static/styles.css
Normal file
1
yocto_console_view/yocto_console_view/static/styles.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.console .table-fixedwidth{width:initial}.console .load-indicator{width:100%;height:100%;z-index:900;background-color:#fff;display:table}.console .load-indicator .spinner{display:table-cell;vertical-align:middle;text-align:center}.console .load-indicator .spinner p{font-weight:300;margin-top:10px}.console .column{min-width:40px;max-width:40px;width:40px}.console table{border:none}.console .tag_row td{margin:0;padding:0}.console .tag_row span{position:relative;float:left;font-size:10px;overflow:hidden;text-decoration:none;white-space:nowrap}.console tr.first-row{background-color:#fff!important}.console tr.first-row th{border:none;background-color:#fff!important}.console tr.first-row .builder{position:relative;float:left;font-size:12px;text-align:center;transform:rotate(-25deg);transform-origin:0 100%;text-decoration:none;white-space:nowrap}.yoctochangedetails>.no-select>*{margin-left:.3em;margin-right:.3em}.select-editable{position:absolute;top:0;border:none;margin:2px;width:90%;height:29px}.select-editable input:focus{outline:0}.modal-big .modal-dialog{width:80%}.modal-big .fa{cursor:pointer}
|
80000
yocto_console_view/yocto_console_view/static/tests.js
Normal file
80000
yocto_console_view/yocto_console_view/static/tests.js
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user