jura 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +2 -0
  4. data/bin/jura +14 -0
  5. data/lib/jura.rb +10 -0
  6. data/lib/jura/api.rb +6 -0
  7. data/lib/jura/api/board.rb +25 -0
  8. data/lib/jura/api/client.rb +22 -0
  9. data/lib/jura/api/issue.rb +42 -0
  10. data/lib/jura/api/sprint.rb +44 -0
  11. data/lib/jura/api/token.rb +33 -0
  12. data/lib/jura/application.rb +74 -0
  13. data/lib/jura/command.rb +50 -0
  14. data/lib/jura/command/board.rb +23 -0
  15. data/lib/jura/command/board/select.rb +25 -0
  16. data/lib/jura/command/exit.rb +12 -0
  17. data/lib/jura/command/help.rb +11 -0
  18. data/lib/jura/command/invalid.rb +11 -0
  19. data/lib/jura/command/issue.rb +28 -0
  20. data/lib/jura/command/issue/base.rb +18 -0
  21. data/lib/jura/command/issue/list.rb +14 -0
  22. data/lib/jura/command/issue/mine.rb +14 -0
  23. data/lib/jura/command/issue/select.rb +22 -0
  24. data/lib/jura/command/issue/show.rb +18 -0
  25. data/lib/jura/command/sprint.rb +22 -0
  26. data/lib/jura/command/sprint/base.rb +18 -0
  27. data/lib/jura/command/sprint/list.rb +14 -0
  28. data/lib/jura/command/sprint/show.rb +22 -0
  29. data/lib/jura/component.rb +5 -0
  30. data/lib/jura/component/board.rb +21 -0
  31. data/lib/jura/component/board/help.rb +17 -0
  32. data/lib/jura/component/help.rb +24 -0
  33. data/lib/jura/component/issue.rb +43 -0
  34. data/lib/jura/component/issue/help.rb +18 -0
  35. data/lib/jura/component/issue/show.rb +30 -0
  36. data/lib/jura/component/logo.rb +22 -0
  37. data/lib/jura/component/sprint.rb +22 -0
  38. data/lib/jura/component/sprint/help.rb +17 -0
  39. data/lib/jura/component/sprint/show.rb +44 -0
  40. data/lib/jura/configuration.rb +36 -0
  41. data/lib/jura/utils.rb +32 -0
  42. data/lib/jura/version.rb +3 -0
  43. metadata +111 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: efabee656c658d42bf38e4a326b957167aecbbdb9c53bab0b0f972eef96781aa
4
+ data.tar.gz: d948e08cb3bc8670a89b4624ed5a6df812f170bbcd9d9e56984b87fff21d40db
5
+ SHA512:
6
+ metadata.gz: 57b2775f58a8f26a06a26a856c4181671f1bb43cbe903ac4e77602335bdce99517d5d6efe5e38b84f2a6f1f3e18a93deca923064509cf7a7dd4a4dd0b07ef4e6
7
+ data.tar.gz: 786a49e54f760545f478e776c569e93aa7c17df8b7d49cf4bd598a9bb70391c16b4b3fffc518835242fd2097891e66b98785ff2decd716ea98590607607ad406
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Hoa Nguyen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # jura
2
+ A simple Jira CLI app by Ruby
data/bin/jura ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
+ require 'httparty'
5
+ require 'jura'
6
+ require 'tty-prompt'
7
+ require 'tty-table'
8
+ require 'tty-box'
9
+ require 'tty-markdown'
10
+ require 'tty-screen'
11
+ require 'pastel'
12
+ require 'optparse'
13
+
14
+ Jura::Application.start(ARGV)
data/lib/jura.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "readline"
2
+ require "json"
3
+
4
+ require "jura/version"
5
+ require "jura/utils"
6
+ require "jura/configuration"
7
+ require "jura/api"
8
+ require "jura/component"
9
+ require "jura/command"
10
+ require "jura/application"
data/lib/jura/api.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ require 'jura/api/client'
3
+ require 'jura/api/board'
4
+ require 'jura/api/issue'
5
+ require 'jura/api/sprint'
6
+ require 'jura/api/token'
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Api
5
+ module Board
6
+ extend self
7
+
8
+ def all
9
+ parse_body(
10
+ Client.get('/board', {
11
+ headers: {
12
+ "Authorization" => "Basic #{Token.get_token}"
13
+ }
14
+ }).body
15
+ )['values']
16
+ end
17
+
18
+ private
19
+
20
+ def parse_body(body)
21
+ JSON.parse(body)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require 'base64'
3
+ require 'singleton'
4
+ require 'httparty'
5
+
6
+ module Jura
7
+ module Api
8
+ class Client
9
+ include Singleton
10
+ include HTTParty
11
+
12
+ base_uri 'https://employmenthero.atlassian.net/rest/agile/1.0'
13
+
14
+ headers ({
15
+ "Accept" => "application/json",
16
+ "Content-Type" => "application/json",
17
+ })
18
+
19
+ raise_on [401, 404, 500]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Api
5
+ module Issue
6
+ extend self
7
+
8
+ def all(board_id, query = nil)
9
+ options = {
10
+ headers: {
11
+ "Authorization" => "Basic #{Token.get_token}"
12
+ }
13
+ }
14
+
15
+ url = "/board/#{board_id}/issue?"
16
+ url = "#{url}jql=#{query}" unless query.nil?
17
+
18
+ parse_body(
19
+ Client.get(url, options).body
20
+ )['issues']
21
+ end
22
+
23
+ def show(issue_id)
24
+ options = {
25
+ headers: {
26
+ "Authorization" => "Basic #{Token.get_token}"
27
+ }
28
+ }
29
+
30
+ url = "/issue/#{issue_id}"
31
+
32
+ parse_body(Client.get(url, options).body)
33
+ end
34
+
35
+ private
36
+
37
+ def parse_body(body)
38
+ JSON.parse(body)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Api
5
+ module Sprint
6
+ extend self
7
+
8
+ def all(board_id, state = nil)
9
+ options = {
10
+ headers: {
11
+ "Authorization" => "Basic #{Token.get_token}"
12
+ }
13
+ }
14
+
15
+ url = "/board/#{board_id}/sprint?"
16
+ url = "#{url}state=#{state}" unless state.nil?
17
+
18
+ parse_body(
19
+ Client.get(url, options).body
20
+ )['values']
21
+ end
22
+
23
+ def show(board_id, sprint_id)
24
+ options = {
25
+ headers: {
26
+ "Authorization" => "Basic #{Token.get_token}"
27
+ }
28
+ }
29
+
30
+ url = "/board/#{board_id}/sprint/#{sprint_id}/issue"
31
+
32
+ parse_body(
33
+ Client.get(url, options).body
34
+ )['issues']
35
+ end
36
+
37
+ private
38
+
39
+ def parse_body(body)
40
+ JSON.parse(body)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Api
5
+ module Token
6
+ extend self
7
+
8
+ def verify?(email, token)
9
+ values = parse_body(
10
+ Client.get('/board?total=1', {
11
+ headers: {
12
+ "Authorization" => "Basic #{Base64.urlsafe_encode64("#{email}:#{token}")}"
13
+ }
14
+ }).body
15
+ )['values']
16
+
17
+ !values.nil?
18
+ rescue HTTParty::ResponseError => e
19
+ false
20
+ end
21
+
22
+ def get_token
23
+ Jura::Configuration.instance.config_obj['token']
24
+ end
25
+
26
+ private
27
+
28
+ def parse_body(body)
29
+ JSON.parse(body)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Application
5
+ extend self
6
+
7
+ def start(args)
8
+ Readline.completion_append_character = " "
9
+
10
+ Readline.completion_proc = lambda { |buffer|
11
+ Command.generate_suggestions(buffer, Readline.line_buffer)
12
+ }
13
+
14
+ prompt = TTY::Prompt.new
15
+
16
+ prompt.say(Jura::Component::Logo.render)
17
+ prompt.say(Jura::Component::Help.render)
18
+
19
+ config = Jura::Configuration.instance.load_config
20
+
21
+ if config.empty?
22
+ config = config_credentials(prompt)
23
+ else
24
+ prompt.say("Welcome back!, " + Utils.paint(config['email'], :green) + "\n\n")
25
+ prompt.say("Your selected board is " + Utils.paint(config['selected_board_name'], :green) + "\n\n") unless config['selected_board_id'].nil?
26
+ end
27
+
28
+ Jura::Configuration.instance.set_config(config)
29
+
30
+ loop do
31
+ command_buffer = Readline.readline("\e[15;48;5;27m Jura Guarrr! \e[0m > ", true)
32
+
33
+ Jura::Command.execute!(command_buffer.strip())
34
+ rescue IndexError, NoMethodError => _e
35
+ Command::Invalid.execute("Something went wrong, please try with another command")
36
+ end
37
+ rescue Interrupt
38
+ Command::Exit.execute
39
+ end
40
+
41
+ def config_credentials(prompt)
42
+ email = prompt.ask("Jira account email: ") { |q| q.validate :email }
43
+
44
+ has_token = prompt.yes?("Already have your JIRA token?")
45
+
46
+ unless has_token
47
+ prompt.say("\nOpening Your default browser")
48
+ prompt.warn("> Warning: If browser does not open, visit")
49
+ prompt.warn("> https://id.atlassian.com/manage-profile/security/api-tokens to obtain your token\n")
50
+
51
+ system "open https://id.atlassian.com/manage-profile/security/api-tokens"
52
+ end
53
+
54
+ token = prompt.mask("Input your Jira token: ") do|q|
55
+ q.required true
56
+ end
57
+
58
+ config = {}
59
+
60
+ if Jura::Api::Token.verify?(email, token)
61
+ prompt.say("Logged in as #{email}\n", color: :green)
62
+ prompt.say("Configuration has been saved to " + Utils.paint(Configuration::CONFIG_FILE_PATH, :green) + "\n")
63
+
64
+ config = { 'email' => email, 'token' => Base64.urlsafe_encode64("#{email}:#{token}") }
65
+
66
+ Jura::Configuration.instance.save_config(config)
67
+ else
68
+ prompt.say("Your token or email is invalid", color: :red)
69
+ end
70
+
71
+ config
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ require 'jura/command/board'
3
+ require 'jura/command/issue'
4
+ require 'jura/command/sprint'
5
+ require 'jura/command/help'
6
+ require 'jura/command/exit'
7
+ require 'jura/command/invalid'
8
+
9
+ module Jura
10
+ module Command
11
+ COMMANDS = {
12
+ "board" => -> (sub_cmd, args) { Command::Board.execute!(sub_cmd, args) },
13
+ "issue" => -> (sub_cmd, args) { Command::Issue.execute!(sub_cmd, args) },
14
+ "sprint" => -> (sub_cmd, args) { Command::Sprint.execute!(sub_cmd, args) },
15
+ "help" => -> (*_args) { Command::Help.execute() },
16
+ "exit" => -> (*_args) { Command::Exit.execute() }
17
+ }
18
+
19
+ def self.execute!(cmd_buffer)
20
+ cmd_name, sub_cmd, *args = cmd_buffer.to_s.strip.split(" ")
21
+
22
+ if cmd_name.nil? || cmd_name.empty?
23
+ # TODO: return and execute empty command error
24
+ end
25
+
26
+ command = COMMANDS[cmd_name]
27
+
28
+ if command.nil?
29
+ return Command::Invalid.execute("Command not found: #{command.inspect}. Run #{"help".inspect} for more informations")
30
+ end
31
+
32
+ puts '' # Empty line
33
+ command.call(sub_cmd, args)
34
+ puts '' # Empty line
35
+ rescue Command::Board::RequiredBoardIdError => _
36
+ puts 'Please select a board first!'
37
+ Command::Board.execute!('select', [])
38
+ end
39
+
40
+ def generate_suggestions(buffer, command_buffer)
41
+ commands = {
42
+ "board" => %[list select],
43
+ "issue" => %[list],
44
+ "sprint" => %[list show]
45
+ }
46
+
47
+ commands.keys.grep(/^#{Regexp.escape(buffer)}/)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jura/command/board/select'
4
+
5
+ module Jura
6
+ module Command
7
+ module Board
8
+ class RequiredBoardIdError < StandardError; end
9
+
10
+ def self.execute!(sub_cmd, args)
11
+ case sub_cmd
12
+ when "list"
13
+ boards = Api::Board.all
14
+ puts Component::Board.render(boards)
15
+ when "select"
16
+ Command::Board::Select.execute
17
+ else
18
+ Command::Invalid.execute("Command not found: #{sub_cmd.inspect}. Run #{"help".inspect} for more informations")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Board
6
+ class Select
7
+ def self.execute
8
+ prompt = TTY::Prompt.new
9
+ boards = Api::Board.all
10
+ board = prompt.select("Choose your board?", filter: true, per_page: 10) do |menu|
11
+ boards.each do |b|
12
+ menu.choice b['location']['displayName'], b
13
+ end
14
+ end
15
+
16
+ config = Jura::Configuration.instance.load_config
17
+ config['selected_board_id'] = board['id']
18
+ config['selected_board_name'] = board['location']['displayName']
19
+
20
+ Jura::Configuration.instance.save_config(config)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ class Exit
6
+ def self.execute
7
+ puts "Guar :("
8
+ exit
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ class Help
6
+ def self.execute
7
+ puts Component::Help.render
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ class Invalid
6
+ def self.execute(message)
7
+ puts message
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jura/command/issue/base'
4
+ require 'jura/command/issue/list'
5
+ require 'jura/command/issue/show'
6
+ require 'jura/command/issue/mine'
7
+ require 'jura/command/issue/select'
8
+
9
+ module Jura
10
+ module Command
11
+ module Issue
12
+ def self.execute!(sub_cmd, args)
13
+ case sub_cmd
14
+ when "mine"
15
+ Command::Issue::Mine.execute!
16
+ when "select"
17
+ Command::Issue::Select.execute!
18
+ when "list"
19
+ Command::Issue::List.execute!
20
+ when "show"
21
+ Command::Issue::Show.execute!(args)
22
+ else
23
+ Command::Invalid.execute("Command not found: #{sub_cmd.inspect}. Run #{"help".inspect} for more informations")
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Issue
6
+ class Base
7
+ def self.board_id
8
+ config = Jura::Configuration.instance.load_config
9
+ board_id = config['selected_board_id']
10
+
11
+ raise Command::Board::RequiredBoardIdError if board_id.nil?
12
+
13
+ board_id
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Issue
6
+ class List < Base
7
+ def self.execute!
8
+ issues = Api::Issue.all(board_id)
9
+ puts Component::Issue.render(issues)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Issue
6
+ class Mine < Base
7
+ def self.execute!
8
+ issues = Api::Issue.all(board_id, "assignee = currentUser()")
9
+ puts Component::Issue.render(issues)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Issue
6
+ class Select < Base
7
+ def self.execute!
8
+ prompt = TTY::Prompt.new
9
+ issues = Api::Issue.all(board_id, "assignee = currentUser()")
10
+ issue = prompt.select("Choose issue", filter: true, per_page: 10) do |menu|
11
+ issues.each do |b|
12
+ menu.choice "#{b['key']} - #{b['fields']['summary']}", b
13
+ end
14
+ end
15
+
16
+ issue = Api::Issue.show(issue['key'])
17
+ puts Component::Issue::Show.render(issue)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Issue
6
+ class Show < Base
7
+ def self.execute!(args)
8
+ if (args.length != 1)
9
+ return
10
+ end
11
+
12
+ issue = Api::Issue.show(args[0])
13
+ puts Component::Issue::Show.render(issue)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jura/command/sprint/base'
4
+ require 'jura/command/sprint/list'
5
+ require 'jura/command/sprint/show'
6
+
7
+ module Jura
8
+ module Command
9
+ module Sprint
10
+ def self.execute!(sub_cmd, args)
11
+ case sub_cmd
12
+ when "show"
13
+ Command::Sprint::Show.execute!(args)
14
+ when "list"
15
+ Command::Sprint::List.execute!
16
+ else
17
+ Command::Invalid.execute("Command not found: #{command.inspect}. Run #{"help".inspect} for more informations")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Sprint
6
+ class Base
7
+ def self.board_id
8
+ config = Jura::Configuration.instance.load_config
9
+ board_id = config['selected_board_id']
10
+
11
+ raise Command::Board::RequiredBoardIdError if board_id.nil?
12
+
13
+ board_id
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Sprint
6
+ class List < Base
7
+ def self.execute!
8
+ sprints = Api::Sprint.all(board_id)
9
+ puts Component::Sprint.render(sprints)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Command
5
+ module Sprint
6
+ class Show < Base
7
+ def self.execute!(args)
8
+ if args.length != 1
9
+ return
10
+ end
11
+
12
+ sprint_id = args[0]
13
+
14
+ issues = Api::Sprint.show(board_id, sprint_id)
15
+ puts Component::Sprint::Show.render(issues)
16
+ rescue HTTParty::ResponseError => _e
17
+ Command::Invalid.execute("Something went wrong, please try with another command")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ require "jura/component/help"
2
+ require "jura/component/board"
3
+ require "jura/component/issue"
4
+ require "jura/component/sprint"
5
+ require "jura/component/logo"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jura/component/board/help"
4
+
5
+ module Jura
6
+ module Component
7
+ module Board
8
+ def self.render(boards)
9
+ <<~TEMPLATE
10
+ #{boards.map { |board| render_board(board) }.join("\n")}
11
+ TEMPLATE
12
+ end
13
+
14
+ private
15
+
16
+ def self.render_board(board)
17
+ "#{board['id']} - #{board['location']['displayName']}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ module Board
6
+ class Help
7
+ def self.render
8
+ <<~TEMPLATE.strip
9
+ #{Utils.format_bold("# Available board commands:")}
10
+ board list - Show list of boards
11
+ board select - Select board
12
+ TEMPLATE
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ class Help
6
+ def self.render
7
+ <<~TEMPLATE
8
+
9
+ #{Component::Board::Help.render()}
10
+
11
+ #{Component::Issue::Help.render()}
12
+
13
+ #{Component::Sprint::Help.render()}
14
+
15
+ #{Utils.format_bold('# Miscellaneous commands:')}
16
+
17
+ help - Display this help message
18
+ exit - Escape from Jurassic park
19
+
20
+ TEMPLATE
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jura/component/issue/help"
4
+ require "jura/component/issue/show"
5
+
6
+ module Jura
7
+ module Component
8
+ module Issue
9
+ def self.render(issues)
10
+ <<~TEMPLATE
11
+ #{issues.map { |i| render_issue(i) }.join("\n")}
12
+ TEMPLATE
13
+ end
14
+
15
+ private
16
+
17
+ def self.render_issue(issue)
18
+ "#{convert_key(issue)} - #{paint(issue)} - #{issue['fields']['summary']}"
19
+ end
20
+
21
+ def self.paint(issue)
22
+ status = issue.dig('fields','status', 'name')
23
+ p = Pastel.new
24
+
25
+ case status.downcase
26
+ when 'in progress'
27
+ p.decorate(status,:blue)
28
+ when 'in review'
29
+ p.decorate(status,:magenta)
30
+ when 'done'
31
+ p.decorate(status,:green)
32
+ else
33
+ p.decorate(status,:white)
34
+ end
35
+ end
36
+
37
+ def self.convert_key(issue)
38
+ kws = issue['key'].split('-')
39
+ "#{kws[0]}-#{(kws[1].rjust(3, ' '))}"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ module Issue
6
+ class Help
7
+ def self.render
8
+ <<~TEMPLATE.strip
9
+ #{Utils.format_bold("# Available issue commands:")}
10
+ issue list - Show list of issues in backlog
11
+ issue mine - Show list of issues which have assingee is mine
12
+ issue show <issue_id> - Show details of an issue
13
+ TEMPLATE
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ module Issue
6
+ class Show
7
+ def self.render(issue)
8
+ issue_id = issue['key']
9
+ project = issue['fields']['project']['name']
10
+ box = TTY::Box.frame(
11
+ border: :thick,
12
+ padding: [1,2],
13
+ title: {top_left: issue_id, bottom_right: project},
14
+ width: TTY::Screen.width
15
+ ) do
16
+ <<~TEMPLATE
17
+ #{Jura::Utils.format_bold(issue['fields']['summary'])}
18
+
19
+ #{Jura::Utils.format_bold('URL')}: #{issue['self']}
20
+
21
+ #{Jura::Utils.format_bold('Description')}
22
+
23
+ #{TTY::Markdown.parse(issue['fields']['description'])}
24
+ TEMPLATE
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ class Logo
6
+ def self.render
7
+ <<~TEMPLATE
8
+
9
+ ██╗██╗ ██╗██████╗ █████╗ ██╗██╗██████╗ █████╗ ██████╗ ██╗ ██╗██████╗ ██╗ ██╗
10
+ ██║██║ ██║██╔══██╗██╔══██╗ ██║██║██╔══██╗██╔══██╗ ██╔══██╗██║ ██║██╔══██╗╚██╗ ██╔╝
11
+ ██║██║ ██║██████╔╝███████║ █████╗ ██║██║██████╔╝███████║ ██████╔╝██║ ██║██████╔╝ ╚████╔╝
12
+ ██ ██║██║ ██║██╔══██╗██╔══██║ ╚════╝ ██ ██║██║██╔══██╗██╔══██║ ██╔══██╗██║ ██║██╔══██╗ ╚██╔╝
13
+ ╚█████╔╝╚██████╔╝██║ ██║██║ ██║ ╚█████╔╝██║██║ ██║██║ ██║ ██║ ██║╚██████╔╝██████╔╝ ██║
14
+ ╚════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚════╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝
15
+
16
+ #{Utils.format_bold(Utils.paint("Jura v#{Jura::VERSION} - Interactive CLI application for Jira", :blue))}
17
+
18
+ TEMPLATE
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jura/component/sprint/help"
4
+ require "jura/component/sprint/show"
5
+
6
+ module Jura
7
+ module Component
8
+ module Sprint
9
+ def self.render(sprints)
10
+ <<~TEMPLATE
11
+ #{sprints.map { |s| render_sprint(s) }.join("\n")}
12
+ TEMPLATE
13
+ end
14
+
15
+ private
16
+
17
+ def self.render_sprint(sprint)
18
+ "#{sprint['id']} - #{sprint['name']} - #{sprint['state']}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ module Sprint
6
+ class Help
7
+ def self.render
8
+ <<~TEMPLATE.strip
9
+ #{Utils.format_bold("# Available sprint commands:")}
10
+ sprint list - Show list of sprints
11
+ sprint show <sprint_id> - Show list of issues of 1 sprint
12
+ TEMPLATE
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ module Component
5
+ module Sprint
6
+ class Show
7
+ def self.render(issues)
8
+ table = TTY::Table.new(
9
+ header: [
10
+ "TO DO",
11
+ Jura::Utils.paint("IN PROGRESS", :blue),
12
+ Jura::Utils.paint("IN REVIEW", :purple),
13
+ Jura::Utils.paint("DONE", :green)
14
+ ]
15
+ )
16
+ convertIssues(table, issues)
17
+ table.render :unicode, resize: true, column_widths: [25, 25, 25, 25] do |renderer|
18
+ renderer.border.separator = :each_row
19
+ end
20
+ end
21
+
22
+ def self.convertIssues(table, issues)
23
+ issues.each do |issue|
24
+ state = issue['fields']['status']['name']
25
+ case state.downcase
26
+ when 'to do'
27
+ table << [render_issue(issue), '', '', '']
28
+ when 'in progress'
29
+ table << ['', render_issue(issue), '', '']
30
+ when 'in review'
31
+ table << ['', '', render_issue(issue), '']
32
+ when 'done'
33
+ table << ['', '', '', render_issue(issue)]
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.render_issue(issue)
39
+ "#{issue['key']} - #{issue['fields']['summary']}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ require 'singleton'
3
+
4
+ module Jura
5
+ class Configuration
6
+ include Singleton
7
+
8
+ CONFIG_FILE_PATH = "~/.jura.config.json"
9
+
10
+ def set_config(data)
11
+ @config_obj = data
12
+ end
13
+
14
+ def freeze_config
15
+ config_obj.freeze
16
+ end
17
+
18
+ def config_obj
19
+ @config_obj ||= {}
20
+ end
21
+
22
+ def load_config
23
+ config_path = File.expand_path(CONFIG_FILE_PATH)
24
+
25
+ if File.exist?(config_path)
26
+ JSON.parse(File.read(config_path))
27
+ else
28
+ {}
29
+ end
30
+ end
31
+
32
+ def save_config(config)
33
+ File.write(File.expand_path(CONFIG_FILE_PATH), config.to_json)
34
+ end
35
+ end
36
+ end
data/lib/jura/utils.rb ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jura
4
+ class Utils
5
+ class << self
6
+ COLOR = {
7
+ :red => 31,
8
+ :pink => 31,
9
+ :blue => 34,
10
+ :green => 32,
11
+ :lime => 32,
12
+ :black => 37,
13
+ :white => 37,
14
+ :purple => 35,
15
+ :yellow => 33,
16
+ :orange => 33,
17
+ :cyan => 36,
18
+ :sky => 36
19
+ }
20
+
21
+ def paint(string, color)
22
+ code = COLOR.fetch(color)
23
+
24
+ "\e[#{code}m#{string}\e[0m"
25
+ end
26
+
27
+ def format_bold(string)
28
+ "\e[1m#{string}\e[0m"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module Jura
2
+ VERSION = "0.0.1".freeze
3
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jura
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Hoa Nguyen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-09-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tty-prompt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.22'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.22'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.18.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.18.1
41
+ description: A simple Jira CLI by Ruby
42
+ email: nvh0412@gmail.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - LICENSE
48
+ - README.md
49
+ - bin/jura
50
+ - lib/jura.rb
51
+ - lib/jura/api.rb
52
+ - lib/jura/api/board.rb
53
+ - lib/jura/api/client.rb
54
+ - lib/jura/api/issue.rb
55
+ - lib/jura/api/sprint.rb
56
+ - lib/jura/api/token.rb
57
+ - lib/jura/application.rb
58
+ - lib/jura/command.rb
59
+ - lib/jura/command/board.rb
60
+ - lib/jura/command/board/select.rb
61
+ - lib/jura/command/exit.rb
62
+ - lib/jura/command/help.rb
63
+ - lib/jura/command/invalid.rb
64
+ - lib/jura/command/issue.rb
65
+ - lib/jura/command/issue/base.rb
66
+ - lib/jura/command/issue/list.rb
67
+ - lib/jura/command/issue/mine.rb
68
+ - lib/jura/command/issue/select.rb
69
+ - lib/jura/command/issue/show.rb
70
+ - lib/jura/command/sprint.rb
71
+ - lib/jura/command/sprint/base.rb
72
+ - lib/jura/command/sprint/list.rb
73
+ - lib/jura/command/sprint/show.rb
74
+ - lib/jura/component.rb
75
+ - lib/jura/component/board.rb
76
+ - lib/jura/component/board/help.rb
77
+ - lib/jura/component/help.rb
78
+ - lib/jura/component/issue.rb
79
+ - lib/jura/component/issue/help.rb
80
+ - lib/jura/component/issue/show.rb
81
+ - lib/jura/component/logo.rb
82
+ - lib/jura/component/sprint.rb
83
+ - lib/jura/component/sprint/help.rb
84
+ - lib/jura/component/sprint/show.rb
85
+ - lib/jura/configuration.rb
86
+ - lib/jura/utils.rb
87
+ - lib/jura/version.rb
88
+ homepage: https://rubygems.org/gems/jura
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '2.5'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.1.2
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Jura Guarrr!
111
+ test_files: []