hone-git_pivot 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -2,13 +2,37 @@
2
2
 
3
3
  Tool that allows you to work with Pivotal Tracker from the command line.
4
4
 
5
+ == Installation and Usage
6
+
7
+ To install:
8
+
9
+ $ gem install hone-git_pivot -s http://gems.github.com
10
+
11
+ Now you'll need to add a <tt>git_pivot.yml</tt> to the root directory of your project:
12
+
13
+ project_id: 213992
14
+ token: 3a9390ed9309ba304903939ae948298
15
+ owner: Matt Buck
16
+ use_git: true
17
+
18
+ ... where <tt>owner</tt> is your name as it appears in the Pivotal Tracker interface. Set <tt>use_git</tt> to <tt>true</tt> if you want GitPivot to automatically create (local) topic branches when you start a story.
19
+
20
+ == Current Features
21
+ * display stories in current
22
+ * display stories under "My Work"
23
+ * start a story (optional git support to start a topic branch)
24
+ * display a story with associated "Notes"
25
+ * add a note to a story
26
+ * finish a story
27
+ * list tasks for a story
28
+ * add a task to a story
29
+ * complete tasks
30
+
5
31
  == Planned Features
6
32
 
7
33
  Planned features include:
8
- * display stories in current sprint
9
- * start working on a ticket that creates a new branch in Git, starts ticket in Pivotal Tracker
10
- * close ticket in Pivotal Tracker
11
34
  * search for stories
35
+ * backlog stories
12
36
 
13
37
  == Note on Patches/Pull Requests
14
38
 
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ begin
12
12
  gem.authors = ["hone"]
13
13
  gem.add_development_dependency "hone-pivotal-tracker"
14
14
  gem.add_development_dependency "rupot"
15
+ gem.add_development_dependency "git"
15
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
17
  end
17
18
  rescue LoadError
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/git_pivot.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{git_pivot}
8
- s.version = "0.0.0"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["hone"]
12
- s.date = %q{2009-08-29}
12
+ s.date = %q{2009-09-08}
13
13
  s.default_executable = %q{git_pivot}
14
14
  s.description = %q{TODO: longer description of your gem}
15
15
  s.email = %q{hone02@gmail.com}
@@ -24,8 +24,10 @@ Gem::Specification.new do |s|
24
24
  "LICENSE",
25
25
  "README.rdoc",
26
26
  "Rakefile",
27
+ "VERSION",
27
28
  "bin/git_pivot",
28
29
  "git_pivot.gemspec",
30
+ "git_pivot.yml.example",
29
31
  "lib/git_pivot.rb",
30
32
  "lib/runner.rb"
31
33
  ]
@@ -43,12 +45,15 @@ Gem::Specification.new do |s|
43
45
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
44
46
  s.add_development_dependency(%q<hone-pivotal-tracker>, [">= 0"])
45
47
  s.add_development_dependency(%q<rupot>, [">= 0"])
48
+ s.add_development_dependency(%q<git>, [">= 0"])
46
49
  else
47
50
  s.add_dependency(%q<hone-pivotal-tracker>, [">= 0"])
48
51
  s.add_dependency(%q<rupot>, [">= 0"])
52
+ s.add_dependency(%q<git>, [">= 0"])
49
53
  end
50
54
  else
51
55
  s.add_dependency(%q<hone-pivotal-tracker>, [">= 0"])
52
56
  s.add_dependency(%q<rupot>, [">= 0"])
57
+ s.add_dependency(%q<git>, [">= 0"])
53
58
  end
54
59
  end
@@ -0,0 +1,3 @@
1
+ project_id: 213992
2
+ token: 3a9390ed9309ba304903939ae948298
3
+ owner: Matt Buck
data/lib/git_pivot.rb CHANGED
@@ -19,14 +19,16 @@
19
19
 
20
20
  require 'ruport'
21
21
  require 'pivotal-tracker'
22
+ require 'git'
22
23
 
23
24
  module GitPivot
24
25
  class GitPivot
25
26
 
26
27
  # ssl should default to yes since http basic auth is insecure
27
- def initialize(project_id, token, owner, use_ssl = true)
28
+ def initialize(project_id, token, owner, git = nil, use_ssl = true)
28
29
  @owner = owner
29
30
  @tracker = PivotalTracker.new(project_id, token, {:use_ssl => use_ssl })
31
+ @g = Git.open('.') if git
30
32
  end
31
33
 
32
34
  # list stories in current sprint
@@ -61,10 +63,11 @@ module GitPivot
61
63
  end
62
64
 
63
65
  # start story
64
- def start_story(id)
66
+ def start_story(id, name = nil)
65
67
  story = @tracker.find_story(id)
66
68
  story.current_state = "started"
67
69
  @tracker.update_story(story)
70
+ create_topic_branch(topic_branch_name(story, name))
68
71
 
69
72
  display_story(id)
70
73
  end
@@ -82,6 +85,36 @@ module GitPivot
82
85
  display_story(id)
83
86
  end
84
87
 
88
+ # add a new note
89
+ def add_note(id, note_text)
90
+ note = Note.new(:text => note_text)
91
+ @tracker.create_note(id, note)
92
+
93
+ display_story(id)
94
+ end
95
+
96
+ def tasks(id)
97
+ tasks = @tracker.tasks(id)
98
+ display_tasks(id, tasks)
99
+ end
100
+
101
+ def add_task(id, task_text)
102
+ task = Task.new(:description => task_text)
103
+ @tracker.create_task(id, task)
104
+
105
+ tasks = @tracker.tasks(id)
106
+ display_tasks(id, tasks)
107
+ end
108
+
109
+ def complete_task(id, task_id)
110
+ task = @tracker.find_task(id, task_id)
111
+ task.complete = true
112
+ @tracker.update_task(id, task)
113
+
114
+ tasks = @tracker.tasks(id)
115
+ display_tasks(id, tasks)
116
+ end
117
+
85
118
  private
86
119
  def display_stories(stories)
87
120
  data = stories.collect do |story|
@@ -91,5 +124,43 @@ module GitPivot
91
124
  puts Table(:data => data, :column_names => ["ID", "Type", "Owner", "State", "Name"])
92
125
  end
93
126
 
127
+ def display_tasks(story_id, tasks)
128
+ data = tasks.collect do |task|
129
+ [task.id, task.position, task.complete, task.created_at, task.description]
130
+ end
131
+
132
+ puts "Story ID: #{story_id}"
133
+ puts Table(:data => data,
134
+ :column_names => ["ID", "Position", "Complete", "Created At", "Description"])
135
+ end
136
+
137
+ def create_topic_branch(name)
138
+ if @g
139
+ # always branch from master
140
+ unless @g.lib.branch_current == "master"
141
+ puts 'Switching to master branch'
142
+ @g.branch('master').checkout
143
+ end
144
+
145
+ puts "Switching to #{name} branch"
146
+ @g.branch(name).checkout
147
+ end
148
+ end
149
+
150
+ def topic_branch_name(story, name = nil)
151
+ name_to_use =
152
+ if name
153
+ name
154
+ else
155
+ story.name
156
+ end
157
+ # convert spaces to underscores and remove all punctation
158
+ "#{story.id}_#{transform_name(name_to_use)}"
159
+ end
160
+
161
+ def transform_name(name)
162
+ name.downcase.gsub(' ', '_').gsub(/[^\w]/, '')
163
+ end
164
+
94
165
  end
95
166
  end
data/lib/runner.rb CHANGED
@@ -17,32 +17,214 @@
17
17
  along with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
  =end
19
19
 
20
- require 'optparse'
20
+ require 'trollop'
21
21
  require 'date'
22
22
 
23
23
  module GitPivot
24
24
  class Runner
25
+ SUB_COMMANDS = %w{current work display start finish note stack push tasks task complete}
26
+ STATE_FILE = "git_pivot.state"
27
+
25
28
  def initialize(args)
26
- @argv = args
27
- process_args
29
+ @method, @cmd, @cmd_opts = process_args(args)
30
+
28
31
  # configuration stuff
29
32
  configuration = YAML.load_file("git_pivot.yml")
33
+ if File.exist?(STATE_FILE)
34
+ File.open(STATE_FILE) do |file|
35
+ @states = Marshal.load(file)
36
+ if @states.is_a?(Array)
37
+ @states.uniq!
38
+ else
39
+ @states = nil
40
+ end
41
+ end
42
+ end
30
43
 
31
- @git_pivot = GitPivot.new(configuration["project_id"], configuration["token"], configuration["owner"])
44
+ @git_pivot = GitPivot.new(configuration["project_id"], configuration["token"], configuration["owner"], configuration["use_git"])
32
45
  end
33
46
 
34
47
  def run
35
- if @arg1
36
- @git_pivot.send(@command, @arg1)
37
- else
38
- @git_pivot.send(@command)
48
+ args = [@method]
49
+ if @method and @git_pivot.method(@method).arity.abs > 0
50
+ if @cmd_opts[:id]
51
+ args << @cmd_opts[:id]
52
+ elsif @states.any?
53
+ args << @states.first
54
+ else
55
+ Trollop::die "Need to specify a story id"
56
+ end
57
+
58
+ if @cmd_opts[:name]
59
+ args << @cmd_opts[:name].join(' ')
60
+ end
61
+ if @cmd_opts[:text]
62
+ args << @cmd_opts[:text].join(' ')
63
+ end
64
+ if @cmd_opts[:"task-id"]
65
+ args << @cmd_opts[:"task-id"]
66
+ end
67
+ end
68
+
69
+ if @method == :start_story
70
+ add_story_to_states(@cmd_opts[:id])
71
+ end
72
+
73
+ if @method
74
+ @git_pivot.send(*args)
75
+ end
76
+
77
+ # must do this after, in case finish fails, don't want to pop
78
+ if @method == :finish_story
79
+ if @states and @states.first == args[1]
80
+ @states.shift
81
+
82
+ save_state
83
+ end
84
+ end
85
+
86
+ case @cmd
87
+ when "stack"
88
+ puts @states
89
+ when "push"
90
+ add_story_to_states(@cmd_opts[:id])
91
+ puts @states
39
92
  end
40
93
  end
41
94
 
42
95
  private
43
- def process_args
44
- @command = @argv.shift
45
- @arg1 = @argv.shift
96
+ def save_state
97
+ File.open(STATE_FILE, 'w') {|file| Marshal.dump(@states, file) }
98
+ end
99
+
100
+ def add_story_to_states(story_id)
101
+ if @states.nil?
102
+ @states = [story_id]
103
+ else
104
+ @states.delete(story_id)
105
+ @states.unshift(story_id)
106
+ end
107
+
108
+ save_state
109
+ end
110
+
111
+ def process_args(args)
112
+ global_opts = Trollop::options do
113
+ banner <<-BANNER
114
+ A command-line interface for Pivotal Tracker.
115
+
116
+ Subcommands:
117
+ current - Lists the stories that are part of the current iteration.
118
+ work - Lists the stories that you own.
119
+ display - Displays information about a specific story.
120
+ start - Marks a story as started.
121
+ finish - Marks a story as finished.
122
+ note - Add a new note to an existing story
123
+ stack - Current Stack of Story ids
124
+ push - Push a story to the top of the Story Stack
125
+ tasks - Display tasks associated to a story
126
+ task - Add a task to the given story
127
+ complete - Mark a task as completed
128
+
129
+ BANNER
130
+ stop_on SUB_COMMANDS
131
+ end
132
+
133
+ command = nil
134
+ cmd = args.shift
135
+ cmd_opts = case cmd
136
+ when "current"
137
+ command = :current_sprint
138
+
139
+ Trollop::options(args) do
140
+ banner "Lists the stories that are part of the current iteration."
141
+ end
142
+ when "work"
143
+ command = :my_work
144
+
145
+ # FIXME: This help message doesn't appear with a 'git_pivot work -h', but the 'git_pivot current -h' message does.
146
+ Trollop::options(args) do
147
+ banner "Lists the stories that you own."
148
+ end
149
+ when "display"
150
+ command = :display_story
151
+
152
+ Trollop::options(args) do
153
+ banner "Display information about a specific story."
154
+
155
+ opt :id, "The id of the story to display.", :type => Integer
156
+ end
157
+ when "start"
158
+ command = :start_story
159
+
160
+ Trollop::options(args) do
161
+ banner "Marks a specific story as started."
162
+
163
+ opt :id, "The id of the story to start.", :required => true, :type => Integer
164
+ opt :name, "Topic branch name", :type => :strings
165
+ end
166
+ when "finish"
167
+ command = :finish_story
168
+
169
+ Trollop::options(args) do
170
+ banner "Marks a specific story as finished."
171
+
172
+ opt :id, "The id of the story to finish.", :type => Integer
173
+ end
174
+ when "note"
175
+ command = :add_note
176
+
177
+ Trollop::options(args) do
178
+ banner "Adds a note to the story."
179
+
180
+ opt :id, "The id of the story to finish.", :type => Integer
181
+ opt :text, "The text of the note.", :required => true, :type => :strings
182
+ end
183
+ when "stack"
184
+ command = nil
185
+
186
+ Trollop::options(args) do
187
+ banner "Displays the stack of story ids."
188
+ end
189
+ when "push"
190
+ command = nil
191
+
192
+ Trollop::options(args) do
193
+ banner "Push story to the top of the story stack."
194
+
195
+ opt :id, "The id of the story.", :type => Integer
196
+ end
197
+ when "tasks"
198
+ command = :tasks
199
+
200
+ Trollop::options(args) do
201
+ banner "Tasks for a given story."
202
+
203
+ opt :id, "The id of the story.", :type => Integer
204
+ end
205
+ when "task"
206
+ command = :add_task
207
+
208
+ Trollop::options(args) do
209
+ banner "Add a task to the story."
210
+
211
+ opt :id, "The id of the story.", :type => Integer
212
+ opt :text, "The text of the task.", :required => true, :type => :strings
213
+ end
214
+ when "complete"
215
+ command = :complete_task
216
+
217
+ Trollop::options(args) do
218
+ banner "Complete a task"
219
+
220
+ opt :id, "The id of the story.", :type => Integer
221
+ opt :"task-id", "The id of the task.", :required => true, :type => Integer
222
+ end
223
+ else
224
+ Trollop::die "unknown subcommand #{cmd.inspect}"
225
+ end
226
+
227
+ [command, cmd, cmd_opts]
46
228
  end
47
229
  end
48
230
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hone-git_pivot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - hone
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-29 00:00:00 -07:00
12
+ date: 2009-09-08 00:00:00 -07:00
13
13
  default_executable: git_pivot
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,16 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: "0"
34
34
  version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: git
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
35
45
  description: "TODO: longer description of your gem"
36
46
  email: hone02@gmail.com
37
47
  executables:
@@ -47,13 +57,14 @@ files:
47
57
  - LICENSE
48
58
  - README.rdoc
49
59
  - Rakefile
60
+ - VERSION
50
61
  - bin/git_pivot
51
62
  - git_pivot.gemspec
63
+ - git_pivot.yml.example
52
64
  - lib/git_pivot.rb
53
65
  - lib/runner.rb
54
66
  has_rdoc: true
55
67
  homepage: http://github.com/hone/git_pivot
56
- licenses:
57
68
  post_install_message:
58
69
  rdoc_options:
59
70
  - --charset=UTF-8
@@ -74,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
85
  requirements: []
75
86
 
76
87
  rubyforge_project:
77
- rubygems_version: 1.3.5
88
+ rubygems_version: 1.2.0
78
89
  signing_key:
79
90
  specification_version: 2
80
91
  summary: "TODO: one-line summary of your gem"