pivotal_shell 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,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
+