zenflow 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
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