pv 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format=progress
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pv.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec'
8
+ gem 'vcr'
9
+ gem 'webmock', '~> 1.8'
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Tom Scott
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.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # PV
2
+
3
+ Use Pivotal Tracker in the shell.
4
+
5
+ ## Installation
6
+
7
+ Install the binary:
8
+
9
+ $ gem install pv
10
+
11
+ Then create `~/.pivotal.yml` with your deets:
12
+
13
+ ```yaml
14
+ username: user@email.com
15
+ password: your-super-secret-password
16
+ project: your-awesome-project-name
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Here are all of the commands Piv can do:
22
+
23
+ ### pv
24
+
25
+ Simply running `piv` will open your `$PAGER` with the stories
26
+ in your "My Work" tab. Each story is one line and includes the
27
+ title and the ID:
28
+
29
+ 123456 My spoon is too big. (A Banana)
30
+
31
+ ### pv show 123456
32
+
33
+ Show the entire story's details, including tasks. Again, this is
34
+ viewed in your `$PAGER`...
35
+
36
+ Feature 123456 (6 points)
37
+ Requester: A Banana <banana@work.com>
38
+ Owner: John Doe <someone@home.com>
39
+ Status: NOT STARTED
40
+
41
+ My spoon is too big.
42
+
43
+ I AM A BANANA!
44
+
45
+
46
+ ### pv edit 123456 -s {start|finish|deliver|accept|reject|restart|close} -m "message"
47
+
48
+ Edits the status of a given story on Pivotal Tracker, with an optional message. The
49
+ message is appended to the story in comments.
50
+
51
+ ### pv {start|finish|deliver|accept|reject|restart|close} 123456 -m "message"
52
+
53
+ Easier-to-remember aliases for the above command.
54
+
55
+ ### pv create "Story title" --points=3
56
+
57
+ Creates a story on Pivotal Tracker. Opens your `$EDITOR` so you can provide more information
58
+ than simply the title, unless you pass --minimal. Stories are created as features by default,
59
+ but you can override this by passing `--bug` or `--chore`. Note: `--points` values, while
60
+ required if creating a feature, are ignored when creating bugs or chores. They are also not
61
+ required on the command.
62
+
63
+ ### pv help
64
+
65
+ Show a command manual.
66
+
67
+ ## Contributing
68
+
69
+ 1. Fork it
70
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
71
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
72
+ 4. Push to the branch (`git push origin my-new-feature`)
73
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/pv ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path('./lib')
4
+
5
+ require 'pv'
6
+
7
+ Pv::Command.start
data/lib/pv.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'pv/configuration'
2
+ require 'pv/command'
3
+ require 'pv/version'
4
+ require 'pv/bug_tracker'
5
+ require 'pv/story'
6
+
7
+ module Pv
8
+ def self.config
9
+ @config ||= Pv::Configuration.new
10
+ end
11
+
12
+ def self.tracker
13
+ @tracker ||= Pv::BugTracker.new
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ require 'pivotal_tracker'
2
+
3
+ module Pv
4
+ class BugTracker
5
+ attr_reader :username, :password, :token
6
+
7
+ def initialize with_username=nil, and_password=nil
8
+ @username = with_username || Pv.config.username
9
+ @password = and_password || Pv.config.password
10
+ @token = PivotalTracker::Client.token(username, password)
11
+
12
+ PivotalTracker::Client.use_ssl = true
13
+ end
14
+
15
+ def connected?
16
+ @token != nil
17
+ end
18
+
19
+ def stories for_project_id=nil, and_full_name=nil
20
+ project_id = for_project_id || Pv.config.project_id
21
+ user = and_full_name || Pv.config.name
22
+
23
+ project = PivotalTracker::Project.all.select { |p| p.id == project_id }.first
24
+ project.stories.all(owned_by: user)
25
+ end
26
+ end
27
+ end
data/lib/pv/command.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'thor'
2
+ require 'active_support/all'
3
+
4
+ module Pv
5
+ class Command < Thor
6
+ include Thor::Actions
7
+
8
+ default_task :log
9
+ desc :log, "Show every story assigned to you on this project."
10
+ def log
11
+ Pv.tracker.stories.each do |story|
12
+ say "[#{story.id}] #{story.name} < #{story.requested_by} >"
13
+ end
14
+ end
15
+
16
+ desc "show STORY_ID", "Show the full text and attributes of a story on this project."
17
+ def show story_id
18
+ story = File.write "/tmp/story", Story.find(story_id).render
19
+ run "less -R /tmp/story"
20
+ end
21
+
22
+ desc "edit STORY_ID", "Edit a story's status on this project."
23
+ method_option :status, default: '', alias: 's'
24
+ method_option :message, default: "", alias: 'm'
25
+ def edit story_id
26
+ story = Story.find story_id
27
+ story.update(status: options[:status]) unless options[:status].blank?
28
+ story.comment! options[:message] unless options[:message].blank?
29
+ end
30
+
31
+ %w(start finish deliver accept reject restart).each do |status|
32
+ desc "#{status} STORY_ID", "#{status.titleize} a story on this project."
33
+ define_method(status) do |story_id|
34
+ options[:status] = status
35
+ edit(story_id)
36
+ end
37
+ end
38
+
39
+ desc :help, "Show all commands"
40
+ def help
41
+ say <<-TEXT
42
+
43
+ pv: pivotal tracker in the shell
44
+
45
+ A simple command-line interface for Pivotal Tracker.
46
+ Configure in ~/.pv:
47
+
48
+ username: 'your-username'
49
+ password: 'secret'
50
+ project_id: 123456
51
+
52
+ Then use the following commands to manage your project:
53
+ TEXT
54
+ say "\n"
55
+ super
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ require 'yaml'
2
+
3
+ module Pv
4
+ class Configuration
5
+ attr_reader :username, :password, :attributes, :project_id, :name
6
+
7
+ def initialize
8
+ @path = File.expand_path "~/.pv"
9
+ @attributes = YAML::load_file @path
10
+ @username = @attributes['username']
11
+ @password = @attributes['password']
12
+ @project_id = @attributes['project_id']
13
+ @name = @attributes['name']
14
+ end
15
+
16
+ def present?
17
+ File.exists? @path
18
+ end
19
+ end
20
+ end
data/lib/pv/story.rb ADDED
@@ -0,0 +1,23 @@
1
+ module Pv
2
+ class Story
3
+ attr_accessor :story_type, :requested_by, :owned_by, :current_state,
4
+ :name, :description, :estimate, :id
5
+
6
+ def initialize from_pivotal_story
7
+ %w(id story_type requested_by owned_by current_state name description estimate).each do |attr|
8
+ self.send "#{attr}=", from_pivotal_story.send(attr)
9
+ end
10
+ end
11
+
12
+ def self.find by_id
13
+ new Pv.tracker.stories.find(by_id).first
14
+ end
15
+
16
+ # Render this Story in plain text.
17
+ def render
18
+ source = IO.read "./lib/templates/story.txt.erb"
19
+ template = ERB.new(source)
20
+ template.result(binding)
21
+ end
22
+ end
23
+ end
data/lib/pv/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Pv
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,8 @@
1
+ <%= story_type.titleize %> <%= id %> (<%= estimate %> points)
2
+ Requested By: <%= requested_by %>
3
+ Assigned To: <%= owned_by %>
4
+ Status: <%= current_state.upcase %>
5
+
6
+ <%= name %>
7
+
8
+ <%= description %>
data/pv.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pv/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "pv"
8
+ gem.version = Pv::VERSION
9
+ gem.authors = ["Tom Scott"]
10
+ gem.email = ["tubbo@psychedeli.ca"]
11
+ gem.description = %q{A command-line interface to Pivotal Tracker.}
12
+ gem.summary = %q{A command-line interface to Pivotal Tracker.}
13
+ gem.homepage = "http://github.com/tubbo/pv"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'pivotal-tracker'
21
+ gem.add_dependency 'thor'
22
+ gem.add_dependency 'active_support'
23
+ gem.add_dependency 'i18n'
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'pv/bug_tracker'
3
+
4
+ module Pv
5
+ describe BugTracker do
6
+ subject do
7
+ VCR.use_cassette :pivotal_client_connection do
8
+ Pv::BugTracker.new("john@doe.com", "password")
9
+ end
10
+ end
11
+
12
+ it "connects to pivotal tracker" do
13
+ subject.should be_connected
14
+ end
15
+
16
+ it "gathers the list of stories this user has to accomplish" do
17
+ VCR.use_cassette :pivotal_project_stories_search do
18
+ subject.stories(461255, "Tom Scott").should_not be_empty
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ require 'pv/configuration'
2
+
3
+ module Pv
4
+ describe Configuration do
5
+ before do
6
+ if File.exists? File.expand_path("~/.pv")
7
+ `cp ~/.pv ~/.pv.safe`
8
+ end
9
+
10
+ `cp spec/fixtures/pv.yml ~/.pv`
11
+ end
12
+
13
+ subject { Pv::Configuration.new }
14
+
15
+ it "reads from ~/.pv YAML" do
16
+ subject.should be_present
17
+ subject.attributes.should_not be_empty
18
+ subject.attributes.count.should == 3
19
+ end
20
+
21
+ it "parses a username" do
22
+ subject.username.should == "john@doe.com"
23
+ end
24
+
25
+ it "parses a password" do
26
+ subject.password.should == "password"
27
+ end
28
+
29
+ after do
30
+ if File.exists? File.expand_path("~/.pv.safe")
31
+ `cp ~/.pv.safe ~/.pv`
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,74 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://www.pivotaltracker.com/services/v3/tokens/active
6
+ body:
7
+ encoding: US-ASCII
8
+ string: username=necromancer&password=2AUcBXdL3EYq8E87vJA3qAUNN
9
+ headers:
10
+ Accept:
11
+ - ! '*/*; q=0.5, application/xml'
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ Content-Length:
15
+ - '55'
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: !binary |-
24
+ T0s=
25
+ headers:
26
+ !binary "Q29udGVudC1UeXBl":
27
+ - !binary |-
28
+ YXBwbGljYXRpb24veG1sOyBjaGFyc2V0PXV0Zi04
29
+ !binary "VHJhbnNmZXItRW5jb2Rpbmc=":
30
+ - !binary |-
31
+ Y2h1bmtlZA==
32
+ !binary "Q29ubmVjdGlvbg==":
33
+ - !binary |-
34
+ Y2xvc2U=
35
+ !binary "U3RhdHVz":
36
+ - !binary |-
37
+ MjAw
38
+ !binary "WC1Qb3dlcmVkLUJ5":
39
+ - !binary |-
40
+ UGh1c2lvbiBQYXNzZW5nZXIgKG1vZF9yYWlscy9tb2RfcmFjaykgMy4wLjE0
41
+ !binary "Q2FjaGUtQ29udHJvbA==":
42
+ - !binary |-
43
+ cHJpdmF0ZSwgbWF4LWFnZT0wLCBtdXN0LXJldmFsaWRhdGU=
44
+ !binary "WC1SdW50aW1l":
45
+ - !binary |-
46
+ MTE3
47
+ !binary "U2V0LUNvb2tpZQ==":
48
+ - !binary |-
49
+ dF9zZXNzaW9uPUJBaDdCem9QWlhod2FYSmxjMTloZEVsMU9nbFVhVzFsRFNZ
50
+ ckhJRHJNR2RWQmpvZlFHMWhjbk5vWVd4ZmQybDBhRjkxZEdOZlkyOWxjbU5w
51
+ YjI1R09nOXpaWE56YVc5dVgybGtJaVZoTUdRNE1tTmpNbUk0TldVMk1EaG1Z
52
+ ekpqTkdOak9XVXhOR1V3T1RGak9RJTNEJTNELS0zZmJiYmY3MjA5MjMwNTI1
53
+ YTQ3N2U3ZmViNTdiNzRkZjQxZDk0ZGFmOyBwYXRoPS87IHNlY3VyZTsgSHR0
54
+ cE9ubHk=
55
+ !binary "RXRhZw==":
56
+ - !binary |-
57
+ ImQzNzdhNzkwNTE3MTNiYTE3MDliNjNhMzEzNWU5MWY1Ig==
58
+ !binary "U2VydmVy":
59
+ - !binary |-
60
+ bmdpbngvMS4yLjIgKyBQaHVzaW9uIFBhc3NlbmdlciAzLjAuMTQgKG1vZF9y
61
+ YWlscy9tb2RfcmFjayk=
62
+ !binary "Q29udGVudC1FbmNvZGluZw==":
63
+ - !binary |-
64
+ Z3ppcA==
65
+ body:
66
+ encoding: ASCII-8BIT
67
+ string: !binary |-
68
+ H4sIAAAAAAAAAy3MQQ7CIBAAwHtfQbgr3cJWTIDefIF+wO5CiAqmotHfmxrv
69
+ k3HT+3YVL14euRYvYdtLwWWulEvy8nQ8bKycQudavXAJnRAuPTMFBNTnmUY0
70
+ cW8sIEc2o8aBIpHesXXqx1afSbTPnb3MpXHiRQaAfkBwagVO/ecvVvIujYkA
71
+ AAA=
72
+ http_version:
73
+ recorded_at: Sun, 18 Nov 2012 06:21:24 GMT
74
+ recorded_with: VCR 2.3.0