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.
- checksums.yaml +7 -0
- data/.gitignore +31 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/Rakefile +5 -0
- data/bin/git-buildtag +6 -0
- data/bin/git-cleanup +7 -0
- data/bin/git-integrate +6 -0
- data/bin/git-nuke +6 -0
- data/bin/git-release +6 -0
- data/bin/git-review +6 -0
- data/bin/git-reviewrequest +8 -0
- data/bin/git-share +6 -0
- data/bin/git-start +6 -0
- data/bin/git-track +6 -0
- data/bin/git-update +6 -0
- data/lib/livebuzz/gitx/cli/base_command.rb +58 -0
- data/lib/livebuzz/gitx/cli/buildtag_command.rb +41 -0
- data/lib/livebuzz/gitx/cli/cleanup_command.rb +47 -0
- data/lib/livebuzz/gitx/cli/integrate_command.rb +95 -0
- data/lib/livebuzz/gitx/cli/nuke_command.rb +64 -0
- data/lib/livebuzz/gitx/cli/release_command.rb +41 -0
- data/lib/livebuzz/gitx/cli/review_command.rb +101 -0
- data/lib/livebuzz/gitx/cli/share_command.rb +17 -0
- data/lib/livebuzz/gitx/cli/start_command.rb +39 -0
- data/lib/livebuzz/gitx/cli/track_command.rb +16 -0
- data/lib/livebuzz/gitx/cli/update_command.rb +37 -0
- data/lib/livebuzz/gitx/configuration.rb +47 -0
- data/lib/livebuzz/gitx/extensions/string.rb +12 -0
- data/lib/livebuzz/gitx/extensions/thor.rb +39 -0
- data/lib/livebuzz/gitx/github.rb +177 -0
- data/lib/livebuzz/gitx/version.rb +5 -0
- data/lib/livebuzz/gitx.rb +10 -0
- data/livebuzz-gitx.gemspec +37 -0
- data/spec/fixtures/vcr_cassettes/pull_request_does_exist_with_failure_status.yml +135 -0
- data/spec/fixtures/vcr_cassettes/pull_request_does_exist_with_success_status.yml +149 -0
- data/spec/fixtures/vcr_cassettes/pull_request_does_not_exist.yml +133 -0
- data/spec/livebuzz/gitx/cli/base_command_spec.rb +41 -0
- data/spec/livebuzz/gitx/cli/buildtag_command_spec.rb +70 -0
- data/spec/livebuzz/gitx/cli/cleanup_command_spec.rb +37 -0
- data/spec/livebuzz/gitx/cli/integrate_command_spec.rb +272 -0
- data/spec/livebuzz/gitx/cli/nuke_command_spec.rb +165 -0
- data/spec/livebuzz/gitx/cli/release_command_spec.rb +148 -0
- data/spec/livebuzz/gitx/cli/review_command_spec.rb +307 -0
- data/spec/livebuzz/gitx/cli/share_command_spec.rb +32 -0
- data/spec/livebuzz/gitx/cli/start_command_spec.rb +96 -0
- data/spec/livebuzz/gitx/cli/track_command_spec.rb +31 -0
- data/spec/livebuzz/gitx/cli/update_command_spec.rb +79 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/support/global_config.rb +24 -0
- data/spec/support/home_env.rb +11 -0
- data/spec/support/matchers/meet_expectations_matcher.rb +7 -0
- data/spec/support/pry.rb +1 -0
- data/spec/support/stub_execution.rb +14 -0
- data/spec/support/timecop.rb +9 -0
- data/spec/support/vcr.rb +6 -0
- data/spec/support/webmock.rb +1 -0
- metadata +350 -0
@@ -0,0 +1,101 @@
|
|
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 ReviewCommand < BaseCommand
|
11
|
+
include LiveBuzz::Gitx::Github
|
12
|
+
|
13
|
+
BUMP_COMMENT_PREFIX = '[gitx] review bump :tada:'
|
14
|
+
BUMP_COMMENT_FOOTER = <<-EOS.dedent
|
15
|
+
# Bump comments should include:
|
16
|
+
# * summary of what changed
|
17
|
+
#
|
18
|
+
# This footer will automatically be stripped from the created comment
|
19
|
+
EOS
|
20
|
+
APPROVAL_COMMENT_PREFIX = '[gitx] review approved :shipit:'
|
21
|
+
APPROVAL_COMMENT_FOOTER = <<-EOS.dedent
|
22
|
+
# Approval comments can include:
|
23
|
+
# * feedback
|
24
|
+
# * post-release follow-up items
|
25
|
+
#
|
26
|
+
# This footer will automatically be stripped from the created comment
|
27
|
+
EOS
|
28
|
+
REJECTION_COMMENT_PREFIX = '[gitx] review rejected'
|
29
|
+
REJECTION_COMMENT_FOOTER = <<-EOS.dedent
|
30
|
+
# Rejection comments should include:
|
31
|
+
# * feedback for fixes required before approved
|
32
|
+
#
|
33
|
+
# This footer will automatically be stripped from the created comment
|
34
|
+
EOS
|
35
|
+
|
36
|
+
desc "review", "Create or update a pull request on github"
|
37
|
+
method_option :description, :type => :string, :aliases => '-d', :desc => 'pull request description'
|
38
|
+
method_option :assignee, :type => :string, :aliases => '-a', :desc => 'pull request assignee'
|
39
|
+
method_option :open, :type => :boolean, :aliases => '-o', :desc => 'open the pull request in a web browser'
|
40
|
+
method_option :bump, :type => :boolean, :aliases => '-b', :desc => 'bump an existing pull request by posting a comment to re-review new changes'
|
41
|
+
method_option :approve, :type => :boolean, :desc => 'approve the pull request an post comment on pull request'
|
42
|
+
method_option :reject, :type => :boolean, :desc => 'reject the pull request an post comment on pull request'
|
43
|
+
# @see http://developer.github.com/v3/pulls/
|
44
|
+
def review
|
45
|
+
fail 'Github authorization token not found' unless authorization_token
|
46
|
+
|
47
|
+
branch = current_branch.name
|
48
|
+
pull_request = find_or_create_pull_request(branch)
|
49
|
+
bump_pull_request(pull_request) if options[:bump]
|
50
|
+
approve_pull_request(pull_request) if options[:approve]
|
51
|
+
reject_pull_request(pull_request) if options[:reject]
|
52
|
+
assign_pull_request(pull_request) if options[:assignee]
|
53
|
+
|
54
|
+
run_cmd "open #{pull_request.html_url}" if options[:open]
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def assign_pull_request(pull_request)
|
60
|
+
assignee = options[:assignee]
|
61
|
+
say "Assigning pull request to "
|
62
|
+
say assignee, :green
|
63
|
+
|
64
|
+
title = pull_request.title
|
65
|
+
body = pull_request.body
|
66
|
+
options = {
|
67
|
+
assignee: assignee
|
68
|
+
}
|
69
|
+
github_client.update_issue(github_slug, pull_request.number, title, body, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def bump_pull_request(pull_request)
|
73
|
+
comment = comment_from_template(pull_request, BUMP_COMMENT_PREFIX, BUMP_COMMENT_FOOTER)
|
74
|
+
set_review_status('pending', 'Peer review in progress')
|
75
|
+
end
|
76
|
+
|
77
|
+
def reject_pull_request(pull_request)
|
78
|
+
comment = comment_from_template(pull_request, REJECTION_COMMENT_PREFIX, REJECTION_COMMENT_FOOTER)
|
79
|
+
set_review_status('failure', 'Peer review rejected')
|
80
|
+
end
|
81
|
+
|
82
|
+
def approve_pull_request(pull_request)
|
83
|
+
comment = comment_from_template(pull_request, APPROVAL_COMMENT_PREFIX, APPROVAL_COMMENT_FOOTER)
|
84
|
+
set_review_status('success', 'Peer review approved')
|
85
|
+
end
|
86
|
+
|
87
|
+
def comment_from_template(pull_request, prefix, footer)
|
88
|
+
text = ask_editor("\n\n#{footer}", repo.config['core.editor'])
|
89
|
+
comment = [prefix, text].join("\n\n")
|
90
|
+
comment = comment.gsub(footer, '').chomp.strip
|
91
|
+
github_client.add_comment(github_slug, pull_request.number, comment)
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_review_status(state, description)
|
95
|
+
latest_commit = repo.head.target_id
|
96
|
+
update_review_status(latest_commit, state, description)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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 ShareCommand < BaseCommand
|
9
|
+
desc 'share', 'Share the current branch in the remote repository'
|
10
|
+
def share
|
11
|
+
run_cmd "git push origin #{current_branch.name}"
|
12
|
+
run_cmd "git branch --set-upstream-to origin/#{current_branch.name}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
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 StartCommand < BaseCommand
|
9
|
+
EXAMPLE_BRANCH_NAMES = %w( api-fix-invalid-auth desktop-cleanup-avatar-markup share-form-add-edit-link )
|
10
|
+
VALID_BRANCH_NAME_REGEX = /^[A-Za-z0-9\-_]+$/
|
11
|
+
|
12
|
+
desc 'start', 'start a new git branch with latest changes from master'
|
13
|
+
def start(branch_name = nil)
|
14
|
+
until valid_new_branch_name?(branch_name)
|
15
|
+
branch_name = ask("What would you like to name your branch? (ex: #{EXAMPLE_BRANCH_NAMES.sample})")
|
16
|
+
end
|
17
|
+
|
18
|
+
checkout_branch LiveBuzz::Gitx::BASE_BRANCH
|
19
|
+
run_cmd 'git pull'
|
20
|
+
repo.create_branch branch_name, LiveBuzz::Gitx::BASE_BRANCH
|
21
|
+
checkout_branch branch_name
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def valid_new_branch_name?(branch)
|
27
|
+
return false if repo_branches.include?(branch)
|
28
|
+
branch =~ VALID_BRANCH_NAME_REGEX
|
29
|
+
end
|
30
|
+
|
31
|
+
def repo_branches
|
32
|
+
@branch_names ||= repo.branches.each_name.map do |branch|
|
33
|
+
branch.split('/').last
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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 TrackCommand < BaseCommand
|
9
|
+
desc 'track', 'set the current branch to track the remote branch with the same name'
|
10
|
+
def track
|
11
|
+
run_cmd "git branch --set-upstream-to origin/#{current_branch.name}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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 UpdateCommand < BaseCommand
|
9
|
+
desc 'update', 'Update the current branch with latest changes from the remote feature branch and master'
|
10
|
+
def update
|
11
|
+
say "Updating "
|
12
|
+
say "#{current_branch.name} ", :green
|
13
|
+
say "with latest changes from "
|
14
|
+
say LiveBuzz::Gitx::BASE_BRANCH, :green
|
15
|
+
|
16
|
+
update_branch(current_branch.name) if remote_branch_exists?(current_branch.name)
|
17
|
+
update_branch(LiveBuzz::Gitx::BASE_BRANCH)
|
18
|
+
run_cmd 'git push origin HEAD'
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def update_branch(branch)
|
24
|
+
begin
|
25
|
+
run_cmd "git pull origin #{branch}"
|
26
|
+
rescue
|
27
|
+
fail MergeError, "Merge Conflict Occurred. Please fix merge conflict and rerun the update command"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def remote_branch_exists?(branch)
|
32
|
+
repo.branches.each_name(:remote).include?("origin/#{branch}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module LiveBuzz
|
4
|
+
module Gitx
|
5
|
+
class Configuration
|
6
|
+
DEFAULT_CONFIG = {
|
7
|
+
'aggregate_branches' => %w( staging prototype ),
|
8
|
+
'reserved_branches' => %w( HEAD master next_release staging prototype ),
|
9
|
+
'taggable_branches' => %w( master staging )
|
10
|
+
}
|
11
|
+
CONFIG_FILE = '.gitx.yml'
|
12
|
+
|
13
|
+
attr_reader :config
|
14
|
+
|
15
|
+
def initialize(root_dir)
|
16
|
+
@config = Thor::CoreExt::HashWithIndifferentAccess.new(DEFAULT_CONFIG)
|
17
|
+
config_file_path = File.join(root_dir, CONFIG_FILE)
|
18
|
+
if File.exists?(config_file_path)
|
19
|
+
@config.merge!(::YAML::load_file(config_file_path))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def aggregate_branches
|
24
|
+
config[:aggregate_branches]
|
25
|
+
end
|
26
|
+
def aggregate_branch?(branch)
|
27
|
+
aggregate_branches.include?(branch)
|
28
|
+
end
|
29
|
+
|
30
|
+
def reserved_branches
|
31
|
+
config[:reserved_branches]
|
32
|
+
end
|
33
|
+
|
34
|
+
def reserved_branch?(branch)
|
35
|
+
reserved_branches.include?(branch)
|
36
|
+
end
|
37
|
+
|
38
|
+
def taggable_branches
|
39
|
+
config[:taggable_branches]
|
40
|
+
end
|
41
|
+
|
42
|
+
def taggable_branch?(branch)
|
43
|
+
taggable_branches.include?(branch)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class String
|
2
|
+
# @see http://api.rubyonrails.org/classes/String.html#method-i-strip_heredoc
|
3
|
+
def undent
|
4
|
+
indent = scan(/^[ \t]*(?=\S)/).min.size || 0
|
5
|
+
gsub(/^[ \t]{#{indent}}/, '')
|
6
|
+
end
|
7
|
+
alias :dedent :undent
|
8
|
+
|
9
|
+
def blank?
|
10
|
+
self.to_s == ''
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'English'
|
2
|
+
|
3
|
+
class Thor
|
4
|
+
module Actions
|
5
|
+
# execute a shell command and raise an error if non-zero exit code is returned
|
6
|
+
# return the string output from the command
|
7
|
+
def run_cmd(cmd, options = {})
|
8
|
+
say "$ #{cmd}"
|
9
|
+
output = `#{cmd}`
|
10
|
+
success = $CHILD_STATUS.to_i == 0
|
11
|
+
fail "#{cmd} failed" unless success || options[:allow_failure]
|
12
|
+
output
|
13
|
+
end
|
14
|
+
|
15
|
+
# launch configured editor to retreive message/string
|
16
|
+
# see http://osdir.com/ml/ruby-talk/2010-06/msg01424.html
|
17
|
+
# see https://gist.github.com/rkumar/456809
|
18
|
+
# see http://rdoc.info/github/visionmedia/commander/master/Commander/UI.ask_editor
|
19
|
+
def ask_editor(initial_text = '', editor = nil)
|
20
|
+
editor ||= ENV['EDITOR'] || 'vi'
|
21
|
+
Tempfile.open('comment.md') do |f|
|
22
|
+
f << initial_text
|
23
|
+
f.flush
|
24
|
+
|
25
|
+
flags = case editor
|
26
|
+
when 'mate', 'emacs', 'subl'
|
27
|
+
'-w'
|
28
|
+
when 'mvim'
|
29
|
+
'-f'
|
30
|
+
else
|
31
|
+
''
|
32
|
+
end
|
33
|
+
pid = fork { exec([editor, flags, f.path].join(' ')) }
|
34
|
+
Process.waitpid(pid)
|
35
|
+
File.read(f.path)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module LiveBuzz
|
6
|
+
module Gitx
|
7
|
+
module Github
|
8
|
+
GLOBAL_CONFIG_FILE = '~/.config/gitx/github.yml'
|
9
|
+
REVIEW_CONTEXT = 'peer_review'
|
10
|
+
CLIENT_URL = 'https://github.com/livebuzzevents/livebuzz-gitx'
|
11
|
+
PULL_REQUEST_FOOTER = <<-EOS.dedent
|
12
|
+
# Pull Request Protips(tm):
|
13
|
+
# * Include description of how this change accomplishes the task at hand.
|
14
|
+
# * Use GitHub flavored Markdown http://github.github.com/github-flavored-markdown/
|
15
|
+
# * Review CONTRIBUTING.md for recommendations of artifacts, links, images, screencasts, etc.
|
16
|
+
#
|
17
|
+
# This footer will automatically be stripped from the pull request description
|
18
|
+
EOS
|
19
|
+
|
20
|
+
def find_or_create_pull_request(branch)
|
21
|
+
pull_request = find_pull_request(branch)
|
22
|
+
pull_request ||= begin
|
23
|
+
execute_command(LiveBuzz::Gitx::Cli::UpdateCommand, :update)
|
24
|
+
pull_request = create_pull_request(branch)
|
25
|
+
say 'Created pull request: '
|
26
|
+
say pull_request.html_url, :green
|
27
|
+
|
28
|
+
pull_request
|
29
|
+
end
|
30
|
+
pull_request
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Sawyer::Resource] data structure of pull request info if found
|
34
|
+
# @return nil if no pull request found
|
35
|
+
def find_pull_request(branch)
|
36
|
+
head_reference = "#{github_organization}:#{branch}"
|
37
|
+
params = {
|
38
|
+
head: head_reference,
|
39
|
+
state: 'open'
|
40
|
+
}
|
41
|
+
pull_requests = github_client.pull_requests(github_slug, params)
|
42
|
+
pull_requests.first
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get the current commit status of a branch
|
46
|
+
# @see https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
47
|
+
def branch_status(branch)
|
48
|
+
response = github_client.status(github_slug, branch)
|
49
|
+
response.state
|
50
|
+
end
|
51
|
+
|
52
|
+
# Update build status with peer review status
|
53
|
+
def update_review_status(commit_sha, state, description)
|
54
|
+
github_client.create_status(github_slug, commit_sha, state, context: REVIEW_CONTEXT, description: description)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @see http://developer.github.com/v3/pulls/
|
58
|
+
def create_pull_request(branch)
|
59
|
+
say "Creating pull request for "
|
60
|
+
say "#{branch} ", :green
|
61
|
+
say "against "
|
62
|
+
say "#{LiveBuzz::Gitx::BASE_BRANCH} ", :green
|
63
|
+
say "in "
|
64
|
+
say github_slug, :green
|
65
|
+
|
66
|
+
title = branch
|
67
|
+
body = pull_request_body(branch)
|
68
|
+
github_client.create_pull_request(github_slug, LiveBuzz::Gitx::BASE_BRANCH, branch, title, body)
|
69
|
+
end
|
70
|
+
|
71
|
+
def pull_request_body(branch)
|
72
|
+
changelog = run_cmd("git log #{LiveBuzz::Gitx::BASE_BRANCH}...#{branch} --reverse --no-merges --pretty=format:'* %s%n%b'")
|
73
|
+
description = options[:description]
|
74
|
+
|
75
|
+
description_template = []
|
76
|
+
description_template << "#{description}\n" if description
|
77
|
+
description_template << '### Changelog'
|
78
|
+
description_template << changelog
|
79
|
+
description_template << PULL_REQUEST_FOOTER
|
80
|
+
|
81
|
+
body = ask_editor(description_template.join("\n"), repo.config['core.editor'])
|
82
|
+
body.gsub(PULL_REQUEST_FOOTER, '').chomp.strip
|
83
|
+
end
|
84
|
+
|
85
|
+
# authorization token used for github API calls
|
86
|
+
# the token is cached on the filesystem for future use
|
87
|
+
# @return [String] auth token stored in git (current repo, user config or installed global settings)
|
88
|
+
# @see http://developer.github.com/v3/oauth/#scopes
|
89
|
+
# @see http://developer.github.com/v3/#user-agent-required
|
90
|
+
def authorization_token
|
91
|
+
auth_token = global_config['token']
|
92
|
+
auth_token ||= begin
|
93
|
+
new_token = create_authorization
|
94
|
+
save_global_config('token' => new_token)
|
95
|
+
new_token
|
96
|
+
end
|
97
|
+
auth_token
|
98
|
+
end
|
99
|
+
|
100
|
+
def create_authorization
|
101
|
+
password = ask_without_echo("Github password for #{username}: ")
|
102
|
+
client = Octokit::Client.new(login: username, password: password)
|
103
|
+
options = {
|
104
|
+
:scopes => ['repo'],
|
105
|
+
:note => github_client_name,
|
106
|
+
:note_url => CLIENT_URL
|
107
|
+
}
|
108
|
+
two_factor_auth_token = ask_without_echo("Github two factor authorization token (if enabled): ")
|
109
|
+
options[:headers] = {'X-GitHub-OTP' => two_factor_auth_token} if two_factor_auth_token
|
110
|
+
response = client.create_authorization(options)
|
111
|
+
response.token
|
112
|
+
rescue Octokit::ClientError => e
|
113
|
+
say "Error creating authorization: #{e.message}", :red
|
114
|
+
retry
|
115
|
+
end
|
116
|
+
|
117
|
+
def github_client_name
|
118
|
+
timestamp = Time.now.utc.strftime('%FT%R:%S%z')
|
119
|
+
client_name = "The Garage Git eXtensions #{timestamp}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def github_client
|
123
|
+
@client ||= Octokit::Client.new(:access_token => authorization_token)
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [String] github username (ex: 'wireframe') of the current github.user
|
127
|
+
# @raise error if github.user is not configured
|
128
|
+
def username
|
129
|
+
username = repo.config['github.user']
|
130
|
+
fail "Github user not configured. Run: `git config --global github.user 'me@email.com'`" unless username
|
131
|
+
username
|
132
|
+
end
|
133
|
+
|
134
|
+
# @return the github slug for the current repository's remote origin url.
|
135
|
+
# @example
|
136
|
+
# git@github.com:socialcast/livebuzz/gitx.git #=> livebuzz/gitx
|
137
|
+
# @example
|
138
|
+
# https://github.com/socialcast/livebuzz/gitx.git #=> livebuzz/gitx
|
139
|
+
def github_slug
|
140
|
+
remote = repo.config['remote.origin.url']
|
141
|
+
remote.to_s.gsub(/\.git$/,'').split(/[:\/]/).last(2).join('/')
|
142
|
+
end
|
143
|
+
|
144
|
+
def github_organization
|
145
|
+
github_slug.split('/').first
|
146
|
+
end
|
147
|
+
|
148
|
+
def global_config_file
|
149
|
+
File.expand_path(GLOBAL_CONFIG_FILE)
|
150
|
+
end
|
151
|
+
|
152
|
+
def global_config
|
153
|
+
@config ||= begin
|
154
|
+
File.exists?(global_config_file) ? YAML.load_file(global_config_file) : {}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def save_global_config(options)
|
159
|
+
config_dir = File.dirname(global_config_file)
|
160
|
+
::FileUtils.mkdir_p(config_dir, mode: 0700) unless File.exists?(config_dir)
|
161
|
+
|
162
|
+
@config = global_config.merge(options)
|
163
|
+
File.open(global_config_file, "a+") do |file|
|
164
|
+
file.truncate(0)
|
165
|
+
file.write(@config.to_yaml)
|
166
|
+
end
|
167
|
+
File.chmod(0600, global_config_file)
|
168
|
+
end
|
169
|
+
|
170
|
+
def ask_without_echo(message)
|
171
|
+
value = ask(message, echo: false)
|
172
|
+
say ''
|
173
|
+
value
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'livebuzz/gitx/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "livebuzz-gitx"
|
8
|
+
spec.version = LiveBuzz::Gitx::VERSION
|
9
|
+
spec.authors = ["LiveBuzz, forked from code by Ryan Sonnek"]
|
10
|
+
spec.email = ["rob.lambell@livebuzz.co.uk"]
|
11
|
+
spec.description = %q{Git eXtensions for common development workflow}
|
12
|
+
spec.summary = %q{Utility scripts for Git to increase productivity for common operations}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "rugged", '~> 0.21.0'
|
22
|
+
spec.add_runtime_dependency "thor"
|
23
|
+
spec.add_runtime_dependency "octokit"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec", '~> 3.0'
|
28
|
+
spec.add_development_dependency "pry", '>= 0'
|
29
|
+
spec.add_development_dependency "webmock", '>= 0'
|
30
|
+
spec.add_development_dependency "timecop", "~> 0.7.0"
|
31
|
+
spec.add_development_dependency "vcr"
|
32
|
+
spec.add_development_dependency "guard"
|
33
|
+
spec.add_development_dependency "guard-rspec"
|
34
|
+
spec.add_development_dependency "coveralls"
|
35
|
+
spec.add_development_dependency 'terminal-notifier'
|
36
|
+
spec.add_development_dependency 'terminal-notifier-guard'
|
37
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.github.com/repos/livebuzzevents/livebuzz-gitx/pulls?head=livebuzz:feature-branch&state=open
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- application/vnd.github.v3+json
|
12
|
+
User-Agent:
|
13
|
+
- Octokit Ruby Gem 3.4.0
|
14
|
+
Content-Type:
|
15
|
+
- application/json
|
16
|
+
Authorization:
|
17
|
+
- token 123123
|
18
|
+
Accept-Encoding:
|
19
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Server:
|
26
|
+
- GitHub.com
|
27
|
+
Date:
|
28
|
+
- Wed, 10 Dec 2014 19:14:11 GMT
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
Status:
|
32
|
+
- 200 OK
|
33
|
+
X-Github-Media-Type:
|
34
|
+
- github.v3; format=json
|
35
|
+
X-Ratelimit-Limit:
|
36
|
+
- '60'
|
37
|
+
X-Ratelimit-Remaining:
|
38
|
+
- '58'
|
39
|
+
X-Ratelimit-Reset:
|
40
|
+
- '1418242282'
|
41
|
+
X-Xss-Protection:
|
42
|
+
- 1; mode=block
|
43
|
+
X-Frame-Options:
|
44
|
+
- deny
|
45
|
+
Content-Security-Policy:
|
46
|
+
- default-src 'none'
|
47
|
+
Content-Length:
|
48
|
+
- '83'
|
49
|
+
Access-Control-Allow-Credentials:
|
50
|
+
- 'true'
|
51
|
+
Access-Control-Expose-Headers:
|
52
|
+
- ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
|
53
|
+
X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
|
54
|
+
Access-Control-Allow-Origin:
|
55
|
+
- "*"
|
56
|
+
X-Github-Request-Id:
|
57
|
+
- C6CBAFAF:141F:450BDAC:54889B83
|
58
|
+
Strict-Transport-Security:
|
59
|
+
- max-age=31536000; includeSubdomains; preload
|
60
|
+
X-Content-Type-Options:
|
61
|
+
- nosniff
|
62
|
+
body:
|
63
|
+
encoding: UTF-8
|
64
|
+
string: '[{"html_url":"https://path/to/html/pull/request","issue_url":"https://api/path/to/issue/url","number":10,"head":{"ref":"branch_name"}}]'
|
65
|
+
http_version:
|
66
|
+
recorded_at: Wed, 10 Dec 2014 19:14:11 GMT
|
67
|
+
- request:
|
68
|
+
method: get
|
69
|
+
uri: https://api.github.com/repos/livebuzzevents/livebuzz-gitx/commits/feature-branch/status
|
70
|
+
body:
|
71
|
+
encoding: US-ASCII
|
72
|
+
string: ''
|
73
|
+
headers:
|
74
|
+
Accept:
|
75
|
+
- application/vnd.github.v3+json
|
76
|
+
User-Agent:
|
77
|
+
- Octokit Ruby Gem 3.4.0
|
78
|
+
Content-Type:
|
79
|
+
- application/json
|
80
|
+
Authorization:
|
81
|
+
- token 123123
|
82
|
+
Accept-Encoding:
|
83
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
84
|
+
response:
|
85
|
+
status:
|
86
|
+
code: 200
|
87
|
+
message: OK
|
88
|
+
headers:
|
89
|
+
Server:
|
90
|
+
- GitHub.com
|
91
|
+
Date:
|
92
|
+
- Wed, 10 Dec 2014 19:01:27 GMT
|
93
|
+
Content-Type:
|
94
|
+
- application/json; charset=utf-8
|
95
|
+
Transfer-Encoding:
|
96
|
+
- chunked
|
97
|
+
Status:
|
98
|
+
- 200 OK
|
99
|
+
X-Ratelimit-Limit:
|
100
|
+
- '5000'
|
101
|
+
X-Ratelimit-Remaining:
|
102
|
+
- '4993'
|
103
|
+
X-Ratelimit-Reset:
|
104
|
+
- '1418241620'
|
105
|
+
X-Oauth-Scopes:
|
106
|
+
- repo
|
107
|
+
X-Accepted-Oauth-Scopes:
|
108
|
+
- repo, repo:status
|
109
|
+
X-Github-Media-Type:
|
110
|
+
- github.v3; format=json
|
111
|
+
X-Xss-Protection:
|
112
|
+
- 1; mode=block
|
113
|
+
X-Frame-Options:
|
114
|
+
- deny
|
115
|
+
Content-Security-Policy:
|
116
|
+
- default-src 'none'
|
117
|
+
Access-Control-Allow-Credentials:
|
118
|
+
- 'true'
|
119
|
+
Access-Control-Expose-Headers:
|
120
|
+
- ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
|
121
|
+
X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
|
122
|
+
Access-Control-Allow-Origin:
|
123
|
+
- "*"
|
124
|
+
X-Github-Request-Id:
|
125
|
+
- C6CBAFAF:141D:2F27072:54889887
|
126
|
+
Strict-Transport-Security:
|
127
|
+
- max-age=31536000; includeSubdomains; preload
|
128
|
+
X-Content-Type-Options:
|
129
|
+
- nosniff
|
130
|
+
body:
|
131
|
+
encoding: UTF-8
|
132
|
+
string: '{"state":"failure"}'
|
133
|
+
http_version:
|
134
|
+
recorded_at: Wed, 10 Dec 2014 19:14:11 GMT
|
135
|
+
recorded_with: VCR 2.9.2
|