story_branch 0.2.11 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +37 -0
  3. data/.github/ISSUE_TEMPLATE.md +12 -0
  4. data/.gitignore +3 -0
  5. data/.rspec +2 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +94 -0
  8. data/{LICENCE → LICENSE.txt} +1 -1
  9. data/README.md +79 -60
  10. data/Rakefile +6 -0
  11. data/exe/git-finish +3 -0
  12. data/exe/git-start +3 -0
  13. data/exe/git-story +3 -0
  14. data/exe/git-unstart +3 -0
  15. data/exe/story_branch +18 -0
  16. data/lib/story_branch.rb +2 -477
  17. data/lib/story_branch/cli.rb +93 -0
  18. data/lib/story_branch/command.rb +121 -0
  19. data/lib/story_branch/commands/.gitkeep +1 -0
  20. data/lib/story_branch/commands/add.rb +48 -0
  21. data/lib/story_branch/commands/create.rb +21 -0
  22. data/lib/story_branch/commands/finish.rb +20 -0
  23. data/lib/story_branch/commands/migrate.rb +100 -0
  24. data/lib/story_branch/commands/start.rb +20 -0
  25. data/lib/story_branch/commands/unstart.rb +20 -0
  26. data/lib/story_branch/config_manager.rb +18 -0
  27. data/lib/story_branch/git_utils.rb +85 -0
  28. data/lib/story_branch/main.rb +124 -0
  29. data/lib/story_branch/pivotal_utils.rb +146 -0
  30. data/lib/story_branch/string_utils.rb +23 -0
  31. data/lib/story_branch/templates/.gitkeep +1 -0
  32. data/lib/story_branch/templates/add/.gitkeep +1 -0
  33. data/lib/story_branch/templates/config/.gitkeep +1 -0
  34. data/lib/story_branch/templates/create/.gitkeep +1 -0
  35. data/lib/story_branch/templates/finish/.gitkeep +1 -0
  36. data/lib/story_branch/templates/migrate/.gitkeep +1 -0
  37. data/lib/story_branch/templates/start/.gitkeep +1 -0
  38. data/lib/story_branch/templates/unstart/.gitkeep +1 -0
  39. data/lib/story_branch/version.rb +3 -0
  40. data/story_branch.gemspec +54 -0
  41. metadata +168 -22
  42. data/bin/git-finish +0 -4
  43. data/bin/git-start +0 -4
  44. data/bin/git-story +0 -4
  45. data/bin/git-unstart +0 -4
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module StoryBranch
6
+ # Handle the application command line parsing
7
+ # and the dispatch to various command objects
8
+ #
9
+ # @api public
10
+ class CLI < Thor
11
+ # Error raised by this runner
12
+ Error = Class.new(StandardError)
13
+
14
+ desc 'version', 'story_branch gem version'
15
+ def version
16
+ require_relative 'version'
17
+ puts "v#{StoryBranch::VERSION}"
18
+ end
19
+ map %w[--version -v] => :version
20
+
21
+ desc 'unstart', 'Mark a started story as un-started in Pivotal Tracker'
22
+ method_option :help, aliases: '-h', type: :boolean,
23
+ desc: 'Display usage information'
24
+ def unstart(*)
25
+ if options[:help]
26
+ invoke :help, ['unstart']
27
+ else
28
+ require_relative 'commands/unstart'
29
+ StoryBranch::Commands::Unstart.new(options).execute
30
+ end
31
+ end
32
+
33
+ desc 'start', 'Mark an estimated story as started in Pivotal Tracker'
34
+ method_option :help, aliases: '-h', type: :boolean,
35
+ desc: 'Display usage information'
36
+ def start(*)
37
+ if options[:help]
38
+ invoke :help, ['start']
39
+ else
40
+ require_relative 'commands/start'
41
+ StoryBranch::Commands::Start.new(options).execute
42
+ end
43
+ end
44
+
45
+ desc 'finish', 'Creates a git commit message for the staged changes with a [Finishes] tag'
46
+ method_option :help, aliases: '-h', type: :boolean,
47
+ desc: 'Display usage information'
48
+ def finish(*)
49
+ if options[:help]
50
+ invoke :help, ['finish']
51
+ else
52
+ require_relative 'commands/finish'
53
+ StoryBranch::Commands::Finish.new(options).execute
54
+ end
55
+ end
56
+
57
+ desc 'create', 'Create branch from estimated stories in pivotal tracker'
58
+ method_option :help, aliases: '-h', type: :boolean,
59
+ desc: 'Display usage information'
60
+ def create(*)
61
+ if options[:help]
62
+ invoke :help, ['create']
63
+ else
64
+ require_relative 'commands/create'
65
+ StoryBranch::Commands::Create.new(options).execute
66
+ end
67
+ end
68
+
69
+ desc 'add', 'Add a new story branch configuration'
70
+ method_option :help, aliases: '-h', type: :boolean,
71
+ desc: 'Display usage information'
72
+ def add(*)
73
+ if options[:help]
74
+ invoke :help, ['add']
75
+ else
76
+ require_relative 'commands/add'
77
+ StoryBranch::Commands::Add.new(options).execute
78
+ end
79
+ end
80
+
81
+ desc 'migrate', 'Migrate old story branch configuration to the new format'
82
+ method_option :help, aliases: '-h', type: :boolean,
83
+ desc: 'Display usage information'
84
+ def migrate(*)
85
+ if options[:help]
86
+ invoke :help, ['migrate']
87
+ else
88
+ require_relative 'commands/migrate'
89
+ StoryBranch::Commands::Migrate.new(options).execute
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module StoryBranch
6
+ class Command
7
+ extend Forwardable
8
+
9
+ def_delegators :command, :run
10
+
11
+ # Execute this command
12
+ #
13
+ # @api public
14
+ def execute(*)
15
+ raise(
16
+ NotImplementedError,
17
+ "#{self.class}##{__method__} must be implemented"
18
+ )
19
+ end
20
+
21
+ # The external commands runner
22
+ #
23
+ # @see http://www.rubydoc.info/gems/tty-command
24
+ #
25
+ # @api public
26
+ def command(**options)
27
+ require 'tty-command'
28
+ TTY::Command.new(options)
29
+ end
30
+
31
+ # The cursor movement
32
+ #
33
+ # @see http://www.rubydoc.info/gems/tty-cursor
34
+ #
35
+ # @api public
36
+ def cursor
37
+ require 'tty-cursor'
38
+ TTY::Cursor
39
+ end
40
+
41
+ # Open a file or text in the user's preferred editor
42
+ #
43
+ # @see http://www.rubydoc.info/gems/tty-editor
44
+ #
45
+ # @api public
46
+ def editor
47
+ require 'tty-editor'
48
+ TTY::Editor
49
+ end
50
+
51
+ # File manipulation utility methods
52
+ #
53
+ # @see http://www.rubydoc.info/gems/tty-file
54
+ #
55
+ # @api public
56
+ def generator
57
+ require 'tty-file'
58
+ TTY::File
59
+ end
60
+
61
+ # Terminal output paging
62
+ #
63
+ # @see http://www.rubydoc.info/gems/tty-pager
64
+ #
65
+ # @api public
66
+ def pager(**options)
67
+ require 'tty-pager'
68
+ TTY::Pager.new(options)
69
+ end
70
+
71
+ # Terminal platform and OS properties
72
+ #
73
+ # @see http://www.rubydoc.info/gems/tty-pager
74
+ #
75
+ # @api public
76
+ def platform
77
+ require 'tty-platform'
78
+ TTY::Platform.new
79
+ end
80
+
81
+ # The interactive prompt
82
+ #
83
+ # @see http://www.rubydoc.info/gems/tty-prompt
84
+ #
85
+ # @api public
86
+ def prompt(**options)
87
+ require 'tty-prompt'
88
+ TTY::Prompt.new(options)
89
+ end
90
+
91
+ # Get terminal screen properties
92
+ #
93
+ # @see http://www.rubydoc.info/gems/tty-screen
94
+ #
95
+ # @api public
96
+ def screen
97
+ require 'tty-screen'
98
+ TTY::Screen
99
+ end
100
+
101
+ # The unix which utility
102
+ #
103
+ # @see http://www.rubydoc.info/gems/tty-which
104
+ #
105
+ # @api public
106
+ def which(*args)
107
+ require 'tty-which'
108
+ TTY::Which.which(*args)
109
+ end
110
+
111
+ # Check if executable exists
112
+ #
113
+ # @see http://www.rubydoc.info/gems/tty-which
114
+ #
115
+ # @api public
116
+ def exec_exist?(*args)
117
+ require 'tty-which'
118
+ TTY::Which.exist?(*args)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../config_manager'
4
+ require_relative '../command'
5
+ require 'tty-config'
6
+ require 'tty-prompt'
7
+
8
+ module StoryBranch
9
+ module Commands
10
+ # Command responsible for adding a new configuration to
11
+ # the available configurations
12
+ #
13
+ # It will try to load the existing global story branch config
14
+ # and then add the project id specified by the user.
15
+ class Add < StoryBranch::Command
16
+ def initialize(options)
17
+ @options = options
18
+ @config = ConfigManager.init_config(ENV['HOME'])
19
+ @local_config = ConfigManager.init_config('.')
20
+ end
21
+
22
+ def execute(_input: $stdin, output: $stdout)
23
+ create_global_config
24
+ create_local_config
25
+ output.puts 'Configuration added successfully'
26
+ end
27
+
28
+ private
29
+
30
+ def create_local_config
31
+ @local_config.set(:project_id, value: project_id)
32
+ @local_config.write(force: true)
33
+ end
34
+
35
+ def create_global_config
36
+ api_key = prompt.ask 'Please provide the api key:'
37
+ @config.set(project_id, :api_key, value: api_key)
38
+ @config.write(force: true)
39
+ end
40
+
41
+ def project_id
42
+ return @project_id if @project_id
43
+ @project_id = prompt.ask "Please provide this project's id:"
44
+ @project_id
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+
5
+ module StoryBranch
6
+ module Commands
7
+ # Create command is used to create a branch from
8
+ # started stories in the tracker
9
+ class Create < StoryBranch::Command
10
+ def initialize(options)
11
+ @options = options
12
+ end
13
+
14
+ def execute(_input: $stdin, _output: $stdout)
15
+ require_relative '../main'
16
+ sb = StoryBranch::Main.new
17
+ sb.create_story_branch
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+
5
+ module StoryBranch
6
+ module Commands
7
+ # Command to finish a story
8
+ class Finish < StoryBranch::Command
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def execute(_input: $stdin, _output: $stdout)
14
+ require_relative '../main'
15
+ sb = StoryBranch::Main.new
16
+ sb.story_finish
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../config_manager'
4
+ require_relative '../command'
5
+ require 'yaml'
6
+ require 'fileutils'
7
+
8
+ module StoryBranch
9
+ module Commands
10
+ # Migrate command is intended to make the migration from old version
11
+ # of story branch to the latest one easier.
12
+ class Migrate < StoryBranch::Command
13
+ GLOBAL_CONFIG_FILE = "#{Dir.home}/.story_branch".freeze
14
+ LOCAL_CONFIG_FILE = '.story_branch'.freeze
15
+ OLD_CONFIG_FILES = [LOCAL_CONFIG_FILE, GLOBAL_CONFIG_FILE].freeze
16
+
17
+ def initialize(options)
18
+ @options = options
19
+ @config = ConfigManager.init_config(Dir.home)
20
+ end
21
+
22
+ def execute(_input: $stdin, output: $stdout)
23
+ if missing_old_config?
24
+ error_migrating(output, old_config_file_not_found)
25
+ return
26
+ end
27
+ @config.set(project_id, :api_key, value: api_key)
28
+ @config.write(force: true)
29
+ create_local_config
30
+ clean_old_config_files
31
+ output.puts 'Migration complete'
32
+ end
33
+
34
+ private
35
+
36
+ def project_id
37
+ return @project_id if @project_id
38
+ @project_id = old_config_value('project', 'PIVOTAL_PROJECT_ID')
39
+ @project_id
40
+ end
41
+
42
+ def api_key
43
+ return @api_key if @api_key
44
+ @api_key = old_config_value('api', 'PIVOTAL_API_KEY')
45
+ @api_key
46
+ end
47
+
48
+ def error_migrating(output, error_message)
49
+ output.puts error_message
50
+ end
51
+
52
+ def missing_old_config?
53
+ OLD_CONFIG_FILES.each { |file| return false if File.exist?(file) }
54
+ return false if env_set?
55
+ true
56
+ end
57
+
58
+ def env_set?
59
+ ENV['PIVOTAL_API_KEY'].length.positive? ||
60
+ ENV['PIVOTAL_PROJECT_ID'].length.positive?
61
+ end
62
+
63
+ def old_config_value(key, env)
64
+ OLD_CONFIG_FILES.each do |config_file|
65
+ if File.exist? config_file
66
+ old_config = YAML.load_file config_file
67
+ return old_config[key].to_s if old_config && old_config[key]
68
+ end
69
+ end
70
+ ENV[env]
71
+ end
72
+
73
+ def create_local_config
74
+ local_config = ConfigManager.init_config('.')
75
+ local_config.set(:project_id, value: project_id)
76
+ local_config.write
77
+ end
78
+
79
+ def clean_old_config_files
80
+ [GLOBAL_CONFIG_FILE, LOCAL_CONFIG_FILE].each do |file|
81
+ FileUtils.rm file if File.exist? file
82
+ end
83
+ end
84
+
85
+ def old_config_file_not_found
86
+ <<-MESSAGE
87
+ Old configuration not found.
88
+ Trying to start from scratch? Use story_branch add
89
+ MESSAGE
90
+ end
91
+
92
+ def cant_migrate_missing_value
93
+ <<-MESSAGE
94
+ Old configuration not found. Nothing has been migrated
95
+ Trying to start from scratch? Use story_branch add
96
+ MESSAGE
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+
5
+ module StoryBranch
6
+ module Commands
7
+ # Command to start an estimated story
8
+ class Start < StoryBranch::Command
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def execute(_input: $stdin, _output: $stdout)
14
+ require_relative '../main'
15
+ sb = StoryBranch::Main.new
16
+ sb.story_start
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+
5
+ module StoryBranch
6
+ module Commands
7
+ # Command to unstart a previously started story
8
+ class Unstart < StoryBranch::Command
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def execute(_input: $stdin, _output: $stdout)
14
+ require_relative '../main'
15
+ sb = StoryBranch::Main.new
16
+ sb.story_unstart
17
+ end
18
+ end
19
+ end
20
+ end