pivotal_shell 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ .pivotalrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in pivotal_shell.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pivotal_shell (0.0.1)
5
+ pivotal-tracker (= 0.3)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ builder (3.0.0)
11
+ happymapper (0.3.2)
12
+ libxml-ruby (~> 1.1.3)
13
+ libxml-ruby (1.1.4)
14
+ mime-types (1.16)
15
+ nokogiri (1.4.3.1)
16
+ pivotal-tracker (0.3.0)
17
+ builder
18
+ happymapper (>= 0.3.2)
19
+ nokogiri (~> 1.4.3.1)
20
+ rest-client (~> 1.6.0)
21
+ rest-client (1.6.1)
22
+ mime-types (>= 1.16)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ pivotal-tracker (= 0.3)
29
+ pivotal_shell!
data/README.markdown ADDED
@@ -0,0 +1,65 @@
1
+ # pivotal_shell
2
+
3
+ A command-line wrapper for [Pivotal Tracker](http://www.pivotaltracker.com)
4
+
5
+ ## Installation
6
+
7
+ gem install pivotal_shell
8
+
9
+ ## Configuration
10
+
11
+ First, you need to [create an API token for your profile](https://www.pivotaltracker.com/profile) (scroll to the bottom) and put it into `~/.pivotalrc`:
12
+
13
+ api_token: abcdef0123456789
14
+
15
+ The token is the same for all of your Pivotal Tracker projects.
16
+
17
+ Second, you need to create a `.pivotalrc` in your project root and set up projectwide settings:
18
+
19
+ # For the https://www.pivotaltracker.com/projects/123456 project, the id would be...
20
+ project_id: 123456
21
+
22
+ # these are your initials used in the project
23
+ me: LS
24
+
25
+ Both `.pivotalrc` files are regular YAML files.
26
+
27
+ ## Usage
28
+
29
+ pivotal
30
+
31
+ ## Example
32
+
33
+ List all your unfinished stories
34
+
35
+ pivotal stories
36
+
37
+ List all your stories, regardless of status
38
+
39
+ pivotal stories --all --mine
40
+
41
+ List all finished stories for everyone
42
+
43
+ pivotal stories --all --finished
44
+
45
+ List all unassigned bugs
46
+
47
+ pivotal stories --unowned --bugs
48
+
49
+ Show info on a story
50
+
51
+ pivotal story 123456
52
+
53
+ ## TODO
54
+
55
+ Start story
56
+
57
+ pivotal start 123456
58
+
59
+ Finish story
60
+
61
+ pivotal finish 123456
62
+
63
+ Commit (with git, all comments after the story id go to git, story id gets appended to comments)
64
+
65
+ pivotal commit 123456 "some more comments"
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/bin/pivotal ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'pivotal_shell'
5
+ require 'pivotal_shell/configuration'
6
+ #require 'active_support/core_ext'
7
+
8
+ PivotalShell::Configuration.load
9
+
10
+ commands = {
11
+ 'stories' => 'show a list of stories',
12
+ 'story' => 'show information about a specific story',
13
+ }
14
+
15
+ banner = "Pivotal command-line client\nUsage: pivotal COMMAND PARAMS\n\nAvailable commands:\n\n#{commands.map{|c, d| "#{c} - #{d}"}.join("\n")}\n\nRun pivotal COMMAND --help for more info on a specific command\n\n"
16
+
17
+ command = ARGV.shift
18
+
19
+ unless commands.keys.include?(command)
20
+ puts banner
21
+ exit
22
+ end
23
+
24
+ require "pivotal_shell/commands/#{command}"
25
+
26
+ command_class = PivotalShell::Commands.const_get(command[0,1].upcase+command[1..-1])
27
+
28
+ command_class.new(ARGV).execute
@@ -0,0 +1,4 @@
1
+ class PivotalShell::Command
2
+ def initialize(options)
3
+ end
4
+ end
@@ -0,0 +1,69 @@
1
+ #<PivotalTracker::Story:0x90b74f4 @jira_url=nil, @requested_by="Pavel Pavlovsky", @name="Add titles for the pages", @attachments=[], @project_id=110960, @jira_id=nil, @id=5952583, @current_state="accepted", @integration_id=nil, @accepted_at=#<DateTime: 212157861559/86400,1/12,2299161>, @labels="ui", @url="http://www.pivotaltracker.com/story/show/5952583", @estimate=nil, @description="so they are identified correctly by user.\nto clarify", @other_id=nil, @created_at=#<DateTime: 5303878313/2160,1/8,2299161>, @owned_by="Leonid Shevtsov", @story_type="chore">
2
+
3
+ module PivotalShell::Commands
4
+ class PivotalShell::Commands::Stories < PivotalShell::Command
5
+ def initialize(options)
6
+ @options = {:params => {}}
7
+
8
+ available_statuses = %w(unscheduled unstarted started finished delivered accepted rejected)
9
+ available_types = %w(features bugs chores)
10
+
11
+ opts = OptionParser.new do |opts|
12
+ opts.banner = "List Pivotal stories\nUsage: pivotal stories [options]\n\nThe default is to show all unfinished stories assigned to yourself\n\nDisplay format:\n [id]\n type: Feature/Bug/Chore\n estimate: * (irrelevant)/0/1/2/3\n state: . (unscheduled)/Unstarted/Started/Finished/Delivered/Accepted/Rejected\n title\n\nOptions:"
13
+
14
+
15
+ opts.on('--all', 'Show all tasks (reset default filter on state and owner)') do
16
+ @options[:all] = true
17
+ end
18
+
19
+ available_statuses.each do |status|
20
+ opts.on("--#{status}", "Show #{status} stories") do
21
+ @options[:params][:state] ||= []
22
+ @options[:params][:state] << status
23
+ end
24
+ end
25
+
26
+ available_types.each do |type|
27
+ opts.on("--#{type}", "Show #{type}") do
28
+ @options[:params][:type] ||= []
29
+ @options[:params][:type] << type[0..-2] # chomp s
30
+ end
31
+ end
32
+
33
+ opts.on('--for [USER]', 'Show tasks assigned to USER; accepts comma-separated list') do |user|
34
+ @options[:params][:owner] = user
35
+ end
36
+
37
+ opts.on('--unowned', 'Show tasks not assigned to anyone') do
38
+ @options[:unowned] = true
39
+ end
40
+
41
+ opts.on('--anyone', 'Show tasks assigned to anyone') do
42
+ @options[:anyone] = true
43
+ end
44
+
45
+ opts.on('--mine', 'Show your tasks') do
46
+ @options[:params][:owner] = PivotalShell::Configuration.me
47
+ end
48
+
49
+ opts.on_tail('--help', 'Show this help') do
50
+ puts opts
51
+ exit
52
+ end
53
+ end
54
+ opts.parse!
55
+
56
+ @options[:params][:owner] ||= PivotalShell::Configuration.me unless @options[:unowned] || @options[:anyone] || @options[:all]
57
+ @options[:params][:state] ||= %w(unestimated unstarted started) unless @options[:all]
58
+ end
59
+
60
+ def execute
61
+ stories = PivotalShell::Configuration.project.stories.all(@options[:params])
62
+ if @options[:unowned]
63
+ stories.reject!{|s| !s.owned_by.nil?}
64
+ end
65
+
66
+ puts stories.empty? ? 'No stories!' : stories.map{|s| "#{("[#{s.id}]").rjust 12} #{PivotalShell::Configuration.icon(s.story_type, s.current_state, s.estimate)} #{s.name.strip}"}.join("\n")
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,41 @@
1
+ #<PivotalTracker::Story:0x90b74f4 @jira_url=nil, @requested_by="Pavel Pavlovsky", @name="Add titles for the pages", @attachments=[], @project_id=110960, @jira_id=nil, @id=5952583, @current_state="accepted", @integration_id=nil, @accepted_at=#<DateTime: 212157861559/86400,1/12,2299161>, @labels="ui", @url="http://www.pivotaltracker.com/story/show/5952583", @estimate=nil, @description="so they are identified correctly by user.\nto clarify", @other_id=nil, @created_at=#<DateTime: 5303878313/2160,1/8,2299161>, @owned_by="Leonid Shevtsov", @story_type="chore">
2
+ require 'optparse'
3
+
4
+ module PivotalShell::Commands
5
+ class PivotalShell::Commands::Story < PivotalShell::Command
6
+ def initialize(options)
7
+ opts = OptionParser.new do |opts|
8
+ opts.banner = "Show information on a Pivotal story\nUsage: pivotal story STORY_ID [options]\n\n"
9
+
10
+ opts.on_tail('--help', 'Show this help') do
11
+ puts opts
12
+ exit
13
+ end
14
+ end
15
+ opts.parse!(options)
16
+ if options.empty? || options.length>1
17
+ puts opts
18
+ exit
19
+ else
20
+ @story_id = options.first
21
+ end
22
+ end
23
+
24
+ def execute
25
+ @story = PivotalShell::Configuration.project.stories.find(@story_id)
26
+ if @story.nil?
27
+ puts 'Story not found'
28
+ else
29
+ puts ["[#{@story.id}] - #{@story.name}",
30
+ "State: #{@story.current_state}",
31
+ "Owner: #{@story.owned_by}",
32
+ "Creator: #{@story.requested_by}",
33
+ "URL: #{@story.url}",
34
+ "",
35
+ "#{@story.description.strip}",
36
+ "",
37
+ ""].join("\n")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,64 @@
1
+ require 'yaml'
2
+ require 'pivotal_tracker'
3
+
4
+ module PivotalShell::Configuration
5
+ def self.load
6
+ @global_config = YAML.load_file(global_config_path)
7
+ @project_config = YAML.load_file(project_config_path)
8
+ PivotalTracker::Client.token = @global_config['api_token']
9
+ end
10
+
11
+ def self.project
12
+ @project ||= PivotalTracker::Project.find(@project_config['project_id'])
13
+ end
14
+
15
+ def self.me
16
+ @me ||= @project_config['me']
17
+ end
18
+
19
+ def self.global_config_path
20
+ @global_config_path ||= File.expand_path('~/.pivotalrc')
21
+ end
22
+
23
+ def self.project_config_path
24
+ @project_config_path ||= find_project_config
25
+ end
26
+
27
+ def self.status_icon(status)
28
+ {
29
+ 'unscheduled' => ' ',
30
+ 'unstarted' => '.',
31
+ 'started' => 'S',
32
+ 'finished' => 'F',
33
+ 'delivered' => 'D',
34
+ 'accepted' => 'A',
35
+ 'rejected' => 'R'
36
+ }[status]
37
+ end
38
+
39
+ def self.estimate_icon(estimate)
40
+ estimate.nil? ? '*' : ({-1 => '?', 0 => '0', 1=>'1', 2=>'2', 3 => '3'}[estimate] || "[#{estimate.inspect}]")
41
+ end
42
+
43
+ def self.type_icon(type)
44
+ {'feature' => 'F', 'chore' => 'C', 'bug' => 'B'}[type]
45
+ end
46
+
47
+ def self.icon(type, status, estimate)
48
+ type_icon(type) + ' ' + estimate_icon(estimate) + ' ' + status_icon(status)
49
+ end
50
+
51
+ private
52
+
53
+ def self.find_project_config
54
+ dirs = File.split(Dir.pwd)
55
+ until dirs.empty? || File.exists?(File.join(dirs, '.pivotalrc'))
56
+ dirs.pop
57
+ end
58
+ if dirs.empty? || File.join(dirs, '.pivotalrc')==global_config_path
59
+ raise PivotalShell::Exception.new('No project .pivotalrc found')
60
+ else
61
+ File.join(dirs, '.pivotalrc')
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module PivotalShell
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,27 @@
1
+ require 'pivotal_tracker'
2
+
3
+ module PivotalShell
4
+ class Exception < StandardError; end
5
+ end
6
+
7
+ require 'pivotal_shell/command'
8
+
9
+ # fixing pivotal-tracker's options encoding; it did not work with array filters
10
+ module PivotalTracker
11
+ class <<self
12
+ def encode_options(options)
13
+ return nil if !options.is_a?(Hash) || options.empty?
14
+ options_strings = []
15
+ # remove options which are not filters, and encode them as such
16
+ [:limit, :offset].each do |o|
17
+ options_strings << "#{CGI.escape(o.to_s)}=#{CGI.escape(options.delete(o))}" if options[o]
18
+ end
19
+ # assume remaining key-value pairs describe filters, and encode them as such.
20
+ filters_string = options.map do |key, value|
21
+ "#{CGI.escape(key.to_s)}%3A#{CGI.escape([value].flatten.map{|v| v.include?(' ') ? '"'+v+'"' : v}.join(','))}"
22
+ end
23
+ options_strings << "filter=#{filters_string.join('+')}" unless filters_string.empty?
24
+ return "?#{options_strings.join('&')}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "pivotal_shell/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "pivotal_shell"
7
+ s.version = PivotalShell::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Leonid Shevtsov"]
10
+ s.email = ["leonid@shevtsov.me"]
11
+ s.homepage = "http://rubygems.org/gems/pivotal_shell"
12
+ s.summary = %q{A command-line client for Pivotal Tracker}
13
+
14
+ s.add_dependency 'pivotal-tracker', '=0.3'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pivotal_shell
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Leonid Shevtsov
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-02 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: pivotal-tracker
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 0
32
+ - 3
33
+ version: "0.3"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description:
37
+ email:
38
+ - leonid@shevtsov.me
39
+ executables:
40
+ - pivotal
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - Gemfile
48
+ - Gemfile.lock
49
+ - README.markdown
50
+ - Rakefile
51
+ - bin/pivotal
52
+ - lib/pivotal_shell.rb
53
+ - lib/pivotal_shell/command.rb
54
+ - lib/pivotal_shell/commands/stories.rb
55
+ - lib/pivotal_shell/commands/story.rb
56
+ - lib/pivotal_shell/configuration.rb
57
+ - lib/pivotal_shell/version.rb
58
+ - pivotal_shell.gemspec
59
+ has_rdoc: true
60
+ homepage: http://rubygems.org/gems/pivotal_shell
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.3.7
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: A command-line client for Pivotal Tracker
93
+ test_files: []
94
+