zenflow 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.zenflow +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +12 -1
- data/README.markdown +19 -13
- data/VERSION.yml +1 -1
- data/lib/zenflow/cli.rb +28 -20
- data/lib/zenflow/helpers/ask.rb +10 -0
- data/lib/zenflow/helpers/branch.rb +22 -3
- data/lib/zenflow/helpers/branch_command.rb +3 -2
- data/lib/zenflow/helpers/branch_commands/finish.rb +2 -3
- data/lib/zenflow/helpers/branch_commands/start.rb +2 -2
- data/lib/zenflow/helpers/branch_commands/update.rb +3 -3
- data/lib/zenflow/helpers/changelog.rb +1 -1
- data/lib/zenflow/helpers/github.rb +8 -6
- data/lib/zenflow/helpers/pull_request.rb +1 -1
- data/spec/fixtures/cassettes/create_bad_pull_request.yml +10 -10
- data/spec/fixtures/cassettes/create_pull_request.yml +14 -16
- data/spec/fixtures/cassettes/existing_pull_request.yml +30 -34
- data/spec/fixtures/cassettes/pull_request_by_ref.yml +30 -34
- data/spec/fixtures/cassettes/pull_request_find.yml +9 -11
- data/spec/fixtures/cassettes/pull_request_for_non-existent_ref.yml +30 -34
- data/spec/fixtures/cassettes/pull_request_list.yml +15 -17
- data/spec/fixtures/cassettes/unexisting_pull_request.yml +30 -34
- data/spec/spec_helper.rb +6 -0
- data/spec/zenflow/helpers/ask_spec.rb +4 -0
- data/spec/zenflow/helpers/branch_command_spec.rb +116 -38
- data/spec/zenflow/helpers/branch_spec.rb +40 -0
- data/spec/zenflow/helpers/changelog_spec.rb +2 -2
- data/spec/zenflow/helpers/cli_spec.rb +31 -10
- data/spec/zenflow/helpers/help_spec.rb +4 -3
- data/spec/zenflow/helpers/log_spec.rb +1 -1
- data/spec/zenflow/helpers/pull_request_spec.rb +31 -28
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9d8ccc7d838dd8da74652e08db81f9c90e1f7fc
|
4
|
+
data.tar.gz: 6d69ea2a6f87cfccf50eaa3246ec34c0db8ad28e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1be8b2137b79aa83045c2bb68d03f794f7628327cd03d525d17b901c868afb61f9bbbe7ef8781973ac870ed5b7d2dd666432e0b03de259481d804ea5adf1b22e
|
7
|
+
data.tar.gz: 7d5c7c29425dca685c9c5930b6b5290baae381cc0c0ba7e90ab39981195d40df2f883085978bf2874059d59fb4d26d5e36dc7e5c4288d9760253d6cc7e44e99f
|
data/.zenflow
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
zenflow (0.8.
|
4
|
+
zenflow (0.8.2)
|
5
5
|
colored (~> 1.2)
|
6
6
|
httparty (~> 0.11.0)
|
7
7
|
terminal-table (~> 1.4.5)
|
@@ -13,7 +13,14 @@ GEM
|
|
13
13
|
addressable (2.3.5)
|
14
14
|
coderay (1.0.9)
|
15
15
|
colored (1.2)
|
16
|
+
colorize (0.5.8)
|
16
17
|
columnize (0.3.6)
|
18
|
+
coveralls (0.6.7)
|
19
|
+
colorize
|
20
|
+
multi_json (~> 1.3)
|
21
|
+
rest-client
|
22
|
+
simplecov (>= 0.7)
|
23
|
+
thor
|
17
24
|
crack (0.4.0)
|
18
25
|
safe_yaml (~> 0.9.0)
|
19
26
|
debugger (1.6.1)
|
@@ -47,6 +54,7 @@ GEM
|
|
47
54
|
rb-kqueue (>= 0.2)
|
48
55
|
lumberjack (1.0.4)
|
49
56
|
method_source (0.8.1)
|
57
|
+
mime-types (1.23)
|
50
58
|
multi_json (1.7.7)
|
51
59
|
multi_xml (0.5.4)
|
52
60
|
pry (0.9.12.2)
|
@@ -58,6 +66,8 @@ GEM
|
|
58
66
|
ffi (>= 0.5.0)
|
59
67
|
rb-kqueue (0.2.0)
|
60
68
|
ffi (>= 0.5.0)
|
69
|
+
rest-client (1.6.7)
|
70
|
+
mime-types (>= 1.16)
|
61
71
|
rspec (2.14.0)
|
62
72
|
rspec-core (~> 2.14.0)
|
63
73
|
rspec-expectations (~> 2.14.0)
|
@@ -85,6 +95,7 @@ PLATFORMS
|
|
85
95
|
ruby
|
86
96
|
|
87
97
|
DEPENDENCIES
|
98
|
+
coveralls
|
88
99
|
debugger (~> 1.6.1)
|
89
100
|
fuubar (~> 1.1.1)
|
90
101
|
guard-rspec (~> 3.0.2)
|
data/README.markdown
CHANGED
@@ -1,15 +1,21 @@
|
|
1
1
|
# Zenflow
|
2
2
|
|
3
|
+
[](http://badge.fury.io/rb/zenflow)
|
3
4
|
[](https://codeclimate.com/repos/51bf6e3b7e00a411ad00f6c3/feed)
|
5
|
+
[](https://coveralls.io/r/zencoder/zenflow)
|
6
|
+
[](https://gemnasium.com/zencoder/zenflow)
|
4
7
|

|
8
|
+
|
5
9
|
-------
|
6
10
|
|
7
|
-
[Getting Started](#getting-started)
|
8
|
-
[Usage](#usage)
|
9
|
-
[Commands Quick Reference](#commands)
|
10
|
-
[Requirements](#requirements)
|
11
|
+
* [Getting Started](#getting-started)
|
12
|
+
* [Usage](#usage)
|
13
|
+
* [Commands Quick Reference](#commands)
|
14
|
+
* [Requirements](#requirements)
|
15
|
+
|
16
|
+
-------
|
11
17
|
|
12
|
-
### What is
|
18
|
+
### What is Zenflow?
|
13
19
|
|
14
20
|
Zenflow is a Ruby implimentation of the [GitFlow process](http://nvie.com/posts/a-successful-git-branching-model/) for managing development in Git. It's been used at [Zencoder](http://zencoder.com) since 2010 and we've benefitted greatly from the structure it helps enforce, so we wanted to share it with the world.
|
15
21
|
|
@@ -77,16 +83,16 @@ To deploy to production, type `zenflow deploy production`. Hotfixes are not auto
|
|
77
83
|
|
78
84
|
#### <a name="commands"></a> Commands Quick Ref
|
79
85
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
zenflow init
|
87
|
+
zenflow (feature|hotfix|release) start
|
88
|
+
zenflow (feature|hotfix|release) deploy
|
89
|
+
zenflow (feature|hotfix|release) review
|
90
|
+
zenflow (feature|hotfix|release) finish
|
91
|
+
zenflow deploy (qa|staging|production)
|
86
92
|
|
87
93
|
### <a name="requirements"></a> Requirements/Assumptions
|
88
94
|
|
89
|
-
* Git
|
90
|
-
* Ruby
|
95
|
+
* Git >= 1.8
|
96
|
+
* Ruby >= 1.9.3
|
91
97
|
* Capistrano and cap-ext
|
92
98
|
* A repository on GitHub
|
data/VERSION.yml
CHANGED
data/lib/zenflow/cli.rb
CHANGED
@@ -37,22 +37,26 @@ module Zenflow
|
|
37
37
|
|
38
38
|
desc "init", "Write the zenflow config file."
|
39
39
|
def init(force=false)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
40
|
+
if Zenflow::Config.configured? && !force
|
41
|
+
already_configured
|
42
|
+
else
|
43
|
+
set_up_github
|
44
|
+
authorize_github
|
45
|
+
configure_project
|
46
|
+
configure_branches
|
47
|
+
configure_merge_strategy
|
48
|
+
configure_remotes
|
49
|
+
confirm_some_stuff
|
50
|
+
set_up_changelog
|
51
|
+
Zenflow::Config.save!
|
52
|
+
end
|
49
53
|
end
|
50
54
|
|
51
55
|
desc "set_up_github", "Set up GitHub user information"
|
52
56
|
def set_up_github
|
53
57
|
user = Zenflow::Github.user
|
54
58
|
if user.to_s != ''
|
55
|
-
if Zenflow::Ask("Your GitHub user is currently #{user}. Do you want to use that?", :options => ["
|
59
|
+
if Zenflow::Ask("Your GitHub user is currently #{user}. Do you want to use that?", :options => ["Y", "n"], :default => "y") == "n"
|
56
60
|
Zenflow::Github.set_user
|
57
61
|
end
|
58
62
|
else
|
@@ -63,7 +67,7 @@ module Zenflow
|
|
63
67
|
desc "authorize_github", "Get an auth token from GitHub"
|
64
68
|
def authorize_github
|
65
69
|
if Zenflow::Github.zenflow_token
|
66
|
-
if Zenflow::Ask("You already have a token from GitHub. Do you want to set a new one?", :options => ["
|
70
|
+
if Zenflow::Ask("You already have a token from GitHub. Do you want to set a new one?", :options => ["y", "N"], :default => "n") == "y"
|
67
71
|
Zenflow::Github.authorize
|
68
72
|
end
|
69
73
|
else
|
@@ -75,7 +79,7 @@ module Zenflow
|
|
75
79
|
|
76
80
|
def already_configured
|
77
81
|
Zenflow::Log("Warning", :color => :red)
|
78
|
-
if Zenflow::Ask("There is an existing config file. Overwrite it?", :options => ["y", "N"], :default => "
|
82
|
+
if Zenflow::Ask("There is an existing config file. Overwrite it?", :options => ["y", "N"], :default => "n") == "y"
|
79
83
|
init(true)
|
80
84
|
else
|
81
85
|
Zenflow::Log("Aborting...", :color => :red)
|
@@ -97,7 +101,7 @@ module Zenflow
|
|
97
101
|
end
|
98
102
|
|
99
103
|
def configure_branch(branch, question, default)
|
100
|
-
if Zenflow::Ask(question, :options => ["Y", "n"], :default => "
|
104
|
+
if Zenflow::Ask(question, :options => ["Y", "n"], :default => "y") == "y"
|
101
105
|
Zenflow::Config[branch] = Zenflow::Ask("What is the name of that branch?", :default => default)
|
102
106
|
else
|
103
107
|
Zenflow::Config[branch] = false
|
@@ -106,23 +110,27 @@ module Zenflow
|
|
106
110
|
|
107
111
|
def configure_remotes
|
108
112
|
Zenflow::Config[:remote] = Zenflow::Ask("What is the name of your primary remote?", :default => "origin")
|
109
|
-
if Zenflow::Ask("Use a backup remote?", :options => ["
|
113
|
+
if Zenflow::Ask("Use a backup remote?", :options => ["y", "N"], :default => "n") == "y"
|
110
114
|
Zenflow::Config[:backup_remote] = Zenflow::Ask("What is the name of your backup remote?", :default => "backup")
|
111
115
|
else
|
112
116
|
Zenflow::Config[:backup_remote] = false
|
113
117
|
end
|
114
118
|
end
|
115
119
|
|
116
|
-
def
|
117
|
-
|
118
|
-
Zenflow::Log("Changelog Management")
|
119
|
-
Zenflow::Changelog.create if Zenflow::Ask("Set up a changelog?", :options => ["Y", "n"], :default => "Y") == "y"
|
120
|
+
def configure_merge_strategy
|
121
|
+
Zenflow::Config[:merge_strategy] = Zenflow::Ask("What merge strategy would you prefer?", default: "merge", options: ['merge', 'rebase'])
|
120
122
|
end
|
121
123
|
|
122
124
|
def confirm_some_stuff
|
123
125
|
Zenflow::Log("Confirmations")
|
124
|
-
Zenflow::Config[:confirm_staging] = Zenflow::Ask("Require deployment to a staging environment?", :options => ["Y", "n"], :default => "
|
125
|
-
Zenflow::Config[:confirm_review] = Zenflow::Ask("Require code reviews?", :options => ["Y", "n"], :default => "
|
126
|
+
Zenflow::Config[:confirm_staging] = Zenflow::Ask("Require deployment to a staging environment?", :options => ["Y", "n"], :default => "y") == "y"
|
127
|
+
Zenflow::Config[:confirm_review] = Zenflow::Ask("Require code reviews?", :options => ["Y", "n"], :default => "y") == "y"
|
128
|
+
end
|
129
|
+
|
130
|
+
def set_up_changelog
|
131
|
+
return if File.exist?("CHANGELOG.md")
|
132
|
+
Zenflow::Log("Changelog Management")
|
133
|
+
Zenflow::Changelog.create if Zenflow::Ask("Set up a changelog?", :options => ["Y", "n"], :default => "y") == "y"
|
126
134
|
end
|
127
135
|
|
128
136
|
end
|
data/lib/zenflow/helpers/ask.rb
CHANGED
@@ -45,6 +45,16 @@ module Zenflow
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.valid_response?(response, options={})
|
48
|
+
if response == ''
|
49
|
+
response = options[:default].downcase if options[:default]
|
50
|
+
end
|
51
|
+
|
52
|
+
# The guard in the line below is required to allow branches to be named
|
53
|
+
# directly on the command line and bypass the prompt for branch name
|
54
|
+
response.downcase! unless options[:response]
|
55
|
+
|
56
|
+
options[:options].map!(&:downcase) if options[:options]
|
57
|
+
|
48
58
|
return false if options[:options] && !options[:options].include?(response)
|
49
59
|
return false if options[:validate] && options[:validate].is_a?(Regexp) && !response[options[:validate]]
|
50
60
|
return false if options[:required] && response == ""
|
@@ -13,9 +13,23 @@ module Zenflow
|
|
13
13
|
branch.chomp.sub(/\* #{prefix}\/?/, "") unless branch.empty?
|
14
14
|
end
|
15
15
|
|
16
|
-
def update(name)
|
17
|
-
Zenflow::
|
18
|
-
|
16
|
+
def update(name, rebase_override=false)
|
17
|
+
if Zenflow::Config[:merge_strategy] == 'rebase' || rebase_override == true
|
18
|
+
Zenflow::Log("Updating the #{name} branch using pull with --rebase")
|
19
|
+
Zenflow::Shell["git checkout #{name} && git pull --rebase"]
|
20
|
+
else
|
21
|
+
Zenflow::Log("Updating the #{name} branch")
|
22
|
+
Zenflow::Shell["git checkout #{name} && git pull"]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def apply_merge_strategy(flow, name, destination, rebase_override=false)
|
27
|
+
if Zenflow::Config[:merge_strategy] == 'rebase' || rebase_override == true
|
28
|
+
Zenflow::Branch.rebase("#{flow}/#{name}", destination)
|
29
|
+
else
|
30
|
+
Zenflow::Branch.checkout("#{flow}/#{name}")
|
31
|
+
Zenflow::Branch.merge(destination)
|
32
|
+
end
|
19
33
|
end
|
20
34
|
|
21
35
|
def create(name, base)
|
@@ -51,6 +65,11 @@ module Zenflow
|
|
51
65
|
Zenflow::Shell["git checkout #{name}"]
|
52
66
|
end
|
53
67
|
|
68
|
+
def rebase(name, source)
|
69
|
+
Zenflow::Log("Rebasing #{name} on top of the #{source} branch")
|
70
|
+
Zenflow::Shell["git rebase #{source} #{name}"]
|
71
|
+
end
|
72
|
+
|
54
73
|
def merge(name)
|
55
74
|
Zenflow::Log("Merging in the #{name} branch")
|
56
75
|
Zenflow::Shell["git merge --no-ff #{name}"]
|
@@ -51,12 +51,13 @@ module Zenflow
|
|
51
51
|
|
52
52
|
protected
|
53
53
|
|
54
|
+
#TODO: move the validation regex to a single place
|
54
55
|
def branch_name
|
55
56
|
@branch_name ||= Zenflow::Branch.current(flow) ||
|
56
57
|
Zenflow::Ask("Name of the #{flow}:",
|
57
58
|
required: true,
|
58
|
-
validate: /^[-
|
59
|
-
error_message: "Names can only contain dashes, 0-9, and a-z").downcase
|
59
|
+
validate: /^[-_0-9a-z]+$/,
|
60
|
+
error_message: "Names can only contain dashes, underscores, 0-9, and a-z").downcase
|
60
61
|
end
|
61
62
|
|
62
63
|
|
@@ -23,7 +23,7 @@ module Zenflow
|
|
23
23
|
no_commands do
|
24
24
|
def confirm(confirmation, question, failure_response)
|
25
25
|
return unless Zenflow::Config[confirmation]
|
26
|
-
if Zenflow::Ask(question, options: ["Y", "n"], default: "
|
26
|
+
if Zenflow::Ask(question, options: ["Y", "n"], default: "y") == "n"
|
27
27
|
Zenflow::Log(failure_response, color: :red)
|
28
28
|
exit(1)
|
29
29
|
end
|
@@ -47,8 +47,7 @@ module Zenflow
|
|
47
47
|
def update_branch_from_destination
|
48
48
|
destination = (branch(:destination) || branch(:source))
|
49
49
|
Zenflow::Branch.update(destination) if !options[:offline]
|
50
|
-
Zenflow::Branch.
|
51
|
-
Zenflow::Branch.merge(destination)
|
50
|
+
Zenflow::Branch.apply_merge_strategy(flow, branch_name, destination)
|
52
51
|
end
|
53
52
|
|
54
53
|
def merge_branch_into_destination
|
@@ -10,8 +10,8 @@ module Zenflow
|
|
10
10
|
def start(name=nil)
|
11
11
|
@branch_name = Zenflow::Ask("Name of the #{flow}:",
|
12
12
|
required: true,
|
13
|
-
validate: /^[-
|
14
|
-
error_message: "Names can only contain dashes, 0-9, and a-z",
|
13
|
+
validate: /^[-_0-9a-z]+$/,
|
14
|
+
error_message: "Names can only contain dashes, underscores, 0-9, and a-z",
|
15
15
|
response: name).downcase
|
16
16
|
|
17
17
|
create_new_branch(options[:offline])
|
@@ -7,11 +7,11 @@ module Zenflow
|
|
7
7
|
|
8
8
|
desc "update", "Update the branch to the latest code"
|
9
9
|
option :offline, type: :boolean, desc: "Runs in offline mode"
|
10
|
+
option :rebase, type: :boolean, desc: "Rebases the current branch against a source branch instead of doing a merge of that source into itself"
|
10
11
|
def update
|
11
12
|
branch_name
|
12
|
-
Zenflow::Branch.update(branch(:source)) if !options[:offline]
|
13
|
-
Zenflow::Branch.
|
14
|
-
Zenflow::Branch.merge(branch(:source))
|
13
|
+
Zenflow::Branch.update(branch(:source), options[:rebase]) if !options[:offline]
|
14
|
+
Zenflow::Branch.apply_merge_strategy(flow, branch_name, branch(:source), options[:rebase])
|
15
15
|
end
|
16
16
|
|
17
17
|
end
|
@@ -29,7 +29,7 @@ module Zenflow
|
|
29
29
|
f.write prepended_changelog(new_changes)
|
30
30
|
end
|
31
31
|
rotate(:name => options[:name]) if options[:rotate]
|
32
|
-
Zenflow::Shell["git add . && git commit -a -m 'Adding line to CHANGELOG: #{new_changes}'"]
|
32
|
+
Zenflow::Shell["git add CHANGELOG.md && git commit -a -m 'Adding line to CHANGELOG: #{new_changes}'"]
|
33
33
|
end
|
34
34
|
|
35
35
|
def prepended_changelog(new_changes)
|
@@ -2,15 +2,17 @@ module Zenflow
|
|
2
2
|
|
3
3
|
module Github
|
4
4
|
def self.user
|
5
|
-
|
6
|
-
user = user.chomp unless user.nil?
|
7
|
-
user
|
5
|
+
get_config('github.user')
|
8
6
|
end
|
9
7
|
|
10
8
|
def self.zenflow_token
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
get_config('zenflow.token')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.get_config(key)
|
13
|
+
config = Zenflow::Shell.run("git config --get #{key.to_s}", silent: true)
|
14
|
+
config = config.chomp unless config.nil?
|
15
|
+
config
|
14
16
|
end
|
15
17
|
|
16
18
|
def self.authorize
|
@@ -5,12 +5,13 @@ http_interactions:
|
|
5
5
|
uri: https://api.github.com/repos/zencoder/zenflow-example/pulls
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
|
-
string: '{"base":
|
8
|
+
string: '{"base":"master","head":"feature/phoney","title":"this feature does
|
9
|
+
not exist","body":"gonna fail"}'
|
9
10
|
headers:
|
10
11
|
Authorization:
|
11
12
|
- token <ZENFLOW-TOKEN>
|
12
13
|
User-Agent:
|
13
|
-
- Zencoder/Zenflow-0.8.
|
14
|
+
- Zencoder/Zenflow-0.8.2
|
14
15
|
response:
|
15
16
|
status:
|
16
17
|
code: 422
|
@@ -19,19 +20,17 @@ http_interactions:
|
|
19
20
|
Server:
|
20
21
|
- GitHub.com
|
21
22
|
Date:
|
22
|
-
-
|
23
|
+
- Thu, 18 Jul 2013 17:06:44 GMT
|
23
24
|
Content-Type:
|
24
25
|
- application/json; charset=utf-8
|
25
|
-
Connection:
|
26
|
-
- keep-alive
|
27
26
|
Status:
|
28
27
|
- 422 Unprocessable Entity
|
29
28
|
X-Ratelimit-Limit:
|
30
29
|
- '5000'
|
31
30
|
X-Ratelimit-Remaining:
|
32
|
-
- '
|
31
|
+
- '4974'
|
33
32
|
X-Ratelimit-Reset:
|
34
|
-
- '
|
33
|
+
- '1374170098'
|
35
34
|
X-Oauth-Scopes:
|
36
35
|
- repo
|
37
36
|
X-Accepted-Oauth-Scopes:
|
@@ -41,7 +40,7 @@ http_interactions:
|
|
41
40
|
X-Content-Type-Options:
|
42
41
|
- nosniff
|
43
42
|
Content-Length:
|
44
|
-
- '
|
43
|
+
- '298'
|
45
44
|
Access-Control-Allow-Credentials:
|
46
45
|
- 'true'
|
47
46
|
Access-Control-Expose-Headers:
|
@@ -51,7 +50,8 @@ http_interactions:
|
|
51
50
|
- '*'
|
52
51
|
body:
|
53
52
|
encoding: UTF-8
|
54
|
-
string: '{"message":"Validation Failed","errors":[{"resource":"PullRequest","code":"missing_field","field":"
|
53
|
+
string: '{"message":"Validation Failed","errors":[{"resource":"PullRequest","code":"missing_field","field":"head_sha"},{"resource":"PullRequest","code":"missing_field","field":"base_sha"},{"resource":"PullRequest","code":"custom","message":"No
|
54
|
+
commits between zencoder:master and zencoder:feature/phoney"}]}'
|
55
55
|
http_version:
|
56
|
-
recorded_at:
|
56
|
+
recorded_at: Thu, 18 Jul 2013 17:06:44 GMT
|
57
57
|
recorded_with: VCR 2.5.0
|