zz-export-pull-requests 0.3.5

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 +7 -0
  2. data/Changes +58 -0
  3. data/README.md +98 -0
  4. data/bin/epr +385 -0
  5. metadata +106 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4fac5c505982f4e25b9dd2ac9cbeac689c0ba84cc1e0f90e3980f8dc8641a922
4
+ data.tar.gz: 53cde9d89cf8026a46ddd8c8de6c72d583cc00a445aef2f02a5e0f0ee6ae3e7e
5
+ SHA512:
6
+ metadata.gz: f8b2fd94abe182a4151c077cc8717f9feaca7f848c82bc8ce306d7d9557ee5ea0af2b6d07f7bb9c8fe1d6df200c73ae7c4581e48758a67ab235a6e73e2ff79b7
7
+ data.tar.gz: cbb6dd165e062e1367a2d53a801c9ada34ba6811bd289c9d14f1003aca25e6804bc27bbba9f82ca43195cdb221d427961b4ab86d67e4f1e021519ab47eb02dfd
data/Changes ADDED
@@ -0,0 +1,58 @@
1
+ v0.3.3 2019-05-01
2
+ --------------------
3
+ Bug Fixes:
4
+ * GitHub PR only exports were output as an "issue" instead of "PR"
5
+
6
+ v0.3.2 2019-02-09
7
+ --------------------
8
+ Bug Fixes:
9
+ * Don't supply assignee or milestone for GitHub if nil
10
+
11
+ --------------------
12
+ v0.3.1 2019-01-28
13
+ --------------------
14
+ Enhancements:
15
+ * Add support for filtering on milestones and labels to GitLab
16
+
17
+ --------------------
18
+ v0.3.0 2019-01-10
19
+ --------------------
20
+ Enhancements:
21
+ * Add support for filtering on milestones and labels (GitHub only)
22
+ * Add support for filtering on assignees (GitHub only, thanks Caroline Boyden)
23
+
24
+ --------------------
25
+ v0.2.2 2018-11-30
26
+ --------------------
27
+ Enhancements:
28
+ * Add support for exporting issue body (GitHub only)
29
+
30
+ --------------------
31
+ v0.2.1 2018-06-05
32
+ --------------------
33
+ Enhancements:
34
+ * Add support for custom endpoints
35
+
36
+ --------------------
37
+ v0.2.0 2017-09-21
38
+ --------------------
39
+ Enhancements:
40
+ * Add support for issues
41
+
42
+ Changes:
43
+ * Always show Repository column (was excluded if only 1 repo was given)
44
+
45
+ --------------------
46
+ v0.1.1 2017-07-23
47
+ --------------------
48
+ Enhancements:
49
+ * Add support for Bitbucket
50
+
51
+ --------------------
52
+ v0.1.0 2017-07-23
53
+ --------------------
54
+ Enhancements:
55
+ * Add support for GitLab
56
+
57
+ Changes:
58
+ * Do not require a token
data/README.md ADDED
@@ -0,0 +1,98 @@
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 zz-export-pull-requests
14
+
15
+ This installs the `epr` executable.
16
+
17
+ ## Usage
18
+
19
+ usage: epr [options] user/repo1 [user/repo2...]
20
+ -b, --body Include the issue/pr body description in the output (GitHub only)
21
+ -c, --creator=USER1,USER2,... Export PRs created by given username(s); prepend `!' to exclude user
22
+ -e, --endpoint=URL Endpoint URL for 'enterprise', etc... repositories
23
+ -m, --milestone=WHAT Export items assigned to the given milestone (GitHub/GitLab only)
24
+ -a, --assignee=USER Export items assigned to the given user (GitHub/GitLab only)
25
+ -l, --labels=LABEL(S) Export items with the given label(s) (GitHub/GitLab only)
26
+ -h, --help Show this message
27
+ -p, --provider=NAME Service provider: bitbucket, github, or gitlab; defaults to github
28
+ -s, --state=STATE Export items in the given state, defaults to open
29
+ -t, --token=TOKEN API token
30
+ -x, --export=WHAT What to export: pr, pr_comments (BitBucket only), issues, or all; defaults to all
31
+ -v, --version epr version
32
+
33
+ ### Config
34
+
35
+ These can all be set by one of the below methods or [via the command line](#usage).
36
+
37
+ #### Token
38
+
39
+ The API token can be set by:
40
+
41
+ - `EPR_TOKEN` environment variable
42
+ - `epr.token` setting in `.gitconfig` (add via `git config --add epr.token <your API token>`)
43
+ - `github.oauth-token` setting in `.gitconfig`
44
+
45
+ #### Default Service
46
+
47
+ github is the default. You can set a new default via `EPR_SERVICE`.
48
+
49
+ ### Examples
50
+
51
+ Export open PRs and issues in `sshaw/git-link` and `sshaw/itunes_store_transporter`:
52
+
53
+ epr sshaw/git-link sshaw/itunes_store_transporter > pr.csv
54
+
55
+ Export open pull request not created by `sshaw` in `padrino/padrino-framework`:
56
+
57
+ epr -x pr -c '!sshaw' padrino/padrino-framework > pr.csv
58
+
59
+ Export open merge requests from a GitLab project:
60
+
61
+ epr -x pr -p gitlab gitlab-org/gitlab-ce > pr.csv
62
+
63
+ Export all issues from a GitLab project:
64
+
65
+ epr -x issues -p gitlab gitlab-org/gitlab-ce > pr.csv
66
+
67
+ ## Service Notes
68
+
69
+ To connect to a custom/"Enterprise" installation of any of the supported services use the endpoint option (`-e`)
70
+
71
+ ### Bitbucket
72
+
73
+ You can use [app passwords](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html) for the API token.
74
+ Just provide your token info in `bitbucket_username:app_password` format:
75
+
76
+ epr -p bitbucket -t bitbucket_username:app_password user/repo1
77
+
78
+ ### GitLab
79
+
80
+ Authentication can be done via a [personal access token](https://gitlab.com/profile/personal_access_tokens).
81
+
82
+ Enterprise editions of GitLab have an [issue export feature](https://docs.gitlab.com/ee/user/project/issues/csv_export.html).
83
+
84
+ ## See Also
85
+
86
+ - [Batch Labels](https://github.com/sshaw/batchlabels) - Add/remove labels in batches to/from GitHub issues and pull requests.
87
+
88
+ ## Author
89
+
90
+ Skye Shaw [skye.shaw AT gmail]
91
+
92
+ ## License
93
+
94
+ Released under the MIT License: www.opensource.org/licenses/MIT
95
+
96
+ ---
97
+
98
+ Made by [ScreenStaring](http://screenstaring.com)
data/bin/epr ADDED
@@ -0,0 +1,385 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "csv"
4
+ require "optparse"
5
+ require "time"
6
+ require "logger"
7
+
8
+ require "github_api"
9
+ require "gitlab"
10
+ require "bitbucket_rest_api"
11
+
12
+ VERSION = "0.3.5"
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
+ TYPE_PR_COMMENT = "PR Comment"
19
+
20
+ EXPORT_ISSUES = "issues"
21
+ EXPORT_PRS = "pr"
22
+ EXPORT_PR_COMMENTS = "pr_comments"
23
+
24
+ DEFAULT_BODY_LENGTH = 2 ** 32 - 1
25
+
26
+ def localtime(t)
27
+ # MM/DD/YY HH:MM:SS
28
+ # Time.parse(t).localtime.strftime("%x %X")
29
+
30
+ # Epoch
31
+ Time.parse(t).localtime.to_i
32
+ end
33
+
34
+ def parse_repos(repos)
35
+ repos.map do |r|
36
+ abort "invalid repository #{r}" unless r =~ %r{\A(\S+)/(\S+)\z}
37
+ [ $1, $2 ]
38
+ end
39
+ end
40
+
41
+ def skip_user?(user)
42
+ $exclude_users.include?(user) || $include_users.any? && !$include_users.include?(user)
43
+ end
44
+
45
+ def lookup_token
46
+ return ENV["EPR_TOKEN"] unless ENV["EPR_TOKEN"].to_s.strip.empty?
47
+
48
+ begin
49
+ GIT_CONFIGS.each do |setting|
50
+ token = `git config #{setting}`.chomp
51
+ return token unless token.empty?
52
+ end
53
+ rescue Errno::ENOENT
54
+ # git not found, ignore
55
+ end
56
+ end
57
+
58
+ def bitbucket(user, repo)
59
+ # TODO: make sure no need to translate any states
60
+ # https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/pullrequests
61
+
62
+ options = { :basic_auth => $token }
63
+ options[:endpoint] = $endpoint if $endpoint
64
+
65
+ $bitbucket ||= BitBucket.new(options)
66
+
67
+ rows = []
68
+ no_user = "Anonymous"
69
+ repo_name = "#{repo}"
70
+
71
+ pull_requests = lambda do
72
+ page = 0
73
+
74
+ loop do
75
+ page += 1
76
+
77
+ prs = $bitbucket.repos.pull_request.all(user, repo, :page => page, :state => $filter.upcase)
78
+ prs["values"].each do |pr|
79
+ next if pr.author && skip_user?(pr.author.display_name)
80
+
81
+ rows << [
82
+ repo_name,
83
+ TYPE_PR,
84
+ pr.id,
85
+ pr.author ? pr.author.display_name : no_user,
86
+ pr.title,
87
+ pr.state,
88
+ localtime(pr.created_on),
89
+ localtime(pr.updated_on),
90
+ pr["links"].html.href,
91
+ pr.summary.raw,
92
+ pr.summary.html,
93
+ !pr.source.commit.nil? ? pr.source.commit["hash"] : "",
94
+ !pr.destination.commit.nil? ? pr.destination.commit["hash"] : "",
95
+ !pr.source.branch.nil? ? pr.source.branch.name : "",
96
+ !pr.destination.branch.nil? ? pr.destination.branch.name : "",
97
+ !pr.reason.nil? ? pr.reason : "",
98
+ !pr.merge_commit.nil? ? pr.merge_commit["hash"] : ""
99
+ ]
100
+ end
101
+
102
+ break unless prs["next"]
103
+ end
104
+ end
105
+
106
+ pull_request_comments = lambda do
107
+ pr_page = 0
108
+
109
+ loop do
110
+ pr_page += 1
111
+ prs = $bitbucket.repos.pull_request.all(user, repo, :page => pr_page, :state => $filter.upcase)
112
+
113
+ prs["values"].each do |pr|
114
+ comment_page = 0
115
+ loop do
116
+ comment_page += 1
117
+ comments = $bitbucket.repos.pull_request.comments(user, repo, pr.id, :page => comment_page)
118
+ comments["values"].each do |comment|
119
+ rows << [
120
+ repo_name,
121
+ TYPE_PR_COMMENT,
122
+ comment.pullrequest.id,
123
+ comment.user.display_name,
124
+ comment.inline? ? "inline" : "normal",
125
+ comment.content.raw,
126
+ comment.content.html,
127
+ localtime(comment.updated_on),
128
+ comment.deleted,
129
+ comment.inline? ? comment.inline.to : "",
130
+ comment.inline? ? comment.inline.from : "",
131
+ comment.inline? ? comment.inline.path : "",
132
+ comment["links"].code? ? comment["links"].code.href : ""
133
+ ]
134
+ end
135
+ break unless comments["next"]
136
+ end
137
+ end
138
+
139
+ break unless prs["next"]
140
+ end
141
+ end
142
+
143
+ issues = lambda do
144
+ start = 0
145
+
146
+ loop do
147
+ issues = $bitbucket.issues.list_repo(user, repo, :start => start, :status => $filter)
148
+ break unless issues.any?
149
+
150
+ issues.each do |issue|
151
+ next if issue["reported_by"] && skip_user?(issue["reported_by"]["username"])
152
+
153
+ rows << [
154
+ repo_name,
155
+ TYPE_ISSUE,
156
+ issue["local_id"],
157
+ issue["reported_by"] ? issue["reported_by"]["username"] : no_user,
158
+ issue["title"],
159
+ issue["status"],
160
+ localtime(issue["utc_created_on"]),
161
+ localtime(issue["utc_last_updated"]),
162
+ # Not in response
163
+ sprintf("https://bitbucket.org/%s/issues/%s", repo_name, issue["local_id"])
164
+ ]
165
+ end
166
+
167
+ start += issues.size
168
+ end
169
+ end
170
+
171
+ case $export
172
+ when EXPORT_PRS
173
+ pull_requests[]
174
+ when EXPORT_PR_COMMENTS
175
+ pull_request_comments[]
176
+ when EXPORT_ISSUES
177
+ issues[]
178
+ else
179
+ pull_requests[]
180
+ issues[]
181
+ end
182
+
183
+ rows
184
+ end
185
+
186
+ def github(user, repo)
187
+ rows = []
188
+ method = $export == EXPORT_PRS ? :pull_requests : :issues
189
+
190
+ options = { :oauth_token => $token, :auto_pagination => true }
191
+ options[:endpoint] = $endpoint if $endpoint
192
+
193
+ $gh ||= Github.new(options)
194
+
195
+ options = { :user => user, :repo => repo, :state => $filter, :labels => $labels }
196
+ options[:milestone] = $milestone if $milestone
197
+ options[:assignee] = $assignee if $assignee
198
+
199
+ $gh.public_send(method).list(options).each_page do |page|
200
+
201
+ next if page.size.zero? # Needed for auto_pagination
202
+
203
+ page.each do |item|
204
+ # issues method will return issues and PRs
205
+ next if $export == EXPORT_ISSUES && item.pull_request
206
+ next if skip_user?(item.user.login)
207
+
208
+ rows << [
209
+ "#{user}/#{repo}",
210
+ # If we're only retrieving PRs then item.pull_request will be nil
211
+ # It's only populated when retrieving both (issues method).
212
+ item.pull_request || method == :pull_requests ? TYPE_PR : TYPE_ISSUE,
213
+ item.number,
214
+ item.user.login,
215
+ item.title,
216
+ item.state,
217
+ localtime(item.created_at),
218
+ localtime(item.updated_at),
219
+ item.html_url,
220
+ ]
221
+
222
+ if $body
223
+ body = item.body
224
+ # -3 for "..."
225
+ body = body.slice(0, DEFAULT_BODY_LENGTH - 3) << "..." if body.size > DEFAULT_BODY_LENGTH unless body == nil
226
+ rows[-1].insert(4, body)
227
+ end
228
+ end
229
+ end
230
+
231
+ rows
232
+ end
233
+
234
+ def gitlab(user, repo)
235
+ rows = []
236
+
237
+ case $export
238
+ when EXPORT_PRS
239
+ methods = [:merge_requests]
240
+ when EXPORT_ISSUES
241
+ methods = [:issues]
242
+ else
243
+ methods = [:merge_requests, :issues]
244
+ end
245
+
246
+ # Do we care about this differing in output?
247
+ state = $filter == "open" ? "opened" : $filter
248
+ options = {
249
+ :milestone => $milestone,
250
+ :labels => $labels,
251
+ :state => state
252
+ }
253
+
254
+ # If assignee_id is nil an error is raised
255
+ options[:assignee_id] = $assignee if $assignee
256
+
257
+ $gitlab ||= Gitlab.client(:auth_token => $token, :endpoint => $endpoint || "https://gitlab.com/api/v4")
258
+ methods.each do |method|
259
+ $gitlab.public_send(method, "#{user}/#{repo}", options).auto_paginate do |item|
260
+ next if skip_user?(item.author.username)
261
+
262
+ rows << [
263
+ "#{user}/#{repo}",
264
+ method == :issues ? TYPE_ISSUE : TYPE_PR,
265
+ # Yes, it's called iid
266
+ item.iid,
267
+ item.author.username,
268
+ item.title,
269
+ item.state,
270
+ localtime(item.created_at),
271
+ localtime(item.updated_at),
272
+ item.web_url
273
+ ]
274
+ end
275
+ end
276
+
277
+ rows
278
+ end
279
+
280
+ def export_repos(argv)
281
+ rows = []
282
+
283
+ if $export == EXPORT_PR_COMMENTS
284
+ rows << %w[Repository Type PRNumber User CommentType BodyRaw BodyHTML CreatedAt IsDeleted ToLine FromLine FilePath Diff]
285
+ else
286
+ rows << %w[Repository Type # User Title State CreatedAt UpdatedAt URL BodyRaw BodyHTML SourceCommit DestinationCommit SourceBranch DestinationBranch DeclineReason MergeCommit]
287
+ end
288
+
289
+ rows[-1].insert(4, "Body") if $body
290
+ repos = parse_repos(argv)
291
+
292
+ repos.each do |user, repo|
293
+ case $provider
294
+ when "github"
295
+ rows.concat(github(user, repo))
296
+ when "gitlab"
297
+ rows.concat(gitlab(user, repo))
298
+ when "bitbucket"
299
+ rows.concat(bitbucket(user, repo))
300
+ else
301
+ abort "unknown service provider: #$provider"
302
+ end
303
+
304
+ rows.each { |r| puts r.to_csv }
305
+ rows.clear
306
+ end
307
+ end
308
+
309
+ # Hashie is used by Bitbucket, and it spews warnings to stdout. We stop that,
310
+ # specifically: https://github.com/bitbucket-rest-api/bitbucket/issues/87
311
+ Hashie.logger = Logger.new(File::NULL) if defined?(Hashie)
312
+
313
+ $exclude_users = []
314
+ $include_users = []
315
+ $export = "all"
316
+ $endpoint = nil
317
+ $milestone = $labels = $assignee = nil
318
+ $filter = "open"
319
+ $provider = ENV["EPR_SERVICE"] || SERVICES[0]
320
+ $token = lookup_token
321
+ $body = false
322
+
323
+ parser = OptionParser.new do |opts|
324
+ opts.banner = "usage: #{File.basename($0)} [options] user/repo1 [user/repo2...]"
325
+
326
+ opts.on "-b", "--body", "Include the issue/pr body description in the output (GitHub only)" do
327
+ $body = true
328
+ end
329
+
330
+ opts.on "-c", "--creator=USER1,USER2,...", Array, "Export PRs created by given username(s); prepend `!' to exclude user" do |u|
331
+ $exclude_users, $include_users = u.partition { |name| name.start_with?("!") }
332
+ $exclude_users.map! { |name| name[1..-1] } # remove "!"
333
+ end
334
+
335
+ opts.on "-e", "--endpoint=URL", "Endpoint URL for 'enterprise', etc... repositories" do |url|
336
+ $endpoint = url
337
+ end
338
+
339
+ opts.on "-m", "--milestone=WHAT", "Export items assigned to the given milestone (GitHub/GitLab only)" do |m|
340
+ $milestone = m
341
+ end
342
+
343
+ opts.on "-a", "--assignee=USER", "Export items assigned to the given user (GitHub/GitLab only)" do |a|
344
+ $assignee = a
345
+ end
346
+
347
+ opts.on "-l", "--labels=LABEL(S)", "Export items with the given label(s) (GitHub/GitLab only)" do |l|
348
+ $labels = l
349
+ end
350
+
351
+ opts.on "-h", "--help", "Show this message" do
352
+ puts opts
353
+ exit
354
+ end
355
+
356
+ opts.on "-p, --provider=NAME", SERVICES, "Service provider: bitbucket, github, or gitlab; defaults to github" do |name|
357
+ $provider = name
358
+ end
359
+
360
+ opts.on "-s", "--state=STATE", "Export items in the given state, defaults to open" do |f|
361
+ $filter = f
362
+ end
363
+
364
+ opts.on "-t", "--token=TOKEN", "API token" do |t|
365
+ $token = t
366
+ end
367
+
368
+ opts.on "-x", "--export=WHAT", %w[pr pr_comments issues all], "What to export: pr, pr_comments, issues, or all; defaults to all" do |x|
369
+ $export = x
370
+ end
371
+
372
+ opts.on "-v", "--version", "epr version" do
373
+ puts "v#{VERSION} (GitHub v#{Github::VERSION}, GitLab v#{Gitlab::VERSION}, Bitbucket v#{BitBucket::VERSION::STRING})"
374
+ exit
375
+ end
376
+ end
377
+
378
+ parser.parse!
379
+ abort parser.banner if ARGV.empty?
380
+
381
+ begin
382
+ export_repos(ARGV)
383
+ rescue => e
384
+ abort "Export failed: #{e}"
385
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zz-export-pull-requests
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.5
5
+ platform: ruby
6
+ authors:
7
+ - Zulhilmi Zainudin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: github_api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.16'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gitlab
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: zz_bitbucket_rest_api
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.8
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.8
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ description: Program to export GitHub, GitLab, or Bitbucket pull requests/merge requests
70
+ and issues to CSV a file. This is forked version of https://github.com/sshaw/export-pull-requests
71
+ project.
72
+ email: zulhfreelancer@gmail.com
73
+ executables:
74
+ - epr
75
+ extensions: []
76
+ extra_rdoc_files:
77
+ - README.md
78
+ - Changes
79
+ files:
80
+ - Changes
81
+ - README.md
82
+ - bin/epr
83
+ homepage: https://github.com/zulhfreelancer/export-pull-requests
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message: Use the `epr' command to export your pull requests.
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.0.3
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Export pull requests and issues to a CSV file.
106
+ test_files: []