second_curtain 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/bin/second_curtain +35 -40
- data/lib/second_curtain.rb +4 -0
- data/lib/second_curtain/kaleidoscope_command.rb +18 -0
- data/lib/second_curtain/parser.rb +51 -0
- data/lib/second_curtain/template.mustache.html +176 -0
- data/lib/second_curtain/test_suite.rb +22 -0
- data/lib/second_curtain/upload.rb +0 -4
- data/lib/second_curtain/upload_manager.rb +3 -5
- data/lib/second_curtain/web_preview.rb +16 -0
- data/lib/second_curtain/xcode_test_case.rb +46 -0
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZmUyZjgyMzZjMWNmMzE2NDY3ZDk2NWIyYmQwOWJkNTFjYWFlNDYwNw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjYyZTc1NDRiOTA5NzAzOGUzMzU5ZjBhZWZlNzEzOGNkNDRlMTg0YQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
N2RjOWMyMDc0MjE3NjJiZmI3MTgzOGNjM2I4N2FhZTRhZjRiNDMwMDJmNzlm
|
10
|
+
Y2M0MTcwZDkxYjhkZTk4MGZiYjdhYjNmMGM0N2Q1MWZlYWExM2FhNTgwYTE0
|
11
|
+
ZGM0YzIxNjFmOGRlNjEzZmMwYjc4N2Y5ZWQ2YjJiZmViYTNhNmM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YTFhOGJhOTExOWFmY2I4NzE5YmU3M2M0ODZjYzRkMjY0MmRkODM2YjRmZWZl
|
14
|
+
Y2VlNTRkZDUxYTc1OWQ4OTFjYzZkYTY2NmNhOWZjOWE5Zjk3OWUyM2YzZDk3
|
15
|
+
MTMxNjM3Yzk2YmRhYTA2ZjZlNGZhNjkzMGIyZjhjOGMzZWFhZDQ=
|
data/bin/second_curtain
CHANGED
@@ -2,56 +2,51 @@
|
|
2
2
|
|
3
3
|
require 'second_curtain'
|
4
4
|
|
5
|
-
|
5
|
+
parser = Parser.new()
|
6
6
|
|
7
7
|
ARGF.each_line do |line|
|
8
|
-
|
8
|
+
parser.parse_line(line)
|
9
9
|
print line
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
if parser.has_failing_commands
|
13
|
+
bucket_name = ENV['UPLOAD_IOS_SNAPSHOT_BUCKET_NAME']
|
13
14
|
|
14
|
-
if bucket_name == nil
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
aws_key = ENV['AWS_ACCESS_KEY_ID']
|
19
|
-
aws_secret = ENV['AWS_SECRET_ACCESS_KEY']
|
20
|
-
if aws_key == nil || aws_secret == nil
|
21
|
-
abort "error: Second Curtain AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be defined as environment variables"
|
22
|
-
end
|
15
|
+
if bucket_name == nil
|
16
|
+
abort "error: Second Curtain bucket name must be specified in environment UPLOAD_IOS_SNAPSHOT_BUCKET_NAME variable"
|
17
|
+
end
|
23
18
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
aws_key = ENV['AWS_ACCESS_KEY_ID']
|
20
|
+
aws_secret = ENV['AWS_SECRET_ACCESS_KEY']
|
21
|
+
if aws_key == nil || aws_secret == nil
|
22
|
+
abort "error: Second Curtain AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be defined as environment variables"
|
23
|
+
end
|
28
24
|
|
29
|
-
|
30
|
-
if !
|
31
|
-
|
32
|
-
end
|
25
|
+
path_prefix = ENV['UPLOAD_IOS_SNAPSHOT_BUCKET_PREFIX'] || '/'
|
26
|
+
if !path_prefix.end_with?('/')
|
27
|
+
path_prefix += '/'
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
30
|
+
folder_name = ENV['UPLOAD_IOS_SNAPSHOT_FOLDER_NAME']
|
31
|
+
if !folder_name
|
32
|
+
folder_name = ENV['TRAVIS_JOB_ID']
|
33
|
+
end
|
38
34
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
input.each do |line|
|
44
|
-
if line.start_with?('ksdiff')
|
45
|
-
parts = line.split(/"/)
|
46
|
-
if (parts.count >= 4)
|
47
|
-
expected_path = parts[1]
|
48
|
-
actual_path = parts[3]
|
49
|
-
manager.enqueue_upload(expected_path, actual_path)
|
50
|
-
end
|
35
|
+
if !folder_name
|
36
|
+
now = DateTime.now()
|
37
|
+
folder_name = now.strftime('%Y-%m-%d--%H-%M')
|
51
38
|
end
|
52
|
-
end
|
53
39
|
|
54
|
-
|
55
|
-
|
56
|
-
|
40
|
+
s3 = AWS::S3.new
|
41
|
+
bucket = s3.buckets[bucket_name]
|
42
|
+
manager = UploadManager.new(bucket, path_prefix)
|
43
|
+
|
44
|
+
parser.failing_commands.each do |command|
|
45
|
+
manager.enqueue_upload(command.before_path, command.after_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
failures_address = manager.upload(folder_name)
|
49
|
+
if failures_address
|
50
|
+
$stderr.puts ("Failures: " + failures_address)
|
51
|
+
end
|
57
52
|
end
|
data/lib/second_curtain.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
class KaleidoscopeCommand
|
2
|
+
attr_accessor :fails
|
3
|
+
attr_accessor :before_path
|
4
|
+
attr_accessor :after_path
|
5
|
+
|
6
|
+
def self.command_from_line(line)
|
7
|
+
components = line.split("\"")
|
8
|
+
if components.count >= 4
|
9
|
+
KaleidoscopeCommand.new(components[1], components[3])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(before_path, after_path)
|
14
|
+
@before_path = before_path
|
15
|
+
@after_path = after_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'second_curtain/xcode_test_case'
|
2
|
+
require 'second_curtain/test_suite'
|
3
|
+
require 'second_curtain/kaleidoscope_command'
|
4
|
+
|
5
|
+
# Lifted from https://github.com/orta/Snapshots/blob/master/SnapshotDiffs/ORLogReader.m
|
6
|
+
|
7
|
+
class Parser
|
8
|
+
def initialize
|
9
|
+
@test_suites = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_line(line)
|
13
|
+
if line.include?("Test Suite")
|
14
|
+
test_suite = TestSuite.suite_from_line(line)
|
15
|
+
@test_suites.push test_suite unless test_suite == nil
|
16
|
+
end
|
17
|
+
|
18
|
+
if line.include?("Test Case") && latest_test_suite
|
19
|
+
if line.include?("started.")
|
20
|
+
test_case = XcodeTestCase.test_case_from_line(line)
|
21
|
+
latest_test_suite.test_cases.push test_case unless test_case == nil
|
22
|
+
elsif line.include?("' failed (")
|
23
|
+
latest_test_suite.latest_test_case.latest_command.fails = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if line.include?("ksdiff") && latest_test_suite
|
28
|
+
command_string = extract_command_string_from_line(line)
|
29
|
+
command = KaleidoscopeCommand.command_from_line(command_string)
|
30
|
+
if command != nil
|
31
|
+
latest_test_suite.latest_test_case.add_command command
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def latest_test_suite
|
37
|
+
@test_suites.last
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_command_string_from_line(line)
|
41
|
+
return line.split("diff:\n").last
|
42
|
+
end
|
43
|
+
|
44
|
+
def failing_commands
|
45
|
+
@test_suites.map { |e| e.test_cases }.flatten.map { |e| e.commands }.flatten.select { |e| e.fails }
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_failing_commands
|
49
|
+
failing_commands.count > 0
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<style>
|
4
|
+
html {
|
5
|
+
background-color:#FFFAFC;
|
6
|
+
font-family: 'Josefin Sans', sans-serif;
|
7
|
+
color:#BE99CC;
|
8
|
+
}
|
9
|
+
|
10
|
+
nav {
|
11
|
+
height:60px;
|
12
|
+
background-color:white;
|
13
|
+
}
|
14
|
+
|
15
|
+
nav h1 {
|
16
|
+
display:inline-block;
|
17
|
+
margin-top:6px;
|
18
|
+
}
|
19
|
+
|
20
|
+
nav ul {
|
21
|
+
margin-top:18px;
|
22
|
+
display:inline-block;
|
23
|
+
float:right;
|
24
|
+
}
|
25
|
+
|
26
|
+
nav ul li {
|
27
|
+
float:right;
|
28
|
+
margin-left:30px;
|
29
|
+
}
|
30
|
+
|
31
|
+
nav ul li a {
|
32
|
+
text-decoration: none;
|
33
|
+
}
|
34
|
+
|
35
|
+
h1 {
|
36
|
+
font-weight: 400;
|
37
|
+
font-size:48px;
|
38
|
+
}
|
39
|
+
|
40
|
+
h2, nav ul, h3 {
|
41
|
+
font-weight: 300;
|
42
|
+
font-size:24px;
|
43
|
+
}
|
44
|
+
|
45
|
+
.content {
|
46
|
+
width:1200px;
|
47
|
+
margin:0 auto;
|
48
|
+
}
|
49
|
+
|
50
|
+
img.before {
|
51
|
+
border: 2px solid #9FCC99;
|
52
|
+
}
|
53
|
+
|
54
|
+
img.after {
|
55
|
+
border: 2px solid #CC7B7B;
|
56
|
+
background-color:green;
|
57
|
+
pointer-events:none;
|
58
|
+
}
|
59
|
+
|
60
|
+
article.content {
|
61
|
+
margin:36px auto;
|
62
|
+
}
|
63
|
+
|
64
|
+
section img {
|
65
|
+
background-repeat: repeat-x repeat-y;
|
66
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAeUlEQVRYCe3TIQ7AIBBE0QXRut7/mlSVGorE/22C+KtAzIa8DKW3Z0TiHNeZuC2ipm77YZkPpKgKKkgFaN4OKkgFaN4OKkgFaN4OKkgFaL6MOXTJmn/vvl7x2U9CCRVUkArQvB1UkArQvB1UkArQvB1UkArQ/PYd/AC9pgss8BZEQAAAAABJRU5ErkJggg==);
|
67
|
+
}
|
68
|
+
|
69
|
+
section div.onion {
|
70
|
+
position: relative;
|
71
|
+
}
|
72
|
+
|
73
|
+
section div.onion p {
|
74
|
+
text-align:center;
|
75
|
+
position:absolute;
|
76
|
+
top:600px;
|
77
|
+
left:0px;
|
78
|
+
width:100%;
|
79
|
+
}
|
80
|
+
|
81
|
+
section div.onion img {
|
82
|
+
position:absolute;
|
83
|
+
top:1px;
|
84
|
+
left:1;
|
85
|
+
max-height:520px;
|
86
|
+
}
|
87
|
+
|
88
|
+
section {
|
89
|
+
background-color:white;
|
90
|
+
height:660px;
|
91
|
+
}
|
92
|
+
|
93
|
+
</style>
|
94
|
+
<link href='http://fonts.googleapis.com/css?family=Josefin+Sans:300,400' rel='stylesheet' type='text/css'>
|
95
|
+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
96
|
+
</head>
|
97
|
+
|
98
|
+
<body>
|
99
|
+
<nav>
|
100
|
+
<div class="content">
|
101
|
+
<h1>Second Curtain</h1>
|
102
|
+
<ul>
|
103
|
+
<!-- <li><a href="file:///Users/orta/dev/ruby/second_curtain/lib/second_curtain/template.mustache.html">artsy/eigen#1112</a></li>
|
104
|
+
<li><a href="file:///Users/orta/dev/ruby/second_curtain/lib/second_curtain/template.mustache.html">travis#5240812</a></li> -->
|
105
|
+
</ul>
|
106
|
+
</div>
|
107
|
+
</nav>
|
108
|
+
|
109
|
+
<!-- <article class="content">
|
110
|
+
<h1>ARAmbiguousSplitStackViewSpec</h1>
|
111
|
+
<h3>Single Stack With Two Views</h3>
|
112
|
+
<section >
|
113
|
+
<div class="onion">
|
114
|
+
<img class="before" src="https://github.com/artsy/energy/raw/2c1b4d2eb35bba900c697a11e7e65f22024e7d0a/ArtsyFolio%20Tests/ReferenceImages/ARAmbiguousSplitStackViewSpec/single_stack_with_two_views%402x.png?raw=true">
|
115
|
+
<img class="after" src="https://github.com/orta/energy/raw/5978c5bfa0dfdd0317f2b68e855efad7d7dc7df2/ArtsyFolio%20Tests/ReferenceImages/ARAmbiguousSplitStackViewSpec/single_stack_with_two_views%402x.png?raw=true">
|
116
|
+
<p>320 x 280</p>
|
117
|
+
</div>
|
118
|
+
</section>
|
119
|
+
</article> -->
|
120
|
+
|
121
|
+
{{#uploads}}
|
122
|
+
<article class="content">
|
123
|
+
<section>
|
124
|
+
<div class="onion">
|
125
|
+
<img class="before" src="{{ uploaded_expected_url }}">
|
126
|
+
<img class="after" src="{{ uploaded_actual_url }}">
|
127
|
+
</div>
|
128
|
+
</section>
|
129
|
+
</article>
|
130
|
+
{{/uploads}}
|
131
|
+
|
132
|
+
|
133
|
+
<script>
|
134
|
+
|
135
|
+
/*!
|
136
|
+
* imagesLoaded PACKAGED v3.1.8
|
137
|
+
* JavaScript is all like "You images are done yet or what?"
|
138
|
+
* MIT License
|
139
|
+
*/
|
140
|
+
|
141
|
+
(function(){function e(){}function t(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function n(e){return function(){return this[e].apply(this,arguments)}}var i=e.prototype,r=this,o=r.EventEmitter;i.getListeners=function(e){var t,n,i=this._getEvents();if("object"==typeof e){t={};for(n in i)i.hasOwnProperty(n)&&e.test(n)&&(t[n]=i[n])}else t=i[e]||(i[e]=[]);return t},i.flattenListeners=function(e){var t,n=[];for(t=0;e.length>t;t+=1)n.push(e[t].listener);return n},i.getListenersAsObject=function(e){var t,n=this.getListeners(e);return n instanceof Array&&(t={},t[e]=n),t||n},i.addListener=function(e,n){var i,r=this.getListenersAsObject(e),o="object"==typeof n;for(i in r)r.hasOwnProperty(i)&&-1===t(r[i],n)&&r[i].push(o?n:{listener:n,once:!1});return this},i.on=n("addListener"),i.addOnceListener=function(e,t){return this.addListener(e,{listener:t,once:!0})},i.once=n("addOnceListener"),i.defineEvent=function(e){return this.getListeners(e),this},i.defineEvents=function(e){for(var t=0;e.length>t;t+=1)this.defineEvent(e[t]);return this},i.removeListener=function(e,n){var i,r,o=this.getListenersAsObject(e);for(r in o)o.hasOwnProperty(r)&&(i=t(o[r],n),-1!==i&&o[r].splice(i,1));return this},i.off=n("removeListener"),i.addListeners=function(e,t){return this.manipulateListeners(!1,e,t)},i.removeListeners=function(e,t){return this.manipulateListeners(!0,e,t)},i.manipulateListeners=function(e,t,n){var i,r,o=e?this.removeListener:this.addListener,s=e?this.removeListeners:this.addListeners;if("object"!=typeof t||t instanceof RegExp)for(i=n.length;i--;)o.call(this,t,n[i]);else for(i in t)t.hasOwnProperty(i)&&(r=t[i])&&("function"==typeof r?o.call(this,i,r):s.call(this,i,r));return this},i.removeEvent=function(e){var t,n=typeof e,i=this._getEvents();if("string"===n)delete i[e];else if("object"===n)for(t in i)i.hasOwnProperty(t)&&e.test(t)&&delete i[t];else delete this._events;return this},i.removeAllListeners=n("removeEvent"),i.emitEvent=function(e,t){var n,i,r,o,s=this.getListenersAsObject(e);for(r in s)if(s.hasOwnProperty(r))for(i=s[r].length;i--;)n=s[r][i],n.once===!0&&this.removeListener(e,n.listener),o=n.listener.apply(this,t||[]),o===this._getOnceReturnValue()&&this.removeListener(e,n.listener);return this},i.trigger=n("emitEvent"),i.emit=function(e){var t=Array.prototype.slice.call(arguments,1);return this.emitEvent(e,t)},i.setOnceReturnValue=function(e){return this._onceReturnValue=e,this},i._getOnceReturnValue=function(){return this.hasOwnProperty("_onceReturnValue")?this._onceReturnValue:!0},i._getEvents=function(){return this._events||(this._events={})},e.noConflict=function(){return r.EventEmitter=o,e},"function"==typeof define&&define.amd?define("eventEmitter/EventEmitter",[],function(){return e}):"object"==typeof module&&module.exports?module.exports=e:this.EventEmitter=e}).call(this),function(e){function t(t){var n=e.event;return n.target=n.target||n.srcElement||t,n}var n=document.documentElement,i=function(){};n.addEventListener?i=function(e,t,n){e.addEventListener(t,n,!1)}:n.attachEvent&&(i=function(e,n,i){e[n+i]=i.handleEvent?function(){var n=t(e);i.handleEvent.call(i,n)}:function(){var n=t(e);i.call(e,n)},e.attachEvent("on"+n,e[n+i])});var r=function(){};n.removeEventListener?r=function(e,t,n){e.removeEventListener(t,n,!1)}:n.detachEvent&&(r=function(e,t,n){e.detachEvent("on"+t,e[t+n]);try{delete e[t+n]}catch(i){e[t+n]=void 0}});var o={bind:i,unbind:r};"function"==typeof define&&define.amd?define("eventie/eventie",o):e.eventie=o}(this),function(e,t){"function"==typeof define&&define.amd?define(["eventEmitter/EventEmitter","eventie/eventie"],function(n,i){return t(e,n,i)}):"object"==typeof exports?module.exports=t(e,require("wolfy87-eventemitter"),require("eventie")):e.imagesLoaded=t(e,e.EventEmitter,e.eventie)}(window,function(e,t,n){function i(e,t){for(var n in t)e[n]=t[n];return e}function r(e){return"[object Array]"===d.call(e)}function o(e){var t=[];if(r(e))t=e;else if("number"==typeof e.length)for(var n=0,i=e.length;i>n;n++)t.push(e[n]);else t.push(e);return t}function s(e,t,n){if(!(this instanceof s))return new s(e,t);"string"==typeof e&&(e=document.querySelectorAll(e)),this.elements=o(e),this.options=i({},this.options),"function"==typeof t?n=t:i(this.options,t),n&&this.on("always",n),this.getImages(),a&&(this.jqDeferred=new a.Deferred);var r=this;setTimeout(function(){r.check()})}function f(e){this.img=e}function c(e){this.src=e,v[e]=this}var a=e.jQuery,u=e.console,h=u!==void 0,d=Object.prototype.toString;s.prototype=new t,s.prototype.options={},s.prototype.getImages=function(){this.images=[];for(var e=0,t=this.elements.length;t>e;e++){var n=this.elements[e];"IMG"===n.nodeName&&this.addImage(n);var i=n.nodeType;if(i&&(1===i||9===i||11===i))for(var r=n.querySelectorAll("img"),o=0,s=r.length;s>o;o++){var f=r[o];this.addImage(f)}}},s.prototype.addImage=function(e){var t=new f(e);this.images.push(t)},s.prototype.check=function(){function e(e,r){return t.options.debug&&h&&u.log("confirm",e,r),t.progress(e),n++,n===i&&t.complete(),!0}var t=this,n=0,i=this.images.length;if(this.hasAnyBroken=!1,!i)return this.complete(),void 0;for(var r=0;i>r;r++){var o=this.images[r];o.on("confirm",e),o.check()}},s.prototype.progress=function(e){this.hasAnyBroken=this.hasAnyBroken||!e.isLoaded;var t=this;setTimeout(function(){t.emit("progress",t,e),t.jqDeferred&&t.jqDeferred.notify&&t.jqDeferred.notify(t,e)})},s.prototype.complete=function(){var e=this.hasAnyBroken?"fail":"done";this.isComplete=!0;var t=this;setTimeout(function(){if(t.emit(e,t),t.emit("always",t),t.jqDeferred){var n=t.hasAnyBroken?"reject":"resolve";t.jqDeferred[n](t)}})},a&&(a.fn.imagesLoaded=function(e,t){var n=new s(this,e,t);return n.jqDeferred.promise(a(this))}),f.prototype=new t,f.prototype.check=function(){var e=v[this.img.src]||new c(this.img.src);if(e.isConfirmed)return this.confirm(e.isLoaded,"cached was confirmed"),void 0;if(this.img.complete&&void 0!==this.img.naturalWidth)return this.confirm(0!==this.img.naturalWidth,"naturalWidth"),void 0;var t=this;e.on("confirm",function(e,n){return t.confirm(e.isLoaded,n),!0}),e.check()},f.prototype.confirm=function(e,t){this.isLoaded=e,this.emit("confirm",this,t)};var v={};return c.prototype=new t,c.prototype.check=function(){if(!this.isChecked){var e=new Image;n.bind(e,"load",this),n.bind(e,"error",this),e.src=this.src,this.isChecked=!0}},c.prototype.handleEvent=function(e){var t="on"+e.type;this[t]&&this[t](e)},c.prototype.onload=function(e){this.confirm(!0,"onload"),this.unbindProxyEvents(e)},c.prototype.onerror=function(e){this.confirm(!1,"onerror"),this.unbindProxyEvents(e)},c.prototype.confirm=function(e,t){this.isConfirmed=!0,this.isLoaded=e,this.emit("confirm",this,t)},c.prototype.unbindProxyEvents=function(e){n.unbind(e.target,"load",this),n.unbind(e.target,"error",this)},s});
|
142
|
+
|
143
|
+
/* Second Curtain JS */
|
144
|
+
|
145
|
+
$(".onion").each(function(index, element) {
|
146
|
+
|
147
|
+
var $before = $($(element).find(".before"))[0]
|
148
|
+
var $after = $($(element).find(".after"))[0]
|
149
|
+
|
150
|
+
// position once we have the images
|
151
|
+
|
152
|
+
imagesLoaded( element, function( instance ) {
|
153
|
+
|
154
|
+
var left = ((1200 - $($before).width()) / 2) + "px"
|
155
|
+
var top = ((660 - $($before).height()) / 2) + "px"
|
156
|
+
|
157
|
+
$($before).css("top", top)
|
158
|
+
$($before).css("left", left)
|
159
|
+
|
160
|
+
$($after).css("top", top)
|
161
|
+
$($after).css("left", left)
|
162
|
+
});
|
163
|
+
|
164
|
+
// allow mouse drag to change the clip on the after
|
165
|
+
|
166
|
+
$( $before ).mousemove(function( event ) {
|
167
|
+
var x = event.pageX - element.offsetLeft - ((1200 - $(this).width() ) / 2)
|
168
|
+
var css = "rect( 0px, " + x + "px, " + $(this).height() + "px, 0px)"
|
169
|
+
$after.style.clip = css
|
170
|
+
});
|
171
|
+
|
172
|
+
});
|
173
|
+
</script>
|
174
|
+
|
175
|
+
</body>
|
176
|
+
</html>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class TestSuite
|
2
|
+
attr_accessor :test_cases
|
3
|
+
attr_accessor :name
|
4
|
+
|
5
|
+
def self.suite_from_line(line)
|
6
|
+
components = line.split("Test Suite '")
|
7
|
+
end_components = line.split("' started at")
|
8
|
+
|
9
|
+
if components.count == 2 && end_components.count == 2
|
10
|
+
TestSuite.new(components.last.split("'").first)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize (name)
|
15
|
+
@name = name
|
16
|
+
@test_cases = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def latest_test_case
|
20
|
+
@test_cases.last
|
21
|
+
end
|
22
|
+
end
|
@@ -28,8 +28,4 @@ class Upload
|
|
28
28
|
actual_object.write(:file => @actual_path)
|
29
29
|
@uploaded_actual_url = actual_object.public_url
|
30
30
|
end
|
31
|
-
|
32
|
-
def to_html
|
33
|
-
"<li><a href='#{ @uploaded_expected_url.to_s }'>Expected</a>, <a href='#{ @uploaded_actual_url.to_s }'>Actual</li>"
|
34
|
-
end
|
35
31
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'aws-sdk'
|
2
2
|
require 'second_curtain/upload'
|
3
|
+
require 'second_curtain/web_preview'
|
3
4
|
|
4
5
|
class UploadManager
|
5
6
|
def initialize (bucket, path_prefix)
|
@@ -22,12 +23,9 @@ class UploadManager
|
|
22
23
|
upload.upload(@bucket, @path_prefix)
|
23
24
|
end
|
24
25
|
|
26
|
+
preview = WebPreview.new(@uploads)
|
25
27
|
index_object = @bucket.objects[@path_prefix + folder_name + "/index.html"]
|
26
|
-
index_object.write(
|
28
|
+
index_object.write(preview.generate_html)
|
27
29
|
index_object.public_url.to_s
|
28
30
|
end
|
29
|
-
|
30
|
-
def to_html
|
31
|
-
"<html><body>#{@uploads.map(&:to_html).join}</body></html>"
|
32
|
-
end
|
33
31
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
class WebPreview
|
4
|
+
attr_reader :uploads
|
5
|
+
|
6
|
+
def initialize(uploads)
|
7
|
+
@uploads = uploads
|
8
|
+
end
|
9
|
+
|
10
|
+
def generate_html
|
11
|
+
lib_path = File.expand_path(File.dirname(__FILE__))
|
12
|
+
template = File.read(lib_path + "/template.mustache.html")
|
13
|
+
|
14
|
+
Mustache.render(template, :uploads => @uploads, :travis_id => ENV['TRAVIS_JOB_ID'])
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class XcodeTestCase
|
2
|
+
attr_accessor :commands
|
3
|
+
attr_accessor :name
|
4
|
+
|
5
|
+
def self.test_case_from_line(line)
|
6
|
+
components = line.split("Test Case '-[")
|
7
|
+
|
8
|
+
if components.count == 2 && line.include?("]' started.")
|
9
|
+
# Let's make it readable
|
10
|
+
name = components.last.split("'").first
|
11
|
+
name = name.split(" ").last
|
12
|
+
name = name.split("]").first
|
13
|
+
name = name.gsub("_", " ")
|
14
|
+
|
15
|
+
# We avoid hitting ends of words by addng the space, but that potentially misses the first one
|
16
|
+
name += " "
|
17
|
+
|
18
|
+
name.gsub!(" hasnt ", " hasn't")
|
19
|
+
name.gsub!(" isn t", " isn't")
|
20
|
+
name.gsub!(" won t", " won't")
|
21
|
+
name.gsub!(" don t", " don't")
|
22
|
+
name.gsub!(" doesn t", " doesn't")
|
23
|
+
name.gsub!(" shouldn t", " shouldn't")
|
24
|
+
name.gsub!(" can t", " can't")
|
25
|
+
|
26
|
+
first_char_upper = name[0].upcase
|
27
|
+
name[0] = first_char_upper
|
28
|
+
name.strip!
|
29
|
+
XcodeTestCase.new(name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize (name)
|
34
|
+
@commands = []
|
35
|
+
@name = name
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_command(command)
|
39
|
+
@commands.push(command)
|
40
|
+
end
|
41
|
+
|
42
|
+
def latest_command
|
43
|
+
@commands.last
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: second_curtain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ash Furrow
|
8
|
+
- Orta Therox
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
12
|
+
date: 2014-08-05 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: aws-sdk
|
@@ -24,6 +25,20 @@ dependencies:
|
|
24
25
|
- - ~>
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '1.48'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: mustache
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0.99'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0.99'
|
27
42
|
description: ! "\n If you're using the cool FBSnapshotTestCase to test your iOS view
|
28
43
|
logic, awesome! Even better if you have continuous integration, like on Travis,
|
29
44
|
to automate running those tests!\n\n Wouldn't it be awesome if we could upload
|
@@ -37,8 +52,14 @@ extra_rdoc_files: []
|
|
37
52
|
files:
|
38
53
|
- bin/second_curtain
|
39
54
|
- lib/second_curtain.rb
|
55
|
+
- lib/second_curtain/kaleidoscope_command.rb
|
56
|
+
- lib/second_curtain/parser.rb
|
57
|
+
- lib/second_curtain/template.mustache.html
|
58
|
+
- lib/second_curtain/test_suite.rb
|
40
59
|
- lib/second_curtain/upload.rb
|
41
60
|
- lib/second_curtain/upload_manager.rb
|
61
|
+
- lib/second_curtain/web_preview.rb
|
62
|
+
- lib/second_curtain/xcode_test_case.rb
|
42
63
|
homepage: https://github.com/AshFurrow/second_curtain
|
43
64
|
licenses:
|
44
65
|
- MIT
|