ki_youtrack 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  spec/fixtures
19
+ spec/configs
data/bin/ki_youtrack CHANGED
@@ -33,25 +33,36 @@ command :issue do |c|
33
33
  pretty = $stdout.tty?
34
34
 
35
35
  id = args.first
36
- json = KiYoutrack::Api.issue(id, :pretty => pretty)
37
- $stdout.puts(json)
36
+
37
+ begin
38
+ api = KiYoutrack::Api.new
39
+ json = api.issue(id, :pretty => pretty)
40
+ $stdout.puts(json)
41
+ rescue Kiseru::ConfigError => e
42
+ $stderr.puts e.message
43
+ $stderr.puts "Run 'ki_youtrack init' or edit #{api.config.path}"
44
+ exit 1
45
+ rescue KiYoutrack::SessionError => e
46
+ $stderr.puts e.message
47
+ exit 1
48
+ end
38
49
  end
39
50
  end
40
51
 
41
- desc 'Set up config file'
42
- command :setup do |c|
43
- c.action do |global_options, options, args|
44
- config = Kiseru::Config[:ki_youtrack]
45
-
46
- ui = HighLine.new
47
-
48
- username = config.read(:username) || ui.ask("Username: ")
49
- password = config.read(:password) || ui.ask("Password: ") { |q| q.echo = false }
50
- subdomain = config.read(:subdomain) || ui.ask("Subdomain: ")
52
+ on_error do |error|
53
+ case error
54
+ when SystemExit
55
+ exit error.status
56
+ false
57
+ else
58
+ true
59
+ end
60
+ end
51
61
 
52
- config.write(:username, username)
53
- config.write(:password, password)
54
- config.write(:subdomain, subdomain)
62
+ desc 'Initialize config file'
63
+ command :init do |c|
64
+ c.action do |global_options, options, args|
65
+ KiYoutrack::Initializer.init
55
66
  end
56
67
  end
57
68
 
data/ki_youtrack.gemspec CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |gem|
23
23
  gem.add_dependency('highline')
24
24
 
25
25
  gem.add_development_dependency('debugger')
26
+ gem.add_development_dependency('rake')
26
27
  gem.add_development_dependency('rspec')
27
28
  gem.add_development_dependency('simplecov')
28
29
  gem.add_development_dependency('test-construct')
@@ -2,17 +2,26 @@ module KiYoutrack
2
2
 
3
3
  class Api
4
4
 
5
- def self.issue(id, opts = {})
6
- config = Kiseru::Config[:ki_youtrack]
7
- username = config.read(:username)
8
- password = config.read(:password)
9
- subdomain = config.read(:subdomain)
10
- ssl = config.read(:ssl)
11
- session = Session.new(username, password, subdomain, :ssl => ssl)
12
- session.init
13
- response = session.get_bug(id)
14
-
15
- filtered_data = IssueFilter.filter(response.body['issue'])
5
+ attr_reader :config
6
+
7
+ def initialize(config=Kiseru::Config[:ki_youtrack])
8
+ @config = config
9
+ end
10
+
11
+ def issue(id, opts = {})
12
+ config.ensure_present(:login, :password, :subdomain, :ssl)
13
+
14
+ login = @config.read(:login)
15
+ password = @config.read(:password)
16
+ subdomain = @config.read(:subdomain)
17
+ ssl = @config.read(:ssl)
18
+
19
+ session = Session.new(login, password, subdomain, :ssl => ssl)
20
+ response = session.init
21
+
22
+ issue = session.issue(id)
23
+
24
+ filtered_data = IssueFilter.filter(issue)
16
25
  MultiJson.dump(filtered_data, :pretty => opts[:pretty])
17
26
  end
18
27
 
@@ -0,0 +1,41 @@
1
+ module KiYoutrack
2
+
3
+ class Initializer
4
+
5
+ def self.init
6
+ config = Kiseru::Config[:ki_youtrack]
7
+
8
+ ui = HighLine.new
9
+
10
+ $stdout.puts "Initializing config file at #{config.path}"
11
+
12
+ old_subdomain = config.read(:subdomain)
13
+ old_ssl = config.read(:ssl)
14
+ old_login = config.read(:login)
15
+ old_password = config.read(:password)
16
+
17
+ subdomain = ui.ask("Subdomain: ") { |q| q.default = old_subdomain }
18
+ convert_to_boolean = lambda do |string|
19
+ return true if string.downcase == "true"
20
+ return false if string.downcase == "false"
21
+ string
22
+ end
23
+ ssl = ui.ask("SSL?: ", convert_to_boolean) do |q|
24
+ q.default = old_ssl || "true";
25
+ q
26
+ end
27
+ login = ui.ask("Login (or email): ") { |q| q.default = old_login }
28
+
29
+ $stdout.puts "WARNING: Your YouTrack password will be written in plaintext to #{config.path}"
30
+ password = ui.ask("Password: ") { |q| q.echo = "*" }
31
+
32
+ config.write(:login, login)
33
+ config.write(:password, password)
34
+ config.write(:subdomain, subdomain)
35
+ config.write(:ssl, ssl)
36
+
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -1,16 +1,23 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+
1
4
  module Kiseru
2
5
 
6
+ class ConfigError < StandardError; end;
7
+
3
8
  class ConfigDir
4
9
 
5
- DIR_NAME = '.kiseru'
10
+ NAME = '.kiseru'
6
11
 
7
12
  attr_reader :path
8
13
 
9
14
  def initialize(opts = {})
15
+ name = opts.fetch(:name) { NAME }
10
16
  root = Pathname.new(File.expand_path(opts.fetch(:root) { '~' }))
11
- @path = root + DIR_NAME
17
+ @path = root + name
12
18
  unless File.directory?(@path)
13
19
  Dir.mkdir(@path)
20
+ FileUtils.chmod(0700, @path)
14
21
  end
15
22
  end
16
23
 
@@ -22,18 +29,34 @@ module Kiseru
22
29
 
23
30
  class Config
24
31
 
32
+ attr_reader :path
33
+
25
34
  def self.[](key)
26
35
  ConfigDir.new.config(key)
27
36
  end
28
37
 
29
38
  def initialize(root_path, app_name)
30
- file_path = (root_path + "#{app_name}.yml").to_s
31
- @store = YAML::Store.new(file_path)
39
+ @path = (root_path + "#{app_name}.yml").to_s
40
+ unless File.exists?(@path)
41
+ FileUtils.touch(@path)
42
+ FileUtils.chmod(0600, @path)
43
+ end
44
+ @store = YAML::Store.new(@path)
45
+ @store.transaction do
46
+ end
47
+ end
48
+
49
+ def ensure_present(*keys)
50
+ keys.each do |key|
51
+ if read(key).nil?
52
+ raise ConfigError, "'#{key}' is not defined in config"
53
+ end
54
+ end
32
55
  end
33
56
 
34
- def write(key, time)
57
+ def write(key, value)
35
58
  @store.transaction do
36
- @store[key] = time
59
+ @store[key] = value
37
60
  end
38
61
  end
39
62
 
@@ -1,5 +1,7 @@
1
1
  module KiYoutrack
2
2
 
3
+ class SessionError < StandardError; end;
4
+
3
5
  class Session
4
6
 
5
7
  attr_reader :session_cookies, :api_url
@@ -12,26 +14,50 @@ module KiYoutrack
12
14
  "#{protocol}://#{subdomain}.myjetbrains.com"
13
15
  end
14
16
 
15
- def initialize(username, password, subdomain, opts = {})
17
+ def initialize(login, password, subdomain, opts = {})
16
18
  ssl = opts.fetch(:ssl, true)
17
- @username = username
19
+ @login = login
18
20
  @password = password
19
21
  @api_url = Session.url(subdomain, ssl)
20
22
  end
21
23
 
22
24
  def init
23
25
  response = connection.post("/youtrack/rest/user/login",
24
- :login => @username,
26
+ :login => @login,
25
27
  :password => @password)
26
28
  @session_cookies = response.headers['set-cookie']
27
- response
29
+ case response.status
30
+ when 404
31
+ if response.body =~ /HTTPS is supported in paid version only/
32
+ raise SessionError, "Authentication failed because HTTPS is not supported for this domain."
33
+ else
34
+ raise SessionError, "Authentication failed. Check subdomain and SSL settings."
35
+ end
36
+ when 302
37
+ raise SessionError, "Authentication failed. Check subdomain."
38
+ when 403
39
+ raise SessionError, "Authentication failed. Check login and password."
40
+ when 200
41
+ response
42
+ else
43
+ raise SessionError, "Unhandled status code #{response.status}"
44
+ end
28
45
  end
29
46
 
30
- def get_bug(id)
31
- connection.get do |req|
47
+ def issue(id)
48
+ response = connection.get do |req|
32
49
  req.url "/youtrack/rest/issue/#{id}"
33
50
  req.headers['Cookie'] = session_cookies
34
51
  end
52
+
53
+ case response.status
54
+ when 200
55
+ response.body['issue']
56
+ when 404
57
+ raise SessionError, "Can't find issue #{id}"
58
+ else
59
+ raise SessionError, "Unhandled status code #{response.status}"
60
+ end
35
61
  end
36
62
 
37
63
  private
@@ -1,3 +1,3 @@
1
1
  module KiYoutrack
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/ki_youtrack.rb CHANGED
@@ -10,6 +10,7 @@ autoload :Kiseru, 'ki_youtrack/kiseru'
10
10
 
11
11
  module KiYoutrack
12
12
 
13
+ autoload :Initializer, 'ki_youtrack/initializer'
13
14
  autoload :Api, 'ki_youtrack/api'
14
15
  autoload :Creds, 'ki_youtrack/creds'
15
16
  autoload :Session, 'ki_youtrack/session'
@@ -4,21 +4,28 @@ include KiYoutrack
4
4
 
5
5
  describe KiYoutrack::Api do
6
6
 
7
+ let(:config) do
8
+ Kiseru::ConfigDir.new(:root => SPEC_DIR,
9
+ :name => SPEC_CONFIG_DIR).config(:ki_youtrack)
10
+ end
11
+
7
12
  it "gets JSON for issue", :vcr do
8
- json = Api.issue("KI-1")
13
+ api = Api.new(config)
14
+ json = api.issue("KI-1")
9
15
  data = MultiJson.load(json)
10
16
  data['id'].should == 'KI-1'
11
17
  data['ki_type'].should == 'youtrack_issue'
12
18
  end
13
19
 
14
20
  it "pretty prints JSON if requested", :vcr do
15
- json = Api.issue("KI-1", :pretty => false)
21
+ api = Api.new(config)
22
+ json = api.issue("KI-1", :pretty => false)
16
23
 
17
24
  pretty_json = MultiJson.dump(MultiJson.load(json), :pretty => true)
18
25
  normal_json = MultiJson.dump(MultiJson.load(json), :pretty => false)
19
26
 
20
27
  json.should == normal_json
21
- Api.issue("KI-1", :pretty => true).should == pretty_json
28
+ api.issue("KI-1", :pretty => true).should == pretty_json
22
29
  end
23
30
 
24
31
  end
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,9 @@ require 'construct'
13
13
  include Construct::Helpers
14
14
  include KiYoutrack
15
15
 
16
+ SPEC_DIR = File.expand_path(File.dirname(__FILE__))
17
+ SPEC_CONFIG_DIR = 'configs'
18
+
16
19
  if [0, 'false', false, 'f', 'n', 'no', 'off'].include?(ENV['VCR'])
17
20
  puts "VCR off"
18
21
  else
@@ -5,8 +5,9 @@ describe KiYoutrack::Session do
5
5
  before do
6
6
  # These tests will fail until you create a valid config file
7
7
  # by doing 'ki_youtrack setup'
8
- config = Kiseru::Config[:ki_youtrack]
9
- @username = config.read(:username)
8
+ config = Kiseru::ConfigDir.new(:root => SPEC_DIR,
9
+ :name => SPEC_CONFIG_DIR).config(:ki_youtrack)
10
+ @login = config.read(:login)
10
11
  @password = config.read(:password)
11
12
  @subdomain = config.read(:subdomain)
12
13
  end
@@ -16,26 +17,23 @@ describe KiYoutrack::Session do
16
17
  # a valid subdomain must be supplied otherwise the HTTP
17
18
  # status code will be 404 instead of 403
18
19
  session = Session.new("foo", "bar", @subdomain, :ssl => false)
19
- response = session.init
20
- response.status.should == 403
21
- response.body['error'].should match /Incorrect login or password/
20
+ lambda do
21
+ response = session.init
22
+ end.should raise_error SessionError, /Authentication failed/
22
23
  end
23
24
 
24
25
  it "responds 200 and gets headers if creds are valid", :vcr do
25
- session = Session.new(@username, @password, @subdomain, :ssl => false)
26
+ session = Session.new(@login, @password, @subdomain, :ssl => false)
26
27
  response = session.init
27
28
  response.status.should == 200
28
29
  response.headers["set-cookie"].should_not be_nil
29
30
  session.session_cookies.should == response.headers["set-cookie"]
30
31
  end
31
32
 
32
- it "uses authentication cookies to get bug", :vcr do
33
- session = Session.new(@username, @password, @subdomain, :ssl => false)
33
+ it "uses authentication cookies to get issue", :vcr do
34
+ session = Session.new(@login, @password, @subdomain, :ssl => false)
34
35
  session.init
35
- response = session.get_bug("KI-1")
36
- response.status.should == 200
37
- response.body.should_not be_nil
38
- issue = response.body['issue']
36
+ issue = session.issue("KI-1")
39
37
  issue['id'].should == "KI-1"
40
38
  end
41
39
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ki_youtrack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-08-14 00:00:00.000000000Z
13
+ date: 2012-08-15 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: gli
17
- requirement: &70324410656340 !ruby/object:Gem::Requirement
17
+ requirement: &70195634193200 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70324410656340
25
+ version_requirements: *70195634193200
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: faraday
28
- requirement: &70324410655920 !ruby/object:Gem::Requirement
28
+ requirement: &70195634192780 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *70324410655920
36
+ version_requirements: *70195634192780
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: faraday_middleware
39
- requirement: &70324410655500 !ruby/object:Gem::Requirement
39
+ requirement: &70195634192360 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *70324410655500
47
+ version_requirements: *70195634192360
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: multi_xml
50
- requirement: &70324410655080 !ruby/object:Gem::Requirement
50
+ requirement: &70195634191940 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: '0'
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *70324410655080
58
+ version_requirements: *70195634191940
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: multi_json
61
- requirement: &70324410654660 !ruby/object:Gem::Requirement
61
+ requirement: &70195611982480 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: '0'
67
67
  type: :runtime
68
68
  prerelease: false
69
- version_requirements: *70324410654660
69
+ version_requirements: *70195611982480
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: highline
72
- requirement: &70324410654240 !ruby/object:Gem::Requirement
72
+ requirement: &70195611982060 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ! '>='
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: '0'
78
78
  type: :runtime
79
79
  prerelease: false
80
- version_requirements: *70324410654240
80
+ version_requirements: *70195611982060
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: debugger
83
- requirement: &70324410653820 !ruby/object:Gem::Requirement
83
+ requirement: &70195611981640 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ! '>='
@@ -88,10 +88,21 @@ dependencies:
88
88
  version: '0'
89
89
  type: :development
90
90
  prerelease: false
91
- version_requirements: *70324410653820
91
+ version_requirements: *70195611981640
92
+ - !ruby/object:Gem::Dependency
93
+ name: rake
94
+ requirement: &70195611981220 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ type: :development
101
+ prerelease: false
102
+ version_requirements: *70195611981220
92
103
  - !ruby/object:Gem::Dependency
93
104
  name: rspec
94
- requirement: &70324410653400 !ruby/object:Gem::Requirement
105
+ requirement: &70195611980800 !ruby/object:Gem::Requirement
95
106
  none: false
96
107
  requirements:
97
108
  - - ! '>='
@@ -99,10 +110,10 @@ dependencies:
99
110
  version: '0'
100
111
  type: :development
101
112
  prerelease: false
102
- version_requirements: *70324410653400
113
+ version_requirements: *70195611980800
103
114
  - !ruby/object:Gem::Dependency
104
115
  name: simplecov
105
- requirement: &70324410652980 !ruby/object:Gem::Requirement
116
+ requirement: &70195611980380 !ruby/object:Gem::Requirement
106
117
  none: false
107
118
  requirements:
108
119
  - - ! '>='
@@ -110,10 +121,10 @@ dependencies:
110
121
  version: '0'
111
122
  type: :development
112
123
  prerelease: false
113
- version_requirements: *70324410652980
124
+ version_requirements: *70195611980380
114
125
  - !ruby/object:Gem::Dependency
115
126
  name: test-construct
116
- requirement: &70324410652560 !ruby/object:Gem::Requirement
127
+ requirement: &70195611979960 !ruby/object:Gem::Requirement
117
128
  none: false
118
129
  requirements:
119
130
  - - ! '>='
@@ -121,10 +132,10 @@ dependencies:
121
132
  version: '0'
122
133
  type: :development
123
134
  prerelease: false
124
- version_requirements: *70324410652560
135
+ version_requirements: *70195611979960
125
136
  - !ruby/object:Gem::Dependency
126
137
  name: vcr
127
- requirement: &70324410652140 !ruby/object:Gem::Requirement
138
+ requirement: &70195611979540 !ruby/object:Gem::Requirement
128
139
  none: false
129
140
  requirements:
130
141
  - - ! '>='
@@ -132,10 +143,10 @@ dependencies:
132
143
  version: '0'
133
144
  type: :development
134
145
  prerelease: false
135
- version_requirements: *70324410652140
146
+ version_requirements: *70195611979540
136
147
  - !ruby/object:Gem::Dependency
137
148
  name: webmock
138
- requirement: &70324410651720 !ruby/object:Gem::Requirement
149
+ requirement: &70195611979120 !ruby/object:Gem::Requirement
139
150
  none: false
140
151
  requirements:
141
152
  - - ! '>='
@@ -143,7 +154,7 @@ dependencies:
143
154
  version: '0'
144
155
  type: :development
145
156
  prerelease: false
146
- version_requirements: *70324410651720
157
+ version_requirements: *70195611979120
147
158
  description: Kiseru YouTrack client
148
159
  email:
149
160
  - ben@freeagent.com
@@ -164,6 +175,7 @@ files:
164
175
  - lib/ki_youtrack.rb
165
176
  - lib/ki_youtrack/api.rb
166
177
  - lib/ki_youtrack/creds.rb
178
+ - lib/ki_youtrack/initializer.rb
167
179
  - lib/ki_youtrack/issue_filter.rb
168
180
  - lib/ki_youtrack/kiseru.rb
169
181
  - lib/ki_youtrack/session.rb