export-pull-requests 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/Changes +23 -0
  3. data/README.md +83 -0
  4. data/bin/epr +128 -58
  5. metadata +10 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a531cf40cb67b6e178bc75a254ee821758369d6
4
- data.tar.gz: da773616d8a630e16bc43b68bf19a6dcddfca440
3
+ metadata.gz: 4d378c2d847231e7d5b29e98aeec72a952100258
4
+ data.tar.gz: f0a364c762a48ec22d0dc35ed1f94fb501bf76ca
5
5
  SHA512:
6
- metadata.gz: 859d3b348f3e95edefa52cf74de68a5a3ce253863ddd9c8695b663fa5b3488193d9672740822f51b6becf14558a9ac4d623d36f56df79fc2ddd23d365f2a3aea
7
- data.tar.gz: 883f927bd24a27b417b085550fc4697e06ce4f631c3212ce54e53e8ce74f901df02c7b33ae9d7df99f9aa20b80cdc81288deadea57c1e0eb860f8a7f7af6ca20
6
+ metadata.gz: 007731af9e311ef0f38155aa1c0a13c3dafb61211939239f3f2a5ac7483d953d1e1daac26ac1c511c51d6297595b151368c7a093918b84fab7bd84a7f879e1e6
7
+ data.tar.gz: 663950b5114a6634b51d063885fc9e862766694f4f9817b7da5f900affa39ff868629de0aab642fd4ba005febbf4bae1aceb3eba75c0923838d45ff67fc6a335
data/Changes ADDED
@@ -0,0 +1,23 @@
1
+ --------------------
2
+ v0.2.0 2017-09-21
3
+ --------------------
4
+ Enhancements:
5
+ * Add support for issues
6
+
7
+ Changes:
8
+ * Always show Repository column (was excluded if only 1 repo was given)
9
+
10
+ --------------------
11
+ v0.1.1 2017-07-23
12
+ --------------------
13
+ Enhancements:
14
+ * Add support for Bitbucket
15
+
16
+ --------------------
17
+ v0.1.0 2017-07-23
18
+ --------------------
19
+ Enhancements:
20
+ * Add support for GitLab
21
+
22
+ Changes:
23
+ * Do not require a token
@@ -0,0 +1,83 @@
1
+ # Export Pull Requests
2
+
3
+ Export pull requests/merge requests and/or issues to a CSV file.
4
+
5
+ Supports GitHub, GitLab, and Bitbucket.
6
+
7
+ ## Installation
8
+
9
+ [Ruby](https://www.ruby-lang.org/en/documentation/installation/) is required.
10
+
11
+ With Ruby installed run:
12
+
13
+ gem install export-pull-requests
14
+
15
+ This installs the `epr` executable.
16
+
17
+ ## Usage
18
+
19
+ usage: epr [-hv] [-s state] [-t token] [-c user1,user2...] user/repo1 [user/repo2...]
20
+ -c, --creator=USER1,USER2,... Export PRs created by given username(s); prepend `!' to exclude user
21
+ -h, --help Show this message
22
+ -p, --provider=NAME Service provider: bitbucket, github, or gitlab; defaults to github
23
+ -t, --token=TOKEN API token
24
+ -s, --state=STATE Export PRs in the given state, defaults to open
25
+ -v, --version epr version
26
+ -x, --export=TYPE What to export: pr, issues, or all; defaults to all
27
+
28
+ ### Config
29
+
30
+ These can all be set by one of the below methods or [via the command line](#usage).
31
+
32
+ #### Token
33
+
34
+ The API token can be set by:
35
+
36
+ * `EPR_TOKEN` environment variable
37
+ * `epr.token` setting in `.gitconfig`
38
+ * `github.oauth-token` setting in `.gitconfig`
39
+
40
+ #### Default Service
41
+
42
+ github is the default. You can set a new default via `EPR_SERVICE`.
43
+
44
+ ### Examples
45
+
46
+ Export open PRs and issues in `sshaw/git-link` and `sshaw/itunes_store_transporter`:
47
+
48
+ epr sshaw/git-link sshaw/itunes_store_transporter > pr.csv
49
+
50
+ Export open pull request not created by `sshaw` in `padrino/padrino-framework`:
51
+
52
+ epr -x pr -c '!sshaw' padrino/padrino-framework > pr.csv
53
+
54
+ Export open merge requests from a GitLab project:
55
+
56
+ epr -x pr -p gitlab gitlab-org/gitlab-ce > pr.csv
57
+
58
+ Export all issues from a GitLab project:
59
+
60
+ epr -x issues -p gitlab gitlab-org/gitlab-ce > pr.csv
61
+
62
+ ## Service Notes
63
+
64
+ ### Bitbucket
65
+
66
+ You can use [app passwords](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html) for the API token.
67
+ Just provide your token HTTP Auth style using: `username:app_password`.
68
+
69
+ ### GitLab
70
+
71
+ Authentication can be done via a [personal access token](https://gitlab.com/profile/personal_access_tokens).
72
+
73
+ Currently the API endpoint URL is hardcoded to `https://gitlab.com/api/v4`.
74
+
75
+ Enterprise editions of GitLab have an [issue export feature](https://docs.gitlab.com/ee/user/project/issues/csv_export.html).
76
+
77
+ ## Author
78
+
79
+ Skye Shaw [skye.shaw AT gmail]
80
+
81
+ ## License
82
+
83
+ Released under the MIT License: www.opensource.org/licenses/MIT
data/bin/epr CHANGED
@@ -9,8 +9,15 @@ require "github_api"
9
9
  require "gitlab"
10
10
  require "bitbucket_rest_api"
11
11
 
12
- VERSION = "0.1.1"
12
+ VERSION = "0.2.0"
13
13
  SERVICES = %w[github gitlab bitbucket]
14
+ GIT_CONFIGS = %w[epr.token github.oauth-token]
15
+
16
+ TYPE_ISSUE = "Issue"
17
+ TYPE_PR = "PR"
18
+
19
+ EXPORT_ISSUES = "issues"
20
+ EXPORT_PRS = "pr"
14
21
 
15
22
  def localtime(t)
16
23
  Time.parse(t).localtime.strftime("%x %X")
@@ -31,7 +38,7 @@ def lookup_token
31
38
  return ENV["EPR_TOKEN"] unless ENV["EPR_TOKEN"].to_s.strip.empty?
32
39
 
33
40
  begin
34
- %w[epr.token github.oauth-token].each do |setting|
41
+ GIT_CONFIGS.each do |setting|
35
42
  token = `git config #{setting}`.chomp
36
43
  return token unless token.empty?
37
44
  end
@@ -41,33 +48,78 @@ def lookup_token
41
48
  end
42
49
 
43
50
  def bitbucket(user, repo)
44
- page = 0
45
- rows = []
46
-
47
- $bitbucket ||= BitBucket.new(:basic_auth => $token)
48
51
  # TODO: make sure no need to translate any states
49
52
  # https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/pullrequests
50
53
 
51
- loop do
52
- page += 1
54
+ $bitbucket ||= BitBucket.new(:basic_auth => $token)
53
55
 
54
- prs = $bitbucket.repos.pull_request.all(user, repo, :page => page, :state => $filter.upcase)
55
- prs["values"].each do |pr|
56
- next if pr.author && skip_user?(pr.author.username)
56
+ rows = []
57
+ no_user = "Anonymous"
58
+ repo_name = "#{user}/#{repo}"
59
+
60
+ pull_requests = lambda do
61
+ page = 0
62
+
63
+ loop do
64
+ page += 1
65
+
66
+ prs = $bitbucket.repos.pull_request.all(user, repo, :page => page, :state => $filter.upcase)
67
+ prs["values"].each do |pr|
68
+ next if pr.author && skip_user?(pr.author.username)
69
+
70
+ rows << [
71
+ repo_name,
72
+ TYPE_PR,
73
+ pr.id,
74
+ pr.author ? pr.author.username : no_user,
75
+ pr.title,
76
+ pr.state,
77
+ localtime(pr.created_on),
78
+ localtime(pr.updated_on),
79
+ pr["links"].html.href
80
+ ]
81
+ end
82
+
83
+ break unless prs["next"]
84
+ end
85
+ end
57
86
 
58
- rows << [
59
- "#{user}/#{repo}",
60
- pr.id,
61
- pr.author ? pr.author.username : "-",
62
- pr.title,
63
- pr.state,
64
- localtime(pr.created_on),
65
- localtime(pr.updated_on),
66
- pr["links"].html.href
67
- ]
87
+ issues = lambda do
88
+ start = 0
89
+
90
+ loop do
91
+ issues = $bitbucket.issues.list_repo(user, repo, :start => start, :status => $filter)
92
+ break unless issues.any?
93
+
94
+ issues.each do |issue|
95
+ next if issue["reported_by"] && skip_user?(issue["reported_by"]["username"])
96
+
97
+ rows << [
98
+ repo_name,
99
+ TYPE_ISSUE,
100
+ issue["local_id"],
101
+ issue["reported_by"] ? issue["reported_by"]["username"] : no_user,
102
+ issue["title"],
103
+ issue["status"],
104
+ localtime(issue["utc_created_on"]),
105
+ localtime(issue["utc_last_updated"]),
106
+ # Not in response
107
+ sprintf("https://bitbucket.org/%s/issues/%s", repo_name, issue["local_id"])
108
+ ]
109
+ end
110
+
111
+ start += issues.size
68
112
  end
113
+ end
69
114
 
70
- break unless prs["next"]
115
+ case $export
116
+ when EXPORT_PRS
117
+ pull_requests[]
118
+ when EXPORT_ISSUES
119
+ issues[]
120
+ else
121
+ pull_requests[]
122
+ issues[]
71
123
  end
72
124
 
73
125
  rows
@@ -75,23 +127,27 @@ end
75
127
 
76
128
  def github(user, repo)
77
129
  rows = []
130
+ method = $export == EXPORT_PRS ? :pull_requests : :issues
78
131
 
79
132
  $gh ||= Github.new(:oauth_token => $token, :auto_pagination => true)
80
- $gh.pull_requests.list(:user => user, :repo => repo, :state => $filter).each_page do |page|
133
+ $gh.public_send(method).list(:user => user, :repo => repo, :state => $filter).each_page do |page|
81
134
  next if page.size.zero? # Needed for auto_pagination
82
135
 
83
- page.each do |pr|
84
- next if skip_user?(pr.user.login)
136
+ page.each do |item|
137
+ # issues method will return issues and PRs
138
+ next if $export == EXPORT_ISSUES && item.pull_request
139
+ next if skip_user?(item.user.login)
85
140
 
86
141
  rows << [
87
142
  "#{user}/#{repo}",
88
- pr.number,
89
- pr.user.login,
90
- pr.title,
91
- pr.state,
92
- localtime(pr.created_at),
93
- localtime(pr.updated_at),
94
- pr.html_url,
143
+ item.pull_request ? TYPE_PR : TYPE_ISSUE,
144
+ item.number,
145
+ item.user.login,
146
+ item.title,
147
+ item.state,
148
+ localtime(item.created_at),
149
+ localtime(item.updated_at),
150
+ item.html_url,
95
151
  ]
96
152
  end
97
153
  end
@@ -102,34 +158,47 @@ end
102
158
  def gitlab(user, repo)
103
159
  rows = []
104
160
 
161
+ case $export
162
+ when EXPORT_PRS
163
+ methods = [:merge_requests]
164
+ when EXPORT_ISSUES
165
+ methods = [:issues]
166
+ else
167
+ methods = [:merge_requests, :issues]
168
+ end
169
+
105
170
  # Do we care about this differing in output?
106
171
  state = $filter == "open" ? "opened" : $filter
107
172
 
108
173
  # TODO: custom endpoint
109
- $gitlab ||= Gitlab.client(:token => $token, :endpoint => "https://gitlab.com/api/v4")
110
- $gitlab.merge_requests("#{user}/#{repo}", :state => state).auto_paginate do |mr|
111
- next if skip_user?(mr.author.username)
112
-
113
- rows << [
114
- "#{user}/#{repo}",
115
- # Yes, it's called iid
116
- mr.iid,
117
- mr.author.username,
118
- mr.title,
119
- mr.state,
120
- localtime(mr.created_at),
121
- localtime(mr.updated_at),
122
- mr.web_url
123
- ]
174
+ $gitlab ||= Gitlab.client(:auth_token => $token, :endpoint => "https://gitlab.com/api/v4")
175
+ methods.each do |method|
176
+ $gitlab.public_send(method, "#{user}/#{repo}", :state => state).auto_paginate do |item|
177
+ next if skip_user?(item.author.username)
178
+
179
+ rows << [
180
+ "#{user}/#{repo}",
181
+ method == :issues ? TYPE_ISSUE : TYPE_PR,
182
+ # Yes, it's called iid
183
+ item.iid,
184
+ item.author.username,
185
+ item.title,
186
+ item.state,
187
+ localtime(item.created_at),
188
+ localtime(item.updated_at),
189
+ item.web_url
190
+ ]
191
+ end
124
192
  end
125
193
 
126
194
  rows
127
195
  end
128
196
 
129
- def export_repos(repos)
197
+ def export_repos(argv)
130
198
  rows = []
131
- rows << %w[Repository # User Title State Created Updated URL]
199
+ rows << %w[Repository Type # User Title State Created Updated URL]
132
200
 
201
+ repos = parse_repos(argv)
133
202
  repos.each do |user, repo|
134
203
  case $provider
135
204
  when "github"
@@ -142,11 +211,7 @@ def export_repos(repos)
142
211
  abort "unknown service provider: #$provider"
143
212
  end
144
213
 
145
- rows.each do |r|
146
- # Drop Repository column if we only have one repo
147
- r.shift unless repos.size > 1
148
- puts r.to_csv
149
- end
214
+ rows.each { |r| puts r.to_csv }
150
215
  rows.clear
151
216
  end
152
217
  end
@@ -157,6 +222,7 @@ Hashie.logger = Logger.new(File::NULL) if defined?(Hashie)
157
222
 
158
223
  $exclude_users = []
159
224
  $include_users = []
225
+ $export = "all"
160
226
  $filter = "open"
161
227
  $provider = ENV["EPR_SERVICE"] || SERVICES[0]
162
228
  $token = lookup_token
@@ -164,7 +230,7 @@ $token = lookup_token
164
230
  parser = OptionParser.new do |opts|
165
231
  opts.banner = "usage: #{File.basename($0)} [-hv] [-s state] [-t token] [-c user1,user2...] user/repo1 [user/repo2...]"
166
232
 
167
- opts.on "-c", "--creator=user1,user2,...", Array, "Export PRs created by given username(s); prepend `!' to exclude user" do |u|
233
+ opts.on "-c", "--creator=USER1,USER2,...", Array, "Export PRs created by given username(s); prepend `!' to exclude user" do |u|
168
234
  $exclude_users, $include_users = u.partition { |name| name.start_with?("!") }
169
235
  $exclude_users.map! { |name| name[1..-1] } # remove "!"
170
236
  end
@@ -178,14 +244,18 @@ parser = OptionParser.new do |opts|
178
244
  $token = t
179
245
  end
180
246
 
181
- opts.on "-p, --provider=NAME", SERVICES, "Service provider, one of: #{SERVICES}" do |name|
247
+ opts.on "-p, --provider=NAME", SERVICES, "Service provider: bitbucket, github, or gitlab; defaults to github" do |name|
182
248
  $provider = name
183
249
  end
184
250
 
185
- opts.on "-s", "--state=STATE", %w[open closed all merged], "Export PRs in the given state, defaults to open" do |f|
251
+ opts.on "-s", "--state=STATE", "Export items in the given state, defaults to open" do |f|
186
252
  $filter = f
187
253
  end
188
254
 
255
+ opts.on "-x", "--export=WHAT", %w[pr issues all], "What to export: pr, issues, or all; defaults to all" do |x|
256
+ $export = x
257
+ end
258
+
189
259
  opts.on "-v", "--version", "epr version" do
190
260
  puts "v#{VERSION} (GitHub v#{Github::VERSION}, GitLab v#{Gitlab::VERSION}, Bitbucket v#{BitBucket::VERSION::STRING})"
191
261
  exit
@@ -196,7 +266,7 @@ parser.parse!
196
266
  abort parser.banner if ARGV.empty?
197
267
 
198
268
  begin
199
- export_repos(parse_repos(ARGV))
269
+ export_repos(ARGV)
200
270
  rescue => e
201
271
  abort "Export failed: #{e}"
202
272
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: export-pull-requests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skye Shaw
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-23 00:00:00.000000000 Z
11
+ date: 2017-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: github_api
@@ -67,19 +67,23 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.9'
69
69
  description: Program to export GitHub, GitLab, or Bitbucket pull requests/merge requests
70
- to CSV a file.
70
+ and issues to CSV a file.
71
71
  email: skye.shaw@gmail.com
72
72
  executables:
73
73
  - epr
74
74
  extensions: []
75
- extra_rdoc_files: []
75
+ extra_rdoc_files:
76
+ - README.md
77
+ - Changes
76
78
  files:
79
+ - Changes
80
+ - README.md
77
81
  - bin/epr
78
82
  homepage: https://github.com/sshaw/export-pull-requests
79
83
  licenses:
80
84
  - MIT
81
85
  metadata: {}
82
- post_install_message:
86
+ post_install_message: Use the `epr' command to export your pull requests.
83
87
  rdoc_options: []
84
88
  require_paths:
85
89
  - lib
@@ -98,5 +102,5 @@ rubyforge_project:
98
102
  rubygems_version: 2.4.5.1
99
103
  signing_key:
100
104
  specification_version: 4
101
- summary: Export pull requests to a CSV file.
105
+ summary: Export pull requests and issues to a CSV file.
102
106
  test_files: []