jira-cli 0.0.3 → 0.0.4

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: 26e38024a72dacde2712cf36890c7343dd878241
4
- data.tar.gz: 1e5ee3a5a3719235da6f4890847c419708af349b
3
+ metadata.gz: 24aaafc8c0cbd9ae1830d16781ccfdae4d57c695
4
+ data.tar.gz: 64d3470c5ae4c3b0bcb5f9adfa403e0d0c4f0cf1
5
5
  SHA512:
6
- metadata.gz: d7fcc3a1fb30afb8d9adfa180d6c36a0529ad9feb9f197a74bd273d244ce30e717bee96adc921583b5ca8faaa877942fea75e08de642c8b388f9bb86c85f9108
7
- data.tar.gz: d2ddb2c5c015c9ba04492d3f7c7f31de6c52b928b1d5218001a3b1ea920ebbc91e4575c1f2aef00056837f85c2ea7e2e6fb41f467f91309102a1da254368fb6f
6
+ metadata.gz: ff546c7868f58330d07439fb52cbf01f9db9a076696f3b7d77b1ebde128ac5ea96f246484eb34e9194e262b75f748aba7ac3b7de6487507386e23cd60218cc8c
7
+ data.tar.gz: 88acd2274a38804e271b0a0f9dbbb00d19ea9e26cf3577cb72fba1f34d0cb3c8539e5030b31896b450a178379459a0fd6cdeb4671c140bfcb0dfaadab2eb0f0e
data/README.md CHANGED
@@ -1,4 +1,18 @@
1
- jira-cli
1
+ JIRA CLI
2
2
  ========
3
3
 
4
4
  Ruby gem CLI tool used to manage JIRA workflows leveraging git
5
+
6
+ Disclaimer
7
+ ----------
8
+ This tool is in very early alpha and its architecture and commands
9
+ are expected to change drastically. Please only use this tool for testing
10
+ purposes.
11
+
12
+ Installation
13
+ ------------
14
+ cd path/to/jira/repo
15
+ jira install
16
+
17
+ Note: Authentication files are expected to drastically change. Currently, they
18
+ are completely unencrypted. Use are your own risk... (see disclaimer above)
@@ -1,6 +1,9 @@
1
1
  require 'thor'
2
2
  require 'fileutils'
3
3
  require 'jira/constants'
4
+ require 'jira/core'
5
+ require 'jira/api'
6
+ require 'jira/format'
4
7
  require 'jira/mixins'
5
8
  require 'jira/version'
6
9
  require 'jira/install'
@@ -9,5 +12,11 @@ require 'jira/lookup'
9
12
  module Jira
10
13
  class CLI < Thor
11
14
 
15
+ def initialize(args=[], options={}, config={})
16
+ super
17
+ Jira::Core.setup
18
+ @api = Jira::API.new
19
+ end
20
+
12
21
  end
13
22
  end
@@ -0,0 +1,51 @@
1
+ module Jira
2
+ class API
3
+
4
+ #
5
+ # Initialize Jira::API
6
+ #
7
+ def initialize
8
+ @client = Faraday.new
9
+ @client.basic_auth(Jira::Core.username, Jira::Core.password)
10
+ end
11
+
12
+ #
13
+ # Issue an API GET request and return parsed JSON
14
+ #
15
+ # @param path [String] API path
16
+ #
17
+ # @return [JSON] parsed API response
18
+ #
19
+ def get(path)
20
+ response = @client.get(self.endpoint(path))
21
+ JSON.parse(response.body)
22
+ end
23
+
24
+ #
25
+ # Issue an API POST request and return parsed JSON
26
+ #
27
+ # @param path [String] API path
28
+ # @param params [Hash] params to post
29
+ #
30
+ # @return [JSON] parsed API response
31
+ #
32
+ def post(path, params)
33
+ response = @client.post(self.endpoint(path), params)
34
+ JSON.parse(response.body)
35
+ end
36
+
37
+ protected
38
+
39
+ #
40
+ # Returns the full JIRA REST API endpoint
41
+ #
42
+ # @param path [String] API path
43
+ #
44
+ # @return [String] API endpoint
45
+ #
46
+ def endpoint(path)
47
+ "#{Jira::Core.url}/rest/api/2/#{path}"
48
+ end
49
+
50
+ end
51
+ end
@@ -1,5 +1,5 @@
1
1
  module Jira
2
2
 
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
 
5
5
  end
@@ -0,0 +1,125 @@
1
+ module Jira
2
+ class Core
3
+ class << self
4
+
5
+ #
6
+ # Memoizes url, username, and password
7
+ #
8
+ def setup
9
+ self.url
10
+ self.auth
11
+ end
12
+
13
+ ### Virtual Attributes
14
+
15
+ #
16
+ # @return [String] JIRA project endpoint
17
+ #
18
+ def url
19
+ @url ||= self.read(self.url_path)
20
+ end
21
+
22
+ #
23
+ # @return [String] JIRA username
24
+ #
25
+ def username
26
+ @username ||= self.auth.first
27
+ end
28
+
29
+ #
30
+ # @return [String] JIRA password
31
+ #
32
+ def password
33
+ @password ||= self.auth.last
34
+ end
35
+
36
+ #
37
+ # Determines whether or not the input ticket matches the expected JIRA
38
+ # ticketing syntax.
39
+ #
40
+ # @param ticket [String] input ticket name
41
+ #
42
+ # @return [Boolean] whether input string matches JIRA ticket syntax
43
+ #
44
+ def ticket?(ticket)
45
+ !!ticket[/^[a-zA-Z]+-[0-9]+$/]
46
+ end
47
+
48
+ ### Relevant Paths
49
+
50
+ #
51
+ # @return [String] path to .jira-url file
52
+ #
53
+ def url_path
54
+ @url_path ||= self.root_path + "/.jira-url"
55
+ end
56
+
57
+ #
58
+ # @return [String] path to .jira-auth file
59
+ #
60
+ def auth_path
61
+ @auth_path ||= self.root_path + "/.jira-auth"
62
+ end
63
+
64
+ #
65
+ # @return [String] path of root git directory
66
+ #
67
+ def root_path
68
+ return @root_path if !@root_path.nil?
69
+ if !system('git rev-parse')
70
+ puts "JIRA commands can only be run within a git repository."
71
+ abort
72
+ end
73
+ @root_path ||= `git rev-parse --show-toplevel`.strip
74
+ end
75
+
76
+ protected
77
+
78
+ #
79
+ # Determines and parses the auth file
80
+ #
81
+ # @return [String] JIRA username
82
+ # @return [String] JIRA password
83
+ #
84
+ def auth
85
+ self.read(self.auth_path).split(':')
86
+ end
87
+
88
+ ### Core Actions
89
+
90
+ #
91
+ # Discards memozied class variables
92
+ #
93
+ def discard_memoized
94
+ @url = nil
95
+ @username = nil
96
+ @password = nil
97
+ end
98
+
99
+ #
100
+ # Validates the location and reads the contents of the input path
101
+ #
102
+ # @param path [String] path of file to read
103
+ #
104
+ # @return [String] contents of the file at the input path
105
+ #
106
+ def read(path)
107
+ self.validate_path!(path)
108
+ File.read(path).strip
109
+ end
110
+
111
+ #
112
+ # Aborts command if no file at the input path exists.
113
+ #
114
+ # @param path [String] path to validate
115
+ #
116
+ def validate_path!(path)
117
+ if !File.exists?(path)
118
+ say "Please run `jira install` before running this command."
119
+ abort
120
+ end
121
+ end
122
+
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,35 @@
1
+ module Jira
2
+ class Format
3
+ class << self
4
+
5
+ def star
6
+ "#{Thor::Shell::Color::BOLD}"\
7
+ "#{Thor::Shell::Color::YELLOW}"\
8
+ "*"\
9
+ "#{Thor::Shell::Color::CLEAR}"
10
+ end
11
+
12
+ def ticket(ticket)
13
+ "#{Thor::Shell::Color::RED}"\
14
+ "#{ticket}"\
15
+ "#{Thor::Shell::Color::CLEAR}"
16
+ end
17
+
18
+ def status(status)
19
+ "["\
20
+ "#{Thor::Shell::Color::BLUE}"\
21
+ "#{status}"\
22
+ "#{Thor::Shell::Color::CLEAR}"\
23
+ "]".center(26)
24
+ end
25
+
26
+ def summary(summary)
27
+ "#{Thor::Shell::Color::BOLD}"\
28
+ "#{Thor::Shell::Color::WHITE}"\
29
+ "#{summary}"\
30
+ "#{Thor::Shell::Color::CLEAR}"
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -7,11 +7,12 @@ module Jira
7
7
 
8
8
  desc "install", "Guides the user through JIRA installation"
9
9
  def install
10
- create_file self.jira_url_path, nil, verbose:false do
10
+
11
+ create_file Jira::Core.url_path, nil, verbose:false do
11
12
  self.cli.ask("Enter your JIRA URL: ")
12
13
  end
13
14
 
14
- create_file self.jira_auth_path, nil, verbose:false do
15
+ create_file Jira::Core.auth_path, nil, verbose:false do
15
16
  username = self.cli.ask("Enter your JIRA username: ")
16
17
  password = self.cli.ask("Enter your JIRA password: ") do |q|
17
18
  q.echo = false
@@ -19,7 +20,7 @@ module Jira
19
20
  "#{username}:#{password}"
20
21
  end
21
22
 
22
- self.discard_memoized
23
+ Jira::Core.send(:discard_memoized)
23
24
  end
24
25
 
25
26
  end
@@ -1,42 +1,52 @@
1
1
  module Jira
2
2
  class CLI < Thor
3
3
 
4
- desc "summarize", "Outputs the summary of the input ticket"
5
- def summarize(ticket=nil)
6
- ticket ||= ex('git rev-parse --abbrev-ref HEAD')
7
- json = self.api_get("issue/#{ticket}")
8
- summary = json['fields']['summary']
9
- status = json['fields']['status']['name']
10
- self.mutex.synchronize do
11
- say "#{self.colored_ticket(ticket)} "\
12
- "#{self.colored_status(status).center(26)} "\
13
- "#{self.colored_summary(summary)}"
14
- end
4
+ desc "describe", "Describes the input ticket"
5
+ def describe(ticket=nil)
6
+ ticket ||= `git rev-parse --abbrev-ref HEAD`.strip
7
+ output_summary(ticket)
15
8
  end
16
9
 
17
- desc "all", "Summarizes all tickets that have local branches"
10
+ desc "all", "Describes all local branches that match JIRA ticketing syntax"
18
11
  def all
19
- tickets = []
20
- branches = ex("git branch").delete("*").split("\n")
12
+ # determine which local branches match JIRA ticket syntax
13
+ # TODO - move to Jira::Git
14
+ tickets = {
15
+ current: nil,
16
+ others: []
17
+ }
18
+ branches = `git branch`.strip.split("\n")
21
19
  branches.each do |branch|
22
- stripped = branch.strip
23
- if !!stripped[/^[a-zA-Z]+-[0-9]+$/]
24
- tickets << stripped
20
+ ticket = branch.delete('*').strip
21
+ if Jira::Core.ticket?(ticket)
22
+ if branch.include?('*')
23
+ tickets[:current] = ticket
24
+ else
25
+ tickets[:others] << ticket
26
+ end
25
27
  end
26
28
  end
27
29
 
30
+
31
+ # asynchronously fetch and describe tickets
32
+ output = ""
28
33
  threads = []
29
- tickets.each do |ticket|
30
- threads << Thread.new{ self.summarize(ticket) }
34
+ threads << Thread.new{ puts description(tickets[:current], true) }
35
+ mutex = Mutex.new
36
+ tickets[:others].each do |ticket|
37
+ threads << Thread.new do
38
+ out = description(ticket) + "\n"
39
+ mutex.synchronize{ output << out }
40
+ end
31
41
  end
32
42
  threads.each{ |thread| thread.join }
43
+
44
+ puts output
33
45
  end
34
46
 
35
47
  desc "comment", "Add a comment to the input ticket"
36
48
  def comment(ticket=nil)
37
49
  say "Coming soon"
38
- #ticket ||= ex('get rev-parse --abbrev-ref HEAD')
39
- #json = self.api_post("issue/#{ticket}")
40
50
  end
41
51
 
42
52
  desc "transition", "Transitions the input ticket to the next state"
@@ -46,55 +56,22 @@ module Jira
46
56
 
47
57
  protected
48
58
 
49
- def colored_ticket(ticket)
50
- "("\
51
- "#{Thor::Shell::Color::RED}"\
52
- "#{ticket}"\
53
- "#{Thor::Shell::Color::CLEAR}"\
54
- ")"
55
- end
56
-
57
- def colored_status(status)
58
- "["\
59
- "#{Thor::Shell::Color::BLUE}"\
60
- "#{status}"\
61
- "#{Thor::Shell::Color::CLEAR}"\
62
- "]"
63
- end
64
-
65
- def colored_summary(summary)
66
- "#{Thor::Shell::Color::BOLD}"\
67
- "#{Thor::Shell::Color::WHITE}"\
68
- "#{summary}"\
69
- "#{Thor::Shell::Color::CLEAR}"
70
- end
71
-
72
- def api_get(path)
73
- response = self.client.get self.api_path(path)
74
- return JSON.parse(response.body)
75
- end
76
-
77
- def api_post(path, params)
78
- response = self.client.post self.api_path(path), params
79
- return JSON.parse(response)
80
- end
81
-
82
- def api_path(path)
83
- "#{self.jira_url}/rest/api/2/#{path}"
84
- end
85
-
86
- def mutex
87
- @mutex ||= Mutex.new
88
- end
89
-
90
- def client
91
- self.mutex.synchronize do
92
- return @client if !@client.nil?
93
- @client = Faraday.new
94
- username, password = self.jira_auth
95
- @client.basic_auth(username, password)
96
- return @client
97
- end
59
+ #
60
+ # Returns a formatted description of the input ticket
61
+ #
62
+ # @param ticket [String] the ticket to describe
63
+ # @param star [Boolean] if true, adds a * indicator
64
+ #
65
+ # @return [String] formatted summary string
66
+ #
67
+ def description(ticket, star=false)
68
+ json = @api.get("issue/#{ticket}")
69
+ summary = json['fields']['summary']
70
+ status = json['fields']['status']['name']
71
+ return Jira::Format.ticket(ticket) +
72
+ (star ? Jira::Format.star : " ") +
73
+ Jira::Format.status(status) +
74
+ Jira::Format.summary(summary)
98
75
  end
99
76
 
100
77
  end
@@ -5,57 +5,9 @@ module Jira
5
5
  require 'json'
6
6
  require 'faraday'
7
7
  include Thor::Actions
8
- include Thor::Shell
9
8
 
10
9
  protected
11
10
 
12
- #
13
- # @return [String] JIRA endpoint
14
- #
15
- def jira_url
16
- return @jira_url if !@jira_url.nil?
17
- path = self.jira_url_path
18
- self.validate_path!(path)
19
- @jira_url ||= File.read(path).strip
20
- end
21
-
22
- #
23
- # @return [String] JIRA authorization
24
- #
25
- # @return [String] username
26
- # @return [String] password
27
- #
28
- def jira_auth
29
- if !@username.nil? && !@password.nil?
30
- return @username, @password
31
- end
32
- path = self.jira_auth_path
33
- self.validate_path!(path)
34
- @username, @password = File.read(path).strip.split(':')
35
- return @username, @password
36
- end
37
-
38
- #
39
- # @return [String] path to .jira-url file
40
- #
41
- def jira_url_path
42
- @url_path ||= self.root_path + "/.jira-url"
43
- end
44
-
45
- #
46
- # @return [String] path to .jira-auth file
47
- #
48
- def jira_auth_path
49
- @auth_path ||= self.root_path + "/.jira-auth"
50
- end
51
-
52
- #
53
- # @return [String] path to root git directory
54
- #
55
- def root_path
56
- @root_path ||= ex "git rev-parse --show-toplevel"
57
- end
58
-
59
11
  #
60
12
  # @return [Highline] HighLine instance for handling input
61
13
  #
@@ -63,28 +15,5 @@ module Jira
63
15
  @highline ||= ::HighLine.new
64
16
  end
65
17
 
66
- #
67
- # Execute shell command
68
- #
69
- # @param command [String] command to run
70
- # @return [String] output of the run command
71
- #
72
- def ex(command)
73
- run(command, verbose:false, capture:true).strip
74
- end
75
-
76
- def validate_path!(path)
77
- if !File.exists?(path)
78
- say "Please run `jira install` before running this action..."
79
- abort
80
- end
81
- end
82
-
83
- def discard_memoized
84
- @username = nil
85
- @password = nil
86
- @jira_url = nil
87
- end
88
-
89
18
  end
90
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jira-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darren Lin Cheng
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-05 00:00:00.000000000 Z
11
+ date: 2013-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -60,7 +60,10 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - bin/jira
63
+ - lib/jira/api.rb
63
64
  - lib/jira/constants.rb
65
+ - lib/jira/core.rb
66
+ - lib/jira/format.rb
64
67
  - lib/jira/install.rb
65
68
  - lib/jira/lookup.rb
66
69
  - lib/jira/mixins.rb