story_branch 0.2.11 → 0.3.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.
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