octaccord 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +62 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +9 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.org +95 -0
  8. data/Rakefile +7 -0
  9. data/bin/octaccord +311 -0
  10. data/examples/Itr0000-template.md.erb +93 -0
  11. data/examples/octaccord-completion.zsh +11 -0
  12. data/lib/extensions.rb +2 -0
  13. data/lib/extensions/octokit.rb +16 -0
  14. data/lib/octaccord.rb +10 -0
  15. data/lib/octaccord/command.rb +16 -0
  16. data/lib/octaccord/command/add_collaborator.rb +34 -0
  17. data/lib/octaccord/command/comments.rb +50 -0
  18. data/lib/octaccord/command/completions.rb +56 -0
  19. data/lib/octaccord/command/create_iteration.rb +21 -0
  20. data/lib/octaccord/command/get_team_members.rb +18 -0
  21. data/lib/octaccord/command/info.rb +18 -0
  22. data/lib/octaccord/command/label.rb +16 -0
  23. data/lib/octaccord/command/scan.rb +122 -0
  24. data/lib/octaccord/command/show.rb +28 -0
  25. data/lib/octaccord/command/update_issues.rb +28 -0
  26. data/lib/octaccord/errors.rb +2 -0
  27. data/lib/octaccord/formatter.rb +105 -0
  28. data/lib/octaccord/formatter/comment.rb +58 -0
  29. data/lib/octaccord/formatter/debug.rb +17 -0
  30. data/lib/octaccord/formatter/issue.rb +134 -0
  31. data/lib/octaccord/formatter/list.rb +36 -0
  32. data/lib/octaccord/formatter/number.rb +14 -0
  33. data/lib/octaccord/formatter/pbl.rb +23 -0
  34. data/lib/octaccord/formatter/table.rb +17 -0
  35. data/lib/octaccord/formatter/text.rb +14 -0
  36. data/lib/octaccord/formatter/user.rb +42 -0
  37. data/lib/octaccord/iteration.rb +61 -0
  38. data/lib/octaccord/version.rb +3 -0
  39. data/octaccord.gemspec +24 -0
  40. data/spec/octaccord_spec.rb +11 -0
  41. data/spec/spec_helper.rb +2 -0
  42. metadata +130 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f41906f4168cda2e216acac50a102ad60bcfbedc
4
+ data.tar.gz: 3a19307ac59fbb1a20c21d1086a711ff04c5c417
5
+ SHA512:
6
+ metadata.gz: 8213ef2b4423e1cc6b0ac200a1d63d8a8f223710668ffd10773ae05f0fe3146f1561c3047e5283ada35162139298c69f8f580952994f3740dbed75f2c5845808
7
+ data.tar.gz: 24c88ad022a415bbff508c8a515f7f3c7aec1d28e2217874abaaebc8f571eee149e918e1b36b58564edc628711bd9bf402c17ab21c5cf08860c927900dbdf616
@@ -0,0 +1,62 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ #
24
+ # Added from https://raw.github.com/github/gitignore/master/Ruby.gitignore
25
+ #
26
+ *.gem
27
+ *.rbc
28
+ /.config
29
+ /coverage/
30
+ /InstalledFiles
31
+ /pkg/
32
+ /spec/reports/
33
+ /test/tmp/
34
+ /test/version_tmp/
35
+ /tmp/
36
+
37
+ ## Specific to RubyMotion:
38
+ .dat*
39
+ .repl_history
40
+ build/
41
+
42
+ ## Documentation cache and generated files:
43
+ /.yardoc/
44
+ /_yardoc/
45
+ /doc/
46
+ /rdoc/
47
+
48
+ ## Environment normalisation:
49
+ /.bundle/
50
+ /lib/bundler/man/
51
+
52
+ # for a library or gem, you might want to ignore these files since the code is
53
+ # intended to run in multiple environments; otherwise, check them in:
54
+ # Gemfile.lock
55
+ .ruby-version
56
+ .ruby-gemset
57
+
58
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
59
+ .rvmrc
60
+
61
+ /vendor/bundle/
62
+ /attic/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in octaccord.gemspec
4
+ gemspec
5
+ gem "octokit"
6
+ gem "pit"
7
+ gem "thor"
8
+ gem "rugged"
9
+ gem 'faraday-http-cache'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Yoshinari Nomura
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ #+TITLE: octaccord
2
+ #+AUTHOR: Nomura Laboratory, Yoshinari Nomura
3
+ #+EMAIL:
4
+ #+DATE: 2014-07-26
5
+ #+OPTIONS: H:3 num:2 toc:nil
6
+ #+OPTIONS: ^:nil @:t \n:nil ::t |:t f:t TeX:t
7
+ #+OPTIONS: skip:nil
8
+ #+OPTIONS: author:t
9
+ #+OPTIONS: email:nil
10
+ #+OPTIONS: creator:nil
11
+ #+OPTIONS: timestamp:nil
12
+ #+OPTIONS: timestamps:nil
13
+ #+OPTIONS: d:nil
14
+ #+OPTIONS: tags:t
15
+ #+TEXT:
16
+ #+DESCRIPTION:
17
+ #+KEYWORDS:
18
+ #+LANGUAGE: ja
19
+ #+LATEX_CLASS: jsarticle
20
+ #+LATEX_CLASS_OPTIONS: [a4j]
21
+ # #+LATEX_HEADER: \usepackage{plain-article}
22
+ # #+LATEX_HEADER: \renewcommand\maketitle{}
23
+ # #+LATEX_HEADER: \pagestyle{empty}
24
+ # #+LaTeX: \thispagestyle{empty}
25
+
26
+ * Octaccord
27
+ ** What is octaccord?
28
+
29
+ Octaccord is a small CLI tool to manipulate issues (tickets) for the GitHub.
30
+ It reduces some complex operations on the issues of GitHub:
31
+
32
+ + Bulk label update with complex search queries
33
+ + Pretty issue printer in many format including Markdown
34
+ + Extract statistic information to the GitHub Wiki
35
+
36
+ ** INSTALL for developers:
37
+ Current code is a very alpha and kind of proof-of-concept demonstration.
38
+ I recommend you not to install via usual gem-style procedure.
39
+
40
+ 1) Install rbenv + ruby-build
41
+ (see https://github.com/sstephenson/rbenv#basic-github-checkout for details)
42
+ #+BEGIN_SRC shell-script
43
+ $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
44
+ $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
45
+ # Edit your shell dot files to add some path and environment variables.
46
+ #+END_SRC
47
+
48
+ 2) Install Latest Ruby and bundler
49
+ #+BEGIN_SRC shell-script
50
+ # Install ruby 2.1.2
51
+ $ rbenv install 2.1.2
52
+
53
+ # Installation check
54
+ $ rbenv global 2.1.2
55
+ $ ruby -v # -> You will see: ruby 2.1.2...
56
+
57
+ # Install bundler for your new Ruby
58
+ $ gem install bundler
59
+
60
+ # Get back to your sytem default Ruby if you want
61
+ $ rbenv global system # say, /usr/bin/ruby
62
+ $ ruby -v
63
+ #+END_SRC
64
+
65
+ 3) Clone octaccord from github
66
+ #+BEGIN_SRC shell-script
67
+ $ git clone git@github.com:nomlab/octaccord.git ~/src/octaccord
68
+ #+END_SRC
69
+
70
+ 4) Set default ruby version in octaccord project
71
+ #+BEGIN_SRC shell-script
72
+ $ cd ~/src/octaccord
73
+ $ echo '2.1.2' > .ruby-version
74
+ $ ruby -v # -> You will see: ruby 2.1.2...
75
+ #+END_SRC
76
+
77
+ 5) Install requied gem packages in sandbox ~/src/octaccord/vendor/bundle
78
+ #+BEGIN_SRC shell-script
79
+ $ cd ~/src/octaccord
80
+ $ bundle install --path vendor/bundle
81
+ #+END_SRC
82
+
83
+ 6) Setup data-cache and auth-cache directory
84
+ #+BEGIN_SRC shell-script
85
+ $ mkdir -p ~/.cache/octaccord
86
+ $ mkdir -p ~/.pit
87
+ #+END_SRC
88
+
89
+ 7) Check if octaccord is alive.
90
+ #+BEGIN_SRC shell-script
91
+ $ ~/src/octaccord/bin/octaccord scan nomlab/octaccord
92
+ #+END_SRC
93
+
94
+ You may add ~/src/octaccord/bin directory to your $PATH for dogfooding.
95
+ If you are zsh user, [[file:examples/octaccord-completion.zsh]] would help you.
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if File.symlink?(__FILE__) and ENV["RBENV_VERSION"]
4
+ ENV["RBENV_VERSION"] = nil
5
+ shims_path = File.expand_path("shims", ENV["RBENV_ROOT"])
6
+ ENV["PATH"] = shims_path + ":" + ENV["PATH"]
7
+ exec(File.readlink(__FILE__), *ARGV)
8
+ end
9
+
10
+ ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
11
+
12
+ require 'rubygems'
13
+ require 'bundler/setup'
14
+ Bundler.require
15
+
16
+ require "time"
17
+ require "shellwords"
18
+ require "pp"
19
+
20
+ Encoding.default_external="UTF-8"
21
+
22
+ require "dbm"
23
+ class FileStore
24
+ CACHE_FILE = "#{ENV["HOME"]}/.cache/octaccord/http_cache"
25
+
26
+ def initialize
27
+ @cache = DBM.open(CACHE_FILE, 0666)
28
+ end
29
+
30
+ def read(key)
31
+ if value = @cache[key]
32
+ STDERR.puts "HIT #{key}" if $OCTACCORD_DEBUG
33
+
34
+ else
35
+ STDERR.puts "MISS #{key}" if $OCTACCORD_DEBUG
36
+ end
37
+ value
38
+ end
39
+
40
+ def write(key, value)
41
+ @cache[key] = value
42
+ end
43
+ end
44
+
45
+ class OctaccordCLI < Thor
46
+ check_unknown_options! :except => :completions
47
+ package_name 'Octaccord'
48
+
49
+ class_option :debug, :type => :boolean, :desc => "Set debug flag"
50
+
51
+ map ["--version", "-v"] => :version
52
+
53
+ default_command :help
54
+ map ["--help", "-h"] => :help
55
+
56
+ desc "version", "Show version"
57
+ def version
58
+ puts Octaccord::VERSION
59
+ end
60
+
61
+ ################################################################
62
+ ## Command: scan
63
+ ################################################################
64
+ desc "scan REPOSITORY [OPTIONS...]", "Scan issues"
65
+
66
+ long_desc <<-LONGDESC
67
+ scan and print issues in various formats
68
+ LONGDESC
69
+
70
+ method_option :format, :desc => "Set printing format", :enum => %w(debug list number pbl table text)
71
+ method_option :type, :desc => "Set issue type", :enum => %w(pr issue)
72
+ method_option :search, :desc => "Set search query"
73
+ method_option :topology, :desc => "Set information file name for topological sort", :banner => "FILE"
74
+
75
+ def scan(repos)
76
+ if options[:topology] == "-"
77
+ orig_text = $stdin.gets(nil)
78
+ elsif options[:topology]
79
+ orig_text = File.open(options[:topology]).gets(nil)
80
+ end
81
+ Octaccord::Command::Scan.new(client, repos, orig_text, **symbolize_keys(options))
82
+ end
83
+
84
+ ################################################################
85
+ ## Command: subscriptions
86
+ ################################################################
87
+ desc "subscriptions", "List your watching repositories"
88
+
89
+ long_desc <<-LONGDESC
90
+ List your watching repositories
91
+ LONGDESC
92
+
93
+ def subscriptions
94
+ client.subscriptions.each do |repos|
95
+ puts repos.full_name
96
+ end
97
+ end
98
+
99
+ ################################################################
100
+ ## Command: update_issues
101
+ ################################################################
102
+ desc "update_issues REPOSITORY [OPTIONS...] NUM...", "Update issues"
103
+
104
+ long_desc <<-LONGDESC
105
+ update issues in specified repository
106
+ LONGDESC
107
+
108
+ method_option "add-label", :desc => "Add a LABEL to issues", :banner => "LABEL"
109
+ method_option "remove-label", :desc => "Remove a LABEL from issues", :banner => "LABEL"
110
+
111
+ def update_issues(repos, *issues)
112
+ Octaccord::Command::UpdateIssues.new(client, repos, issues, **symbolize_keys(options))
113
+ end
114
+
115
+ ################################################################
116
+ ## Command: add_collaborator
117
+ ################################################################
118
+ desc "add_collaborator REPOSITORY [OPTIONS...]", "Add collaborator to a REPOSITORY"
119
+
120
+ long_desc <<-LONGDESC
121
+ add users or team members to collaborator of repository
122
+ LONGDESC
123
+
124
+ method_option :users, :desc => "Add users to collaborator of repository"
125
+ method_option :teams, :desc => "Add team members to collaborator of repository"
126
+
127
+ def add_collaborator(repos)
128
+ Octaccord::Command::AddCollaborator.new(client, repos, **symbolize_keys(options))
129
+ end
130
+
131
+ ################################################################
132
+ ## Command: comments
133
+ ################################################################
134
+ desc "comments REPOSITORY [OPTIONS...]", "List comments created in a period of time"
135
+
136
+ long_desc <<-LONGDESC
137
+ list comments created in a period of time
138
+ LONGDESC
139
+
140
+ method_option :since, :banner => "ISO8601_DATETIME", :desc => "Only comments updated at or after this time"
141
+ method_option :before, :banner => "ISO8601_DATETIME", :desc => "Only comments updated at or before this time"
142
+ def comments(repos)
143
+ since = Time.iso8601(options[:since])
144
+ before = if options[:before] then Time.iso8601(options[:before]) else Time.now end
145
+ Octaccord::Command::Comments.new(client, repos, since, before)
146
+ end
147
+
148
+ ################################################################
149
+ ## Command: completions
150
+ ################################################################
151
+ desc "completions [COMMAND]", "List available commands or options for COMMAND", :hide => true
152
+
153
+ long_desc <<-LONGDESC
154
+ List available commands or options for COMMAND
155
+ This is supposed to be a zsh compsys helper"
156
+ LONGDESC
157
+
158
+ def completions(*command)
159
+ help = self.class.commands
160
+ global_options = self.class.class_options
161
+ Octaccord::Command::Completions.new(help, global_options, command)
162
+ end
163
+
164
+ ################################################################
165
+ ## Command: create_iteration
166
+ ################################################################
167
+ desc "create_iteration REPOSITORY ITERATION_NAME", "Make new iteration record file"
168
+
169
+ long_desc <<-LONGDESC
170
+ Make a new iteration record file from skeleton
171
+ LONGDESC
172
+
173
+ method_option :start, :desc => "start date-time", :banner => "ISO8601_DATETIME"
174
+ method_option :due, :desc => "due date-time", :banner => "ISO8601_DATETIME"
175
+ method_option :manager, :desc => "set manager name", :banner => "USER"
176
+ method_option :team, :desc => "set github organization/team style team name"
177
+ method_option :template, :desc => "set ERB template", :banner => "FILE"
178
+ def create_iteration(repos, iteration_name)
179
+ Octaccord::Command::CreateIteration.new(client, repos, iteration_name, **symbolize_keys(options))
180
+ end
181
+
182
+ ################################################################
183
+ ## Command: filter
184
+ ################################################################
185
+ desc "filter", "Decorate markdown as filter"
186
+
187
+ def filter
188
+ block_finalize = false
189
+ block_inside = false
190
+ block_content = ""
191
+ block_argv = []
192
+
193
+ while line = STDIN.gets # STDIN.noecho(&:gets)
194
+ if /begin:octaccord (.*)-->/ =~ line
195
+ block_inside = true
196
+ block_argv = $1.chomp.shellsplit
197
+ print line
198
+ next
199
+ end
200
+
201
+ if /end:octaccord/ =~ line
202
+ orig_stdout = $stdout
203
+ orig_stdin = $stdin
204
+ $stdout = StringIO.new
205
+ $stdin = StringIO.new(block_content)
206
+ self.class.start(block_argv)
207
+ result = $stdout.string
208
+ $stdout = orig_stdout
209
+ $stdin = orig_stdin
210
+
211
+ print result
212
+ print line
213
+ block_inside = false
214
+ next
215
+ end
216
+
217
+ if block_inside
218
+ block_content << line
219
+ else
220
+ print line.gsub(/(^|[^\[])\#(\d+)/, '\1[#\2](../issues/\2)')
221
+ end
222
+ end
223
+ end
224
+
225
+ ################################################################
226
+ ## Command: get_team_members
227
+ ################################################################
228
+ desc "get_team_members ORGANIZATION/TEAM", "Get team members"
229
+
230
+ long_desc <<-LONGDESC
231
+ Get team members
232
+ LONGDESC
233
+
234
+ def get_team_members(teams)
235
+ Octaccord::Command::GetTeamMembers.new(client, teams, **symbolize_keys(options))
236
+ end
237
+
238
+ ################################################################
239
+ ## Command: info
240
+ ################################################################
241
+ desc "info", "Show github remote info"
242
+
243
+ def info
244
+ Octaccord::Command::Info.new(client, **symbolize_keys(options))
245
+ end
246
+
247
+ ################################################################
248
+ ## Command: show
249
+ ################################################################
250
+ desc "show REPOSITORY NUM", "Show details of issue #NUM"
251
+
252
+ def show(repos, issue)
253
+ Octaccord::Command::Show.new(client, repos, issue, **symbolize_keys(options))
254
+ end
255
+
256
+ ################################################################
257
+ ## patch to insert setup_global_options
258
+ ################################################################
259
+ no_commands do
260
+ def invoke_command(command, *args)
261
+ setup_global_options
262
+ super
263
+ end
264
+ end
265
+
266
+ ################################################################
267
+ ## private
268
+ ################################################################
269
+ private
270
+
271
+ def exit_on_error(&block)
272
+ begin
273
+ yield if block_given?
274
+ rescue Octaccord::ConfigurationError => e
275
+ STDERR.print "ERROR: #{e.message}.\n"
276
+ exit 1
277
+ end
278
+ end
279
+
280
+ attr_reader :client, :config
281
+
282
+ def setup_global_options
283
+ exit_on_error do
284
+ @config ||= Pit.get("github.com", :require => {
285
+ "login" => "Your login name here",
286
+ "password" => "Your password here"
287
+ })
288
+
289
+ $OCTACCORD_DEBUG = true if options[:debug]
290
+ @store ||= FileStore.new
291
+ @stack ||= Faraday::RackBuilder.new do |builder|
292
+ builder.response :logger if options[:debug]
293
+ builder.use Faraday::HttpCache, shared_cache: false, store: @store, serializer: YAML
294
+ builder.use Octokit::Response::RaiseError
295
+ builder.adapter Faraday.default_adapter
296
+ end
297
+
298
+ Octokit.middleware = @stack
299
+ Octokit.auto_paginate = true
300
+ @client ||= Octokit::Client.new(:login => @config["login"],
301
+ :password => @config["password"])
302
+ end
303
+ end
304
+
305
+ def symbolize_keys(hash)
306
+ Hash[hash.map {|k,v| [k.to_s.gsub('-', '_').to_sym, v]}]
307
+ end
308
+
309
+ end # class OctaccordCLI
310
+
311
+ command = OctaccordCLI.start(ARGV)