zenflow 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.zenflow +10 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +95 -0
- data/Guardfile +6 -0
- data/LICENSE.md +22 -0
- data/README.markdown +92 -0
- data/VERSION.yml +5 -0
- data/bin/zenflow +17 -0
- data/lib/zenflow.rb +35 -0
- data/lib/zenflow/cli.rb +130 -0
- data/lib/zenflow/commands/deploy.rb +33 -0
- data/lib/zenflow/commands/feature.rb +10 -0
- data/lib/zenflow/commands/hotfix.rb +15 -0
- data/lib/zenflow/commands/release.rb +16 -0
- data/lib/zenflow/commands/reviews.rb +12 -0
- data/lib/zenflow/helpers/ask.rb +66 -0
- data/lib/zenflow/helpers/branch.rb +80 -0
- data/lib/zenflow/helpers/branch_command.rb +95 -0
- data/lib/zenflow/helpers/branch_commands/abort.rb +21 -0
- data/lib/zenflow/helpers/branch_commands/branches.rb +21 -0
- data/lib/zenflow/helpers/branch_commands/compare.rb +20 -0
- data/lib/zenflow/helpers/branch_commands/deploy.rb +29 -0
- data/lib/zenflow/helpers/branch_commands/diff.rb +19 -0
- data/lib/zenflow/helpers/branch_commands/finish.rb +68 -0
- data/lib/zenflow/helpers/branch_commands/review.rb +58 -0
- data/lib/zenflow/helpers/branch_commands/start.rb +39 -0
- data/lib/zenflow/helpers/branch_commands/update.rb +22 -0
- data/lib/zenflow/helpers/changelog.rb +100 -0
- data/lib/zenflow/helpers/config.rb +36 -0
- data/lib/zenflow/helpers/github.rb +40 -0
- data/lib/zenflow/helpers/help.rb +37 -0
- data/lib/zenflow/helpers/log.rb +21 -0
- data/lib/zenflow/helpers/pull_request.rb +68 -0
- data/lib/zenflow/helpers/repo.rb +13 -0
- data/lib/zenflow/helpers/shell.rb +89 -0
- data/lib/zenflow/helpers/version.rb +87 -0
- data/lib/zenflow/version.rb +3 -0
- data/spec/fixtures/VERSION.yml +5 -0
- data/spec/fixtures/cassettes/create_bad_pull_request.yml +57 -0
- data/spec/fixtures/cassettes/create_pull_request.yml +68 -0
- data/spec/fixtures/cassettes/existing_pull_request.yml +145 -0
- data/spec/fixtures/cassettes/pull_request_by_ref.yml +145 -0
- data/spec/fixtures/cassettes/pull_request_find.yml +70 -0
- data/spec/fixtures/cassettes/pull_request_for_non-existent_ref.yml +145 -0
- data/spec/fixtures/cassettes/pull_request_list.yml +74 -0
- data/spec/fixtures/cassettes/unexisting_pull_request.yml +145 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/shared_examples_for_version_number.rb +19 -0
- data/spec/zenflow/commands/deploy_spec.rb +48 -0
- data/spec/zenflow/commands/feature_spec.rb +11 -0
- data/spec/zenflow/commands/hotfix_spec.rb +14 -0
- data/spec/zenflow/commands/release_spec.rb +15 -0
- data/spec/zenflow/commands/reviews_spec.rb +15 -0
- data/spec/zenflow/helpers/ask_spec.rb +115 -0
- data/spec/zenflow/helpers/branch_command_spec.rb +310 -0
- data/spec/zenflow/helpers/branch_spec.rb +300 -0
- data/spec/zenflow/helpers/changelog_spec.rb +188 -0
- data/spec/zenflow/helpers/cli_spec.rb +277 -0
- data/spec/zenflow/helpers/github_spec.rb +45 -0
- data/spec/zenflow/helpers/help_spec.rb +36 -0
- data/spec/zenflow/helpers/log_spec.rb +31 -0
- data/spec/zenflow/helpers/pull_request_spec.rb +108 -0
- data/spec/zenflow/helpers/shell_spec.rb +135 -0
- data/spec/zenflow/helpers/version_spec.rb +111 -0
- data/zenflow.gemspec +33 -0
- metadata +273 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
module Zenflow
|
2
|
+
module BranchCommands
|
3
|
+
module Finish
|
4
|
+
|
5
|
+
def self.included(thor)
|
6
|
+
thor.class_eval do
|
7
|
+
|
8
|
+
desc "finish", "Finish the branch and close the code review"
|
9
|
+
option :offline, type: :boolean, desc: "Runs in offline mode"
|
10
|
+
def finish
|
11
|
+
branch_name
|
12
|
+
confirm(:confirm_staging, "Has this been tested in a staging environment first?",
|
13
|
+
"Sorry, deploy to a staging environment first")
|
14
|
+
confirm(:confirm_review, "Has this been code reviewed yet?",
|
15
|
+
"Please have someone look at this first")
|
16
|
+
update_branch_from_destination
|
17
|
+
update_version_and_changelog(version, changelog)
|
18
|
+
merge_branch_into_destination
|
19
|
+
create_tag
|
20
|
+
delete_branches
|
21
|
+
end
|
22
|
+
|
23
|
+
no_commands do
|
24
|
+
def confirm(confirmation, question, failure_response)
|
25
|
+
return unless Zenflow::Config[confirmation]
|
26
|
+
if Zenflow::Ask(question, options: ["Y", "n"], default: "Y") == "n"
|
27
|
+
Zenflow::Log(failure_response, color: :red)
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_version_and_changelog(version, changelog)
|
33
|
+
if version
|
34
|
+
Zenflow::Version.update(version)
|
35
|
+
end
|
36
|
+
if changelog
|
37
|
+
@change = Zenflow::Changelog.update(rotate: (changelog == :rotate), name: branch_name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_tag
|
42
|
+
return unless tag
|
43
|
+
Zenflow::Branch.tag(Zenflow::Version.current.to_s, @change)
|
44
|
+
Zenflow::Branch.push(:tags) if !options[:offline]
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_branch_from_destination
|
48
|
+
destination = (branch(:destination) || branch(:source))
|
49
|
+
Zenflow::Branch.update(destination) if !options[:offline]
|
50
|
+
Zenflow::Branch.checkout("#{flow}/#{branch_name}")
|
51
|
+
Zenflow::Branch.merge(destination)
|
52
|
+
end
|
53
|
+
|
54
|
+
def merge_branch_into_destination
|
55
|
+
[branch(:source), branch(:destination)].compact.each do |finish|
|
56
|
+
Zenflow::Branch.checkout(finish)
|
57
|
+
Zenflow::Branch.merge("#{flow}/#{branch_name}")
|
58
|
+
Zenflow::Branch.push(finish) if !options[:offline]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Zenflow
|
2
|
+
module BranchCommands
|
3
|
+
module Review
|
4
|
+
|
5
|
+
def self.included(thor)
|
6
|
+
thor.class_eval do
|
7
|
+
|
8
|
+
desc "review", "Start a code review."
|
9
|
+
def review
|
10
|
+
branch_name
|
11
|
+
create_pull_request
|
12
|
+
end
|
13
|
+
|
14
|
+
no_commands do
|
15
|
+
def create_pull_request
|
16
|
+
already_created?(Zenflow::PullRequest.find_by_ref("#{flow}/#{branch_name}"))
|
17
|
+
|
18
|
+
pull = Zenflow::PullRequest.create(
|
19
|
+
base: branch(:source),
|
20
|
+
head: "#{flow}/#{branch_name}",
|
21
|
+
title: "#{flow}: #{branch_name}",
|
22
|
+
body: Zenflow::Ask("Describe this #{flow}:", required: true)
|
23
|
+
)
|
24
|
+
|
25
|
+
return handle_invalid_pull_request(pull) unless pull.valid?
|
26
|
+
|
27
|
+
Zenflow::Log("Pull request was created!")
|
28
|
+
Zenflow::Log(pull["html_url"], indent: true, color: false)
|
29
|
+
Zenflow::Shell["open #{pull['html_url']}"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def already_created?(pull)
|
33
|
+
return unless pull
|
34
|
+
Zenflow::Log("A pull request for #{flow}/#{branch_name} already exists", color: :red)
|
35
|
+
Zenflow::Log(pull[:html_url], indent: true, color: false)
|
36
|
+
exit(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def handle_invalid_pull_request(pull)
|
40
|
+
Zenflow::Log("There was a problem creating the pull request:", color: :red)
|
41
|
+
if pull["errors"]
|
42
|
+
pull["errors"].each do |error|
|
43
|
+
Zenflow::Log("* #{error['message'].gsub(/^base\s*/,'')}", indent: true, color: :red)
|
44
|
+
end
|
45
|
+
elsif pull["message"]
|
46
|
+
Zenflow::Log("* #{pull['message']}", indent: true, color: :red)
|
47
|
+
else
|
48
|
+
Zenflow::Log(" * unexpected failure, both 'errors' and 'message' were empty in the response")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Zenflow
|
2
|
+
module BranchCommands
|
3
|
+
module Start
|
4
|
+
|
5
|
+
def self.included(thor)
|
6
|
+
thor.class_eval do
|
7
|
+
|
8
|
+
desc "start [NAME]", "Start a branch"
|
9
|
+
option :offline, type: :boolean, desc: "Runs in offline mode"
|
10
|
+
def start(name=nil)
|
11
|
+
@branch_name = Zenflow::Ask("Name of the #{flow}:",
|
12
|
+
required: true,
|
13
|
+
validate: /^[-0-9a-z]+$/,
|
14
|
+
error_message: "Names can only contain dashes, 0-9, and a-z",
|
15
|
+
response: name).downcase
|
16
|
+
|
17
|
+
create_new_branch(options[:offline])
|
18
|
+
end
|
19
|
+
|
20
|
+
no_commands do
|
21
|
+
def create_new_branch(offline=false)
|
22
|
+
if !offline
|
23
|
+
Zenflow::Branch.update(branch(:source))
|
24
|
+
Zenflow::Branch.create("#{flow}/#{branch_name}", branch(:source))
|
25
|
+
Zenflow::Branch.push("#{flow}/#{branch_name}")
|
26
|
+
Zenflow::Branch.track("#{flow}/#{branch_name}")
|
27
|
+
else
|
28
|
+
Zenflow::Branch.checkout(branch(:source))
|
29
|
+
Zenflow::Branch.create("#{flow}/#{branch_name}", branch(:source))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Zenflow
|
2
|
+
module BranchCommands
|
3
|
+
module Update
|
4
|
+
|
5
|
+
def self.included(thor)
|
6
|
+
thor.class_eval do
|
7
|
+
|
8
|
+
desc "update", "Update the branch to the latest code"
|
9
|
+
option :offline, type: :boolean, desc: "Runs in offline mode"
|
10
|
+
def update
|
11
|
+
branch_name
|
12
|
+
Zenflow::Branch.update(branch(:source)) if !options[:offline]
|
13
|
+
Zenflow::Branch.checkout("#{flow}/#{branch_name}")
|
14
|
+
Zenflow::Branch.merge(branch(:source))
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Zenflow
|
2
|
+
module Changelog
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def exist?
|
6
|
+
File.exist?("CHANGELOG.md")
|
7
|
+
end
|
8
|
+
|
9
|
+
def update(options={})
|
10
|
+
return unless exist?
|
11
|
+
change = prompt_for_change(options)
|
12
|
+
if change
|
13
|
+
prepend_change_to_changelog(change, options)
|
14
|
+
else
|
15
|
+
rotate(:commit => true) if options[:rotate]
|
16
|
+
end
|
17
|
+
change
|
18
|
+
end
|
19
|
+
|
20
|
+
def prompt_for_change(options={})
|
21
|
+
required = ' (optional)' if options[:required] == false
|
22
|
+
Zenflow::Ask("Add one line to the changelog#{required}:", :required => !(options[:required] == false))
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepend_change_to_changelog(change, options={})
|
26
|
+
return unless exist?
|
27
|
+
new_changes = Zenflow::Shell.shell_escape_for_single_quoting(change)
|
28
|
+
File.open("CHANGELOG.md", "w") do |f|
|
29
|
+
f.write prepended_changelog(new_changes)
|
30
|
+
end
|
31
|
+
rotate(:name => options[:name]) if options[:rotate]
|
32
|
+
Zenflow::Shell["git add . && git commit -a -m 'Adding line to CHANGELOG: #{new_changes}'"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def prepended_changelog(new_changes)
|
36
|
+
existing_changes, changelog = get_changes
|
37
|
+
|
38
|
+
<<-EOS
|
39
|
+
#{new_changes}
|
40
|
+
#{existing_changes}
|
41
|
+
--------------------------------------------------------------------------------
|
42
|
+
#{changelog}
|
43
|
+
EOS
|
44
|
+
end
|
45
|
+
|
46
|
+
def rotate(options={})
|
47
|
+
return unless changelog = rotated_changelog(options)
|
48
|
+
Zenflow::Log("Managing changelog for version #{Zenflow::Version.current} / #{Time.now.strftime('%Y-%m-%d')} #{"/ " + options[:name] + " " if options[:name]}")
|
49
|
+
|
50
|
+
File.open("CHANGELOG.md", "w") do |f|
|
51
|
+
f.write changelog
|
52
|
+
end
|
53
|
+
Zenflow::Shell["git add CHANGELOG.md && git commit -a -m 'Rotating CHANGELOG.'"] if options[:commit]
|
54
|
+
end
|
55
|
+
|
56
|
+
def rotated_changelog(options={})
|
57
|
+
changes, changelog = get_changes
|
58
|
+
return if changes.nil?
|
59
|
+
<<-EOS
|
60
|
+
#{changelog}
|
61
|
+
|
62
|
+
#{row_name(options[:name])}
|
63
|
+
#{changes}
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_changes
|
68
|
+
return unless exist?
|
69
|
+
changelog = File.read("CHANGELOG.md").strip
|
70
|
+
changes = changelog.split("--------------------------------------------------------------------------------")[0]
|
71
|
+
return if changes.strip.empty?
|
72
|
+
changelog = changelog.sub(changes, "")
|
73
|
+
return changes.strip, changelog
|
74
|
+
end
|
75
|
+
|
76
|
+
def row_name(name=nil)
|
77
|
+
formatted_name = "/ #{name} " if name
|
78
|
+
"---- #{Zenflow::Version.current} / #{Time.now.strftime('%Y-%m-%d')} #{formatted_name}".ljust(80, "-")
|
79
|
+
end
|
80
|
+
|
81
|
+
def create
|
82
|
+
File.open("CHANGELOG.md", "w") do |f|
|
83
|
+
f.write changelog_template
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def changelog_template
|
88
|
+
<<-EOS
|
89
|
+
--------------------------------------------------------------------------------
|
90
|
+
^ ADD NEW CHANGES ABOVE ^
|
91
|
+
--------------------------------------------------------------------------------
|
92
|
+
|
93
|
+
CHANGELOG
|
94
|
+
=========
|
95
|
+
|
96
|
+
EOS
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Zenflow
|
2
|
+
class Config
|
3
|
+
class << self
|
4
|
+
attr_accessor :config
|
5
|
+
|
6
|
+
CONFIG_FILE = "#{Dir.pwd}/.zenflow"
|
7
|
+
|
8
|
+
def load!
|
9
|
+
@config = {}
|
10
|
+
@config = YAML.load_file(CONFIG_FILE) if configured?
|
11
|
+
end
|
12
|
+
|
13
|
+
def save!
|
14
|
+
File.open(CONFIG_FILE, "w") do |out|
|
15
|
+
YAML.dump(@config, out)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
load!
|
21
|
+
@config[key.to_s]
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(key, value)
|
25
|
+
load!
|
26
|
+
@config[key.to_s] = value
|
27
|
+
save!
|
28
|
+
end
|
29
|
+
|
30
|
+
def configured?
|
31
|
+
File.exist?(CONFIG_FILE)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Zenflow
|
2
|
+
|
3
|
+
module Github
|
4
|
+
def self.user
|
5
|
+
Zenflow::Shell.run('git config --get github.user', silent: true).chomp
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.zenflow_token
|
9
|
+
zenflow_token = Zenflow::Shell.run('git config --get zenflow.token', silent: true).chomp
|
10
|
+
zenflow_token = nil if zenflow_token.to_s.strip == ''
|
11
|
+
zenflow_token
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.authorize
|
15
|
+
Zenflow::Log("Authorizing with GitHub... Enter your GitHub password.")
|
16
|
+
oauth_response = JSON.parse(Zenflow::Shell.run(%{curl -u "#{Zenflow::Github.user}" https://api.github.com/authorizations -d '{"scopes":["repo"], "note":"Zenflow"}' --silent}, silent: true))
|
17
|
+
if oauth_response['token']
|
18
|
+
Zenflow::Shell.run("git config --global zenflow.token #{oauth_response['token']}", silent: true)
|
19
|
+
Zenflow::Log("Authorized!")
|
20
|
+
else
|
21
|
+
Zenflow::Log("Something went wrong. Error from GitHub was: #{oauth_response['message']}")
|
22
|
+
return
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.set_user
|
28
|
+
username = Zenflow::Ask("What is your Github username?")
|
29
|
+
Zenflow::Shell.run("git config --global github.user #{username}", silent: true)
|
30
|
+
end
|
31
|
+
|
32
|
+
class GithubRequest
|
33
|
+
include HTTParty
|
34
|
+
base_uri "https://api.github.com/repos/#{Zenflow::Repo.slug}"
|
35
|
+
format :json
|
36
|
+
headers "Authorization" => "token #{Zenflow::Github.zenflow_token}"
|
37
|
+
headers "User-Agent" => "Zencoder/Zenflow-#{VERSION}"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Zenflow
|
2
|
+
|
3
|
+
def self.Help(options={})
|
4
|
+
Zenflow::Help.new(options)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Help
|
8
|
+
attr_accessor :options
|
9
|
+
|
10
|
+
def initialize(options={})
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def title(text)
|
15
|
+
"- #{text} ".ljust(40, "-").cyan
|
16
|
+
end
|
17
|
+
|
18
|
+
def banner
|
19
|
+
help = []
|
20
|
+
help << "#{title("Summary")}\n#{options[:summary]}" if options[:summary]
|
21
|
+
help << "#{title("Usage")}\n#{options[:usage]}" if options[:usage]
|
22
|
+
help << "#{title("Available Commands")}\n#{options[:commands]}" if options[:commands]
|
23
|
+
help << "#{title("Options")}"
|
24
|
+
help.join("\n\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
def unknown_command
|
28
|
+
if options[:command].nil?
|
29
|
+
Zenflow::Log("Missing command", :color => :red)
|
30
|
+
else
|
31
|
+
Zenflow::Log("Unknown command #{options[:command].inspect}", :color => :red)
|
32
|
+
end
|
33
|
+
exit(1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Zenflow
|
2
|
+
|
3
|
+
LOG_PATH = File.join(Dir.pwd, ".zenflow-log")
|
4
|
+
|
5
|
+
def self.Log(message, options={})
|
6
|
+
output = ""
|
7
|
+
output << " " if options[:indent]
|
8
|
+
output << "-----> " if !(options[:arrows] === false)
|
9
|
+
output << message
|
10
|
+
LogToFile(output)
|
11
|
+
output = output.send(options[:color] || :cyan) unless options[:color] == false
|
12
|
+
puts output
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.LogToFile(message)
|
16
|
+
File.open(LOG_PATH, "a") do |f|
|
17
|
+
f.write(message+"\n")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Zenflow
|
2
|
+
class PullRequest
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def list
|
6
|
+
response = Zenflow::GithubRequest.get("/pulls").parsed_response
|
7
|
+
response.map{ |pull| new(pull) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def find(number)
|
11
|
+
new(Zenflow::GithubRequest.get("/pulls/#{number}").parsed_response["pull"])
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_by_ref(ref, options={})
|
15
|
+
Zenflow::Log("Looking up pull request for #{ref}") unless options[:silent]
|
16
|
+
if !list.nil?
|
17
|
+
pull = list.detect do |p|
|
18
|
+
p["head"]["ref"] == ref
|
19
|
+
end
|
20
|
+
if pull
|
21
|
+
new(pull)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_by_ref!(ref)
|
27
|
+
if pull = find_by_ref(ref)
|
28
|
+
new(pull)
|
29
|
+
else
|
30
|
+
Zenflow::Log("No open pull request was found for #{ref}", color: :red)
|
31
|
+
exit(1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def exist?(ref)
|
36
|
+
!!find_by_ref(ref)
|
37
|
+
end
|
38
|
+
|
39
|
+
def create(options={})
|
40
|
+
response = Zenflow::GithubRequest.post("/pulls",
|
41
|
+
body: {
|
42
|
+
"base" => options[:base],
|
43
|
+
"head" => options[:head],
|
44
|
+
"title" => options[:title],
|
45
|
+
"body" => options[:body]
|
46
|
+
}.to_json
|
47
|
+
)
|
48
|
+
new(response.parsed_response)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
attr_reader :pull
|
54
|
+
|
55
|
+
def initialize(pull)
|
56
|
+
@pull = pull || {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def valid?
|
60
|
+
!pull["errors"] && pull['html_url']
|
61
|
+
end
|
62
|
+
|
63
|
+
def [](key)
|
64
|
+
pull[key.to_s]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|