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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.zenflow +1 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +12 -1
  5. data/README.markdown +19 -13
  6. data/VERSION.yml +1 -1
  7. data/lib/zenflow/cli.rb +28 -20
  8. data/lib/zenflow/helpers/ask.rb +10 -0
  9. data/lib/zenflow/helpers/branch.rb +22 -3
  10. data/lib/zenflow/helpers/branch_command.rb +3 -2
  11. data/lib/zenflow/helpers/branch_commands/finish.rb +2 -3
  12. data/lib/zenflow/helpers/branch_commands/start.rb +2 -2
  13. data/lib/zenflow/helpers/branch_commands/update.rb +3 -3
  14. data/lib/zenflow/helpers/changelog.rb +1 -1
  15. data/lib/zenflow/helpers/github.rb +8 -6
  16. data/lib/zenflow/helpers/pull_request.rb +1 -1
  17. data/spec/fixtures/cassettes/create_bad_pull_request.yml +10 -10
  18. data/spec/fixtures/cassettes/create_pull_request.yml +14 -16
  19. data/spec/fixtures/cassettes/existing_pull_request.yml +30 -34
  20. data/spec/fixtures/cassettes/pull_request_by_ref.yml +30 -34
  21. data/spec/fixtures/cassettes/pull_request_find.yml +9 -11
  22. data/spec/fixtures/cassettes/pull_request_for_non-existent_ref.yml +30 -34
  23. data/spec/fixtures/cassettes/pull_request_list.yml +15 -17
  24. data/spec/fixtures/cassettes/unexisting_pull_request.yml +30 -34
  25. data/spec/spec_helper.rb +6 -0
  26. data/spec/zenflow/helpers/ask_spec.rb +4 -0
  27. data/spec/zenflow/helpers/branch_command_spec.rb +116 -38
  28. data/spec/zenflow/helpers/branch_spec.rb +40 -0
  29. data/spec/zenflow/helpers/changelog_spec.rb +2 -2
  30. data/spec/zenflow/helpers/cli_spec.rb +31 -10
  31. data/spec/zenflow/helpers/help_spec.rb +4 -3
  32. data/spec/zenflow/helpers/log_spec.rb +1 -1
  33. data/spec/zenflow/helpers/pull_request_spec.rb +31 -28
  34. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d2a7fe35213635ae55bf69cce6c44d5914743138
4
- data.tar.gz: 0a798aa732b4204dcdd5c09cc615016129d76424
3
+ metadata.gz: f9d8ccc7d838dd8da74652e08db81f9c90e1f7fc
4
+ data.tar.gz: 6d69ea2a6f87cfccf50eaa3246ec34c0db8ad28e
5
5
  SHA512:
6
- metadata.gz: cc718ca6a9cf65af94caa3b8d21c5742f6674c2ff867071127a61016ba34ab7eec2307a16bd2faa6efaf03c2e592854e5ce269fa7904f8bb4daf6eff1cc223c7
7
- data.tar.gz: 346f1c47fd6e658b8a5fcbf2f1b7742ac0fdb34bdb50f6a243a1925b1239d63ce956c1eb238536a71275620db78d50333763062c69b3623538c8648a227c09b8
6
+ metadata.gz: 1be8b2137b79aa83045c2bb68d03f794f7628327cd03d525d17b901c868afb61f9bbbe7ef8781973ac870ed5b7d2dd666432e0b03de259481d804ea5adf1b22e
7
+ data.tar.gz: 7d5c7c29425dca685c9c5930b6b5290baae381cc0c0ba7e90ab39981195d40df2f883085978bf2874059d59fb4d26d5e36dc7e5c4288d9760253d6cc7e44e99f
data/.zenflow CHANGED
@@ -8,3 +8,4 @@ confirm_staging: true
8
8
  remote: origin
9
9
  release_branch: production
10
10
  staging_branch: staging
11
+ merge_strategy: merge
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ gem 'coveralls', require: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zenflow (0.8.0)
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
+ [![Gem Version](https://badge.fury.io/rb/zenflow.png)](http://badge.fury.io/rb/zenflow)
3
4
  [![Code Climate](https://codeclimate.com/repos/51bf6e3b7e00a411ad00f6c3/badges/111fbe3664cebffa8e23/gpa.png)](https://codeclimate.com/repos/51bf6e3b7e00a411ad00f6c3/feed)
5
+ [![Coverage Status](https://coveralls.io/repos/zencoder/zenflow/badge.png)](https://coveralls.io/r/zencoder/zenflow)
6
+ [![Dependency Status](https://gemnasium.com/a1d29c5ea446d54bead93a6878bc204b.png)](https://gemnasium.com/zencoder/zenflow)
4
7
  ![CircleCI](https://circleci.com/gh/zencoder/zenflow.png?circle-token=992f1e59d778a8f6eef0fb9f2888e80cf60d7226)
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 this?
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
- zenflow init
81
- zenflow (feature|hotfix|release) start
82
- zenflow (feature|hotfix|release) deploy
83
- zenflow (feature|hotfix|release) review
84
- zenflow (feature|hotfix|release) finish
85
- zenflow deploy (qa|staging|production)
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 > 1.8
90
- * Ruby > 1.9.3
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
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  major: 0
3
3
  minor: 8
4
- patch: 2
4
+ patch: 3
5
5
  pre:
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
- already_configured if Zenflow::Config.configured? && !force
41
- set_up_github
42
- authorize_github
43
- configure_project
44
- configure_branches
45
- configure_remotes
46
- confirm_some_stuff
47
- set_up_changelog
48
- Zenflow::Config.save!
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 => ["y", "N"], :default => "Y") == "n"
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 => ["Y", "n"], :default => "Y") == "y"
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 => "N") == "y"
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 => "Y") == "y"
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 => ["Y", "n"], :default => "n") == "y"
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 set_up_changelog
117
- return if File.exist?("CHANGELOG.md")
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 => "Y") == "y"
125
- Zenflow::Config[:confirm_review] = Zenflow::Ask("Require code reviews?", :options => ["Y", "n"], :default => "Y") == "y"
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
@@ -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::Log("Updating the #{name} branch")
18
- Zenflow::Shell["git checkout #{name} && git pull"]
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: /^[-0-9a-z]+$/,
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: "Y") == "n"
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.checkout("#{flow}/#{branch_name}")
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: /^[-0-9a-z]+$/,
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.checkout("#{flow}/#{branch_name}")
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
- user = Zenflow::Shell.run('git config --get github.user', silent: true)
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
- zenflow_token = Zenflow::Shell.run('git config --get zenflow.token', silent: true)
12
- zenflow_token = zenflow_token.chomp unless zenflow_token.nil?
13
- zenflow_token
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
@@ -13,7 +13,7 @@ module Zenflow
13
13
 
14
14
  def find_by_ref(ref, options={})
15
15
  Zenflow::Log("Looking up pull request for #{ref}") unless options[:silent]
16
- if !list.nil?
16
+ if list.any?
17
17
  pull = list.detect do |p|
18
18
  p["head"]["ref"] == ref
19
19
  end
@@ -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":null,"head":null,"title":null,"body":null}'
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.0
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
- - Wed, 10 Jul 2013 23:12:20 GMT
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
- - '4979'
31
+ - '4974'
33
32
  X-Ratelimit-Reset:
34
- - '1373498449'
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
- - '172'
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":"base"},{"resource":"PullRequest","code":"missing_field","field":"head"}]}'
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: Wed, 10 Jul 2013 23:12:20 GMT
56
+ recorded_at: Thu, 18 Jul 2013 17:06:44 GMT
57
57
  recorded_with: VCR 2.5.0