livebuzz-gitx 0.1.0

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +8 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +84 -0
  11. data/Rakefile +5 -0
  12. data/bin/git-buildtag +6 -0
  13. data/bin/git-cleanup +7 -0
  14. data/bin/git-integrate +6 -0
  15. data/bin/git-nuke +6 -0
  16. data/bin/git-release +6 -0
  17. data/bin/git-review +6 -0
  18. data/bin/git-reviewrequest +8 -0
  19. data/bin/git-share +6 -0
  20. data/bin/git-start +6 -0
  21. data/bin/git-track +6 -0
  22. data/bin/git-update +6 -0
  23. data/lib/livebuzz/gitx/cli/base_command.rb +58 -0
  24. data/lib/livebuzz/gitx/cli/buildtag_command.rb +41 -0
  25. data/lib/livebuzz/gitx/cli/cleanup_command.rb +47 -0
  26. data/lib/livebuzz/gitx/cli/integrate_command.rb +95 -0
  27. data/lib/livebuzz/gitx/cli/nuke_command.rb +64 -0
  28. data/lib/livebuzz/gitx/cli/release_command.rb +41 -0
  29. data/lib/livebuzz/gitx/cli/review_command.rb +101 -0
  30. data/lib/livebuzz/gitx/cli/share_command.rb +17 -0
  31. data/lib/livebuzz/gitx/cli/start_command.rb +39 -0
  32. data/lib/livebuzz/gitx/cli/track_command.rb +16 -0
  33. data/lib/livebuzz/gitx/cli/update_command.rb +37 -0
  34. data/lib/livebuzz/gitx/configuration.rb +47 -0
  35. data/lib/livebuzz/gitx/extensions/string.rb +12 -0
  36. data/lib/livebuzz/gitx/extensions/thor.rb +39 -0
  37. data/lib/livebuzz/gitx/github.rb +177 -0
  38. data/lib/livebuzz/gitx/version.rb +5 -0
  39. data/lib/livebuzz/gitx.rb +10 -0
  40. data/livebuzz-gitx.gemspec +37 -0
  41. data/spec/fixtures/vcr_cassettes/pull_request_does_exist_with_failure_status.yml +135 -0
  42. data/spec/fixtures/vcr_cassettes/pull_request_does_exist_with_success_status.yml +149 -0
  43. data/spec/fixtures/vcr_cassettes/pull_request_does_not_exist.yml +133 -0
  44. data/spec/livebuzz/gitx/cli/base_command_spec.rb +41 -0
  45. data/spec/livebuzz/gitx/cli/buildtag_command_spec.rb +70 -0
  46. data/spec/livebuzz/gitx/cli/cleanup_command_spec.rb +37 -0
  47. data/spec/livebuzz/gitx/cli/integrate_command_spec.rb +272 -0
  48. data/spec/livebuzz/gitx/cli/nuke_command_spec.rb +165 -0
  49. data/spec/livebuzz/gitx/cli/release_command_spec.rb +148 -0
  50. data/spec/livebuzz/gitx/cli/review_command_spec.rb +307 -0
  51. data/spec/livebuzz/gitx/cli/share_command_spec.rb +32 -0
  52. data/spec/livebuzz/gitx/cli/start_command_spec.rb +96 -0
  53. data/spec/livebuzz/gitx/cli/track_command_spec.rb +31 -0
  54. data/spec/livebuzz/gitx/cli/update_command_spec.rb +79 -0
  55. data/spec/spec_helper.rb +86 -0
  56. data/spec/support/global_config.rb +24 -0
  57. data/spec/support/home_env.rb +11 -0
  58. data/spec/support/matchers/meet_expectations_matcher.rb +7 -0
  59. data/spec/support/pry.rb +1 -0
  60. data/spec/support/stub_execution.rb +14 -0
  61. data/spec/support/timecop.rb +9 -0
  62. data/spec/support/vcr.rb +6 -0
  63. data/spec/support/webmock.rb +1 -0
  64. metadata +350 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0616b6dbae3062ab6f77cd11e45b9d093347109e
4
+ data.tar.gz: 363feec0115bce1bc18baa4998c8be06e0556bcd
5
+ SHA512:
6
+ metadata.gz: 7d08cf9017d8b2a87190849657421a81bd86b423f31e492da77381456c17fc949e10c79715334ccbb54e2dabd11ca18960794135c633bad0650e7f7001294d8f
7
+ data.tar.gz: fcbbf1f9a923aa23e21c8b1c0691116fd3b39edd77e6d4636a8d79e2efaa9c8315900b70c3689f529c419b9cb9564ab04e300986739dd37c5e24dd68298d2ecc
data/.gitignore ADDED
@@ -0,0 +1,31 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## GIT
17
+ *.orig
18
+
19
+ ## PROJECT::GENERAL
20
+ coverage
21
+ rdoc
22
+ pkg
23
+
24
+ ## bundler
25
+ Gemfile.lock
26
+
27
+ ## RSpec temp files
28
+ spec/tmp
29
+
30
+ ## RubyMine
31
+ /.idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ livebuzz-gitx
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.2
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - '2.1.2'
4
+ before_install:
5
+ - git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
6
+ - git fetch
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in your gemspec file
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, cmd: 'bundle exec rspec', failed_mode: :keep do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ryan Sonnek
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # livebuzz-gitx
2
+
3
+ [![Build Status](https://travis-ci.org/livebuzz/livebuzz-gitx.png?branch=master)](https://travis-ci.org/livebuzz/livebuzz-gitx)
4
+ [![Code Coverage](https://coveralls.io/repos/livebuzz/livebuzz-gitx/badge.png)](https://coveralls.io/r/livebuzz/livebuzz-gitx)
5
+ [![Code Climate](https://codeclimate.com/github/livebuzz/livebuzz-gitx.png)](https://codeclimate.com/github/livebuzz/livebuzz-gitx)
6
+
7
+ Useful Git eXtensions for Development workflow at LiveBuzz.
8
+
9
+ Forked from [TheGarage-GitX](https://github.com/thegarage/thegarage-gitx), which is inspired by the [socialcast-git-extensions gem](https://github.com/socialcast/socialcast-git-extensions)
10
+
11
+ # Git Extensions for Workflow
12
+
13
+ ### Options
14
+ * `--trace` or `-v` = verbose output for debugging commands
15
+ * `--pretend` or `-p` = dry run commands and do not actually invoke operations
16
+
17
+ ## git start <new_branch_name (optional)>
18
+
19
+ update local repository with latest upstream changes and create a new feature branch
20
+
21
+ ## git update
22
+
23
+ update the local feature branch with latest remote changes plus upstream released changes.
24
+
25
+ ## git integrate <aggregate_branch_name (optional, default: staging)>
26
+
27
+ integrate the current feature branch into an aggregate branch (ex: prototype, staging)
28
+
29
+ ## git review
30
+
31
+ create a pull request on github for peer review of the current branch. This command is re-runnable
32
+ in order to re-assign pull requests.
33
+
34
+ options:
35
+ * `--assign` or `-a` = assign pull request to github user
36
+ * `--open` or `-o` = open pull request in default web browser.
37
+ * `--bump` or `-b` = bump an existing pull request by posting a comment to re-review new changes
38
+ * `--approve` = approve/signoff on pull request (with optional feedback)
39
+ * `--reject` = reject pull request (with details)
40
+
41
+ NOTE: the `--bump` option will also update the pull request commit status to mark the branch as 'pending peer review'.
42
+ This setting is cleared when a reviewer approves or rejects the pull request.
43
+
44
+ ## git release
45
+
46
+ release the current feature branch to master. This operation will perform the following:
47
+
48
+ * pull in latest code from remote branch
49
+ * merge in latest code from master branch
50
+ * prompt user to confirm they actually want to perform the release
51
+ * merge current branch into master
52
+ * (optional) cleanup merged branches from remote server
53
+
54
+ options:
55
+ * `--cleanup` = automatically cleanup merged branches after release complete
56
+
57
+ # Extra Utility Git Extensions
58
+
59
+ ## git cleanup
60
+
61
+ delete released branches after they have been merged into master.
62
+
63
+ ## git nuke <aggregate_branch_name>
64
+
65
+ reset an aggregate branch (ex: prototype, staging) back to a known good state.
66
+
67
+ ## git buildtag
68
+
69
+ create a build tag for the current Travis-CI build and push it back to origin
70
+
71
+
72
+ ## Note on Patches/Pull Requests
73
+
74
+ * Fork the project.
75
+ * Make your feature addition or bug fix.
76
+ * Add tests for it. This is important so I don't break it in a
77
+ future version unintentionally.
78
+ * Commit, do not mess with rakefile, version, or history.
79
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
80
+ * Send me a pull request. Bonus points for topic branches.
81
+
82
+ ## Copyright
83
+
84
+ Copyright (c) 2015 LiveBuzz Ltd. (c) 2013 The Garage, Inc. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new('spec')
5
+ task :default => :spec
data/bin/git-buildtag ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/buildtag_command'
5
+ args = ARGV.dup.unshift('buildtag')
6
+ LiveBuzz::Gitx::Cli::BuildtagCommand.start(args)
data/bin/git-cleanup ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/cleanup_command'
5
+ args = ARGV.dup.unshift('cleanup')
6
+ LiveBuzz::Gitx::Cli::CleanupCommand.start(args)
7
+
data/bin/git-integrate ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/integrate_command'
5
+ args = ARGV.dup.unshift('integrate')
6
+ LiveBuzz::Gitx::Cli::IntegrateCommand.start(args)
data/bin/git-nuke ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/nuke_command'
5
+ args = ARGV.dup.unshift('nuke')
6
+ LiveBuzz::Gitx::Cli::NukeCommand.start(args)
data/bin/git-release ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/release_command'
5
+ args = ARGV.dup.unshift('release')
6
+ LiveBuzz::Gitx::Cli::ReleaseCommand.start(args)
data/bin/git-review ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/review_command'
5
+ args = ARGV.dup.unshift('review')
6
+ LiveBuzz::Gitx::Cli::ReviewCommand.start(args)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts 'WARNING: git reviewrequest has been deprecated. use `git review` instead'
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
6
+ require 'livebuzz/gitx/cli/review_command'
7
+ args = ARGV.dup.unshift('review')
8
+ LiveBuzz::Gitx::Cli::ReviewCommand.start(args)
data/bin/git-share ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/share_command'
5
+ args = ARGV.dup.unshift('share')
6
+ LiveBuzz::Gitx::Cli::ShareCommand.start(args)
data/bin/git-start ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/start_command'
5
+ args = ARGV.dup.unshift('start')
6
+ LiveBuzz::Gitx::Cli::StartCommand.start(args)
data/bin/git-track ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/track_command'
5
+ args = ARGV.dup.unshift('track')
6
+ LiveBuzz::Gitx::Cli::TrackCommand.start(args)
data/bin/git-update ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'livebuzz/gitx/cli/update_command'
5
+ args = ARGV.dup.unshift('update')
6
+ LiveBuzz::Gitx::Cli::UpdateCommand.start(args)
@@ -0,0 +1,58 @@
1
+ require 'thor'
2
+ require 'pathname'
3
+ require 'rugged'
4
+ require 'livebuzz/gitx'
5
+
6
+ module LiveBuzz
7
+ module Gitx
8
+ module Cli
9
+ class BaseCommand < Thor
10
+ include Thor::Actions
11
+
12
+ class MergeError < Thor::Error; end
13
+
14
+ add_runtime_options!
15
+
16
+ method_option :trace, :type => :boolean, :aliases => '-v'
17
+ def initialize(*args)
18
+ super(*args)
19
+ end
20
+
21
+ private
22
+
23
+ def repo
24
+ @repo ||= begin
25
+ path = Dir.pwd
26
+ Rugged::Repository.discover(path)
27
+ end
28
+ end
29
+
30
+ def checkout_branch(branch_name)
31
+ run_cmd "git checkout #{branch_name}"
32
+ end
33
+
34
+ # lookup the current branch of the repo
35
+ def current_branch
36
+ repo.branches.find(&:head?)
37
+ end
38
+
39
+ def assert_aggregate_branch!(target_branch)
40
+ fail "Invalid aggregate branch: #{target_branch} must be one of supported aggregate branches #{config.aggregate_branches}" unless config.aggregate_branch?(target_branch)
41
+ end
42
+
43
+ def assert_not_protected_branch!(branch, action)
44
+ raise "Cannot #{action} reserved branch" if config.reserved_branch?(branch) || config.aggregate_branch?(branch)
45
+ end
46
+
47
+ # helper to invoke other CLI commands
48
+ def execute_command(command_class, method, args = [])
49
+ command_class.new.send(method, *args)
50
+ end
51
+
52
+ def config
53
+ @configuration ||= LiveBuzz::Gitx::Configuration.new(repo.workdir)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+ require 'thor'
2
+ require 'livebuzz/gitx'
3
+ require 'livebuzz/gitx/cli/base_command'
4
+
5
+ module LiveBuzz
6
+ module Gitx
7
+ module Cli
8
+ class BuildtagCommand < BaseCommand
9
+
10
+ desc 'buildtag', 'create a tag for the current build and push it back to origin (supports Travis CI and Codeship)'
11
+ def buildtag
12
+ fail "Unknown branch. Environment variables TRAVIS_BRANCH or CI_BRANCH are required" unless branch_name
13
+ fail "Branch must be one of the supported taggable branches: #{config.taggable_branches}" unless config.taggable_branch?(branch_name)
14
+
15
+ label = "buildtag generated by build #{build_number}"
16
+ create_build_tag(branch_name, label)
17
+ end
18
+
19
+ private
20
+
21
+ # pull the current branch name from environment variables
22
+ # supports Travis CI or Codeship variables
23
+ # see https://www.codeship.io/documentation/continuous-integration/set-environment-variables/
24
+ def branch_name
25
+ ENV['TRAVIS_BRANCH'] || ENV['CI_BRANCH']
26
+ end
27
+
28
+ def build_number
29
+ ENV['TRAVIS_BUILD_NUMBER'] || ENV['CI_BUILD_NUMBER']
30
+ end
31
+
32
+ def create_build_tag(branch, label)
33
+ timestamp = Time.now.utc.strftime '%Y-%m-%d-%H-%M-%S'
34
+ git_tag = "build-#{branch}-#{timestamp}"
35
+ run_cmd "git tag #{git_tag} -a -m '#{label}'"
36
+ run_cmd "git push origin #{git_tag}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ require 'thor'
2
+ require 'livebuzz/gitx'
3
+ require 'livebuzz/gitx/cli/base_command'
4
+
5
+ module LiveBuzz
6
+ module Gitx
7
+ module Cli
8
+ class CleanupCommand < BaseCommand
9
+ desc 'cleanup', 'Cleanup branches that have been merged into master from the repo'
10
+ def cleanup
11
+ checkout_branch LiveBuzz::Gitx::BASE_BRANCH
12
+ run_cmd "git pull"
13
+ run_cmd 'git remote prune origin'
14
+
15
+ say "Deleting local and remote branches that have been merged into "
16
+ say LiveBuzz::Gitx::BASE_BRANCH, :green
17
+ merged_branches(remote: true).each do |branch|
18
+ run_cmd "git push origin --delete #{branch}"
19
+ end
20
+ merged_branches(remote: false).each do |branch|
21
+ run_cmd "git branch -d #{branch}"
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ # @return list of branches that have been merged
28
+ def merged_branches(options = {})
29
+ args = []
30
+ args << '-r' if options[:remote]
31
+ args << "--merged"
32
+ output = run_cmd("git branch #{args.join(' ')}").split("\n")
33
+ branches = output.map do |branch|
34
+ branch = branch.gsub(/\*/, '').strip.split(' ').first
35
+ branch = branch.split('/').last if options[:remote]
36
+ branch
37
+ end
38
+ branches.uniq!
39
+ branches -= config.reserved_branches
40
+ branches.reject! { |b| config.aggregate_branch?(b) }
41
+
42
+ branches
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,95 @@
1
+ require 'thor'
2
+ require 'livebuzz/gitx'
3
+ require 'livebuzz/gitx/cli/base_command'
4
+ require 'livebuzz/gitx/cli/update_command'
5
+ require 'livebuzz/gitx/github'
6
+
7
+ module LiveBuzz
8
+ module Gitx
9
+ module Cli
10
+ class IntegrateCommand < BaseCommand
11
+ include LiveBuzz::Gitx::Github
12
+ desc 'integrate', 'integrate the current branch into one of the aggregate development branches (default = staging)'
13
+ method_option :resume, :type => :string, :aliases => '-r', :desc => 'resume merging of feature-branch'
14
+ def integrate(integration_branch = 'staging')
15
+ assert_aggregate_branch!(integration_branch)
16
+
17
+ branch = feature_branch_name
18
+ print_message(branch, integration_branch)
19
+
20
+ begin
21
+ execute_command(UpdateCommand, :update)
22
+ rescue
23
+ fail MergeError, "Merge Conflict Occurred. Please Merge Conflict Occurred. Please fix merge conflict and rerun the integrate command"
24
+ end
25
+
26
+ integrate_branch(branch, integration_branch) unless options[:resume]
27
+ checkout_branch branch
28
+
29
+ create_integrate_comment(branch) unless config.reserved_branch?(branch)
30
+ end
31
+
32
+ private
33
+
34
+ def print_message(branch, integration_branch)
35
+ message = options[:resume] ? 'Resuming integration of' : 'Integrating'
36
+ say "#{message} "
37
+ say "#{branch} ", :green
38
+ say "into "
39
+ say integration_branch, :green
40
+ end
41
+
42
+ def integrate_branch(branch, integration_branch)
43
+ fetch_remote_branch(integration_branch)
44
+ begin
45
+ run_cmd "git merge #{branch}"
46
+ rescue
47
+ fail MergeError, "Merge Conflict Occurred. Please fix merge conflict and rerun command with --resume #{branch} flag"
48
+ end
49
+ run_cmd "git push origin HEAD"
50
+ end
51
+
52
+ def feature_branch_name
53
+ @feature_branch ||= begin
54
+ feature_branch = options[:resume] || current_branch.name
55
+ until local_branch_exists?(feature_branch)
56
+ feature_branch = ask("#{feature_branch} does not exist. Please select one of the available local branches: #{local_branches}")
57
+ end
58
+ feature_branch
59
+ end
60
+ end
61
+
62
+ # nuke local branch and pull fresh version from remote repo
63
+ def fetch_remote_branch(target_branch)
64
+ create_remote_branch(target_branch) unless remote_branch_exists?(target_branch)
65
+ run_cmd "git fetch origin"
66
+ run_cmd "git branch -D #{target_branch}", :allow_failure => true
67
+ checkout_branch target_branch
68
+ end
69
+
70
+ def local_branch_exists?(branch)
71
+ local_branches.include?(branch)
72
+ end
73
+
74
+ def local_branches
75
+ @local_branches ||= repo.branches.each_name(:local)
76
+ end
77
+
78
+ def remote_branch_exists?(target_branch)
79
+ repo.branches.each_name(:remote).include?("origin/#{target_branch}")
80
+ end
81
+
82
+ def create_remote_branch(target_branch)
83
+ repo.create_branch(target_branch, LiveBuzz::Gitx::BASE_BRANCH)
84
+ run_cmd "git push origin #{target_branch}:#{target_branch}"
85
+ end
86
+
87
+ def create_integrate_comment(branch)
88
+ pull_request = find_or_create_pull_request(branch)
89
+ comment = '[gitx] integrated into staging :twisted_rightwards_arrows:'
90
+ github_client.add_comment(github_slug, pull_request.number, comment)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,64 @@
1
+ require 'thor'
2
+ require 'livebuzz/gitx'
3
+ require 'livebuzz/gitx/cli/base_command'
4
+
5
+ module LiveBuzz
6
+ module Gitx
7
+ module Cli
8
+ class NukeCommand < BaseCommand
9
+ desc 'nuke', 'nuke the specified aggregate branch and reset it to a known good state'
10
+ method_option :destination, :type => :string, :aliases => '-d', :desc => 'destination branch to reset to'
11
+ def nuke(bad_branch)
12
+ good_branch = options[:destination] || ask("What branch do you want to reset #{bad_branch} to? (default: #{bad_branch})")
13
+ good_branch = bad_branch if good_branch.length == 0
14
+
15
+ last_known_good_tag = current_build_tag(good_branch)
16
+ return unless yes?("Reset #{bad_branch} to #{last_known_good_tag}? (y/n)", :green)
17
+ assert_aggregate_branch!(bad_branch)
18
+ return if migrations_need_to_be_reverted?(bad_branch, last_known_good_tag)
19
+
20
+ say "Resetting "
21
+ say "#{bad_branch} ", :green
22
+ say "branch to "
23
+ say last_known_good_tag, :green
24
+
25
+ checkout_branch LiveBuzz::Gitx::BASE_BRANCH
26
+ run_cmd "git branch -D #{bad_branch}", :allow_failure => true
27
+ run_cmd "git push origin --delete #{bad_branch}", :allow_failure => true
28
+ run_cmd "git checkout -b #{bad_branch} #{last_known_good_tag}"
29
+ run_cmd "git push origin #{bad_branch}"
30
+ run_cmd "git branch --set-upstream-to origin/#{bad_branch}"
31
+ checkout_branch LiveBuzz::Gitx::BASE_BRANCH
32
+ end
33
+
34
+ private
35
+
36
+ def migrations_need_to_be_reverted?(bad_branch, last_known_good_tag)
37
+ return false unless File.exist?('db/migrate')
38
+ outdated_migrations = run_cmd("git diff #{last_known_good_tag}...#{bad_branch} --name-only db/migrate").split
39
+ return false if outdated_migrations.empty?
40
+
41
+ say "#{bad_branch} contains migrations that may need to be reverted. Ensure any reversable migrations are reverted on affected databases before nuking.", :red
42
+ say 'Example commands to revert outdated migrations:'
43
+ outdated_migrations.reverse.each do |migration|
44
+ version = File.basename(migration).split('_').first
45
+ say "rake db:migrate:down VERSION=#{version}"
46
+ end
47
+ !yes?("Are you sure you want to nuke #{bad_branch}? (y/n) ", :green)
48
+ end
49
+
50
+ def current_build_tag(branch)
51
+ last_build_tag = build_tags_for_branch(branch).last
52
+ raise "No known good tag found for branch: #{branch}. Verify tag exists via `git tag -l 'build-#{branch}-*'`" unless last_build_tag
53
+ last_build_tag
54
+ end
55
+
56
+ def build_tags_for_branch(branch)
57
+ run_cmd "git fetch --tags"
58
+ build_tags = run_cmd("git tag -l 'build-#{branch}-*'").split
59
+ build_tags.sort
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,41 @@
1
+ require 'thor'
2
+ require 'livebuzz/gitx'
3
+ require 'livebuzz/gitx/cli/base_command'
4
+ require 'livebuzz/gitx/cli/update_command'
5
+ require 'livebuzz/gitx/cli/integrate_command'
6
+ require 'livebuzz/gitx/cli/cleanup_command'
7
+ require 'livebuzz/gitx/github'
8
+
9
+ module LiveBuzz
10
+ module Gitx
11
+ module Cli
12
+ class ReleaseCommand < BaseCommand
13
+ include LiveBuzz::Gitx::Github
14
+
15
+ desc 'release', 'release the current branch to production'
16
+ method_option :cleanup, :type => :boolean, :desc => 'cleanup merged branches after release'
17
+ def release
18
+ return unless yes?("Release #{current_branch.name} to production? (y/n)", :green)
19
+
20
+ branch = current_branch.name
21
+ assert_not_protected_branch!(branch, 'release')
22
+ execute_command(UpdateCommand, :update)
23
+
24
+ find_or_create_pull_request(branch)
25
+ status = branch_status(branch)
26
+ if status != 'success'
27
+ return unless yes?("Branch status is currently: #{status}. Proceed with release? (y/n)", :red)
28
+ end
29
+
30
+ checkout_branch LiveBuzz::Gitx::BASE_BRANCH
31
+ run_cmd "git pull origin #{LiveBuzz::Gitx::BASE_BRANCH}"
32
+ run_cmd "git merge --no-ff #{branch}"
33
+ run_cmd "git push origin HEAD"
34
+
35
+ execute_command(IntegrateCommand, :integrate, 'staging')
36
+ execute_command(CleanupCommand, :cleanup) if options[:cleanup]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end