assisted_workflow 0.1.4 → 0.2.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.
- data/Gemfile.lock +1 -1
- data/lib/assisted_workflow.rb +7 -3
- data/lib/assisted_workflow/addons/base.rb +46 -0
- data/lib/assisted_workflow/addons/git.rb +108 -0
- data/lib/assisted_workflow/{github.rb → addons/github.rb} +11 -18
- data/lib/assisted_workflow/{pivotal.rb → addons/pivotal.rb} +10 -15
- data/lib/assisted_workflow/cli.rb +123 -153
- data/lib/assisted_workflow/git.rb +10 -4
- data/lib/assisted_workflow/output.rb +54 -0
- data/lib/assisted_workflow/version.rb +1 -1
- data/spec/assisted_workflow/{git_spec.rb → addons/git_spec.rb} +4 -4
- data/spec/assisted_workflow/{github_spec.rb → addons/github_spec.rb} +12 -6
- data/spec/assisted_workflow/{pivotal_spec.rb → addons/pivotal_spec.rb} +9 -6
- metadata +15 -12
data/Gemfile.lock
CHANGED
data/lib/assisted_workflow.rb
CHANGED
@@ -2,8 +2,12 @@ require "assisted_workflow/version"
|
|
2
2
|
require "assisted_workflow/exceptions"
|
3
3
|
|
4
4
|
module AssistedWorkflow
|
5
|
-
autoload :Pivotal, "assisted_workflow/pivotal"
|
6
|
-
autoload :Git, "assisted_workflow/git"
|
7
|
-
autoload :Github, "assisted_workflow/github"
|
8
5
|
autoload :ConfigFile, "assisted_workflow/config_file"
|
6
|
+
autoload :Output, "assisted_workflow/output"
|
7
|
+
|
8
|
+
module Addons
|
9
|
+
autoload :Pivotal, "assisted_workflow/addons/pivotal"
|
10
|
+
autoload :Git, "assisted_workflow/addons/git"
|
11
|
+
autoload :Github, "assisted_workflow/addons/github"
|
12
|
+
end
|
9
13
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module AssistedWorkflow::Addons
|
2
|
+
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize(output, options = {})
|
6
|
+
@output = output
|
7
|
+
validate_options!(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
self.class.name.downcase.split("::").last
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
def required_options(*args)
|
21
|
+
@required_options = Array(args).map(&:to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_required_options
|
25
|
+
@required_options || []
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
protected #===============================================================
|
30
|
+
|
31
|
+
def log(message)
|
32
|
+
@output.say_status(name, message) if @output
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_options!(options)
|
36
|
+
if options.nil?
|
37
|
+
raise AssistedWorkflow::Error, "#{name} missing configuration"
|
38
|
+
end
|
39
|
+
missing_keys = self.class.get_required_options - options.keys
|
40
|
+
if missing_keys.size > 0
|
41
|
+
raise AssistedWorkflow::Error, "#{name} missing configuration: #{missing_keys.inspect}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "assisted_workflow/exceptions"
|
2
|
+
require "assisted_workflow/addons/base"
|
3
|
+
|
4
|
+
module AssistedWorkflow::Addons
|
5
|
+
|
6
|
+
class GitError < AssistedWorkflow::Error; end
|
7
|
+
|
8
|
+
class Git < Base
|
9
|
+
|
10
|
+
DESCRIPTION_LIMIT = 30
|
11
|
+
|
12
|
+
def initialize(output, options = {})
|
13
|
+
super
|
14
|
+
@command_options = {:raise_error => true}.merge(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# creates a new git branch based on story attributes
|
18
|
+
# the branch name format is:
|
19
|
+
# => story_onwer_username.story_id.story_name
|
20
|
+
def create_story_branch(story)
|
21
|
+
log "creating the feature branch"
|
22
|
+
branch = branch_name(story)
|
23
|
+
git "checkout -b #{branch}"
|
24
|
+
# git "push --set-upstream origin #{branch}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# run all the git steps required for a clean pull request
|
28
|
+
def rebase_and_push
|
29
|
+
check_everything_commited!
|
30
|
+
branch = current_branch
|
31
|
+
git "checkout master"
|
32
|
+
git "pull --rebase"
|
33
|
+
git "checkout #{branch}"
|
34
|
+
git "rebase master"
|
35
|
+
git "push -u -f origin #{branch}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns the current story id based on branch name
|
39
|
+
def current_story_id
|
40
|
+
current_branch.split(".")[1]
|
41
|
+
end
|
42
|
+
|
43
|
+
# returns the current local branch name
|
44
|
+
def current_branch
|
45
|
+
git("rev-parse --abbrev-ref HEAD", :silent => true)
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns the repository name assigned to origin following the format:
|
49
|
+
# owner/project
|
50
|
+
def repository
|
51
|
+
url = git("config --get remote.origin.url", :error => "cannot find 'origin' remote repository url")
|
52
|
+
url.gsub("git@github.com:", "").gsub("https://github.com/", "").gsub(/\.git$/, "").chomp
|
53
|
+
end
|
54
|
+
|
55
|
+
# check if current branch is merged into master
|
56
|
+
def is_merged?
|
57
|
+
check_everything_commited!
|
58
|
+
branch = current_branch
|
59
|
+
git "checkout master"
|
60
|
+
git "pull --rebase"
|
61
|
+
merged = git("branch --merged").include?(branch)
|
62
|
+
git "checkout #{branch}"
|
63
|
+
merged
|
64
|
+
end
|
65
|
+
|
66
|
+
# removes current branch and its remote version
|
67
|
+
def remove_branch
|
68
|
+
branch = current_branch
|
69
|
+
git "push origin :#{branch}", :raise_error => false
|
70
|
+
git "checkout master"
|
71
|
+
git "branch -D #{branch}"
|
72
|
+
end
|
73
|
+
|
74
|
+
private #=================================================================
|
75
|
+
|
76
|
+
def git(command, options = {})
|
77
|
+
options = @command_options.merge(options)
|
78
|
+
puts "git #{command}" unless options[:silent] == true
|
79
|
+
result = system("git #{command}")
|
80
|
+
if system_error? && options[:raise_error]
|
81
|
+
msg = ["git command error", options[:error]].compact.join(": ")
|
82
|
+
raise GitError, msg
|
83
|
+
end
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
def system(command)
|
88
|
+
%x{#{command}}.chomp
|
89
|
+
end
|
90
|
+
|
91
|
+
def system_error?
|
92
|
+
$? != 0
|
93
|
+
end
|
94
|
+
|
95
|
+
def branch_name(story)
|
96
|
+
description = story.name.to_s.downcase.gsub(/\W/, "_").slice(0, DESCRIPTION_LIMIT)
|
97
|
+
[story.other_id, story.id, description].join(".").downcase
|
98
|
+
end
|
99
|
+
|
100
|
+
def not_commited_changes
|
101
|
+
git("status --porcelain", :silent => true).split("\n")
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_everything_commited!
|
105
|
+
raise AssistedWorkflow::Error, "git: there are not commited changes" unless not_commited_changes.empty?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
require "assisted_workflow/exceptions"
|
2
|
+
require "assisted_workflow/addons/base"
|
2
3
|
require "octokit"
|
3
4
|
|
4
|
-
module AssistedWorkflow
|
5
|
+
module AssistedWorkflow::Addons
|
5
6
|
|
6
|
-
class Github
|
7
|
-
|
8
|
-
|
7
|
+
class Github < Base
|
8
|
+
required_options :token
|
9
|
+
|
10
|
+
def initialize(output, options = {})
|
11
|
+
super
|
9
12
|
@client = Octokit::Client.new(:access_token => options["token"])
|
10
13
|
end
|
11
14
|
|
@@ -16,31 +19,21 @@ module AssistedWorkflow
|
|
16
19
|
# @param story [Story] Pivotal story object
|
17
20
|
# @return [Sawyer::Resource] The newly created pull request
|
18
21
|
def create_pull_request(repo, branch, story)
|
22
|
+
log "submiting the new pull request"
|
19
23
|
base = "master"
|
20
24
|
title = "[##{story.id}] #{story.name}"
|
21
25
|
pull_request = @client.create_pull_request(repo, base, branch, title, story.description)
|
22
26
|
if pull_request.nil?
|
23
27
|
raise AssistedWorkflow::Error, "error on submiting the pull request"
|
24
28
|
else
|
25
|
-
pull_request
|
29
|
+
url = pull_request._links.html.href
|
30
|
+
log "new pull request at #{url}"
|
31
|
+
url
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
29
35
|
def valid?
|
30
36
|
@client.user_authenticated?
|
31
37
|
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def validate_options!(options)
|
36
|
-
if options.nil? || options.empty?
|
37
|
-
raise AssistedWorkflow::Error, "github missing configuration"
|
38
|
-
end
|
39
|
-
required_keys = %w(token)
|
40
|
-
missing_keys = required_keys - options.keys
|
41
|
-
if missing_keys.size > 0
|
42
|
-
raise AssistedWorkflow::Error, "github missing configuration: #{missing_keys.inspect}"
|
43
|
-
end
|
44
|
-
end
|
45
38
|
end
|
46
39
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require "assisted_workflow/exceptions"
|
2
|
+
require "assisted_workflow/addons/base"
|
2
3
|
require 'pivotal_tracker'
|
3
4
|
|
4
5
|
# wrapper class to pivotal api client
|
5
|
-
module AssistedWorkflow
|
6
|
-
class Pivotal
|
6
|
+
module AssistedWorkflow::Addons
|
7
|
+
class Pivotal < Base
|
8
|
+
required_options :fullname, :token, :project_id
|
7
9
|
|
8
|
-
def initialize(options)
|
9
|
-
|
10
|
+
def initialize(output, options = {})
|
11
|
+
super
|
10
12
|
|
11
13
|
PivotalTracker::Client.token = options["token"]
|
12
14
|
begin
|
@@ -20,6 +22,7 @@ module AssistedWorkflow
|
|
20
22
|
|
21
23
|
def find_story(story_id)
|
22
24
|
if story_id.to_i > 0
|
25
|
+
log "loading story ##{story_id}"
|
23
26
|
story = @project.stories.find(story_id)
|
24
27
|
story.other_id = @username || @fullname
|
25
28
|
story.other_id = story.other_id.to_s.downcase.split.join
|
@@ -28,16 +31,19 @@ module AssistedWorkflow
|
|
28
31
|
end
|
29
32
|
|
30
33
|
def start_story(story, options = {})
|
34
|
+
log "starting story ##{story.id}"
|
31
35
|
update_story! story, options.merge(:current_state => "started")
|
32
36
|
end
|
33
37
|
|
34
38
|
def finish_story(story, options = {})
|
39
|
+
log "finishing story ##{story.id}"
|
35
40
|
if update_story! story, :current_state => finished_state(story)
|
36
41
|
story.notes.create(:text => options[:note]) if options[:note]
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
45
|
def pending_stories(options = {})
|
46
|
+
log "loading pending stories"
|
41
47
|
states = ["unstarted"]
|
42
48
|
states << "started" if options[:include_started]
|
43
49
|
@project.stories.all(:state => states, :owned_by => @fullname, :limit => 5)
|
@@ -49,17 +55,6 @@ module AssistedWorkflow
|
|
49
55
|
|
50
56
|
private
|
51
57
|
|
52
|
-
def validate_options!(options)
|
53
|
-
if options.nil? || options.empty?
|
54
|
-
raise AssistedWorkflow::Error, "pivotal missing configuration"
|
55
|
-
end
|
56
|
-
required_keys = %w(fullname token project_id)
|
57
|
-
missing_keys = required_keys - options.keys
|
58
|
-
if missing_keys.size > 0
|
59
|
-
raise AssistedWorkflow::Error, "pivotal missing configuration: #{missing_keys.inspect}"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
58
|
def finished_state(story)
|
64
59
|
if story.story_type == "chore"
|
65
60
|
"accepted"
|
@@ -1,188 +1,158 @@
|
|
1
1
|
require "assisted_workflow"
|
2
2
|
require "thor"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module AssistedWorkflow
|
5
|
+
class CLI < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
GLOBAL_CONFIG = File.expand_path(".awconfig", ENV["HOME"])
|
8
|
+
LOCAL_CONFIG = ".awconfig"
|
9
|
+
source_root(File.expand_path(File.join(__FILE__, "..", "templates")))
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# tasks shortcuts
|
12
|
+
map ["-v", "--version"] => :version
|
13
|
+
map "s" => :start
|
14
|
+
map "u" => :submit
|
15
|
+
map "f" => :finish
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
desc "setup", "Setup initial configuration in current project directory"
|
18
|
+
def setup
|
19
|
+
copy_file "awconfig.global.tt", GLOBAL_CONFIG
|
20
|
+
copy_file "awconfig.local.tt", LOCAL_CONFIG
|
21
|
+
if File.exists?(".git")
|
22
|
+
copy_file "commit-msg.tt", ".git/hooks/commit-msg"
|
23
|
+
chmod ".git/hooks/commit-msg", "a+x"
|
24
|
+
else
|
25
|
+
raise AssistedWorkflow::Error, ".git folder not found"
|
26
|
+
end
|
27
|
+
out.next_command "set your own configuration running:", "" do |c|
|
28
|
+
c << "$ aw config pivotal.fullname='Your Pivotal User Name' --global"
|
29
|
+
c << "$ aw config pivotal.token=MYPIVOTALTOKEN --global"
|
30
|
+
c << "$ aw config github.token=MYGITHUBOAUTHTOKEN --global"
|
31
|
+
c << "$ aw config pivotal.project_id=00001"
|
32
|
+
end
|
25
33
|
end
|
26
|
-
say "set your own configuration editing the .awconfig files or running:", :green
|
27
|
-
say_command "$ aw config pivotal.fullname='Flavio Granero' --global"
|
28
|
-
say_command "$ aw config pivotal.token=MYPIVOTALTOKEN --global"
|
29
|
-
say_command "$ aw config github.token=MYGITHUBOAUTHTOKEN --global"
|
30
|
-
say_command "$ aw config pivotal.project_id=00001"
|
31
|
-
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
say "creating the feature branch"
|
50
|
-
git.create_story_branch(story)
|
51
|
-
say "after commiting your changes, submit a pull request using:", :green
|
52
|
-
say_command "$ aw submit"
|
35
|
+
desc "start [STORY_ID]", "Start the pivotal story and create a new branch to receive the changes"
|
36
|
+
method_option :all, :type => :boolean, :default => false, :aliases => "-a", :desc => "Show started and pending stories when no story_id is provided"
|
37
|
+
method_option :estimate, :type => :numeric, :aliases => "-e", :desc => "Sets the story estimate when starting"
|
38
|
+
def start(story_id=nil)
|
39
|
+
check_awfile!
|
40
|
+
story = pivotal.find_story(story_id)
|
41
|
+
if story.nil?
|
42
|
+
stories = pivotal.pending_stories(:include_started => options[:all])
|
43
|
+
out.print_stories "pending stories", stories, options
|
44
|
+
out.next_command "start a story using:", "$ aw start [STORY_ID]"
|
45
|
+
else
|
46
|
+
pivotal.start_story(story, :estimate => options[:estimate])
|
47
|
+
out.print_story story
|
48
|
+
git.create_story_branch(story)
|
49
|
+
out.next_command "after commiting your changes, submit a pull request using:", "$ aw submit"
|
50
|
+
end
|
53
51
|
end
|
54
|
-
end
|
55
52
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
say_command "$ aw finish"
|
72
|
-
else
|
73
|
-
raise AssistedWorkflow::Error, "story not found, make sure a feature branch in active"
|
53
|
+
desc "submit", "Submits the current story creating a new pull request"
|
54
|
+
def submit
|
55
|
+
check_awfile!
|
56
|
+
story_id = git.current_story_id
|
57
|
+
story = pivotal.find_story(story_id)
|
58
|
+
if story
|
59
|
+
git.rebase_and_push
|
60
|
+
pr_url = github.create_pull_request(
|
61
|
+
git.repository, git.current_branch, story
|
62
|
+
)
|
63
|
+
pivotal.finish_story(story, :note => pr_url)
|
64
|
+
out.next_command "after pull request approval, remove the feature branch using:", "$ aw finish"
|
65
|
+
else
|
66
|
+
raise AssistedWorkflow::Error, "story not found, make sure a feature branch in active"
|
67
|
+
end
|
74
68
|
end
|
75
|
-
end
|
76
69
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
say "removing local and remote feature branches"
|
70
|
+
desc "finish", "Check if the changes are merged into master, removing the current feature branch"
|
71
|
+
def finish
|
72
|
+
check_awfile!
|
73
|
+
story_id = git.current_story_id
|
74
|
+
if story_id.to_i > 0
|
75
|
+
git.check_merged!
|
84
76
|
git.remove_branch
|
85
|
-
|
86
|
-
say_command "$ aw start"
|
77
|
+
out.next_command "well done! check your next stories using:", "$ aw start"
|
87
78
|
else
|
88
|
-
|
79
|
+
raise AssistedWorkflow::Error, "story not found, make sure a feature branch in active"
|
89
80
|
end
|
90
|
-
else
|
91
|
-
raise AssistedWorkflow::Error, "story not found, make sure a feature branch in active"
|
92
81
|
end
|
93
|
-
end
|
94
82
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
83
|
+
desc "version", "Display assisted_workflow gem version"
|
84
|
+
def version
|
85
|
+
say AssistedWorkflow::VERSION
|
86
|
+
end
|
99
87
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
88
|
+
desc "config group.key=value", "Set configuration keys in local config file"
|
89
|
+
method_option :global, :type => :boolean, :aliases => "-g", :desc => "Set configuration key in global configuration file (for all projects)"
|
90
|
+
def config(*args)
|
91
|
+
if args.empty?
|
92
|
+
print_table configuration.to_hash
|
93
|
+
else
|
94
|
+
config_file.parse(args).save!
|
95
|
+
end
|
107
96
|
end
|
108
|
-
end
|
109
97
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
98
|
+
desc "thanks", "Aw, Thanks!", :hide => true
|
99
|
+
def thanks
|
100
|
+
out.say "you're welcome!", :on_magenta
|
101
|
+
end
|
114
102
|
|
115
103
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
104
|
+
no_tasks do
|
105
|
+
def out
|
106
|
+
@out ||= Output.new(self.shell)
|
107
|
+
end
|
108
|
+
|
109
|
+
def pivotal
|
110
|
+
@pivotal ||= Addons::Pivotal.new(out, configuration[:pivotal])
|
111
|
+
end
|
120
112
|
|
121
|
-
|
122
|
-
|
123
|
-
|
113
|
+
def git
|
114
|
+
@git ||= Addons::Git.new(out)
|
115
|
+
end
|
124
116
|
|
125
|
-
|
126
|
-
|
127
|
-
|
117
|
+
def github
|
118
|
+
@github ||= Addons::Github.new(out, configuration[:github])
|
119
|
+
end
|
128
120
|
|
129
|
-
|
130
|
-
|
131
|
-
|
121
|
+
def config_file
|
122
|
+
@config_file ||= ConfigFile.new(awfile)
|
123
|
+
end
|
132
124
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
125
|
+
# loads all configuration, merging global and local values
|
126
|
+
def configuration
|
127
|
+
@configuration ||= begin
|
128
|
+
ConfigFile.new(GLOBAL_CONFIG).merge_file(LOCAL_CONFIG)
|
129
|
+
rescue TypeError
|
130
|
+
raise AssistedWorkflow::Error, "Error on loading .awconfig files. Please check the content format."
|
131
|
+
end
|
139
132
|
end
|
140
133
|
end
|
141
|
-
end
|
142
134
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
135
|
+
class << self
|
136
|
+
def start(given_args=ARGV, config={})
|
137
|
+
super
|
138
|
+
rescue AssistedWorkflow::Error => e
|
139
|
+
config[:shell].say e.message, :red
|
140
|
+
exit(1)
|
141
|
+
end
|
149
142
|
end
|
150
|
-
end
|
151
143
|
|
152
|
-
|
144
|
+
private ##################################################################
|
153
145
|
|
154
|
-
|
155
|
-
|
156
|
-
say title.upcase, :green
|
157
|
-
say "-" * title.length, :green
|
158
|
-
end
|
159
|
-
|
160
|
-
def print_stories(stories)
|
161
|
-
rows = stories.map do |story|
|
162
|
-
if options[:all]
|
163
|
-
[story.id, story.current_state, story.name]
|
164
|
-
else
|
165
|
-
[story.id, story.estimate, story.name]
|
166
|
-
end
|
146
|
+
def check_awfile!
|
147
|
+
raise AssistedWorkflow::Error, "#{awfile} does not exist.\nmake sure you run `$ aw setup` in your project folder." unless File.exist?(awfile)
|
167
148
|
end
|
168
|
-
print_table(rows)
|
169
|
-
end
|
170
|
-
|
171
|
-
def say_command(command)
|
172
|
-
with_padding do
|
173
|
-
say command
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def check_awfile!
|
178
|
-
raise AssistedWorkflow::Error, "#{awfile} does not exist.\nmake sure you run `$ aw setup` in your project folder." unless File.exist?(awfile)
|
179
|
-
end
|
180
149
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
150
|
+
def awfile
|
151
|
+
case
|
152
|
+
when options[:awfile] then options[:awfile]
|
153
|
+
when options[:global] then GLOBAL_CONFIG
|
154
|
+
else LOCAL_CONFIG
|
155
|
+
end
|
186
156
|
end
|
187
|
-
|
157
|
+
end
|
188
158
|
end
|
@@ -8,7 +8,8 @@ module AssistedWorkflow
|
|
8
8
|
|
9
9
|
DESCRIPTION_LIMIT = 30
|
10
10
|
|
11
|
-
def initialize(options = {})
|
11
|
+
def initialize(output, options = {})
|
12
|
+
super
|
12
13
|
@command_options = {:raise_error => true}.merge(options)
|
13
14
|
end
|
14
15
|
|
@@ -16,6 +17,7 @@ module AssistedWorkflow
|
|
16
17
|
# the branch name format is:
|
17
18
|
# => story_onwer_username.story_id.story_name
|
18
19
|
def create_story_branch(story)
|
20
|
+
log "creating the new branch"
|
19
21
|
branch = branch_name(story)
|
20
22
|
git "checkout -b #{branch}"
|
21
23
|
# git "push --set-upstream origin #{branch}"
|
@@ -23,6 +25,7 @@ module AssistedWorkflow
|
|
23
25
|
|
24
26
|
# run all the git steps required for a clean pull request
|
25
27
|
def rebase_and_push
|
28
|
+
log "preparing local branch"
|
26
29
|
check_everything_commited!
|
27
30
|
branch = current_branch
|
28
31
|
git "checkout master"
|
@@ -50,18 +53,21 @@ module AssistedWorkflow
|
|
50
53
|
end
|
51
54
|
|
52
55
|
# check if current branch is merged into master
|
53
|
-
def
|
56
|
+
def check_merged!
|
54
57
|
check_everything_commited!
|
55
58
|
branch = current_branch
|
56
59
|
git "checkout master"
|
57
60
|
git "pull --rebase"
|
58
61
|
merged = git("branch --merged").include?(branch)
|
59
62
|
git "checkout #{branch}"
|
60
|
-
merged
|
63
|
+
unless merged
|
64
|
+
raise AssistedWorkflow::Error, "this branch is not merged into master"
|
65
|
+
end
|
61
66
|
end
|
62
67
|
|
63
68
|
# removes current branch and its remote version
|
64
69
|
def remove_branch
|
70
|
+
log "removing local and remote feature branches"
|
65
71
|
branch = current_branch
|
66
72
|
git "push origin :#{branch}", :raise_error => false
|
67
73
|
git "checkout master"
|
@@ -72,7 +78,7 @@ module AssistedWorkflow
|
|
72
78
|
|
73
79
|
def git(command, options = {})
|
74
80
|
options = @command_options.merge(options)
|
75
|
-
|
81
|
+
# log("git #{command}", :step => true) unless options[:silent] == true
|
76
82
|
result = system("git #{command}")
|
77
83
|
if system_error? && options[:raise_error]
|
78
84
|
msg = ["git command error", options[:error]].compact.join(": ")
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module AssistedWorkflow
|
2
|
+
|
3
|
+
# a helper class to provide custom shell print methods
|
4
|
+
class Output < SimpleDelegator
|
5
|
+
def initialize(shell)
|
6
|
+
super
|
7
|
+
@shell = shell
|
8
|
+
end
|
9
|
+
|
10
|
+
# prints a wrapped gray line, showing as comments between log lines
|
11
|
+
def say_comment(comment)
|
12
|
+
@shell.padding = 4
|
13
|
+
say comment, [:black, :bold]
|
14
|
+
@shell.padding = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
# prints a highlighted title section
|
18
|
+
def print_title(title)
|
19
|
+
say "-" * title.length, :green
|
20
|
+
say title.upcase, :green
|
21
|
+
say "-" * title.length, :green
|
22
|
+
end
|
23
|
+
|
24
|
+
# prints as table with stories data
|
25
|
+
def print_stories(title, stories, options = {})
|
26
|
+
print_title title
|
27
|
+
rows = stories.map do |story|
|
28
|
+
if options[:all]
|
29
|
+
[story.id, story.current_state, story.name]
|
30
|
+
else
|
31
|
+
[story.id, story.estimate, story.name]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
print_table(rows)
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_story(story)
|
38
|
+
say "-" * 40
|
39
|
+
print_wrapped story.name, :indent => 2
|
40
|
+
print_wrapped story.description, :indent => 2
|
41
|
+
say "-" * 40
|
42
|
+
end
|
43
|
+
|
44
|
+
def next_command(title, commands, &block)
|
45
|
+
say title, :green
|
46
|
+
_commands = Array(commands)
|
47
|
+
yield(_commands) if block_given?
|
48
|
+
_commands.each do |command|
|
49
|
+
print_wrapped command, :indent => 2
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'assisted_workflow/git'
|
2
|
+
require 'assisted_workflow/addons/git'
|
3
3
|
|
4
|
-
describe AssistedWorkflow::Git do
|
4
|
+
describe AssistedWorkflow::Addons::Git do
|
5
5
|
before do
|
6
|
-
@git = AssistedWorkflow::Git.new(:silent => true)
|
6
|
+
@git = AssistedWorkflow::Addons::Git.new(nil, :silent => true)
|
7
7
|
stub(@git).system_error?{ false }
|
8
8
|
stub(@git).system("git rev-parse --abbrev-ref HEAD"){ "flavio.00001.new_feature"}
|
9
9
|
end
|
@@ -16,7 +16,7 @@ describe AssistedWorkflow::Git do
|
|
16
16
|
it "raises a git error when git command does not exit with success" do
|
17
17
|
mock(@git).system_error?{ true }
|
18
18
|
mock(@git).system("git checkout -b flavio.00001.new_feature")
|
19
|
-
proc { @git.create_story_branch(story) }.must_raise AssistedWorkflow::GitError, "git command error"
|
19
|
+
proc { @git.create_story_branch(story) }.must_raise AssistedWorkflow::Addons::GitError, "git command error"
|
20
20
|
end
|
21
21
|
|
22
22
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'assisted_workflow/github'
|
2
|
+
require 'assisted_workflow/addons/github'
|
3
3
|
|
4
|
-
describe AssistedWorkflow::Github do
|
4
|
+
describe AssistedWorkflow::Addons::Github do
|
5
5
|
before do
|
6
6
|
@configuration = {
|
7
7
|
"token" => "mygithubtoken",
|
@@ -11,7 +11,7 @@ describe AssistedWorkflow::Github do
|
|
11
11
|
stub(@client).user_authenticated?{ true }
|
12
12
|
stub(Octokit::Client).new{ @client }
|
13
13
|
|
14
|
-
@github = AssistedWorkflow::Github.new(@configuration)
|
14
|
+
@github = AssistedWorkflow::Addons::Github.new(nil, @configuration)
|
15
15
|
end
|
16
16
|
|
17
17
|
it "initializes a valid github wrapper" do
|
@@ -20,15 +20,15 @@ describe AssistedWorkflow::Github do
|
|
20
20
|
|
21
21
|
it "requires token" do
|
22
22
|
proc {
|
23
|
-
AssistedWorkflow::Github.new({})
|
23
|
+
AssistedWorkflow::Addons::Github.new(nil, {})
|
24
24
|
}.must_raise AssistedWorkflow::Error, "github missing configuration:[token]"
|
25
25
|
end
|
26
26
|
|
27
27
|
it "creates a new valid pull request" do
|
28
|
-
mock(@client).create_pull_request("flaviogranero/assisted_workflow", "master", "flavio.00001.new_feature", "[#00001] New Feature", "Feature description"){
|
28
|
+
mock(@client).create_pull_request("flaviogranero/assisted_workflow", "master", "flavio.00001.new_feature", "[#00001] New Feature", "Feature description"){ pull_request }
|
29
29
|
@github.create_pull_request(
|
30
30
|
"flaviogranero/assisted_workflow", "flavio.00001.new_feature", story
|
31
|
-
)
|
31
|
+
).must_match /flaviogranero\/assisted_workflow\/pull\/1/
|
32
32
|
end
|
33
33
|
|
34
34
|
it "raises on creating an invalid pull request" do
|
@@ -45,4 +45,10 @@ describe AssistedWorkflow::Github do
|
|
45
45
|
def story
|
46
46
|
@story ||= PivotalTracker::Story.new(:id => "00001", :name => "New Feature", :description => "Feature description")
|
47
47
|
end
|
48
|
+
|
49
|
+
def pull_request
|
50
|
+
agent = Sawyer::Agent.new("", {:links_parser => Sawyer::LinkParsers::Simple.new})
|
51
|
+
data = {_links: {html: {href: "https://github.com/flaviogranero/assisted_workflow/pull/1"}}}
|
52
|
+
Sawyer::Resource.new(agent, data)
|
53
|
+
end
|
48
54
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'assisted_workflow/pivotal'
|
2
|
+
require 'assisted_workflow/addons/pivotal'
|
3
3
|
|
4
|
-
describe AssistedWorkflow::Pivotal do
|
4
|
+
describe AssistedWorkflow::Addons::Pivotal do
|
5
5
|
|
6
6
|
before do
|
7
7
|
@configuration = {
|
@@ -14,7 +14,7 @@ describe AssistedWorkflow::Pivotal do
|
|
14
14
|
@project = PivotalTracker::Project.new(:id => "1")
|
15
15
|
stub(PivotalTracker::Project).find(@configuration["project_id"]){ @project }
|
16
16
|
|
17
|
-
@pivotal = AssistedWorkflow::Pivotal.new(@configuration)
|
17
|
+
@pivotal = AssistedWorkflow::Addons::Pivotal.new(nil, @configuration)
|
18
18
|
end
|
19
19
|
|
20
20
|
it "initializes a valid pivotal wrapper" do
|
@@ -23,7 +23,8 @@ describe AssistedWorkflow::Pivotal do
|
|
23
23
|
|
24
24
|
it "requires fullname" do
|
25
25
|
proc {
|
26
|
-
AssistedWorkflow::Pivotal.new(
|
26
|
+
AssistedWorkflow::Addons::Pivotal.new(
|
27
|
+
nil,
|
27
28
|
@configuration.reject{|k,v| k == "fullname"}
|
28
29
|
)
|
29
30
|
}.must_raise AssistedWorkflow::Error, "pivotal missing configuration:[fullname]"
|
@@ -31,7 +32,8 @@ describe AssistedWorkflow::Pivotal do
|
|
31
32
|
|
32
33
|
it "requires token" do
|
33
34
|
proc {
|
34
|
-
AssistedWorkflow::Pivotal.new(
|
35
|
+
AssistedWorkflow::Addons::Pivotal.new(
|
36
|
+
nil,
|
35
37
|
@configuration.reject{|k,v| k == "token"}
|
36
38
|
)
|
37
39
|
}.must_raise AssistedWorkflow::Error, "pivotal missing configuration:[token]"
|
@@ -39,7 +41,8 @@ describe AssistedWorkflow::Pivotal do
|
|
39
41
|
|
40
42
|
it "requires project_id" do
|
41
43
|
proc {
|
42
|
-
AssistedWorkflow::Pivotal.new(
|
44
|
+
AssistedWorkflow::Addons::Pivotal.new(
|
45
|
+
nil,
|
43
46
|
@configuration.reject{|k,v| k == "project_id"}
|
44
47
|
)
|
45
48
|
}.must_raise AssistedWorkflow::Error, "pivotal missing configuration:[project_id]"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: assisted_workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-02-
|
12
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -144,20 +144,23 @@ files:
|
|
144
144
|
- assisted_workflow.gemspec
|
145
145
|
- bin/aw
|
146
146
|
- lib/assisted_workflow.rb
|
147
|
+
- lib/assisted_workflow/addons/base.rb
|
148
|
+
- lib/assisted_workflow/addons/git.rb
|
149
|
+
- lib/assisted_workflow/addons/github.rb
|
150
|
+
- lib/assisted_workflow/addons/pivotal.rb
|
147
151
|
- lib/assisted_workflow/cli.rb
|
148
152
|
- lib/assisted_workflow/config_file.rb
|
149
153
|
- lib/assisted_workflow/exceptions.rb
|
150
154
|
- lib/assisted_workflow/git.rb
|
151
|
-
- lib/assisted_workflow/
|
152
|
-
- lib/assisted_workflow/pivotal.rb
|
155
|
+
- lib/assisted_workflow/output.rb
|
153
156
|
- lib/assisted_workflow/templates/awconfig.global.tt
|
154
157
|
- lib/assisted_workflow/templates/awconfig.local.tt
|
155
158
|
- lib/assisted_workflow/templates/commit-msg.tt
|
156
159
|
- lib/assisted_workflow/version.rb
|
160
|
+
- spec/assisted_workflow/addons/git_spec.rb
|
161
|
+
- spec/assisted_workflow/addons/github_spec.rb
|
162
|
+
- spec/assisted_workflow/addons/pivotal_spec.rb
|
157
163
|
- spec/assisted_workflow/config_file_spec.rb
|
158
|
-
- spec/assisted_workflow/git_spec.rb
|
159
|
-
- spec/assisted_workflow/github_spec.rb
|
160
|
-
- spec/assisted_workflow/pivotal_spec.rb
|
161
164
|
- spec/spec_helper.rb
|
162
165
|
homepage: https://github.com/flaviogranero/assisted_workflow
|
163
166
|
licenses:
|
@@ -216,7 +219,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
216
219
|
version: '0'
|
217
220
|
segments:
|
218
221
|
- 0
|
219
|
-
hash:
|
222
|
+
hash: -50568132931744746
|
220
223
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
224
|
none: false
|
222
225
|
requirements:
|
@@ -225,7 +228,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
228
|
version: '0'
|
226
229
|
segments:
|
227
230
|
- 0
|
228
|
-
hash:
|
231
|
+
hash: -50568132931744746
|
229
232
|
requirements: []
|
230
233
|
rubyforge_project:
|
231
234
|
rubygems_version: 1.8.24
|
@@ -234,8 +237,8 @@ specification_version: 3
|
|
234
237
|
summary: AW is a CLI tool to automate software development workflows based on github
|
235
238
|
pull requests
|
236
239
|
test_files:
|
240
|
+
- spec/assisted_workflow/addons/git_spec.rb
|
241
|
+
- spec/assisted_workflow/addons/github_spec.rb
|
242
|
+
- spec/assisted_workflow/addons/pivotal_spec.rb
|
237
243
|
- spec/assisted_workflow/config_file_spec.rb
|
238
|
-
- spec/assisted_workflow/git_spec.rb
|
239
|
-
- spec/assisted_workflow/github_spec.rb
|
240
|
-
- spec/assisted_workflow/pivotal_spec.rb
|
241
244
|
- spec/spec_helper.rb
|