git-whistles 1.2.1 → 1.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +5 -3
- data/bin/git-jira-branch +1 -2
- data/bin/git-jira-pr +2 -154
- data/bin/git-pivotal-pr +2 -167
- data/bin/git-pr +18 -0
- data/git-whistles.gemspec +1 -1
- data/lib/git-whistles/jira.rb +3 -4
- data/lib/git-whistles/pull_request/bare.rb +110 -0
- data/lib/git-whistles/pull_request/jira.rb +77 -0
- data/lib/git-whistles/pull_request/pivotal.rb +78 -0
- data/lib/git-whistles/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '078014219cfdf3c6bae4aa0e471e60226f79063e'
|
4
|
+
data.tar.gz: 9418248182d6a8d514852de02f95c41f107544a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15cf0189527e58fd684e4259884108514afc7ae24cc4468fe0fc0faf98466beee7d9c060650c4096c494fbb665e2152760978487bf44621467d93f9c1351239c
|
7
|
+
data.tar.gz: 1033a1b9b25b2c9601c0e0dd25f18c311f1f0b25cc46b3ff65e21c1c4c697a0b8cf4f24e81f88d1c6e872c529da34ef600b1c17e7a1afb1560c24c6c40398f9b
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -11,6 +11,8 @@ Install with:
|
|
11
11
|
|
12
12
|
`git chop [branch1, ...]` - Deletes the local and origin copy of a branch. Useful to close feature branches once a feature is completed. It also accepts multiple branches separated by spaces
|
13
13
|
|
14
|
+
`git pr [--from your-branch] [--to target-branch]` - Open your browser at a Github pull-request page for the specified branch (defaults to the current `head`).
|
15
|
+
|
14
16
|
`git explore [-r REF] [-p PATH]` - Opens the remote origin interface on the given reference and path. Reference defaults to current branch and path to root
|
15
17
|
|
16
18
|
`git ff-all-branches [-f] [-p] [-v]` - Fast-forward all local tracking branches to their remote counterpart (where possible). Very useful on big projects.
|
@@ -37,7 +39,7 @@ Install with:
|
|
37
39
|
|
38
40
|
`git stash-and-checkout [branch]` - Stash and checkout another branch.
|
39
41
|
|
40
|
-
`git youtrack-branch <ticket-id>` - Creates a branch name suggestion from the specified Youtrack ticket ID.
|
42
|
+
`git youtrack-branch <ticket-id>` - Creates a branch name suggestion from the specified Youtrack ticket ID.
|
41
43
|
|
42
44
|
### More details on some of the commands
|
43
45
|
|
@@ -45,7 +47,7 @@ Install with:
|
|
45
47
|
|
46
48
|
`git merge-po <ancestor> <left> <right>`
|
47
49
|
|
48
|
-
For those using `gettext` for I18n, a must-have: this custom merge driver
|
50
|
+
For those using `gettext` for I18n, a must-have: this custom merge driver
|
49
51
|
will handle most merge/conflicts issues when a PO file was edited by different
|
50
52
|
committers.
|
51
53
|
|
@@ -61,7 +63,7 @@ Add this to .gitattributes:
|
|
61
63
|
|
62
64
|
*.po merge=pofile
|
63
65
|
*.pot merge=pofile
|
64
|
-
|
66
|
+
|
65
67
|
Or, if you want to make this setting global:
|
66
68
|
|
67
69
|
Create a user global file ~/.gitattributes and fill it with:
|
data/bin/git-jira-branch
CHANGED
data/bin/git-jira-pr
CHANGED
@@ -9,162 +9,10 @@
|
|
9
9
|
# <team>/<branch-title>-<story-id>
|
10
10
|
#
|
11
11
|
require 'rubygems'
|
12
|
-
require 'jira-ruby'
|
13
12
|
require 'optparse'
|
14
13
|
require 'cgi'
|
15
14
|
require 'term/ansicolor'
|
16
15
|
require 'git-whistles/app'
|
17
|
-
require 'git-whistles/jira'
|
16
|
+
require 'git-whistles/pull_request/jira'
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
BROWSERS = %w(xdg-open open firefox iceweasel)
|
22
|
-
SAFE_QUERY_STRING_SIZE = 8000
|
23
|
-
|
24
|
-
def initialize
|
25
|
-
super
|
26
|
-
|
27
|
-
@client = Git::Whistles::Jira.new.get_client
|
28
|
-
end
|
29
|
-
|
30
|
-
def main(args)
|
31
|
-
super
|
32
|
-
parse_args!(args)
|
33
|
-
|
34
|
-
if args.count > 0
|
35
|
-
die "Too many arguments", :usage => true
|
36
|
-
end
|
37
|
-
|
38
|
-
if options.from == options.to
|
39
|
-
die "You cannot issue a pull request to the same branch (#{options.from})."
|
40
|
-
end
|
41
|
-
|
42
|
-
query = { }
|
43
|
-
|
44
|
-
# guess team name
|
45
|
-
if options.from =~ %r{^(\w+-\w+)/.*}
|
46
|
-
team, issue_id = $1.capitalize.split('-')
|
47
|
-
else
|
48
|
-
issue_id = team = nil
|
49
|
-
end
|
50
|
-
|
51
|
-
# guess title.
|
52
|
-
title = options.from.split('/').last.split(/[_-]/).delete_if { |word| word =~ /^\d+$/ }.join(' ').capitalize
|
53
|
-
query[:"pull_request[title]"] = team ? "#{team}: #{title}" : title
|
54
|
-
|
55
|
-
# add Jira infos
|
56
|
-
add_jira_info(query, "#{team}-#{issue_id}".upcase) if issue_id =~ /(\d+)$/
|
57
|
-
|
58
|
-
query_string = query.map { |key,value|
|
59
|
-
"#{CGI.escape key.to_s}=#{CGI.escape value}"
|
60
|
-
}.join('&')
|
61
|
-
url = "https://github.com/#{repo}/compare/#{options.to}...#{options.from}?#{query_string}"
|
62
|
-
|
63
|
-
puts "Preparing a pull request for branch #{options.from}"
|
64
|
-
|
65
|
-
unless launch_browser(url)
|
66
|
-
log.warn "Sorry, I don't know how to launch a web browser on your system. You can open it yourself and paste this URL:\n#{url}"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def defaults
|
73
|
-
{
|
74
|
-
:from => run!('git symbolic-ref HEAD').strip.gsub(%r(^refs/heads/), ""),
|
75
|
-
:to => 'master',
|
76
|
-
:remote => 'origin'
|
77
|
-
}
|
78
|
-
end
|
79
|
-
|
80
|
-
def option_parser
|
81
|
-
@option_parser ||= OptionParser.new do |op|
|
82
|
-
op.banner = "Usage: git jira-pr [options]"
|
83
|
-
|
84
|
-
op.on("-f", "--from YOUR_BRANCH", "Branch to issue pull request for [head]") do |v|
|
85
|
-
options.from = v
|
86
|
-
end
|
87
|
-
|
88
|
-
op.on("-to", "--to UPSTREAM_BRANCH", "Branch into which you want your code merged [master]") do |v|
|
89
|
-
options.to = v
|
90
|
-
end
|
91
|
-
|
92
|
-
op.on("-r", "--remote NAME", "The remote you're sending this to [origin]") do |v|
|
93
|
-
options.to = v
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def origin_url
|
99
|
-
@origin_url ||= begin
|
100
|
-
run!("git config --get remote.#{options.remote}.url").strip.tap do |url|
|
101
|
-
url =~ /github\.com/ or die "origin does not have a Github URL !"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def repo
|
107
|
-
@repo ||= origin_url.sub(/.*github\.com[\/:]/,'').sub(/\.git$/,'')
|
108
|
-
end
|
109
|
-
|
110
|
-
def add_jira_info(query, issue_id)
|
111
|
-
log.info "Finding your Jira Issue¬"
|
112
|
-
|
113
|
-
issue = @client.Issue.find(issue_id)
|
114
|
-
log.info '.'
|
115
|
-
|
116
|
-
if issue.nil?
|
117
|
-
log.warn "Apologies... I could not find issue #{issue_id}."
|
118
|
-
return
|
119
|
-
end
|
120
|
-
|
121
|
-
log.info "Found story #{issue_id} in '#{issue.fields['project']['name']}'"
|
122
|
-
|
123
|
-
title = "#{issue_id}: #{issue.summary}"
|
124
|
-
headline = "Jira story [##{issue_id}](#{@client.options[:site]}/browse/#{issue_id}) in project *#{issue.project.name}*:"
|
125
|
-
|
126
|
-
description = safe_description(issue.description)
|
127
|
-
query.merge! subject: issue.summary, :"pull_request[title]" => title
|
128
|
-
|
129
|
-
if (headline.length + description.length) > SAFE_QUERY_STRING_SIZE
|
130
|
-
log.warn "Oops looks like your story body exceeds maximum allowed caracters to send a github request"
|
131
|
-
log.warn "Please copy the info below to your pull request body:"
|
132
|
-
puts
|
133
|
-
puts headline
|
134
|
-
puts
|
135
|
-
puts
|
136
|
-
puts description
|
137
|
-
puts
|
138
|
-
puts
|
139
|
-
puts "Press any key to continue..."
|
140
|
-
gets
|
141
|
-
query.merge! :"pull_request[body]" => "Please check your command line for the story body"
|
142
|
-
else
|
143
|
-
body = "TODO: describe your changes\n\n===\n\n#{headline}\n\n#{description}"
|
144
|
-
query.merge! :"pull_request[body]" => body
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def safe_description(description)
|
149
|
-
return '' unless description
|
150
|
-
|
151
|
-
description.split("\n").map do |line|
|
152
|
-
(1..6).each { |i| line.gsub!(/(h#{i}.)/, '#' * i) }
|
153
|
-
line.gsub!(/({{)|(}})/, '`')
|
154
|
-
"> #{line}"
|
155
|
-
end.join("\n")
|
156
|
-
end
|
157
|
-
|
158
|
-
def launch_browser(url)
|
159
|
-
BROWSERS.each do |command|
|
160
|
-
next if run("which #{command}").strip.empty?
|
161
|
-
system(command, url) and return true
|
162
|
-
end
|
163
|
-
false
|
164
|
-
end
|
165
|
-
|
166
|
-
end
|
167
|
-
|
168
|
-
############################################################################
|
169
|
-
|
170
|
-
App.run!
|
18
|
+
Git::Whistles::PullRequest::Jira.run!
|
data/bin/git-pivotal-pr
CHANGED
@@ -9,175 +9,10 @@
|
|
9
9
|
# <team>/<branch-title>-<story-id>
|
10
10
|
#
|
11
11
|
require 'rubygems'
|
12
|
-
require 'pivotal-tracker'
|
13
12
|
require 'optparse'
|
14
13
|
require 'cgi'
|
15
14
|
require 'term/ansicolor'
|
16
15
|
require 'git-whistles/app'
|
16
|
+
require 'git-whistles/pull_request/pivotal'
|
17
17
|
|
18
|
-
|
19
|
-
class App < Git::Whistles::App
|
20
|
-
|
21
|
-
BROWSERS = %w(xdg-open open firefox iceweasel)
|
22
|
-
SAFE_QUERY_STRING_SIZE = 8000
|
23
|
-
|
24
|
-
def initialize
|
25
|
-
super
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
def main(args)
|
30
|
-
super
|
31
|
-
parse_args!(args)
|
32
|
-
|
33
|
-
if args.count > 0
|
34
|
-
die "Too many arguments", :usage => true
|
35
|
-
end
|
36
|
-
|
37
|
-
if options.from == options.to
|
38
|
-
die "You cannot issue a pull request to the same branch (#{options.from})."
|
39
|
-
end
|
40
|
-
|
41
|
-
query = { }
|
42
|
-
|
43
|
-
# guess team name
|
44
|
-
if options.from =~ %r{^(\w+)/.*}
|
45
|
-
team = $1.capitalize
|
46
|
-
else
|
47
|
-
team = nil
|
48
|
-
end
|
49
|
-
|
50
|
-
# guess title.
|
51
|
-
title = options.from.split('/').last.split(/[_-]/).delete_if { |word| word =~ /^\d+$/ }.join(' ').capitalize
|
52
|
-
query[:"pull_request[title]"] = team ? "#{team}: #{title}" : title
|
53
|
-
|
54
|
-
# add Pivotal infos
|
55
|
-
add_pivotal_info(query, $1.to_i) if options.from =~ /(\d+)$/
|
56
|
-
|
57
|
-
query_string = query.map { |key,value|
|
58
|
-
"#{CGI.escape key.to_s}=#{CGI.escape value}"
|
59
|
-
}.join('&')
|
60
|
-
url = "https://github.com/#{repo}/compare/#{options.to}...#{options.from}?#{query_string}"
|
61
|
-
|
62
|
-
puts "Preparing a pull request for branch #{options.from}"
|
63
|
-
|
64
|
-
unless launch_browser(url)
|
65
|
-
log.warn "Sorry, I don't know how to launch a web browser on your system. You can open it yourself and paste this URL:\n#{url}"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def defaults
|
72
|
-
{
|
73
|
-
:from => run!('git symbolic-ref HEAD').strip.gsub(%r(^refs/heads/), ""),
|
74
|
-
:to => 'master',
|
75
|
-
:remote => 'origin'
|
76
|
-
}
|
77
|
-
end
|
78
|
-
|
79
|
-
def option_parser
|
80
|
-
@option_parser ||= OptionParser.new do |op|
|
81
|
-
op.banner = "Usage: git pivotal-pr [options]"
|
82
|
-
|
83
|
-
op.on("-f", "--from YOUR_BRANCH", "Branch to issue pull request for [head]") do |v|
|
84
|
-
options.from = v
|
85
|
-
end
|
86
|
-
|
87
|
-
op.on("-to", "--to UPSTREAM_BRANCH", "Branch into which you want your code merged [master]") do |v|
|
88
|
-
options.to = v
|
89
|
-
end
|
90
|
-
|
91
|
-
op.on("-r", "--remote NAME", "The remote you're sending this to [origin]") do |v|
|
92
|
-
options.to = v
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
def origin_url
|
99
|
-
@origin_url ||= begin
|
100
|
-
run!("git config --get remote.#{options.remote}.url").strip.tap do |url|
|
101
|
-
url =~ /github\.com/ or die "origin does not have a Github URL !"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
|
107
|
-
def repo
|
108
|
-
@repo ||= origin_url.sub(/.*github\.com[\/:]/,'').sub(/\.git$/,'')
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
def add_pivotal_info(query, story_id)
|
113
|
-
token = `git config pivotal-tracker.token`.strip
|
114
|
-
if token.empty?
|
115
|
-
puts Term::ANSIColor.yellow %Q{
|
116
|
-
Your branch appears to have a story ID,
|
117
|
-
but I don't know your Pivotal Tracker token!
|
118
|
-
Please set it with:
|
119
|
-
$ git config [--global] pivotal-tracker.token <token>
|
120
|
-
}
|
121
|
-
die "Aborting."
|
122
|
-
end
|
123
|
-
|
124
|
-
log.info "Finding your project and story¬"
|
125
|
-
|
126
|
-
PivotalTracker::Client.token = token
|
127
|
-
begin
|
128
|
-
story, project = PivotalTracker::Project.all.find do |project|
|
129
|
-
log.info '.¬'
|
130
|
-
story = project.stories.find(story_id) and break story, project
|
131
|
-
end
|
132
|
-
log.info '.'
|
133
|
-
rescue RestClient::Unauthorized
|
134
|
-
log.info '.'
|
135
|
-
die "Your token is not authorized by Pivotal Tracker! Please make sure you have the correct one"
|
136
|
-
end
|
137
|
-
|
138
|
-
if story.nil?
|
139
|
-
log.warn "Apologies... I could not find story #{story_id}."
|
140
|
-
return
|
141
|
-
end
|
142
|
-
|
143
|
-
log.info "Found story #{story_id} in '#{project.name}'"
|
144
|
-
|
145
|
-
title = "#{project.name}: #{story.name} [##{story.id}]"
|
146
|
-
headline = "Pivotal tracker story [##{story_id}](#{story.url}) in project *#{project.name}*:"
|
147
|
-
description = story.description.split("\n").map { |line| "> #{line}" }.join("\n")
|
148
|
-
|
149
|
-
query.merge! subject: story.name, :"pull_request[title]" => title
|
150
|
-
|
151
|
-
if (headline.length + description.length) > SAFE_QUERY_STRING_SIZE
|
152
|
-
log.warn "Oops looks like your story body exceeds maximum allowed caracters to send a github request"
|
153
|
-
log.warn "Please copy the info below to your pull request body:"
|
154
|
-
puts
|
155
|
-
puts headline
|
156
|
-
puts
|
157
|
-
puts
|
158
|
-
puts description
|
159
|
-
puts
|
160
|
-
puts
|
161
|
-
puts "Press any key to continue..."
|
162
|
-
gets
|
163
|
-
query.merge! :"pull_request[body]" => "Please check your command line for the story body"
|
164
|
-
else
|
165
|
-
body = "TODO: describe your changes\n\n===\n\n#{headline}\n\n#{description}"
|
166
|
-
query.merge! :"pull_request[body]" => body
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def launch_browser(url)
|
171
|
-
BROWSERS.each do |command|
|
172
|
-
next if run("which #{command}").strip.empty?
|
173
|
-
system(command, url) and return true
|
174
|
-
end
|
175
|
-
false
|
176
|
-
end
|
177
|
-
|
178
|
-
|
179
|
-
end
|
180
|
-
|
181
|
-
############################################################################
|
182
|
-
|
183
|
-
App.run!
|
18
|
+
Git::Whistles::PullRequest::Pivotal.run!
|
data/bin/git-pr
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# git-pr --
|
5
|
+
#
|
6
|
+
# Open a pull request for the current branch in your default browser
|
7
|
+
#
|
8
|
+
# Assumes the branches are named
|
9
|
+
# <team>/<branch-title>-<story-id>
|
10
|
+
#
|
11
|
+
require 'rubygems'
|
12
|
+
require 'optparse'
|
13
|
+
require 'cgi'
|
14
|
+
require 'term/ansicolor'
|
15
|
+
require 'git-whistles/app'
|
16
|
+
require 'git-whistles/pull_request/bare'
|
17
|
+
|
18
|
+
Git::Whistles::PullRequest::Bare.run!
|
data/git-whistles.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |gem|
|
|
29
29
|
gem.add_dependency "youtrack", "~> 0.0.11"
|
30
30
|
|
31
31
|
gem.files = `git ls-files`.split($\)
|
32
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
32
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
33
33
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
34
34
|
gem.name = "git-whistles"
|
35
35
|
gem.require_paths = ["lib"]
|
data/lib/git-whistles/jira.rb
CHANGED
@@ -31,7 +31,7 @@ module Git
|
|
31
31
|
Please set it with:
|
32
32
|
$ git config [--global] jira.username <username>
|
33
33
|
}
|
34
|
-
|
34
|
+
raise "Aborting."
|
35
35
|
end
|
36
36
|
|
37
37
|
@password = `git config jira.password`.strip
|
@@ -42,7 +42,7 @@ module Git
|
|
42
42
|
Please set it with:
|
43
43
|
$ git config [--global] jira.password <password>
|
44
44
|
}
|
45
|
-
|
45
|
+
raise "Aborting."
|
46
46
|
end
|
47
47
|
|
48
48
|
@site = `git config jira.site`.strip
|
@@ -53,9 +53,8 @@ module Git
|
|
53
53
|
Please set it with:
|
54
54
|
$ git config [--global] jira.site <https://mydomain.atlassian.net>
|
55
55
|
}
|
56
|
-
|
56
|
+
raise "Aborting."
|
57
57
|
end
|
58
|
-
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Git
|
2
|
+
module Whistles
|
3
|
+
module PullRequest
|
4
|
+
class Bare < Git::Whistles::App
|
5
|
+
BROWSERS = %w(xdg-open open firefox iceweasel)
|
6
|
+
SAFE_QUERY_STRING_SIZE = 8000
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def main(args)
|
13
|
+
super
|
14
|
+
|
15
|
+
parse_args!(args)
|
16
|
+
|
17
|
+
if args.count > 0
|
18
|
+
die 'Too many arguments', :usage => true
|
19
|
+
end
|
20
|
+
|
21
|
+
if options.from == options.to
|
22
|
+
die "You cannot issue a pull request to the same branch (#{options.from})."
|
23
|
+
end
|
24
|
+
|
25
|
+
query = {}
|
26
|
+
|
27
|
+
# guess team name
|
28
|
+
if options.from =~ %r{^(\w+)/.*}
|
29
|
+
team = $1.capitalize
|
30
|
+
else
|
31
|
+
team = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# guess title.
|
35
|
+
title = options.from.split('/').last.split(/[_-]/).delete_if { |word| word =~ /^\d+$/ }.join(' ').capitalize
|
36
|
+
query[:"pull_request[title]"] = team ? "#{team}: #{title}" : title
|
37
|
+
|
38
|
+
query.merge!(tracker_related_params(team))
|
39
|
+
|
40
|
+
query_string = query.map { |key,value|
|
41
|
+
"#{CGI.escape key.to_s}=#{CGI.escape value}"
|
42
|
+
}.join('&')
|
43
|
+
url = "https://github.com/#{repo}/compare/#{options.to}...#{options.from}?#{query_string}"
|
44
|
+
|
45
|
+
puts "Preparing a pull request for branch #{options.from}"
|
46
|
+
|
47
|
+
unless launch_browser(url)
|
48
|
+
log.warn "Sorry, I don't know how to launch a web browser on your system. You can open it yourself and paste this URL:\n#{url}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def pr_command # to be overridden by subclass
|
55
|
+
'pr'
|
56
|
+
end
|
57
|
+
|
58
|
+
def tracker_related_params(team)
|
59
|
+
{} # to be overridden by tracker-specific subclass
|
60
|
+
end
|
61
|
+
|
62
|
+
def origin_url
|
63
|
+
@origin_url ||= begin
|
64
|
+
run!("git config --get remote.#{options.remote}.url").strip.tap do |url|
|
65
|
+
url =~ /github\.com/ or die 'origin does not have a Github URL !'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def repo
|
71
|
+
@repo ||= origin_url.sub(/.*github\.com[\/:]/, '').sub(/\.git$/, '')
|
72
|
+
end
|
73
|
+
|
74
|
+
def launch_browser(url)
|
75
|
+
BROWSERS.each do |command|
|
76
|
+
next if run("which #{command}").strip.empty?
|
77
|
+
system(command, url) and return true
|
78
|
+
end
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def defaults
|
83
|
+
{
|
84
|
+
from: run!('git symbolic-ref HEAD').strip.gsub(%r(^refs/heads/), ''),
|
85
|
+
to: 'master',
|
86
|
+
remote: 'origin'
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def option_parser
|
91
|
+
@option_parser ||= OptionParser.new do |op|
|
92
|
+
op.banner = "Usage: git #{pr_command} [options]"
|
93
|
+
|
94
|
+
op.on("-f", "--from YOUR_BRANCH", "Branch to issue pull request for [head]") do |v|
|
95
|
+
options.from = v
|
96
|
+
end
|
97
|
+
|
98
|
+
op.on("-to", "--to UPSTREAM_BRANCH", "Branch into which you want your code merged [master]") do |v|
|
99
|
+
options.to = v
|
100
|
+
end
|
101
|
+
|
102
|
+
op.on("-r", "--remote NAME", "The remote you're sending this to [origin]") do |v|
|
103
|
+
options.to = v
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'jira-ruby'
|
2
|
+
require 'git-whistles/jira'
|
3
|
+
require_relative 'bare'
|
4
|
+
|
5
|
+
module Git
|
6
|
+
module Whistles
|
7
|
+
module PullRequest
|
8
|
+
class Jira < Bare
|
9
|
+
private
|
10
|
+
|
11
|
+
def pr_command
|
12
|
+
'jira-pr'
|
13
|
+
end
|
14
|
+
|
15
|
+
def tracker_related_params(team)
|
16
|
+
params = {}
|
17
|
+
|
18
|
+
if options.from =~ %r{^(\w+-\w+)/.*}
|
19
|
+
team, issue_id = $1.capitalize.split('-')
|
20
|
+
else
|
21
|
+
issue_id = team = nil
|
22
|
+
end
|
23
|
+
issue_id = "#{team}-#{issue_id}".upcase if issue_id =~ /(\d+)$/
|
24
|
+
|
25
|
+
log.info 'Finding your Jira Issue¬'
|
26
|
+
|
27
|
+
client = Git::Whistles::Jira.new.get_client rescue die('Aborting.')
|
28
|
+
issue = client.Issue.find(issue_id)
|
29
|
+
log.info '.'
|
30
|
+
|
31
|
+
if issue.nil?
|
32
|
+
log.warn "Apologies… I could not find issue #{issue_id}."
|
33
|
+
die
|
34
|
+
end
|
35
|
+
|
36
|
+
log.info "Found story #{issue_id} in '#{issue.fields['project']['name']}'"
|
37
|
+
|
38
|
+
title = "#{issue_id}: #{issue.summary}"
|
39
|
+
headline = "Jira story [##{issue_id}](#{client.options[:site]}/browse/#{issue_id}) in project *#{issue.project.name}*:"
|
40
|
+
|
41
|
+
description = safe_description(issue.description)
|
42
|
+
params[:subject] = issue.summary
|
43
|
+
params[:'pull_request[title]'] = title
|
44
|
+
|
45
|
+
if (headline.length + description.length) > SAFE_QUERY_STRING_SIZE
|
46
|
+
log.warn 'Oops looks like your story body exceeds maximum allowed caracters to send a github request'
|
47
|
+
log.warn 'Please copy the info below to your pull request body:'
|
48
|
+
puts
|
49
|
+
puts headline
|
50
|
+
puts
|
51
|
+
puts
|
52
|
+
puts description
|
53
|
+
puts
|
54
|
+
puts
|
55
|
+
puts 'Press any key to continue…'
|
56
|
+
gets
|
57
|
+
params.merge! :"pull_request[body]" => 'Please check your command line for the story body'
|
58
|
+
else
|
59
|
+
body = "TODO: describe your changes\n\n===\n\n#{headline}\n\n#{description}"
|
60
|
+
params[:'pull_request[body]'] = body
|
61
|
+
end
|
62
|
+
params
|
63
|
+
end
|
64
|
+
|
65
|
+
def safe_description(description)
|
66
|
+
return '' unless description
|
67
|
+
|
68
|
+
description.split("\n").map do |line|
|
69
|
+
(1..6).each { |i| line.gsub!(/(h#{i}.)/, '#' * i) }
|
70
|
+
line.gsub!(/({{)|(}})/, '`')
|
71
|
+
"> #{line}"
|
72
|
+
end.join("\n")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'pivotal-tracker'
|
2
|
+
require_relative 'bare'
|
3
|
+
|
4
|
+
module Git
|
5
|
+
module Whistles
|
6
|
+
module PullRequest
|
7
|
+
class Pivotal < Bare
|
8
|
+
private
|
9
|
+
|
10
|
+
def pr_command
|
11
|
+
'pivotal-pr'
|
12
|
+
end
|
13
|
+
|
14
|
+
def tracker_related_params(team)
|
15
|
+
params = {}
|
16
|
+
story_id = $1.to_i if options.from =~ /(\d+)$/
|
17
|
+
|
18
|
+
token = `git config pivotal-tracker.token`.strip
|
19
|
+
if token.empty?
|
20
|
+
puts Term::ANSIColor.yellow %Q{
|
21
|
+
Your branch appears to have a story ID,
|
22
|
+
but I don't know your Pivotal Tracker token!
|
23
|
+
Please set it with:
|
24
|
+
$ git config [--global] pivotal-tracker.token <token>
|
25
|
+
}
|
26
|
+
die 'Aborting.'
|
27
|
+
end
|
28
|
+
|
29
|
+
log.info 'Finding your project and story¬'
|
30
|
+
|
31
|
+
PivotalTracker::Client.token = token
|
32
|
+
begin
|
33
|
+
story, project = PivotalTracker::Project.all.find do |project|
|
34
|
+
log.info '.¬'
|
35
|
+
story = project.stories.find(story_id) and break story, project
|
36
|
+
end
|
37
|
+
log.info '.'
|
38
|
+
rescue RestClient::Unauthorized
|
39
|
+
log.info '.'
|
40
|
+
die "Your token is not authorized by Pivotal Tracker! Please make sure you have the correct one"
|
41
|
+
end
|
42
|
+
|
43
|
+
if story.nil?
|
44
|
+
log.warn "Apologies… I could not find story #{story_id}."
|
45
|
+
die
|
46
|
+
end
|
47
|
+
|
48
|
+
log.info "Found story #{story_id} in '#{project.name}'"
|
49
|
+
|
50
|
+
title = "#{project.name}: #{story.name} [##{story.id}]"
|
51
|
+
headline = "Pivotal tracker story [##{story_id}](#{story.url}) in project *#{project.name}*:"
|
52
|
+
description = story.description.split("\n").map { |line| "> #{line}" }.join("\n")
|
53
|
+
params[:subject] = story.name
|
54
|
+
params[:'pull_request[title]'] = title
|
55
|
+
|
56
|
+
if (headline.length + description.length) > SAFE_QUERY_STRING_SIZE
|
57
|
+
log.warn "Oops looks like your story body exceeds maximum allowed caracters to send a github request"
|
58
|
+
log.warn "Please copy the info below to your pull request body:"
|
59
|
+
puts
|
60
|
+
puts headline
|
61
|
+
puts
|
62
|
+
puts
|
63
|
+
puts description
|
64
|
+
puts
|
65
|
+
puts
|
66
|
+
puts 'Press any key to continue…'
|
67
|
+
gets
|
68
|
+
params.merge! :"pull_request[body]" => "Please check your command line for the story body"
|
69
|
+
else
|
70
|
+
body = "TODO: describe your changes\n\n===\n\n#{headline}\n\n#{description}"
|
71
|
+
params[:'pull_request[body]'] = body
|
72
|
+
end
|
73
|
+
params
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/git-whistles/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-whistles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien Letessier
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -181,6 +181,7 @@ executables:
|
|
181
181
|
- git-pivotal-branch
|
182
182
|
- git-pivotal-open
|
183
183
|
- git-pivotal-pr
|
184
|
+
- git-pr
|
184
185
|
- git-select
|
185
186
|
- git-stash-and-checkout
|
186
187
|
- git-whistles
|
@@ -208,6 +209,7 @@ files:
|
|
208
209
|
- bin/git-pivotal-branch
|
209
210
|
- bin/git-pivotal-open
|
210
211
|
- bin/git-pivotal-pr
|
212
|
+
- bin/git-pr
|
211
213
|
- bin/git-select
|
212
214
|
- bin/git-stash-and-checkout
|
213
215
|
- bin/git-whistles
|
@@ -218,6 +220,9 @@ files:
|
|
218
220
|
- lib/git-whistles/helpers.rb
|
219
221
|
- lib/git-whistles/jira.rb
|
220
222
|
- lib/git-whistles/logger.rb
|
223
|
+
- lib/git-whistles/pull_request/bare.rb
|
224
|
+
- lib/git-whistles/pull_request/jira.rb
|
225
|
+
- lib/git-whistles/pull_request/pivotal.rb
|
221
226
|
- lib/git-whistles/version.rb
|
222
227
|
- lib/git-whistles/youtrack/api.rb
|
223
228
|
- lib/git-whistles/youtrack/branch.rb
|