yapt 0.0.1 → 0.0.2

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: 7f3d3e6e3a120cd87f9c1cc545edd9ac08eb22ac
4
- data.tar.gz: 2257eedb5a60cc3bc2ee63cf40c878c92f9e9ec6
3
+ metadata.gz: 23de5c03a7ac130c7f824eb67fb29f3e16f33a52
4
+ data.tar.gz: 1cc941043e57e0e3557d506bb2f176d0dddf7d1f
5
5
  SHA512:
6
- metadata.gz: 839df234bc2acc4db310d0abc5994a505dfb3ce95902e572b0a62d5bbbe7a0afa51d1935cf2520cd07b15098f9484e1e2f68b6eab4512db68e211b8da15b70e6
7
- data.tar.gz: 9aecd0b88395d255541d8b39361a3c9cc69af75a3c43dd588bd6df64581b65be57f772530a0b63646079d1bbd9bc0fc99ba67c7a17fba3995d62dfaac0c466b8
6
+ metadata.gz: a700985a6d0e2e93665ffa341acec9b17c01cdc498c2f2e2d0274411f8918ef897f1b9689766d8f64076f5b6923fc4c41e944f540fc57298a01e15f2d89df9fb
7
+ data.tar.gz: db5d1a4cfb1d4d4e237838dc490532375ae6dfe1bb64f2ce29718e87220dbd58c6ef772531ac11898b8da0e785a5312ac0896fb67092e53b56b0a2798c3f85a9
data/.gitignore CHANGED
@@ -15,5 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
- .env
18
+ .yapt
19
19
  .yapt_member_cache
data/Gemfile CHANGED
@@ -3,5 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in yapt.gemspec
4
4
  gemspec
5
5
 
6
- gem "dotenv"
7
6
  gem "pry"
data/README.md CHANGED
@@ -8,13 +8,35 @@ A command line Pivotal Tracker client. In early days.
8
8
 
9
9
  ## Usage
10
10
 
11
- Environment variables:
11
+ Put these in a yaml .yapt file in your project or ~ directory:
12
12
 
13
13
  * api_token
14
14
  * project_id
15
15
 
16
16
  yapt list "created_since=last friday" limit=5 keyword
17
17
 
18
+ Use a different template with v(iew)=
19
+
20
+ ```
21
+ yapt list v=detail
22
+ yapt list view=simple
23
+ ```
24
+
25
+ Check out an individual story...
26
+
27
+ ```
28
+ yapt show 12345
29
+ ```
30
+
31
+ Move it ...
32
+
33
+ ```
34
+ yapt move 12345 54321 # move 12345 just above 54321
35
+ yapt move 12345 tback # move 12345 to top of backlog
36
+ ```
37
+
38
+ Other keywords: ticebox, tice, bback, tbacklog, bice, bicebox
39
+
18
40
  ## Contributing
19
41
 
20
42
  1. Fork it
@@ -0,0 +1,36 @@
1
+ require 'yaml'
2
+
3
+ module Yapt
4
+ class Config
5
+ attr_reader :project_path
6
+ def initialize(project_path)
7
+ @project_path = project_path
8
+ end
9
+
10
+ def project_id
11
+ config.fetch('project_id')
12
+ end
13
+
14
+ def api_token
15
+ config.fetch('api_token')
16
+ end
17
+
18
+ private
19
+
20
+ def load_or_hash(path)
21
+ YAML.load_file(path) rescue Hash.new
22
+ end
23
+
24
+ def config
25
+ @config ||= user_config.merge(project_config)
26
+ end
27
+
28
+ def project_config
29
+ load_or_hash("#{project_path}/.yapt")
30
+ end
31
+
32
+ def user_config
33
+ load_or_hash("#{Dir.home}/.yapt")
34
+ end
35
+ end
36
+ end
data/lib/yapt/filter.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'pry'
2
1
  require "chronic"
3
2
 
4
3
  module Yapt
@@ -6,7 +5,6 @@ module Yapt
6
5
  def self.parse(args)
7
6
  args.inject({filter: ""}) do |query, arg|
8
7
  filter = new(arg)
9
- # binding.pry
10
8
  if filter.filter?
11
9
  query[:filter] += "#{filter.to_filter} "
12
10
  else
data/lib/yapt/move.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Yapt
2
+ class Move
3
+ def self.setup(id, target_id)
4
+ to_move = Story.find(id)
5
+ target = Story.find(target_id)
6
+ new(to_move, target)
7
+ end
8
+
9
+ attr_reader :to_move, :target
10
+ def initialize(to_move, target)
11
+ @to_move, @target = to_move, target
12
+ end
13
+
14
+ def description
15
+ "Move #{to_move.id} just above #{target.id}"
16
+ end
17
+
18
+ def params
19
+ {
20
+ before_id: target.id
21
+ }
22
+ end
23
+
24
+ def execute!
25
+ Request.new("stories/#{to_move.id}", params, :put).result
26
+ end
27
+ end
28
+ end
data/lib/yapt/request.rb CHANGED
@@ -2,24 +2,41 @@ require "rest-client"
2
2
 
3
3
  module Yapt
4
4
  class Request
5
+ attr_reader :method, :path, :params
5
6
  def initialize(path, params = {}, method = :get)
6
- @text_result = send(method, path, params)
7
+ @method, @path, @params = method, path, params
7
8
  end
8
9
 
9
10
  def result
10
- JSON.parse(@text_result)
11
+ request(method, params)
11
12
  end
12
13
 
13
- def get(path, params={})
14
- url = "#{base_url}/#{path}"
15
- RestClient.get url,
16
- {
17
- params: params,
18
- "X-TrackerToken" => Yapt.api_token
14
+ def request(method, payload)
15
+ options = {
16
+ "X-TrackerToken" => Yapt.api_token,
17
+ "Content-Type" => "application/json"
19
18
  }
19
+ response_handling = ->(response, request, result, &block) {
20
+ case response.code
21
+ when 200
22
+ JSON.parse(response.to_s)
23
+ else
24
+ puts "Non-200 response!"
25
+ puts response.to_s
26
+ end
27
+ }
28
+ if method == :get
29
+ RestClient.get(url, options.merge(params: payload), &response_handling)
30
+ else
31
+ RestClient.send(method, url, payload, options, &response_handling)
32
+ end
20
33
  end
21
34
 
22
- def base_url
35
+ def url
36
+ "#{self.class.base_url}/#{path}"
37
+ end
38
+
39
+ def self.base_url
23
40
  "https://www.pivotaltracker.com/
24
41
  services/v5/projects/#{Yapt.project_id}".gsub(/\s+/,'')
25
42
  end
data/lib/yapt/story.rb CHANGED
@@ -1,11 +1,98 @@
1
1
  module Yapt
2
2
  class Story
3
3
  def self.find(options = ["limit=5"])
4
+ return find_one(options) if options.kind_of?(String)
4
5
  params = Filter.parse(options)
5
- puts View.headline(params[:filter])
6
- puts
7
6
  results = Request.new("stories", params, :get).result
8
- View.display(results)
7
+ results.collect {|r| new(r) }
8
+ end
9
+
10
+ def self.find_one(id)
11
+ case id
12
+ when /\A\d+\Z/ then find_by_id(id)
13
+ when 'tback' then top_of_backlog
14
+ when 'tbacklog' then top_of_backlog
15
+ when 'tice' then top_of_icebox
16
+ when 'ticebox' then top_of_icebox
17
+
18
+ when 'bback' then bottom_of_backlog
19
+ when 'bbacklog' then bottom_of_backlog
20
+ when 'bice' then bottom_of_icebox
21
+ when 'bicebox' then bottom_of_icebox
22
+ end
23
+ end
24
+
25
+ def self.find_by_id(id)
26
+ new(Request.new("stories/#{id}", {}, :get).result)
27
+ end
28
+
29
+ def self.top_of_backlog
30
+ find(["state:unstarted", "limit:1"]).first
31
+ end
32
+
33
+ def self.top_of_icebox
34
+ find(["state:unscheduled", "limit:1"]).first
35
+ end
36
+
37
+ def self.bottom_of_backlog
38
+ find(["state:unstarted"]).last
39
+ end
40
+
41
+ def self.bottom_of_icebox
42
+ find(["state:unscheduled"]).last
43
+ end
44
+
45
+ def self.just_url(id)
46
+ if id
47
+ "#{base_site_url}/stories/#{id}"
48
+ else
49
+ base_site_url
50
+ end
51
+ end
52
+
53
+ def self.images_url(id)
54
+ "#{just_url(id)}/images"
55
+ end
56
+
57
+ def self.base_site_url
58
+ "https://www.pivotaltracker.com/s/projects/#{Yapt.project_id}"
59
+ end
60
+
61
+ attr_reader :raw_story
62
+ def initialize(raw_story)
63
+ @raw_story = raw_story
64
+ end
65
+
66
+ [:url, :story_type, :description, :id,
67
+ :current_state, :labels, :owned_by_id, :created_at, :kind,
68
+ :project_id, :requested_by_id, :updated_at, :name].each do |attr|
69
+ define_method attr do
70
+ raw_story[attr.to_s]
71
+ end
72
+ end
73
+
74
+ def owner_initials
75
+ if owned_by_id
76
+ "Owner: #{Member.find(owned_by_id).initials}"
77
+ else
78
+ "No owner"
79
+ end
80
+ end
81
+
82
+ def requester_initials
83
+ "Requester: #{Member.find(requested_by_id).initials}"
84
+ end
85
+
86
+ def created_at_display
87
+ "Created: #{time_display(created_at)}"
88
+ end
89
+
90
+ def updated_at_display
91
+ "Updated: #{time_display(updated_at)}"
92
+ end
93
+
94
+ def time_display(time)
95
+ Time.parse(time).strftime("%a %d%b %I:%M")
9
96
  end
10
97
  end
11
98
  end
@@ -0,0 +1,12 @@
1
+ <% @stories.each do |story| -%>
2
+ <%= story.id %> | <%= story.name %>
3
+ <%= story.description %>
4
+ <%= '-' * 100 %>
5
+ <%= story.created_at_display %> | <%= story.updated_at_display %> | <%= story.current_state %> | <%= story.requester_initials %> | <%= story.owner_initials %>
6
+ <%= '=' * 100 %>
7
+ <% end %>
8
+ <% if false %>
9
+ [:url, :story_type, :description, :id,
10
+ :current_state, :labels, :owned_by_id, :created_at, :kind,
11
+ :project_id, :requested_by_id, :updated_at, :name].each do |attr|
12
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% @stories.each do |story| -%>
2
+ <%= story.id %> | <%= story.name %>
3
+ <% end %>
data/lib/yapt/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yapt
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/yapt/view.rb CHANGED
@@ -1,75 +1,29 @@
1
- require "ostruct"
1
+ require 'erb'
2
2
 
3
3
  module Yapt
4
4
  class View
5
- extend Forwardable
6
-
7
- def_delegators :@story, :url, :story_type, :description, :id,
8
- :current_state, :labels, :owned_by_id, :created_at, :kind,
9
- :project_id, :requested_by_id, :updated_at, :name
10
-
11
- def self.headline(str)
12
- "About to display: #{str}"
13
- end
14
-
15
- def self.display(stories)
16
- stories.inject("") do |str, story|
17
- str + new(story).to_s
18
- end
5
+ def self.extract_display_config(args)
6
+ display = args.detect {|a| a =~ /\Av(iew)?[=:]/ }
7
+ args.delete(display)
8
+ display ? display.split(/[=:]/).last : nil
19
9
  end
20
10
 
21
- attr_reader :story
22
- def initialize(story)
23
- @story = OpenStruct.new(story)
11
+ def initialize(stories)
12
+ @stories = stories
24
13
  end
25
14
 
26
- def to_s
27
- [:id, :story_type, :current_state, :name, :nl,
28
- :created_at_display, :updated_at_display,
29
- :owner_initials, :requester_initials,
30
- :nl, :nl
31
- ].inject("") do |str, element|
32
- str += "#{send(element)}"
33
- element == :nl ? str : "#{str} | "
34
- end.gsub(/\| $/, '')
35
- end
36
-
37
- private
38
-
39
- def owner_initials
40
- if owned_by_id
41
- "Owner: #{Member.find(owned_by_id).initials}"
15
+ def display(template_name)
16
+ template_path = "#{template_dir}/#{template_name}.erb"
17
+ if File.exists?(template_path)
18
+ template = IO.read template_path
19
+ ERB.new(template, 0, '-').result(binding)
42
20
  else
43
- "No owner"
21
+ raise "#{template_path} missing!"
44
22
  end
45
23
  end
46
24
 
47
- def requester_initials
48
- "Requester: #{Member.find(requested_by_id).initials}"
49
- end
50
-
51
- def created_at_display
52
- "Created: #{time_display(created_at)}"
53
- end
54
-
55
- def updated_at_display
56
- "Updated: #{time_display(updated_at)}"
57
- end
58
-
59
- def time_display(time)
60
- Time.parse(time).strftime("%a %d%b %I:%M")
61
- end
62
-
63
- def id_name
64
- "#{story.id} | #{story.name}\n"
65
- end
66
-
67
- def nl
68
- "\n"
25
+ def template_dir
26
+ "#{File.dirname(__FILE__)}/templates"
69
27
  end
70
28
  end
71
29
  end
72
- # ["url", "story_type", "description", "id", "current_state",
73
- # "labels", "owned_by_id", "created_at", "kind", "project_id",
74
- # "requested_by_id", "updated_at", "name"]
75
-
data/lib/yapt.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'dotenv'
2
- Dotenv.load
1
+ require 'pry'
2
+ require 'highline/import'
3
3
 
4
4
  module Yapt
5
5
  autoload :VERSION, "yapt/version"
@@ -8,13 +8,19 @@ module Yapt
8
8
  autoload :View, "yapt/view"
9
9
  autoload :Member, "yapt/member"
10
10
  autoload :Request, "yapt/request"
11
+ autoload :Config, "yapt/config"
12
+ autoload :Move, "yapt/move"
13
+
14
+ def self.config
15
+ @config ||= Config.new(Dir.pwd)
16
+ end
11
17
 
12
18
  def self.project_id
13
- @project_id ||= ENV['project_id']
19
+ config.project_id
14
20
  end
15
21
 
16
22
  def self.api_token
17
- @api_token ||= ENV['api_token']
23
+ config.api_token
18
24
  end
19
25
 
20
26
  def self.cache_duration
@@ -30,20 +36,60 @@ module Yapt
30
36
  end
31
37
 
32
38
  class Runner < Boson::Runner
33
- # option :urgent, type: :boolean
39
+ attr_reader :start_time
40
+ def initialize
41
+ @start_time = Time.now
42
+ super
43
+ end
44
+
34
45
  def list(*args)
46
+ display_config = View.extract_display_config(args)
47
+ @stories = Story.find(args)
48
+ display_config ||= (@stories.length > 1) ? "simple" : "detail"
49
+ output View.new(@stories).display(display_config)
50
+ end
51
+
52
+ def show(id)
53
+ @story = Story.find(id)
54
+ output View.new([@story]).display("detail")
55
+ end
56
+
57
+ def open(id = nil)
58
+ system_open Story.just_url(id)
59
+ end
60
+
61
+ def images(id)
62
+ system_open Story.images_url(id)
63
+ end
64
+
65
+ def move(id, destination)
66
+ mover = Move.setup(id, destination)
35
67
  puts
36
- puts Story.find(args)
37
- puts
38
- puts args.inspect
68
+ puts mover.description
69
+ puts View.new([mover.to_move, mover.target]).display("simple")
70
+
71
+ permission = ask("Make this move? ").downcase
72
+ if %w(y yes).include?(permission)
73
+ mover.execute!
74
+ puts "Moved!"
75
+ else
76
+ puts "Aborted. Oh well."
77
+ end
39
78
  end
40
79
 
41
- def members
42
- Member.cache
80
+ private
81
+
82
+ def system_open(whatever)
83
+ puts "Opening: #{whatever}"
84
+ system "open #{whatever}"
43
85
  end
44
86
 
45
- def moo
46
- puts "MOOOO"
87
+ def output(str)
88
+ puts
89
+ puts str
90
+ puts
91
+ puts "Took #{Time.now - start_time} seconds."
92
+ puts
47
93
  end
48
94
  end
49
95
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yapt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Schenkman-Moore
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-30 00:00:00.000000000 Z
11
+ date: 2014-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: boson
@@ -109,10 +109,14 @@ files:
109
109
  - Rakefile
110
110
  - bin/yapt
111
111
  - lib/yapt.rb
112
+ - lib/yapt/config.rb
112
113
  - lib/yapt/filter.rb
113
114
  - lib/yapt/member.rb
115
+ - lib/yapt/move.rb
114
116
  - lib/yapt/request.rb
115
117
  - lib/yapt/story.rb
118
+ - lib/yapt/templates/detail.erb
119
+ - lib/yapt/templates/simple.erb
116
120
  - lib/yapt/version.rb
117
121
  - lib/yapt/view.rb
118
122
  - yapt.gemspec