story_branch 0.4.2 → 0.5.0
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.
- 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
|