Merge branch 'master' into rkh-v3

Conflicts:
	Gemfile
	Gemfile.lock
	lib/travis/api/app.rb
This commit is contained in:
Konstantin Haase 2015-01-21 16:50:34 +01:00
commit df64ee29c8
54 changed files with 265 additions and 36720 deletions

View File

@ -1,5 +0,0 @@
{
"result": {
"covered_percent": 67.05
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,799 +0,0 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 0.9
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* reset.css */
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
article, aside, dialog, figure, footer, header, hgroup, nav, section {display:block;}
body {line-height:1.5;}
table {border-collapse:separate;border-spacing:0;}
caption, th, td {text-align:left;font-weight:normal;}
table, td, th {vertical-align:middle;}
blockquote:before, blockquote:after, q:before, q:after {content:"";}
blockquote, q {quotes:"" "";}
a img {border:none;}
/* typography.css */
html {font-size:100.01%;}
body {font-size:82%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
h1 {font-size:3em;line-height:1;margin-bottom:0.5em;}
h2 {font-size:2em;margin-bottom:0.75em;}
h3 {font-size:1.5em;line-height:1;margin-bottom:1em;}
h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
h6 {font-size:1em;font-weight:bold;}
h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
p {margin:0 0 1.5em;}
p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;}
p img.right {float:right;margin:1.5em 0 1.5em 1.5em;}
a:focus, a:hover {color:#000;}
a {color:#009;text-decoration:underline;}
blockquote {margin:1.5em;color:#666;font-style:italic;}
strong {font-weight:bold;}
em, dfn {font-style:italic;}
dfn {font-weight:bold;}
sup, sub {line-height:0;}
abbr, acronym {border-bottom:1px dotted #666;}
address {margin:0 0 1.5em;font-style:italic;}
del {color:#666;}
pre {margin:1.5em 0;white-space:pre;}
pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
li ul, li ol {margin:0;}
ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;}
ul {list-style-type:disc;}
ol {list-style-type:decimal;}
dl {margin:0 0 1.5em 0;}
dl dt {font-weight:bold;}
dd {margin-left:1.5em;}
table {margin-bottom:1.4em;width:100%;}
th {font-weight:bold;}
thead th {background:#c3d9ff;}
th, td, caption {padding:4px 10px 4px 5px;}
tr.even td {background:#efefef;}
tfoot {font-style:italic;}
caption {background:#eee;}
.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
.hide {display:none;}
.quiet {color:#666;}
.loud {color:#000;}
.highlight {background:#ff0;}
.added {background:#060;color:#fff;}
.removed {background:#900;color:#fff;}
.first {margin-left:0;padding-left:0;}
.last {margin-right:0;padding-right:0;}
.top {margin-top:0;padding-top:0;}
.bottom {margin-bottom:0;padding-bottom:0;}
/* forms.css */
label {font-weight:bold;}
fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;}
legend {font-weight:bold;font-size:1.2em;}
input[type=text], input[type=password], input.text, input.title, textarea, select {background-color:#fff;border:1px solid #bbb;}
input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {border-color:#666;}
input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;}
input.text, input.title {width:300px;padding:5px;}
input.title {font-size:1.5em;}
textarea {width:390px;height:250px;padding:5px;}
input[type=checkbox], input[type=radio], input.checkbox, input.radio {position:relative;top:.25em;}
form.inline {line-height:3;}
form.inline p {margin-bottom:0;}
.error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;}
.error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;}
.notice {background:#FFF6BF;color:#514721;border-color:#FFD324;}
.success {background:#E6EFC2;color:#264409;border-color:#C6D880;}
.error a {color:#8a1f11;}
.notice a {color:#514721;}
.success a {color:#264409;}
.box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;}
hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;}
hr.space {background:#fff;color:#fff;visibility:hidden;}
.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
.clearfix, .container {display:block;}
.clear {clear:both;}
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
pre code {
}
pre .comment,
pre .template_comment,
pre .diff .header,
pre .javadoc {
color: #998;
font-style: italic
}
pre .keyword,
pre .css .rule .keyword,
pre .winutils,
pre .javascript .title,
pre .lisp .title {
color: #000;
font-weight: bold
}
pre .number,
pre .hexcolor {
color: #458
}
pre .string,
pre .tag .value,
pre .phpdoc,
pre .tex .formula {
color: #d14
}
pre .subst {
color: #712;
}
pre .constant,
pre .title,
pre .id {
color: #900;
font-weight: bold
}
pre .javascript .title,
pre .lisp .title,
pre .subst {
font-weight: normal
}
pre .class .title,
pre .haskell .label,
pre .tex .command {
color: #458;
font-weight: bold
}
pre .tag,
pre .tag .title,
pre .rules .property,
pre .django .tag .keyword {
color: #000080;
font-weight: normal
}
pre .attribute,
pre .variable,
pre .instancevar,
pre .lisp .body {
color: #008080
}
pre .regexp {
color: #009926
}
pre .class {
color: #458;
font-weight: bold
}
pre .symbol,
pre .ruby .symbol .string,
pre .ruby .symbol .keyword,
pre .ruby .symbol .keymethods,
pre .lisp .keyword,
pre .tex .special,
pre .input_number {
color: #990073
}
pre .builtin,
pre .built_in,
pre .lisp .title {
color: #0086b3
}
pre .preprocessor,
pre .pi,
pre .doctype,
pre .shebang,
pre .cdata {
color: #999;
font-weight: bold
}
pre .deletion {
background: #fdd
}
pre .addition {
background: #dfd
}
pre .diff .change {
background: #0086b3
}
pre .chunk {
color: #aaa
}
pre .tex .formula {
opacity: 0.5;
}
/*
* jQuery UI CSS Framework @VERSION
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework @VERSION
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
.ui-widget-header a { color: #222222; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
/*
ColorBox Core Style:
The following CSS is consistent between example themes and should not be altered.
*/
#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
#cboxOverlay{position:fixed; width:100%; height:100%;}
#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
#cboxContent{position:relative;}
#cboxLoadedContent{overflow:auto;}
#cboxTitle{margin:0;}
#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none;}
.cboxIframe{width:100%; height:100%; display:block; border:0;}
#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box;}
/*
User Style:
Change the following styles to modify the appearance of ColorBox. They are
ordered & tabbed in a way that represents the nesting of the generated HTML.
*/
#cboxOverlay{background:#000;}
#colorbox{}
#cboxTopLeft{width:14px; height:14px; background:url(colorbox/controls.png) no-repeat 0 0;}
#cboxTopCenter{height:14px; background:url(colorbox/border.png) repeat-x top left;}
#cboxTopRight{width:14px; height:14px; background:url(colorbox/controls.png) no-repeat -36px 0;}
#cboxBottomLeft{width:14px; height:43px; background:url(colorbox/controls.png) no-repeat 0 -32px;}
#cboxBottomCenter{height:43px; background:url(colorbox/border.png) repeat-x bottom left;}
#cboxBottomRight{width:14px; height:43px; background:url(colorbox/controls.png) no-repeat -36px -32px;}
#cboxMiddleLeft{width:14px; background:url(colorbox/controls.png) repeat-y -175px 0;}
#cboxMiddleRight{width:14px; background:url(colorbox/controls.png) repeat-y -211px 0;}
#cboxContent{background:#fff; overflow:visible;}
.cboxIframe{background:#fff;}
#cboxError{padding:50px; border:1px solid #ccc;}
#cboxLoadedContent{margin-bottom:5px;}
#cboxLoadingOverlay{background:url(colorbox/loading_background.png) no-repeat center center;}
#cboxLoadingGraphic{background:url(colorbox/loading.gif) no-repeat center center;}
#cboxTitle{position:absolute; bottom:-25px; left:0; text-align:center; width:100%; font-weight:bold; color:#7C7C7C;}
#cboxCurrent{position:absolute; bottom:-25px; left:58px; font-weight:bold; color:#7C7C7C;}
#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{position:absolute; bottom:-29px; background:url(colorbox/controls.png) no-repeat 0px 0px; width:23px; height:23px; text-indent:-9999px;}
#cboxPrevious{left:0px; background-position: -51px -25px;}
#cboxPrevious:hover{background-position:-51px 0px;}
#cboxNext{left:27px; background-position:-75px -25px;}
#cboxNext:hover{background-position:-75px 0px;}
#cboxClose{right:0; background-position:-100px -25px;}
#cboxClose:hover{background-position:-100px 0px;}
.cboxSlideshow_on #cboxSlideshow{background-position:-125px 0px; right:27px;}
.cboxSlideshow_on #cboxSlideshow:hover{background-position:-150px 0px;}
.cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px; right:27px;}
.cboxSlideshow_off #cboxSlideshow:hover{background-position:-125px 0px;}
#loading {
position: fixed;
left: 40%;
top: 50%; }
a {
color: #333333;
text-decoration: none; }
a:hover {
color: black;
text-decoration: underline; }
body {
font-family: "Lucida Grande", Helvetica, "Helvetica Neue", Arial, sans-serif;
padding: 12px;
background-color: #333333; }
h1, h2, h3, h4 {
color: #1c2324;
margin: 0;
padding: 0;
margin-bottom: 12px; }
table {
width: 100%; }
#content {
clear: left;
background-color: white;
border: 2px solid #dddddd;
border-top: 8px solid #dddddd;
padding: 18px;
-webkit-border-bottom-left-radius: 5px;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-moz-border-radius-bottomright: 5px;
-moz-border-radius-topright: 5px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border-top-right-radius: 5px; }
.dataTables_filter, .dataTables_info {
padding: 2px 6px; }
abbr.timeago {
text-decoration: none;
border: none;
font-weight: bold; }
.timestamp {
float: right;
color: #dddddd; }
.group_tabs {
list-style: none;
float: left;
margin: 0;
padding: 0; }
.group_tabs li {
display: inline;
float: left; }
.group_tabs li a {
font-family: Helvetica, Arial, sans-serif;
display: block;
float: left;
text-decoration: none;
padding: 4px 8px;
background-color: #aaaaaa;
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dddddd), to(#aaaaaa));
background: -moz-linear-gradient(#dddddd, #aaaaaa);
background: linear-gradient(#dddddd, #aaaaaa);
text-shadow: #e5e5e5 1px 1px 0px;
border-bottom: none;
color: #333333;
font-weight: bold;
margin-right: 8px;
border-top: 1px solid #efefef;
-webkit-border-top-left-radius: 2px;
-webkit-border-top-right-radius: 2px;
-moz-border-radius-topleft: 2px;
-moz-border-radius-topright: 2px;
border-top-left-radius: 2px;
border-top-right-radius: 2px; }
.group_tabs li a:hover {
background-color: #cccccc;
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#eeeeee), to(#aaaaaa));
background: -moz-linear-gradient(#eeeeee, #aaaaaa);
background: linear-gradient(#eeeeee, #aaaaaa); }
.group_tabs li a:active {
padding-top: 5px;
padding-bottom: 3px; }
.group_tabs li.active a {
color: black;
text-shadow: white 1px 1px 0px;
background-color: #dddddd;
background: -webkit-gradient(linear, 0 0, 0 bottom, from(white), to(#dddddd));
background: -moz-linear-gradient(white, #dddddd);
background: linear-gradient(white, #dddddd); }
.file_list {
margin-bottom: 18px; }
a.src_link {
background: url("./magnify.png") no-repeat left 50%;
padding-left: 18px; }
tr, td {
margin: 0;
padding: 0; }
th {
white-space: nowrap; }
th.ui-state-default {
cursor: pointer; }
th span.ui-icon {
float: left; }
td {
padding: 4px 8px; }
td.strong {
font-weight: bold; }
.source_table h3, .source_table h4 {
padding: 0;
margin: 0;
margin-bottom: 4px; }
.source_table .header {
padding: 10px; }
.source_table pre {
margin: 0;
padding: 0;
white-space: normal;
color: black;
font-family: "Monaco", "Inconsolata", "Consolas", monospace; }
.source_table code {
color: black;
font-family: "Monaco", "Inconsolata", "Consolas", monospace; }
.source_table pre {
background-color: #333333; }
.source_table pre ol {
margin: 0px;
padding: 0px;
margin-left: 45px;
font-size: 12px;
color: white; }
.source_table pre li {
margin: 0px;
padding: 2px 6px;
border-left: 5px solid white; }
.source_table pre li code {
white-space: pre;
white-space: pre-wrap; }
.source_table pre .hits {
float: right;
margin-left: 10px;
padding: 2px 4px;
background-color: #444444;
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#222222), to(#666666));
background: -moz-linear-gradient(#222222, #666666);
background: linear-gradient(#222222, #666666);
color: white;
font-family: Helvetica, "Helvetica Neue", Arial, sans-serif;
font-size: 10px;
font-weight: bold;
text-align: center;
border-radius: 6px; }
#footer {
color: #dddddd;
font-size: 12px;
font-weight: bold;
margin-top: 12px;
text-align: right; }
#footer a {
color: #eeeeee;
text-decoration: underline; }
#footer a:hover {
color: white;
text-decoration: none; }
.green {
color: #009900; }
.red {
color: #990000; }
.yellow {
color: #ddaa00; }
.source_table .covered {
border-color: #009900; }
.source_table .missed {
border-color: #990000; }
.source_table .never {
border-color: black; }
.source_table .skipped {
border-color: #ffcc00; }
.source_table .covered:nth-child(odd) {
background-color: #cdf2cd; }
.source_table .covered:nth-child(even) {
background-color: #dbf2db; }
.source_table .missed:nth-child(odd) {
background-color: #f7c0c0; }
.source_table .missed:nth-child(even) {
background-color: #f7cfcf; }
.source_table .never:nth-child(odd) {
background-color: #efefef; }
.source_table .never:nth-child(even) {
background-color: #f4f4f4; }
.source_table .skipped:nth-child(odd) {
background-color: #fbf0c0; }
.source_table .skipped:nth-child(even) {
background-color: #fbffcf; }

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because it is too large Load Diff

3
.gitignore vendored
View File

@ -2,3 +2,6 @@ config/travis.yml
.yardoc .yardoc
log/ log/
vendor vendor
config/skylight.yml
.coverage
.coverage/

View File

@ -1 +1 @@
2.1.4 2.1.5

View File

@ -1,17 +1,21 @@
language: ruby language: ruby
sudo: false sudo: false
rvm:
- 2.1.4 rvm: 2.1.5
env: env:
global: global:
- RUBY_GC_MALLOC_LIMIT=90000000 - RUBY_GC_MALLOC_LIMIT=90000000
- RUBY_GC_HEAP_FREE_SLOTS=200000 - RUBY_GC_HEAP_FREE_SLOTS=200000
cache: bundler cache: bundler
addons: addons:
postgresql: 9.3 postgresql: 9.3
services: services:
- redis - redis
before_script: before_script:
- 'RAILS_ENV=test bundle exec rake db:create db:migrate --trace' - 'RAILS_ENV=test bundle exec rake db:create db:migrate --trace'
notifications:
irc: "irc.freenode.org#travis"

View File

@ -1,6 +1,10 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gemspec gemspec
ruby '2.1.2' if ENV.key?('DYNO')
gem 's3', github: 'travis-ci/s3'
gem 'travis-core', github: 'travis-ci/travis-core' gem 'travis-core', github: 'travis-ci/travis-core'
gem 'travis-support', github: 'travis-ci/travis-support' gem 'travis-support', github: 'travis-ci/travis-support'
gem 'travis-config', '~> 0.1.0' gem 'travis-config', '~> 0.1.0'
@ -25,6 +29,7 @@ gem 'metriks', '0.9.9.6'
gem 'metriks-librato_metrics', github: 'eric/metriks-librato_metrics' gem 'metriks-librato_metrics', github: 'eric/metriks-librato_metrics'
gem 'micro_migrations' gem 'micro_migrations'
gem 'simplecov' gem 'simplecov'
gem 'skylight'
group :test do group :test do
gem 'rspec', '~> 2.13' gem 'rspec', '~> 2.13'

View File

@ -41,6 +41,13 @@ GIT
rack-cache (1.2) rack-cache (1.2)
rack (>= 0.4) rack (>= 0.4)
GIT
remote: git://github.com/travis-ci/s3.git
revision: 386361c1b0ede19cde0ddaf86e41a16308575f5d
specs:
s3 (0.3.21)
proxies (~> 0.2.0)
GIT GIT
remote: git://github.com/travis-ci/travis-core.git remote: git://github.com/travis-ci/travis-core.git
revision: a0aa1e2f79d45a4c59c1046a5435fe598eda2d2a revision: a0aa1e2f79d45a4c59c1046a5435fe598eda2d2a
@ -275,8 +282,6 @@ GEM
rspec-expectations (2.99.2) rspec-expectations (2.99.2)
diff-lcs (>= 1.1.3, < 2.0) diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.99.2) rspec-mocks (2.99.2)
s3 (0.3.21)
proxies (~> 0.2.0)
sass (3.4.6) sass (3.4.6)
sidekiq (2.5.0) sidekiq (2.5.0)
celluloid (~> 0.12.0) celluloid (~> 0.12.0)
@ -307,6 +312,8 @@ GEM
rack-test rack-test
sinatra (~> 1.4.0) sinatra (~> 1.4.0)
tilt (~> 1.3) tilt (~> 1.3)
skylight (0.5.2)
activesupport (>= 3.0.0)
slop (3.6.0) slop (3.6.0)
sprockets (2.2.2) sprockets (2.2.2)
hike (~> 1.2) hike (~> 1.2)
@ -369,10 +376,12 @@ DEPENDENCIES
rb-fsevent (~> 0.9.1) rb-fsevent (~> 0.9.1)
rerun rerun
rspec (~> 2.13) rspec (~> 2.13)
s3!
sentry-raven! sentry-raven!
simplecov simplecov
sinatra sinatra
sinatra-contrib sinatra-contrib
skylight
travis-api! travis-api!
travis-config (~> 0.1.0) travis-config (~> 0.1.0)
travis-core! travis-core!

View File

@ -0,0 +1,50 @@
module ConditionalSkylight
module DummyMixin
def self.included(object)
object.extend(self)
super
end
def instrument_method(*)
end
end
extend self
def enabled?
authenticated? and lucky_dyno?
end
def authenticated?
ENV['SKYLIGHT_AUTHENTICATION'.freeze]
end
def lucky_dyno?
@lucky_dyno = detect_lucy_dyno unless instance_variable_defined? :@lucky_dyno
@lucky_dyno
end
def detect_lucy_dyno
unless ENV['DYNO'.freeze]
warn "[ConditionalSkylight] $DYNO not set, skipping lucky dyno check"
return true
end
dyno = Integer ENV['DYNO'.freeze][/\d+/]
if dyno % 5 == 1
warn "[ConditionalSkylight] lucky dyno, enabling Skylight"
true
else
warn "[ConditionalSkylight] not a lucky dyno, disabling Skylight"
false
end
end
if enabled?
require 'skylight'
Mixin = Skylight::Helpers
else
Mixin = DummyMixin
end
end

View File

@ -1,3 +1,4 @@
require 'conditional_skylight'
require 'travis' require 'travis'
require 'travis/model' require 'travis/model'
require 'travis/support/amqp' require 'travis/support/amqp'
@ -18,8 +19,10 @@ require 'metriks/reporter/logger'
require 'metriks/librato_metrics_reporter' require 'metriks/librato_metrics_reporter'
require 'travis/support/log_subscriber/active_record_metrics' require 'travis/support/log_subscriber/active_record_metrics'
require 'fileutils' require 'fileutils'
require 'travis/api/instruments'
require 'travis/api/v2/http' require 'travis/api/v2/http'
require 'travis/api/v3' require 'travis/api/v3'
require 'travis/api/app/stack_instrumentation'
# Rack class implementing the HTTP API. # Rack class implementing the HTTP API.
# Instances respond to #call. # Instances respond to #call.
@ -75,6 +78,8 @@ module Travis::Api
def initialize def initialize
@app = Rack::Builder.app do @app = Rack::Builder.app do
extend StackInstrumentation
use Travis::Api::App::Middleware::Skylight
use(Rack::Config) { |env| env['metriks.request.start'] ||= Time.now.utc } use(Rack::Config) { |env| env['metriks.request.start'] ||= Time.now.utc }
Rack::Utils::HTTP_STATUS_CODES[420] = "Enhance Your Calm" Rack::Utils::HTTP_STATUS_CODES[420] = "Enhance Your Calm"

View File

@ -3,6 +3,8 @@ require 'securerandom'
class Travis::Api::App class Travis::Api::App
class AccessToken class AccessToken
include ConditionalSkylight::Mixin
DEFAULT_SCOPES = [:public, :private] DEFAULT_SCOPES = [:public, :private]
attr_reader :token, :scopes, :user_id, :app_id, :expires_in, :extra attr_reader :token, :scopes, :user_id, :app_id, :expires_in, :extra
@ -22,6 +24,7 @@ class Travis::Api::App
new(token: token, scopes: scopes, user_id: user_id, app_id: app_id, extra: extra) if user_id new(token: token, scopes: scopes, user_id: user_id, app_id: app_id, extra: extra) if user_id
end end
instrument_method
def initialize(options = {}) def initialize(options = {})
raise ArgumentError, 'must supply either user_id or user' unless options.key?(:user) ^ options.key?(:user_id) raise ArgumentError, 'must supply either user_id or user' unless options.key?(:user) ^ options.key?(:user_id)
raise ArgumentError, 'must supply app_id' unless options.key?(:app_id) raise ArgumentError, 'must supply app_id' unless options.key?(:app_id)
@ -40,6 +43,7 @@ class Travis::Api::App
@extra = options[:extra] @extra = options[:extra]
end end
instrument_method
def save def save
key = key(token) key = key(token)
redis.del(key) redis.del(key)
@ -90,6 +94,7 @@ class Travis::Api::App
private private
instrument_method
def reuse_token def reuse_token
redis.get(reuse_key) unless expires_in redis.get(reuse_key) unless expires_in
end end

View File

@ -58,7 +58,9 @@ class Travis::Api::App
get '/:job_id/log' do get '/:job_id/log' do
resource = service(:find_log, params).run resource = service(:find_log, params).run
if (!resource || resource.archived?) if (resource && resource.removed_at) && accepts?('application/json')
respond_with resource
elsif (!resource || resource.archived?)
# the way we use responders makes it hard to validate proper format # the way we use responders makes it hard to validate proper format
# automatically here, so we need to check it explicitly # automatically here, so we need to check it explicitly
if accepts?('text/plain') if accepts?('text/plain')

View File

@ -0,0 +1,7 @@
require 'conditional_skylight'
if ConditionalSkylight.enabled?
require_relative 'skylight/actual'
else
require_relative 'skylight/dummy'
end

View File

@ -0,0 +1,26 @@
require 'travis/api/app'
require 'skylight'
require 'skylight/probes/tilt'
require 'skylight/probes/redis'
class Travis::Api::App
class Middleware
class Skylight < Middleware
set(:setup) { ::Skylight.start! }
use ::Skylight::Middleware
after do
instrumenter = ::Skylight::Instrumenter.instance
trace = instrumenter.current_trace if instrumenter
trace.endpoint = "#{request.request_method} #{endpoint || '???'}" if trace
end
def endpoint
return @endpoint if defined? @endpoint and @endpoint
return unless headers['X-Pattern'].present? and headers['X-Endpoint'].present?
@endpoint = Object.const_get(headers['X-Endpoint']).prefix + headers['X-Pattern']
rescue NameError
end
end
end
end

View File

@ -0,0 +1,7 @@
class Travis::Api::App
class Middleware
module Skylight
def self.new(app) app end
end
end
end

View File

@ -44,6 +44,7 @@ module Travis::Api::App::Responders
super && resource.is_a?(ActiveRecord::Relation) && resource.first.is_a?(Build) super && resource.is_a?(ActiveRecord::Relation) && resource.first.is_a?(Build)
end end
instrument_method
def apply def apply
super super

View File

@ -4,6 +4,7 @@ module Travis::Api::App::Responders
'svg' 'svg'
end end
instrument_method
def apply def apply
set_headers set_headers
send_file(filename, type: :svg, last_modified: last_modified) send_file(filename, type: :svg, last_modified: last_modified)

View File

@ -1,5 +1,6 @@
module Travis::Api::App::Responders module Travis::Api::App::Responders
class Base class Base
include ConditionalSkylight::Mixin
attr_reader :endpoint, :resource, :options attr_reader :endpoint, :resource, :options
def initialize(endpoint, resource, options = {}) def initialize(endpoint, resource, options = {})

View File

@ -10,6 +10,7 @@ module Travis::Api::App::Responders
headers['Content-Disposition'] = %(inline; filename="#{File.basename(filename)}") headers['Content-Disposition'] = %(inline; filename="#{File.basename(filename)}")
end end
instrument_method
def apply def apply
set_headers set_headers
send_file(filename, type: :png, last_modified: last_modified) send_file(filename, type: :png, last_modified: last_modified)

View File

@ -7,6 +7,7 @@ class Travis::Api::App
super && !resource.is_a?(String) && !resource.nil? && accepts_log? super && !resource.is_a?(String) && !resource.nil? && accepts_log?
end end
instrument_method
def apply def apply
super super
@ -23,13 +24,18 @@ class Travis::Api::App
return true unless resource.is_a?(Log) return true unless resource.is_a?(Log)
chunked = accept_params[:chunked] chunked = accept_params[:chunked]
chunked ? !resource.aggregated_at : true if resource.removed_at
true
else
chunked ? !resource.aggregated_at : true
end
end end
def result def result
if builder if builder
p = params p = params
p[:root] = options[:type] if options[:type] p[:root] = options[:root] if options[:root]
p[:root] = options[:type] if options[:type] && !p[:root]
builder.new(resource, p).data builder.new(resource, p).data
else else
basic_type_resource basic_type_resource

View File

@ -13,6 +13,7 @@ module Travis::Api::App::Responders
super && (resource.is_a?(Log) || resource.is_a?(String)) super && (resource.is_a?(Log) || resource.is_a?(String))
end end
instrument_method
def apply def apply
super super

View File

@ -10,6 +10,7 @@ module Travis::Api
resource.respond_to?(:run) resource.respond_to?(:run)
end end
instrument_method
def apply def apply
cache_control cache_control
result = normalize(resource.run) result = normalize(resource.run)

View File

@ -37,6 +37,7 @@ module Travis::Api::App::Responders
super && @resource.first.is_a?(Repository) super && @resource.first.is_a?(Repository)
end end
instrument_method
def apply def apply
super super

View File

@ -0,0 +1,52 @@
require 'travis/api/app'
class Travis::Api::App
module StackInstrumentation
class Middleware
def initialize(app, title = nil)
@app = app
@title = title || StackInstrumentation.title_for(app, :use)
end
def call(env)
instrument { @app.call(env) }
end
def instrument(&block)
return yield unless instrument?
::Skylight.instrument(title: @title, &block)
end
def instrument?
ConditionalSkylight.enabled?
end
end
def self.title_for(object, verb)
object &&= case object
when ::Sinatra::Wrapper then object.settings.inspect
when Class, Module then object.inspect
when String then object
else object.class.inspect
end
"Rack: #{verb} #{object}"
end
def use(*)
super(Middleware)
super
end
def run(app)
super Middleware.new(app, StackInstrumentation.title_for(app, :run))
end
def map(path, &block)
super(path) do
use(Middleware, StackInstrumentation.title_for(path, :map))
extend StackInstrumentation
instance_eval(&block)
end
end
end
end

View File

@ -0,0 +1,8 @@
require 'conditional_skylight'
if ConditionalSkylight.enabled?
Travis.services.send(:services).each_value do |service|
service.send(:include, ConditionalSkylight::Mixin)
service.send(:instrument_method, :run)
end
end

View File

@ -11,8 +11,14 @@ module Travis
end end
def data def data
log_hash = options[:chunked] ? chunked_log_data : log_data
if log.removed_at
log_hash['removed_at'] = log.removed_at
log_hash['removed_by'] = log.removed_by.name || log.removed_by.login
end
{ {
'log' => options[:chunked] ? chunked_log_data : log_data, 'log' => log_hash,
} }
end end
@ -37,16 +43,21 @@ module Travis
end end
def log_parts def log_parts
parts = log.parts if log.removed_at
parts = parts.where(number: part_numbers) if part_numbers # if log is removed we don't have actual parts
parts = parts.where(["number > ?", after]) if after parts = [{ 'number' => 1, 'content' => log.content, 'final' => true }]
parts.sort_by(&:number).map do |part| else
{ parts = log.parts
'id' => part.id, parts = parts.where(number: part_numbers) if part_numbers
'number' => part.number, parts = parts.where(["number > ?", after]) if after
'content' => part.content, parts.sort_by(&:number).map do |part|
'final' => part.final {
} 'id' => part.id,
'number' => part.number,
'content' => part.content,
'final' => part.final
}
end
end end
end end

View File

@ -103,6 +103,21 @@ describe 'Jobs' do
response.should deliver_json_for(job.log, version: 'v2') response.should deliver_json_for(job.log, version: 'v2')
end end
end end
it 'adds removed info if the log is removed' do
time = Time.utc(2015, 1, 9, 12, 57, 31)
job.log.update_attributes(removed_at: time, removed_by: User.first)
headers = { 'HTTP_ACCEPT' => 'application/json; chunked=true; version=2' }
response = get "/jobs/#{job.id}/log", {}, headers
body = JSON.parse(response.body)
body['log']['removed_by'].should == 'Sven Fuchs'
body['log']['removed_at'].should == "2015-01-09T12:57:31Z"
body['log']['id'].should == job.log.id
# make sure we return parts as chunked=true
body['log']['parts'].length.should == 1
end
end end
describe 'PATCH /jobs/:job_id/log' do describe 'PATCH /jobs/:job_id/log' do

View File

@ -3,6 +3,9 @@ require 'spec_helper'
describe Travis::Api::V2::Http::Log do describe Travis::Api::V2::Http::Log do
include Travis::Testing::Stubs include Travis::Testing::Stubs
let(:log) {
stub_log(removed_at: false)
}
let(:data) { described_class.new(log).data } let(:data) { described_class.new(log).data }
it 'log' do it 'log' do
@ -19,7 +22,7 @@ describe Travis::Api::V2::Http::Log do
stub_log(parts: [ stub_log(parts: [
stub_log_part(id: 2, number: 2, content: 'bar', final: true), stub_log_part(id: 2, number: 2, content: 'bar', final: true),
stub_log_part(id: 1, number: 1, content: 'foo') stub_log_part(id: 1, number: 1, content: 'foo')
]) ], removed_at: false)
end end
let(:data) { described_class.new(log, chunked: true).data } let(:data) { described_class.new(log, chunked: true).data }

View File

@ -12,8 +12,8 @@ Gem::Specification.new do |s|
"Piotr Sarnacki", "Piotr Sarnacki",
"Konstantin Haase", "Konstantin Haase",
"Sven Fuchs", "Sven Fuchs",
"Mathias Meyer",
"Hiro Asari", "Hiro Asari",
"Mathias Meyer",
"Josh Kalderimis", "Josh Kalderimis",
"Henrik Hodne", "Henrik Hodne",
"Andre Arko", "Andre Arko",
@ -37,8 +37,8 @@ Gem::Specification.new do |s|
"drogus@gmail.com", "drogus@gmail.com",
"konstantin.mailinglists@googlemail.com", "konstantin.mailinglists@googlemail.com",
"me@svenfuchs.com", "me@svenfuchs.com",
"meyer@paperplanes.de",
"asari.ruby@gmail.com", "asari.ruby@gmail.com",
"meyer@paperplanes.de",
"josh.kalderimis@gmail.com", "josh.kalderimis@gmail.com",
"me@henrikhodne.com", "me@henrikhodne.com",
"henrik@hodne.io", "henrik@hodne.io",
@ -73,6 +73,7 @@ Gem::Specification.new do |s|
"config/database.yml", "config/database.yml",
"config/puma-config.rb", "config/puma-config.rb",
"config/unicorn.rb", "config/unicorn.rb",
"lib/conditional_skylight.rb",
"lib/tasks/build_update_branch.rake", "lib/tasks/build_update_branch.rake",
"lib/tasks/build_update_pull_request_data.rake", "lib/tasks/build_update_pull_request_data.rake",
"lib/tasks/encrypt_all_data.rake", "lib/tasks/encrypt_all_data.rake",
@ -117,6 +118,9 @@ Gem::Specification.new do |s|
"lib/travis/api/app/middleware/metriks.rb", "lib/travis/api/app/middleware/metriks.rb",
"lib/travis/api/app/middleware/rewrite.rb", "lib/travis/api/app/middleware/rewrite.rb",
"lib/travis/api/app/middleware/scope_check.rb", "lib/travis/api/app/middleware/scope_check.rb",
"lib/travis/api/app/middleware/skylight.rb",
"lib/travis/api/app/middleware/skylight/actual.rb",
"lib/travis/api/app/middleware/skylight/dummy.rb",
"lib/travis/api/app/middleware/user_agent_tracker.rb", "lib/travis/api/app/middleware/user_agent_tracker.rb",
"lib/travis/api/app/responders.rb", "lib/travis/api/app/responders.rb",
"lib/travis/api/app/responders/atom.rb", "lib/travis/api/app/responders/atom.rb",
@ -128,6 +132,8 @@ Gem::Specification.new do |s|
"lib/travis/api/app/responders/service.rb", "lib/travis/api/app/responders/service.rb",
"lib/travis/api/app/responders/xml.rb", "lib/travis/api/app/responders/xml.rb",
"lib/travis/api/app/services/schedule_request.rb", "lib/travis/api/app/services/schedule_request.rb",
"lib/travis/api/app/stack_instrumentation.rb",
"lib/travis/api/instruments.rb",
"lib/travis/api/serializer.rb", "lib/travis/api/serializer.rb",
"lib/travis/api/v2.rb", "lib/travis/api/v2.rb",
"lib/travis/api/v2/http.rb", "lib/travis/api/v2/http.rb",
@ -164,8 +170,10 @@ Gem::Specification.new do |s|
"lib/travis/api/v3/access_control/scoped.rb", "lib/travis/api/v3/access_control/scoped.rb",
"lib/travis/api/v3/access_control/signature.rb", "lib/travis/api/v3/access_control/signature.rb",
"lib/travis/api/v3/access_control/user.rb", "lib/travis/api/v3/access_control/user.rb",
"lib/travis/api/v3/error.rb",
"lib/travis/api/v3/opt_in.rb", "lib/travis/api/v3/opt_in.rb",
"lib/travis/api/v3/renderer.rb", "lib/travis/api/v3/renderer.rb",
"lib/travis/api/v3/renderer/error.rb",
"lib/travis/api/v3/renderer/repository.rb", "lib/travis/api/v3/renderer/repository.rb",
"lib/travis/api/v3/result.rb", "lib/travis/api/v3/result.rb",
"lib/travis/api/v3/router.rb", "lib/travis/api/v3/router.rb",
@ -218,6 +226,7 @@ Gem::Specification.new do |s|
"spec/integration/v2_spec.backup.rb", "spec/integration/v2_spec.backup.rb",
"spec/integration/version_spec.rb", "spec/integration/version_spec.rb",
"spec/spec_helper.rb", "spec/spec_helper.rb",
"spec/support/coverage.rb",
"spec/support/formats.rb", "spec/support/formats.rb",
"spec/support/matchers.rb", "spec/support/matchers.rb",
"spec/unit/access_token_spec.rb", "spec/unit/access_token_spec.rb",
@ -269,6 +278,9 @@ Gem::Specification.new do |s|
"spec/unit/middleware/user_agent_tracker_spec.rb", "spec/unit/middleware/user_agent_tracker_spec.rb",
"spec/unit/responders/json_spec.rb", "spec/unit/responders/json_spec.rb",
"spec/unit/responders/service_spec.rb", "spec/unit/responders/service_spec.rb",
"spec/v3/result_spec.rb",
"spec/v3/service_index_spec.rb",
"spec/v3/services/find_repository_spec.rb",
"tmp/.gitkeep", "tmp/.gitkeep",
"travis-api.gemspec" "travis-api.gemspec"
] ]