github_issue_exporter 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 354c890b4dfbc919bdf6a9f613c51f77e9749998
4
- data.tar.gz: fd7dc8cf8f2c0e92f9c3dbaddb6f3f755b7be2e8
3
+ metadata.gz: 83363ad95196320642cfe5355440361c0ecbf873
4
+ data.tar.gz: 88c3ee537a792ea633a8a006686d47365fdf5a09
5
5
  SHA512:
6
- metadata.gz: ecb5b1495eb91c1c905286982274ef5e0551cbbc9b4f29ae264cc8addc85d0d7d0dd617b9a2071b1fb0cb2341af42974b1f54876c43ecd032cf31bd4fa22f871
7
- data.tar.gz: 4dd49545cd5fa7db758abae755ebfafa573421c5a4d72aad17b9f63c588c770bbb6d6bd6632d9eb8c9afb03ab61270465deaa500159f3ca544665a24d336c0a6
6
+ metadata.gz: 4fcc17bad5c974b172e589b085f9c29fb3c705e2757e3b3bdb142c581a182f895999373f79ef259a3e30265471f1a601759e75a50c1e5b938f75521767d64a5a
7
+ data.tar.gz: 90dd4ee16a41cb77ba3adf2f234f11fab999926d38637c24ce3e3ba6f0f49184340dd40d5f6c8a1f159da991cdc5a10bd2da812e67d48ed4b08657a66255be9c
data/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  Need to archive some repositories that are stored on GitHub? Great. Don't forget to hold on to any open issues you may still have. GitHub Issue Exporter is a command-line utility that will download all the open issues for a single repository.
6
6
 
7
+ There's also another executable for importing those issues back into a repository, so you can resurrect an archived repository with all of its issues.
8
+
7
9
  ## Installation
8
10
 
9
11
  GitHub Issue Exporter is built with Ruby and needs Ruby 2.0 or higher. Install it with RubyGems.
@@ -19,7 +21,9 @@ sudo gem install github_issue_exporter
19
21
  ```
20
22
 
21
23
  ## Usage
22
- You'll need 3 things to run this, the name of the owner of the repository, the repository name, and an access token that has the authority to download the Issues. You can generate this token from [here](https://github.com/settings/tokens), and clicking on "Generate new token". Here's a [blog post with some more of the details involved](http://blog.swilliams.me/words/2015/04/01/two-factor-authentication-for-github/).
24
+ There are two executables, `export-github-issues` and `import-github-issues`. Both reneed at least three things to run, the owner of the repository, the repository name, and an access token that has the authority to download the Issues. You can generate this token from [here](https://github.com/settings/tokens), and clicking on "Generate new token". Here's a [blog post with some more of the details involved](http://blog.swilliams.me/words/2015/04/01/two-factor-authentication-for-github/).
25
+
26
+ ### export-github-issues
23
27
 
24
28
  The Exporter has a couple of options.
25
29
 
@@ -27,10 +31,36 @@ The Exporter has a couple of options.
27
31
 
28
32
  `--output` Set the directory to store the issues in. By default it is the current directory.
29
33
 
34
+ The issues will be exported into either a single `issues.json` file or multiple `issue-[NUMBER].json` files.
35
+
36
+ ### Example
37
+
38
+ ```
39
+ export-github-issues tallwave github_issue_exporter [TOKEN]
40
+
41
+ export-github-issues --multiple-files --output ~/issues tallwave github_issue_exporter [TOKEN]
42
+ ```
43
+
44
+ ### import-github-issues
45
+ You can import issues a couple of different ways. First is to provide the name of each JSON file created by the exporter.
46
+
47
+ ```
48
+ import-github-issues issues.json more-issues.json tallwave github_issue_exporter [TOKEN]
49
+ ```
50
+
51
+ Or you can use the `--directory` flag and load all the JSON files in the specified directory.
52
+
53
+ ```
54
+ import-github-issues --directory ~/issues tallwave github_issue_exporter [TOKEN]
55
+ ```
56
+
57
+ #### Importer Notes
58
+ * Issues will be added to the repository as if they were brand new, so old issue numbers will not be used.
59
+ * If your user does not have push access to the repository, assignees, milestones, and labels will not be set. Read more in the [GitHub documentation](https://developer.github.com/v3/issues/#create-an-issue).
60
+
30
61
  ## Roadmap
31
62
 
32
- * Import issues back into a repository.
33
- * Allow outputting to stdout.
63
+ * Better error handling.
34
64
 
35
65
  ## Contributing
36
66
 
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby -W
2
2
  # Copyright (c) 2015 Scott Williams
3
3
 
4
- $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
5
5
 
6
- require 'issue_exporter/cli'
6
+ require "issue_exporter/cli"
7
7
 
8
8
  module IssueExporting
9
9
  class Command
@@ -21,8 +21,6 @@ Usage: #{$PROGRAM_NAME} [OPTION]... [OWNER] [REPO] [TOKEN]
21
21
 
22
22
  Example: #{$PROGRAM_NAME} swilliams issue_exporter abcdef
23
23
 
24
- TOKEN is only necessary for private repositories.
25
-
26
24
  -o, --output DIRECTORY
27
25
  set output path
28
26
  (default: current working directory)
@@ -43,9 +41,13 @@ HERE
43
41
  @multiple_files = false
44
42
  end
45
43
 
44
+ def correct_number_of_args(arg_count)
45
+ arg_count == 3
46
+ end
47
+
46
48
  def define_options(opts)
47
- opts.on('-o', '--output ARG') { |arg| @output = arg }
48
- opts.on('--multiple-files') { @multiple_files = true }
49
+ opts.on("-o", "--output ARG") { |arg| @output = arg }
50
+ opts.on("--multiple-files") { @multiple_files = true }
49
51
  end
50
52
 
51
53
  def process_input(arg, index)
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby -W
2
+ # Copyright (c) 2015 Scott Williams
3
+
4
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
5
+
6
+ require "issue_exporter/cli"
7
+
8
+ module IssueExporting
9
+ class Command
10
+ include CLI
11
+
12
+ def about
13
+ VERSION
14
+ end
15
+
16
+ def usage
17
+ <<HERE
18
+ Import issues downloaded from an archived GitHub repository into a new one.
19
+
20
+ Usage: #{$PROGRAM_NAME} [OPTION] [FILE_NAMES]... [OWNER] [REPO] [TOKEN]
21
+
22
+ --directory DIRECTORY
23
+ rather than read individual files, read all appropriate files
24
+ in the provided directory
25
+
26
+ -h, --help display this help and exit
27
+ --version display the version
28
+ HERE
29
+
30
+ end
31
+
32
+ def initialize
33
+ super
34
+ @directory = nil
35
+ @directory_to_parse = nil
36
+ @args = []
37
+ end
38
+
39
+ def correct_number_of_args(arg_count)
40
+ has_directory? ? arg_count == 1 : arg_count >= 4
41
+ end
42
+
43
+ def define_options(opts)
44
+ opts.on("--directory") { |arg| @directory = arg }
45
+ end
46
+
47
+ def perform_action
48
+ process_args
49
+ if has_directory?
50
+ importer = IssueExporting::DirectoryImporter.new @directory_to_parse
51
+ importer.import
52
+ else
53
+ importer = IssueExporting::Importer.new @files, @owner, @repo, @token
54
+ importer.import
55
+ end
56
+ end
57
+
58
+ # TODO: handle directory flag
59
+ def process_args
60
+ if has_directory?
61
+ @directory_to_parse = @args[0]
62
+ else
63
+ @files = @args[0...@args.count-3]
64
+ @owner = @args[@args.count-3]
65
+ @repo = @args[@args.count-2]
66
+ @token = @args[@args.count-1]
67
+ end
68
+ end
69
+
70
+ def process_input(arg, index)
71
+ @args << arg
72
+ end
73
+
74
+ private
75
+ def has_directory?
76
+ !@directory.nil?
77
+ end
78
+ end
79
+ end
80
+
81
+ IssueExporting::Command.new.run
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.email = 'scott@swilliams.me'
16
16
  s.homepage = 'https://github.com/Tallwave/github_issue_exporter'
17
17
  s.files = Dir['{bin,lib}/**/*'] + ['github_issue_exporter.gemspec']
18
- s.executables = ['export-github-issues']
18
+ s.executables = ['export-github-issues', 'import-github-issues']
19
19
  s.extra_rdoc_files = ['LICENSE', 'README.md']
20
20
  s.require_paths = ['lib']
21
21
  end
@@ -1,9 +1,13 @@
1
1
  # Copyright (c) 2015 Scott Williams
2
2
 
3
- require 'English'
4
- require 'shellwords'
5
- require 'json'
6
- require 'issue_exporter/outputter'
7
- require 'issue_exporter/export'
8
- require 'issue_exporter/error'
9
- require 'issue_exporter/version'
3
+ require "English"
4
+ require "shellwords"
5
+ require "json"
6
+ require "issue_exporter/github"
7
+ require "issue_exporter/error_handler"
8
+ require "issue_exporter/outputter"
9
+ require "issue_exporter/export"
10
+ require "issue_exporter/import"
11
+ require "issue_exporter/directory_importer"
12
+ require "issue_exporter/error"
13
+ require "issue_exporter/version"
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2015 Scott Williams
2
2
 
3
- require 'optparse'
4
- require 'issue_exporter'
3
+ require "optparse"
4
+ require "issue_exporter"
5
5
 
6
6
  module IssueExporting
7
7
  module CLI
@@ -10,12 +10,12 @@ module IssueExporting
10
10
  begin
11
11
  OptionParser.new do |opts|
12
12
  define_options opts
13
- opts.on '-h', '--help' do
13
+ opts.on "-h", "--help" do
14
14
  puts usage
15
15
  exit
16
16
  end
17
17
 
18
- opts.on '--version' do
18
+ opts.on "--version" do
19
19
  puts about
20
20
  exit
21
21
  end
@@ -25,8 +25,8 @@ module IssueExporting
25
25
  raise UsageError, e
26
26
  end
27
27
 
28
- fail UsageError, 'missing argument' if ARGV.empty?
29
- fail UsageError, 'incorrect number of arguments' if ARGV.count != 3
28
+ fail UsageError, "missing argument" if ARGV.empty?
29
+ fail UsageError, "incorrect number of arguments" unless correct_number_of_args ARGV.count
30
30
  ARGV.each_with_index { |arg, index| process_input arg, index }
31
31
  perform_action()
32
32
 
@@ -0,0 +1,16 @@
1
+ module IssueExporting
2
+ class DirectoryImporter
3
+ def initialize(directory, owner, repo, token)
4
+ @directory = directory
5
+ @owner = owner
6
+ @repo = repo
7
+ @token = token
8
+ end
9
+
10
+ def import
11
+ files = Dir.glob "#{@directory}/*.json"
12
+ importer = IssueExporting::Importer.new(files, @owner, @repo, @token)
13
+ importer.import
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ module IssueExporting
2
+ class ErrorHandler
3
+ def response_has_error(response)
4
+ response.code.to_i > 299
5
+ end
6
+
7
+ def error_message(response_text)
8
+ response_object = JSON.parse response_text
9
+ if response_object.is_a? Hash
10
+ response_object["message"]
11
+ end
12
+ end
13
+
14
+ def handle_error(error_message, should_abort = true)
15
+ msg = "ERROR: #{error_message}"
16
+ if should_abort
17
+ abort msg
18
+ else
19
+ puts msg
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2015 Scott Williams
2
2
 
3
- require 'net/http'
4
- require 'json'
3
+ require "net/http"
4
+ require "json"
5
5
 
6
6
  module IssueExporting
7
7
  class Exporter
@@ -16,40 +16,16 @@ module IssueExporting
16
16
  end
17
17
 
18
18
  def export
19
- url = URI.parse make_url
19
+ error_handler = ErrorHandler.new
20
+ url = IssueExporting.make_uri @owner, @repo, @token
20
21
  response = Net::HTTP::get url
21
- if err = error_message(response)
22
- handle_error err
22
+ if err = error_handler.error_message(response)
23
+ error_handler.handle_error err
23
24
  else
24
25
  outputter.write response
25
26
  end
26
27
  end
27
28
 
28
- private
29
- def error_message(response_text)
30
- response_object = JSON.parse response_text
31
- if response_object.is_a? Hash
32
- response_object["message"]
33
- end
34
- end
35
-
36
- def handle_error(error_message)
37
- abort "ERROR: #{error_message}"
38
- end
39
-
40
- def make_url
41
- url_format = @token ? url_with_token : url_without_token
42
- url_format % [@owner, @repo, @token]
43
- end
44
-
45
- def url_with_token
46
- "#{url_without_token}?access_token=%s"
47
- end
48
-
49
- def url_without_token
50
- "https://api.github.com/repos/%s/%s/issues"
51
- end
52
-
53
29
  end
54
30
  end
55
31
 
@@ -0,0 +1,14 @@
1
+ module IssueExporting
2
+ def self.api_url
3
+ "https://api.github.com/repos/%s/%s/issues?access_token=%s"
4
+ end
5
+
6
+ def self.make_url(owner, repo, token)
7
+ url_format = IssueExporting.api_url
8
+ url_format % [owner, repo, token]
9
+ end
10
+
11
+ def self.make_uri(owner, repo, token)
12
+ URI.parse IssueExporting.make_url(owner, repo, token)
13
+ end
14
+ end
@@ -0,0 +1,87 @@
1
+ require "net/http"
2
+ require "json"
3
+
4
+ module IssueExporting
5
+ class Importer
6
+ def initialize(files, owner, repo, token)
7
+ @files = files
8
+ @owner = owner
9
+ @repo = repo
10
+ @token = token
11
+ end
12
+
13
+ def import
14
+ @files.each do |file|
15
+ file_contents = read_file file
16
+ import_json(file_contents) unless file_contents.nil?
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def import_json(json_obj)
23
+ if json_obj.class == Hash
24
+ import_json_hash json_obj
25
+ elsif json_obj.class == Array
26
+ import_json_array json_obj
27
+ else
28
+ puts "Unknown object: #{json_obj.class}"
29
+ end
30
+ end
31
+
32
+ def import_json_array(json_array)
33
+ json_array.each do |json_hash|
34
+ import_json_hash json_hash
35
+ end
36
+ end
37
+
38
+ def import_json_hash(json_hash)
39
+ create_issue(filter_json json_hash)
40
+ end
41
+
42
+ def filter_json(json_hash)
43
+ json_hash.select { |k, _v| allowed_properties.include? k }
44
+ end
45
+
46
+ def create_issue(json_obj)
47
+ uri = IssueExporting.make_uri @owner, @repo, @token
48
+ http = Net::HTTP.new(uri.host, uri.port)
49
+ http.use_ssl = true if uri.scheme == "https"
50
+ request = Net::HTTP::Post.new uri.request_uri
51
+ request.content_type = "application/json"
52
+ request.body = json_obj.to_json
53
+ handle_response http.request(request)
54
+ end
55
+
56
+ def allowed_properties
57
+ ["title", "body", "assignee", "milestone", "labels"]
58
+ end
59
+
60
+ def read_file(filename)
61
+ path = full_path filename
62
+ if File.exist? path
63
+ raw_text = File.read path
64
+ JSON.parse raw_text
65
+ else
66
+ handle_missing_file path
67
+ nil
68
+ end
69
+ end
70
+
71
+ def full_path(filename)
72
+ return filename if File.dirname(filename) != "."
73
+ "#{Dir.pwd}/#{filename}"
74
+ end
75
+
76
+ def handle_response(response)
77
+ error_handler = ErrorHandler.new
78
+ if error_handler.response_has_error response
79
+ error_handler.handle_error error_handler.error_message(response.body), true
80
+ end
81
+ end
82
+
83
+ def handle_missing_file(filename)
84
+ puts "Cannot open file: #{filename}"
85
+ end
86
+ end
87
+ end
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2015 Scott Williams
2
2
 
3
3
  module IssueExporting
4
- VERSION = '0.1.0'
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,20 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: github_issue_exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-11 00:00:00.000000000 Z
11
+ date: 2015-05-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  Download Issues from a GitHub repository.
15
15
  email: scott@swilliams.me
16
16
  executables:
17
17
  - export-github-issues
18
+ - import-github-issues
18
19
  extensions: []
19
20
  extra_rdoc_files:
20
21
  - LICENSE
@@ -23,11 +24,16 @@ files:
23
24
  - LICENSE
24
25
  - README.md
25
26
  - bin/export-github-issues
27
+ - bin/import-github-issues
26
28
  - github_issue_exporter.gemspec
27
29
  - lib/issue_exporter.rb
28
30
  - lib/issue_exporter/cli.rb
31
+ - lib/issue_exporter/directory_importer.rb
29
32
  - lib/issue_exporter/error.rb
33
+ - lib/issue_exporter/error_handler.rb
30
34
  - lib/issue_exporter/export.rb
35
+ - lib/issue_exporter/github.rb
36
+ - lib/issue_exporter/import.rb
31
37
  - lib/issue_exporter/outputter.rb
32
38
  - lib/issue_exporter/version.rb
33
39
  homepage: https://github.com/Tallwave/github_issue_exporter