story_branch 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.story_branch.yml +5 -0
- data/Gemfile.lock +16 -15
- data/README.md +42 -26
- data/lib/story_branch/commands/add.rb +13 -1
- data/lib/story_branch/github/issue.rb +36 -0
- data/lib/story_branch/github/label.rb +14 -0
- data/lib/story_branch/github/milestone.rb +20 -0
- data/lib/story_branch/github/project.rb +24 -0
- data/lib/story_branch/github/tracker.rb +58 -0
- data/lib/story_branch/main.rb +67 -33
- data/lib/story_branch/pivotal/project.rb +28 -0
- data/lib/story_branch/pivotal/story.rb +40 -0
- data/lib/story_branch/pivotal/tracker.rb +60 -0
- data/lib/story_branch/version.rb +1 -1
- data/story_branch.gemspec +3 -3
- metadata +29 -21
- data/lib/story_branch/pivotal_utils.rb +0 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c52f21039ded483c26995d245057c6679485dc75
|
4
|
+
data.tar.gz: a01c935ed4fa49332635a6df573ba5f9b27fa577
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b38676bf0947c462aeece49697c520afc88701a87e993810a19b0cb78408a53ceb17cb37771994aabf9eba71f06edb6e80ac02e223669345b3d9fc3c0d73ad1
|
7
|
+
data.tar.gz: b6b6d43fb4ef939797a648e8c68dcb96a901d1d05de00e199e8575d8b8c96ec78179ecf7d5cb2a90370ab37b79338c8679d8a478dd7c71b37525df16c37491ff
|
data/.gitignore
CHANGED
data/.story_branch.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
story_branch (0.
|
4
|
+
story_branch (0.5.0)
|
5
5
|
blanket_wrapper (~> 3.0)
|
6
6
|
levenshtein-ffi (~> 1.0)
|
7
|
-
pastel (~> 0.7.2)
|
8
7
|
thor (~> 0.20.0)
|
9
8
|
tty-command (~> 0.8.2)
|
10
9
|
tty-config (~> 0.2.0)
|
11
|
-
tty-pager (~> 0.
|
12
|
-
tty-prompt (~> 0.
|
10
|
+
tty-pager (~> 0.12)
|
11
|
+
tty-prompt (~> 0.18)
|
13
12
|
|
14
13
|
GEM
|
15
14
|
remote: https://rubygems.org/
|
@@ -22,7 +21,7 @@ GEM
|
|
22
21
|
fakefs (0.18.0)
|
23
22
|
ffi (1.10.0)
|
24
23
|
git (1.5.0)
|
25
|
-
httparty (0.16.
|
24
|
+
httparty (0.16.4)
|
26
25
|
mime-types (~> 3.0)
|
27
26
|
multi_xml (>= 0.5.2)
|
28
27
|
levenshtein-ffi (1.1.0)
|
@@ -32,6 +31,7 @@ GEM
|
|
32
31
|
mime-types-data (3.2018.0812)
|
33
32
|
multi_xml (0.6.0)
|
34
33
|
necromancer (0.4.0)
|
34
|
+
ostruct (0.1.0)
|
35
35
|
pastel (0.7.2)
|
36
36
|
equatable (~> 0.5.0)
|
37
37
|
tty-color (~> 0.4.0)
|
@@ -58,29 +58,29 @@ GEM
|
|
58
58
|
unicode_utils (~> 1.4.0)
|
59
59
|
strings-ansi (0.1.0)
|
60
60
|
thor (0.20.3)
|
61
|
-
timers (4.
|
61
|
+
timers (4.3.0)
|
62
62
|
tty-color (0.4.3)
|
63
63
|
tty-command (0.8.2)
|
64
64
|
pastel (~> 0.7.0)
|
65
65
|
tty-config (0.2.0)
|
66
66
|
tty-cursor (0.6.0)
|
67
|
-
tty-pager (0.
|
68
|
-
strings (~> 0.1.
|
69
|
-
tty-screen (~> 0.6
|
70
|
-
tty-which (~> 0.
|
71
|
-
tty-prompt (0.
|
67
|
+
tty-pager (0.12.0)
|
68
|
+
strings (~> 0.1.4)
|
69
|
+
tty-screen (~> 0.6)
|
70
|
+
tty-which (~> 0.4)
|
71
|
+
tty-prompt (0.18.1)
|
72
72
|
necromancer (~> 0.4.0)
|
73
73
|
pastel (~> 0.7.0)
|
74
74
|
timers (~> 4.0)
|
75
75
|
tty-cursor (~> 0.6.0)
|
76
|
-
tty-reader (~> 0.
|
77
|
-
tty-reader (0.
|
76
|
+
tty-reader (~> 0.5.0)
|
77
|
+
tty-reader (0.5.0)
|
78
78
|
tty-cursor (~> 0.6.0)
|
79
79
|
tty-screen (~> 0.6.4)
|
80
80
|
wisper (~> 2.0.0)
|
81
81
|
tty-screen (0.6.5)
|
82
|
-
tty-which (0.
|
83
|
-
unicode-display_width (1.4.
|
82
|
+
tty-which (0.4.0)
|
83
|
+
unicode-display_width (1.4.1)
|
84
84
|
unicode_utils (1.4.0)
|
85
85
|
wisper (2.0.0)
|
86
86
|
|
@@ -91,6 +91,7 @@ DEPENDENCIES
|
|
91
91
|
bundler (~> 1.16)
|
92
92
|
fakefs (~> 0.14)
|
93
93
|
git (~> 1.5)
|
94
|
+
ostruct (~> 0.1)
|
94
95
|
rake (~> 10.0)
|
95
96
|
rspec (~> 3)
|
96
97
|
rspec_junit_formatter (~> 0.4)
|
data/README.md
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
|
4
4
|
# Story Branch
|
5
5
|
|
6
|
-
Story branch is a CLI application that interacts with Pivotal Tracker at the
|
7
|
-
at the moment.
|
6
|
+
Story branch is a CLI application that interacts with Pivotal Tracker or Github at the
|
7
|
+
at the moment.
|
8
|
+
It allows you to start and un-start stories in Pivotal Tracker, as well as creating
|
8
9
|
branches based on the story name and id and have a final commit message marking
|
9
10
|
the story as Finished.
|
10
11
|
|
@@ -81,30 +82,6 @@ The one in your project root will keep a reference to the project configuration.
|
|
81
82
|
For now, this reference is the project id. This file can be safely committed to
|
82
83
|
the repository and shared amongst your co-workers.
|
83
84
|
|
84
|
-
## Migrating
|
85
|
-
|
86
|
-
### Old configuration
|
87
|
-
|
88
|
-
If your were using story branch before there are some small changes on the way the
|
89
|
-
tool works. But worry not, we've written a command that allows you to migrate your
|
90
|
-
configuration. Running
|
91
|
-
|
92
|
-
`$ story_branch migrate`
|
93
|
-
|
94
|
-
will grab your existing configuration and convert it into the new format. The only
|
95
|
-
thing you'll need to provide is the project name reference.
|
96
|
-
|
97
|
-
### Old commands
|
98
|
-
|
99
|
-
Story branch was built providing a set of bin commands such as `git-story`, `git-finish`, `git-start` and `git-unstart`. These will be available still as
|
100
|
-
we try as much as possible to keep the updates retro-compatible, but are nothing
|
101
|
-
more than an alias for the CLI commands as follow:
|
102
|
-
|
103
|
-
- `git-story` runs `story_branch create`
|
104
|
-
- `git-finish` runs `story_branch finish`
|
105
|
-
- `git-start` runs `story_branch start`
|
106
|
-
- `git-unstart` runs `story_branch unstart`
|
107
|
-
|
108
85
|
## Commentary
|
109
86
|
|
110
87
|
`story_branch create`: Creates a git branch with automatic reference to a
|
@@ -133,6 +110,45 @@ It'll get all started stories in your current project. You can
|
|
133
110
|
enter text and press TAB to search for a story name, or TAB to show
|
134
111
|
the full list.
|
135
112
|
|
113
|
+
## Configuring PivotalTracker
|
114
|
+
|
115
|
+
When running the command `story_branch add` you'll be asked 3 things:
|
116
|
+
1. project id - This can be fetched from the PivotalTracker url. E.g in the url `https://www.pivotaltracker.com/n/projects/651417`, the project id would be `651417`
|
117
|
+
2. tracker - You should select Pivotal Tracker
|
118
|
+
3. api key - this is your personal api key. You can get that from [your profile page](https://www.pivotaltracker.com/profile)
|
119
|
+
|
120
|
+
## Configuring Github
|
121
|
+
|
122
|
+
When running the command `story_branch add` you'll be asked 3 things:
|
123
|
+
1. project id - This is the github repository name in the format `<owner>/<repo_name>`. E.g. `story-branch/story_branch`.
|
124
|
+
2. tracker - You should select Github
|
125
|
+
3. api key - this is your personal api token. You can create one under your
|
126
|
+
[developer profile tokens page](https://github.com/settings/tokens)
|
127
|
+
|
128
|
+
## Migrating
|
129
|
+
|
130
|
+
### Old configuration
|
131
|
+
|
132
|
+
If your were using story branch before there are some small changes on the way the
|
133
|
+
tool works. But worry not, we've written a command that allows you to migrate your
|
134
|
+
configuration. Running
|
135
|
+
|
136
|
+
`$ story_branch migrate`
|
137
|
+
|
138
|
+
will grab your existing configuration and convert it into the new format. The only
|
139
|
+
thing you'll need to provide is the project name reference.
|
140
|
+
|
141
|
+
### Old commands
|
142
|
+
|
143
|
+
Story branch was built providing a set of bin commands such as `git-story`, `git-finish`, `git-start` and `git-unstart`. These will be available still as
|
144
|
+
we try as much as possible to keep the updates retro-compatible, but are nothing
|
145
|
+
more than an alias for the CLI commands as follow:
|
146
|
+
|
147
|
+
- `git-story` runs `story_branch create`
|
148
|
+
- `git-finish` runs `story_branch finish`
|
149
|
+
- `git-start` runs `story_branch start`
|
150
|
+
- `git-unstart` runs `story_branch unstart`
|
151
|
+
|
136
152
|
## Contributing
|
137
153
|
|
138
154
|
All pull requests are welcome and will be reviewed.
|
@@ -32,6 +32,9 @@ module StoryBranch
|
|
32
32
|
|
33
33
|
puts "Appending #{project_id}"
|
34
34
|
@local_config.append(project_id, to: :project_id)
|
35
|
+
|
36
|
+
puts "Setting #{tracker}"
|
37
|
+
@local_config.set(:tracker, value: tracker)
|
35
38
|
@local_config.write(force: true)
|
36
39
|
end
|
37
40
|
|
@@ -45,7 +48,16 @@ module StoryBranch
|
|
45
48
|
return @project_id if @project_id
|
46
49
|
|
47
50
|
@project_id = prompt.ask "Please provide this project's id:"
|
48
|
-
|
51
|
+
end
|
52
|
+
|
53
|
+
def tracker
|
54
|
+
return @tracker if @tracker
|
55
|
+
|
56
|
+
trackers = {
|
57
|
+
'Pivotal Tracker' => 'pivotal-tracker',
|
58
|
+
'Github' => 'github'
|
59
|
+
}
|
60
|
+
@tracker = prompt.select('Which tracker are you using?', trackers)
|
49
61
|
end
|
50
62
|
|
51
63
|
def local_config_has_value?
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './label'
|
4
|
+
require_relative './milestone'
|
5
|
+
|
6
|
+
module StoryBranch
|
7
|
+
module Github
|
8
|
+
# GitHub Issue representation
|
9
|
+
class Issue
|
10
|
+
attr_accessor :title, :id
|
11
|
+
|
12
|
+
def initialize(blanket_story, repo)
|
13
|
+
@repo = repo
|
14
|
+
@story = blanket_story
|
15
|
+
@title = blanket_story.title
|
16
|
+
@id = blanket_story.number
|
17
|
+
@labels = blanket_story.labels.map { |label| Label.new(label) }
|
18
|
+
@milestone = if blanket_story.milestone
|
19
|
+
Milestone.new(blanket_story.milestone)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_state
|
24
|
+
puts 'What to do in github for this?'
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{@id} - #{@title} [#{@milestone}]"
|
29
|
+
end
|
30
|
+
|
31
|
+
def dashed_title
|
32
|
+
StoryBranch::StringUtils.normalised_branch_name @title
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StoryBranch
|
4
|
+
module Github
|
5
|
+
# Github Labels representation
|
6
|
+
class Label
|
7
|
+
attr_accessor :name, :color
|
8
|
+
def initialize(label_data)
|
9
|
+
@name = label_data.name
|
10
|
+
@color = label_data.color
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StoryBranch
|
4
|
+
module Github
|
5
|
+
# Github Milestones representation
|
6
|
+
class Milestone
|
7
|
+
attr_accessor :id, :title, :description
|
8
|
+
|
9
|
+
def initialize(milestone_data)
|
10
|
+
@id = milestone_data.number
|
11
|
+
@title = milestone_data.title
|
12
|
+
@description = milestone_data.description
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"MS: #{@title} - #{@description}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './issue'
|
4
|
+
|
5
|
+
module StoryBranch
|
6
|
+
module Github
|
7
|
+
# Github API Repository Representation
|
8
|
+
class Project
|
9
|
+
def initialize(blanket_project)
|
10
|
+
@repo = blanket_project
|
11
|
+
end
|
12
|
+
|
13
|
+
def stories(options = {})
|
14
|
+
stories = if options[:id]
|
15
|
+
[@repo.issues(options[:id]).get.payload]
|
16
|
+
else
|
17
|
+
@repo.issues.get(params: options).payload
|
18
|
+
end
|
19
|
+
stories.reject!(&:pull_request)
|
20
|
+
stories.map { |s| Issue.new(s, @repo) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'blanket'
|
4
|
+
require_relative './project'
|
5
|
+
|
6
|
+
module StoryBranch
|
7
|
+
module Github
|
8
|
+
# Github API wrapper for story branch tracker
|
9
|
+
class Tracker
|
10
|
+
API_URL = 'https://api.github.com/'
|
11
|
+
TYPE = 'github'
|
12
|
+
|
13
|
+
attr_reader :type
|
14
|
+
|
15
|
+
def initialize(repo_name, api_key)
|
16
|
+
# NOTE: RepoName should follow owner/repo_name format
|
17
|
+
@repo_name = repo_name
|
18
|
+
@api_key = api_key
|
19
|
+
@type = TYPE
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?
|
23
|
+
!@api_key.nil? && !@repo_name.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO: This should probably be renamed to something more meaningful
|
27
|
+
# in the sense that it should be workable stories/issues
|
28
|
+
# which depend on the tracker's workflow. PivotalTracker they need to
|
29
|
+
# be started and estimated, while for Github they just need to be open
|
30
|
+
def stories
|
31
|
+
project.stories
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_story_by_id(story_id)
|
35
|
+
project.stories(id: story_id).first
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def api
|
41
|
+
raise 'API key must be specified' unless @api_key
|
42
|
+
|
43
|
+
Blanket.wrap API_URL, headers: {
|
44
|
+
'User-Agent' => 'Story Branch',
|
45
|
+
Authorization: "token #{@api_key}"
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def project
|
50
|
+
return @project if @project
|
51
|
+
raise 'repo name must be set' unless @repo_name
|
52
|
+
|
53
|
+
blanket_project = api.repos(@repo_name)
|
54
|
+
@project = Project.new blanket_project
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/story_branch/main.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './
|
3
|
+
require_relative './pivotal/tracker'
|
4
|
+
require_relative './github/tracker'
|
4
5
|
require_relative './git_utils'
|
5
6
|
require_relative './git_wrapper'
|
6
7
|
require_relative './config_manager'
|
@@ -25,7 +26,7 @@ module StoryBranch
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def create_story_branch
|
28
|
-
stories = @tracker.
|
29
|
+
stories = @tracker.stories
|
29
30
|
if stories.empty?
|
30
31
|
prompt.say 'No stories started, exiting'
|
31
32
|
return
|
@@ -38,30 +39,9 @@ module StoryBranch
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def story_finish
|
41
|
-
current_story =
|
42
|
-
|
43
|
-
|
44
|
-
return
|
45
|
-
end
|
46
|
-
|
47
|
-
if GitUtils.status?(:untracked) || GitUtils.status?(:modified)
|
48
|
-
message = <<~MESSAGE
|
49
|
-
There are unstaged changes
|
50
|
-
Use git add to stage changes before running git finish
|
51
|
-
Use git stash if you want to hide changes for this commit
|
52
|
-
MESSAGE
|
53
|
-
prompt.say message
|
54
|
-
return
|
55
|
-
end
|
56
|
-
|
57
|
-
unless GitUtils.status?(:added) || GitUtils.status?(:staged)
|
58
|
-
message = <<~MESSAGE
|
59
|
-
There are no staged changes.
|
60
|
-
Nothing to do.
|
61
|
-
MESSAGE
|
62
|
-
prompt.say message
|
63
|
-
return
|
64
|
-
end
|
42
|
+
current_story = tracked_story
|
43
|
+
return if unstaged_changes?
|
44
|
+
return if nothing_to_add?
|
65
45
|
|
66
46
|
commit_message = "[#{finish_tag} ##{current_story[:id]}] #{current_story[:title]}"
|
67
47
|
proceed = prompt.yes?("Commit with standard message? #{commit_message}")
|
@@ -72,18 +52,68 @@ module StoryBranch
|
|
72
52
|
end
|
73
53
|
end
|
74
54
|
|
55
|
+
# NOTE: This feature is only available for pivotal tracker at the moment
|
56
|
+
# as for github there is no use case
|
75
57
|
def story_start
|
76
|
-
|
58
|
+
return unless require_pivotal
|
59
|
+
|
60
|
+
story = update_status('unstarted', 'started', 'start')
|
61
|
+
create_feature_branch story
|
77
62
|
end
|
78
63
|
|
64
|
+
# NOTE: This feature is only available for pivotal tracker at the moment
|
65
|
+
# as for github there is no use case
|
79
66
|
def story_unstart
|
67
|
+
return unless require_pivotal
|
68
|
+
|
80
69
|
update_status('started', 'unstarted', 'unstart')
|
81
70
|
end
|
82
71
|
|
83
72
|
private
|
84
73
|
|
74
|
+
def require_pivotal
|
75
|
+
if @tracker.type != 'pivotal'
|
76
|
+
prompt.say 'The configured tracker does not support this feature'
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
def tracked_story
|
83
|
+
current_story = GitUtils.current_branch_story_parts
|
84
|
+
if !current_story.empty? && @tracker.get_story_by_id(current_story[:id])
|
85
|
+
return current_story
|
86
|
+
end
|
87
|
+
|
88
|
+
prompt.error('No tracked feature associated with this branch')
|
89
|
+
end
|
90
|
+
|
91
|
+
def unstaged_changes?
|
92
|
+
unless GitUtils.status?(:untracked) || GitUtils.status?(:modified)
|
93
|
+
return false
|
94
|
+
end
|
95
|
+
|
96
|
+
message = <<~MESSAGE
|
97
|
+
There are unstaged changes
|
98
|
+
Use git add to stage changes before running git finish
|
99
|
+
Use git stash if you want to hide changes for this commit
|
100
|
+
MESSAGE
|
101
|
+
prompt.say message
|
102
|
+
end
|
103
|
+
|
104
|
+
def nothing_to_add?
|
105
|
+
return false if GitUtils.status?(:added) || GitUtils.status?(:staged)
|
106
|
+
|
107
|
+
message = <<~MESSAGE
|
108
|
+
There are no staged changes.
|
109
|
+
Nothing to do.
|
110
|
+
MESSAGE
|
111
|
+
prompt.say message
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
85
115
|
def update_status(current_status, next_status, action)
|
86
|
-
stories = @tracker.
|
116
|
+
stories = @tracker.stories_with_state(current_status)
|
87
117
|
if stories.empty?
|
88
118
|
prompt.say "No #{current_status} stories, exiting"
|
89
119
|
return
|
@@ -102,6 +132,7 @@ module StoryBranch
|
|
102
132
|
return
|
103
133
|
end
|
104
134
|
prompt.ok("#{story.id} #{next_status}")
|
135
|
+
story
|
105
136
|
end
|
106
137
|
|
107
138
|
def build_stories_structure(stories)
|
@@ -171,10 +202,7 @@ module StoryBranch
|
|
171
202
|
end
|
172
203
|
|
173
204
|
def api_key
|
174
|
-
|
175
|
-
|
176
|
-
@api_key = @global_config.fetch(project_id, :api_key)
|
177
|
-
@api_key
|
205
|
+
@api_key || @api_key = @global_config.fetch(project_id, :api_key)
|
178
206
|
end
|
179
207
|
|
180
208
|
def initialize_tracker
|
@@ -182,7 +210,13 @@ module StoryBranch
|
|
182
210
|
prompt.say 'Project ID not set'
|
183
211
|
exit 0
|
184
212
|
end
|
185
|
-
|
213
|
+
tracker_type = @local_config.fetch(:tracker, default: 'pivotal-tracker')
|
214
|
+
@tracker = case tracker_type
|
215
|
+
when 'github'
|
216
|
+
StoryBranch::Github::Tracker.new(project_id, api_key)
|
217
|
+
else
|
218
|
+
StoryBranch::Pivotal::Tracker.new(project_id, api_key)
|
219
|
+
end
|
186
220
|
end
|
187
221
|
end
|
188
222
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './story'
|
4
|
+
|
5
|
+
module StoryBranch
|
6
|
+
module Pivotal
|
7
|
+
# PivotalTracker Project representation
|
8
|
+
class Project
|
9
|
+
def initialize(blanket_project)
|
10
|
+
@project = blanket_project
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns an array of PT Stories (Story Class)
|
14
|
+
# TODO: add other possible args
|
15
|
+
def stories(options = {}, estimated = true)
|
16
|
+
stories = if options[:id]
|
17
|
+
[@project.stories(options[:id]).get.payload]
|
18
|
+
else
|
19
|
+
@project.stories.get(params: options).payload
|
20
|
+
end
|
21
|
+
stories = stories.map { |s| Story.new(s, @project) }
|
22
|
+
return stories if estimated == false
|
23
|
+
|
24
|
+
stories.select(&:estimated)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../string_utils'
|
4
|
+
|
5
|
+
module StoryBranch
|
6
|
+
module Pivotal
|
7
|
+
# PivotalTracker Story representation
|
8
|
+
class Story
|
9
|
+
NON_ESTIMATED_TYPES = %w[chore bug release].freeze
|
10
|
+
attr_accessor :title, :id
|
11
|
+
|
12
|
+
def initialize(blanket_story, project)
|
13
|
+
@project = project
|
14
|
+
@story = blanket_story
|
15
|
+
@title = blanket_story.name
|
16
|
+
@id = blanket_story.id
|
17
|
+
@story_type = blanket_story.story_type
|
18
|
+
@estimate = blanket_story.estimate
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_state(new_state)
|
22
|
+
params = { current_state: new_state }
|
23
|
+
@project.stories(@id).put(body: params).payload
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"#{@id} - #{@title}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def dashed_title
|
31
|
+
StoryBranch::StringUtils.normalised_branch_name @title
|
32
|
+
end
|
33
|
+
|
34
|
+
def estimated
|
35
|
+
(@story_type == 'feature' && !@estimate.nil?) ||
|
36
|
+
NON_ESTIMATED_TYPES.include?(@story_type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'blanket'
|
4
|
+
require_relative './project'
|
5
|
+
|
6
|
+
module StoryBranch
|
7
|
+
module Pivotal
|
8
|
+
# Utility class for integration with PivotalTracker. It relies on Blanket
|
9
|
+
# wrapper to communicate with pivotal tracker's api.
|
10
|
+
class Tracker
|
11
|
+
API_URL = 'https://www.pivotaltracker.com/services/v5/'
|
12
|
+
TYPE = 'pivotal'
|
13
|
+
|
14
|
+
attr_reader :type
|
15
|
+
|
16
|
+
def initialize(project_id, api_key)
|
17
|
+
@project_id = project_id
|
18
|
+
@api_key = api_key
|
19
|
+
@type = TYPE
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?
|
23
|
+
!@api_key.nil? && !@project_id.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO: This should probably be renamed to something more meaningful
|
27
|
+
# in the sense that it should be workable stories/issues
|
28
|
+
# which depend on the tracker's workflow. PivotalTracker they need to
|
29
|
+
# be started and estimated, while for Github they just need to be open
|
30
|
+
def stories
|
31
|
+
stories_with_state('started')
|
32
|
+
end
|
33
|
+
|
34
|
+
def stories_with_state(state)
|
35
|
+
project.stories(with_state: state)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_story_by_id(story_id)
|
39
|
+
project.stories(id: story_id).first
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def api
|
45
|
+
raise 'API key must be specified' unless @api_key
|
46
|
+
|
47
|
+
Blanket.wrap API_URL, headers: { 'X-TrackerToken' => @api_key }
|
48
|
+
end
|
49
|
+
|
50
|
+
def project
|
51
|
+
return @project if @project
|
52
|
+
raise 'Project ID must be set' unless @project_id
|
53
|
+
|
54
|
+
blanket_project = api.projects(@project_id.to_i)
|
55
|
+
@project = Project.new blanket_project
|
56
|
+
@project
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/story_branch/version.rb
CHANGED
data/story_branch.gemspec
CHANGED
@@ -54,16 +54,16 @@ Gem::Specification.new do |spec|
|
|
54
54
|
|
55
55
|
spec.add_runtime_dependency 'blanket_wrapper', '~> 3.0'
|
56
56
|
spec.add_runtime_dependency 'levenshtein-ffi', '~> 1.0'
|
57
|
-
spec.add_runtime_dependency 'pastel', '~> 0.7.2'
|
58
57
|
spec.add_runtime_dependency 'thor', '~> 0.20.0'
|
59
58
|
spec.add_runtime_dependency 'tty-command', '~> 0.8.2'
|
60
59
|
spec.add_runtime_dependency 'tty-config', '~> 0.2.0'
|
61
|
-
spec.add_runtime_dependency 'tty-pager', '~> 0.
|
62
|
-
spec.add_runtime_dependency 'tty-prompt', '~> 0.
|
60
|
+
spec.add_runtime_dependency 'tty-pager', '~> 0.12'
|
61
|
+
spec.add_runtime_dependency 'tty-prompt', '~> 0.18'
|
63
62
|
|
64
63
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
65
64
|
spec.add_development_dependency 'fakefs', '~> 0.14'
|
66
65
|
spec.add_development_dependency 'git', '~> 1.5'
|
66
|
+
spec.add_development_dependency 'ostruct', '~> 0.1'
|
67
67
|
spec.add_development_dependency 'rake', '~> 10.0'
|
68
68
|
spec.add_development_dependency 'rspec', '~> 3'
|
69
69
|
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: story_branch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rui Baltazar
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: exe
|
14
14
|
cert_chain: []
|
15
|
-
date: 2019-
|
15
|
+
date: 2019-03-04 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: blanket_wrapper
|
@@ -42,20 +42,6 @@ dependencies:
|
|
42
42
|
- - "~>"
|
43
43
|
- !ruby/object:Gem::Version
|
44
44
|
version: '1.0'
|
45
|
-
- !ruby/object:Gem::Dependency
|
46
|
-
name: pastel
|
47
|
-
requirement: !ruby/object:Gem::Requirement
|
48
|
-
requirements:
|
49
|
-
- - "~>"
|
50
|
-
- !ruby/object:Gem::Version
|
51
|
-
version: 0.7.2
|
52
|
-
type: :runtime
|
53
|
-
prerelease: false
|
54
|
-
version_requirements: !ruby/object:Gem::Requirement
|
55
|
-
requirements:
|
56
|
-
- - "~>"
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
version: 0.7.2
|
59
45
|
- !ruby/object:Gem::Dependency
|
60
46
|
name: thor
|
61
47
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,28 +90,28 @@ dependencies:
|
|
104
90
|
requirements:
|
105
91
|
- - "~>"
|
106
92
|
- !ruby/object:Gem::Version
|
107
|
-
version: 0.
|
93
|
+
version: '0.12'
|
108
94
|
type: :runtime
|
109
95
|
prerelease: false
|
110
96
|
version_requirements: !ruby/object:Gem::Requirement
|
111
97
|
requirements:
|
112
98
|
- - "~>"
|
113
99
|
- !ruby/object:Gem::Version
|
114
|
-
version: 0.
|
100
|
+
version: '0.12'
|
115
101
|
- !ruby/object:Gem::Dependency
|
116
102
|
name: tty-prompt
|
117
103
|
requirement: !ruby/object:Gem::Requirement
|
118
104
|
requirements:
|
119
105
|
- - "~>"
|
120
106
|
- !ruby/object:Gem::Version
|
121
|
-
version: 0.
|
107
|
+
version: '0.18'
|
122
108
|
type: :runtime
|
123
109
|
prerelease: false
|
124
110
|
version_requirements: !ruby/object:Gem::Requirement
|
125
111
|
requirements:
|
126
112
|
- - "~>"
|
127
113
|
- !ruby/object:Gem::Version
|
128
|
-
version: 0.
|
114
|
+
version: '0.18'
|
129
115
|
- !ruby/object:Gem::Dependency
|
130
116
|
name: bundler
|
131
117
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,6 +154,20 @@ dependencies:
|
|
168
154
|
- - "~>"
|
169
155
|
- !ruby/object:Gem::Version
|
170
156
|
version: '1.5'
|
157
|
+
- !ruby/object:Gem::Dependency
|
158
|
+
name: ostruct
|
159
|
+
requirement: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - "~>"
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0.1'
|
164
|
+
type: :development
|
165
|
+
prerelease: false
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - "~>"
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0.1'
|
171
171
|
- !ruby/object:Gem::Dependency
|
172
172
|
name: rake
|
173
173
|
requirement: !ruby/object:Gem::Requirement
|
@@ -236,6 +236,7 @@ files:
|
|
236
236
|
- ".gitignore"
|
237
237
|
- ".rspec"
|
238
238
|
- ".ruby-version"
|
239
|
+
- ".story_branch.yml"
|
239
240
|
- Changelog.md
|
240
241
|
- Gemfile
|
241
242
|
- Gemfile.lock
|
@@ -261,8 +262,15 @@ files:
|
|
261
262
|
- lib/story_branch/config_manager.rb
|
262
263
|
- lib/story_branch/git_utils.rb
|
263
264
|
- lib/story_branch/git_wrapper.rb
|
265
|
+
- lib/story_branch/github/issue.rb
|
266
|
+
- lib/story_branch/github/label.rb
|
267
|
+
- lib/story_branch/github/milestone.rb
|
268
|
+
- lib/story_branch/github/project.rb
|
269
|
+
- lib/story_branch/github/tracker.rb
|
264
270
|
- lib/story_branch/main.rb
|
265
|
-
- lib/story_branch/
|
271
|
+
- lib/story_branch/pivotal/project.rb
|
272
|
+
- lib/story_branch/pivotal/story.rb
|
273
|
+
- lib/story_branch/pivotal/tracker.rb
|
266
274
|
- lib/story_branch/string_utils.rb
|
267
275
|
- lib/story_branch/templates/.gitkeep
|
268
276
|
- lib/story_branch/templates/add/.gitkeep
|
@@ -1,107 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'blanket'
|
4
|
-
require_relative './string_utils'
|
5
|
-
|
6
|
-
module StoryBranch
|
7
|
-
# PivotalTracker Story representation
|
8
|
-
class Story
|
9
|
-
NON_ESTIMATED_TYPES = %w[chore bug release].freeze
|
10
|
-
attr_accessor :title, :id
|
11
|
-
|
12
|
-
def initialize(blanket_story, project)
|
13
|
-
@project = project
|
14
|
-
@story = blanket_story
|
15
|
-
@title = blanket_story.name
|
16
|
-
@id = blanket_story.id
|
17
|
-
@story_type = blanket_story.story_type
|
18
|
-
@estimate = blanket_story.estimate
|
19
|
-
end
|
20
|
-
|
21
|
-
def update_state(new_state)
|
22
|
-
params = { current_state: new_state }
|
23
|
-
@project.stories(@id).put(body: params).payload
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_s
|
27
|
-
"#{@id} - #{@title}"
|
28
|
-
end
|
29
|
-
|
30
|
-
def dashed_title
|
31
|
-
StoryBranch::StringUtils.normalised_branch_name @title
|
32
|
-
end
|
33
|
-
|
34
|
-
def estimated
|
35
|
-
(@story_type == 'feature' && !@estimate.nil?) ||
|
36
|
-
NON_ESTIMATED_TYPES.include?(@story_type)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# PivotalTracker Project representation
|
41
|
-
class Project
|
42
|
-
def initialize(blanket_project)
|
43
|
-
@project = blanket_project
|
44
|
-
end
|
45
|
-
|
46
|
-
# NOTE: takes in possible keys:
|
47
|
-
# - with_state
|
48
|
-
# Returns an array of PT Stories (Story Class)
|
49
|
-
# TODO: add other possible args
|
50
|
-
def stories(options = {}, estimated = true)
|
51
|
-
stories = if options[:id]
|
52
|
-
[@project.stories(options[:id]).get.payload]
|
53
|
-
else
|
54
|
-
params = { with_state: options[:with_state] }
|
55
|
-
@project.stories.get(params: params).payload
|
56
|
-
end
|
57
|
-
stories = stories.map { |s| Story.new(s, @project) }
|
58
|
-
return stories if estimated == false
|
59
|
-
|
60
|
-
stories.select(&:estimated)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Utility class for integration with PivotalTracker. It relies on Blanket
|
65
|
-
# wrapper to communicate with pivotal tracker's api.
|
66
|
-
class PivotalUtils
|
67
|
-
API_URL = 'https://www.pivotaltracker.com/services/v5/'
|
68
|
-
|
69
|
-
def initialize(project_id, api_key)
|
70
|
-
@project_id = project_id
|
71
|
-
@api_key = api_key
|
72
|
-
end
|
73
|
-
|
74
|
-
def valid?
|
75
|
-
!@api_key.nil? && !@project_id.nil?
|
76
|
-
end
|
77
|
-
|
78
|
-
# TODO: Maybe add some other predicates
|
79
|
-
# - Filtering on where a story lives (Backlog, IceBox)
|
80
|
-
# - Filtering on labels
|
81
|
-
# - Filtering on story type
|
82
|
-
def get_stories(state)
|
83
|
-
project.stories(with_state: state)
|
84
|
-
end
|
85
|
-
|
86
|
-
def get_story_by_id(story_id)
|
87
|
-
project.stories(id: story_id).first
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
def api
|
93
|
-
raise 'API key must be specified' unless @api_key
|
94
|
-
|
95
|
-
Blanket.wrap API_URL, headers: { 'X-TrackerToken' => @api_key }
|
96
|
-
end
|
97
|
-
|
98
|
-
def project
|
99
|
-
return @project if @project
|
100
|
-
raise 'Project ID must be set' unless @project_id
|
101
|
-
|
102
|
-
blanket_project = api.projects(@project_id.to_i)
|
103
|
-
@project = Project.new blanket_project
|
104
|
-
@project
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|