bookbindery 1.0.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/{bin → install_bin}/bookbinder +0 -0
  3. data/lib/bookbinder.rb +2 -9
  4. data/lib/bookbinder/archive.rb +1 -1
  5. data/lib/bookbinder/archive_menu_configuration.rb +34 -0
  6. data/lib/bookbinder/book.rb +17 -17
  7. data/lib/bookbinder/cli.rb +25 -36
  8. data/lib/bookbinder/code_example.rb +5 -38
  9. data/lib/bookbinder/code_example_reader.rb +40 -0
  10. data/lib/bookbinder/colorizer.rb +14 -0
  11. data/lib/bookbinder/command_runner.rb +9 -16
  12. data/lib/bookbinder/command_validator.rb +14 -7
  13. data/lib/bookbinder/commands/bind.rb +321 -0
  14. data/lib/bookbinder/commands/build_and_push_tarball.rb +7 -6
  15. data/lib/bookbinder/commands/chain.rb +11 -0
  16. data/lib/bookbinder/commands/generate_pdf.rb +4 -3
  17. data/lib/bookbinder/commands/help.rb +49 -10
  18. data/lib/bookbinder/commands/naming.rb +9 -1
  19. data/lib/bookbinder/commands/push_local_to_staging.rb +4 -3
  20. data/lib/bookbinder/commands/push_to_prod.rb +36 -4
  21. data/lib/bookbinder/commands/run_publish_ci.rb +21 -24
  22. data/lib/bookbinder/commands/tag.rb +3 -3
  23. data/lib/bookbinder/commands/update_local_doc_repos.rb +5 -4
  24. data/lib/bookbinder/commands/version.rb +11 -8
  25. data/lib/bookbinder/configuration.rb +8 -3
  26. data/lib/bookbinder/configuration_fetcher.rb +7 -25
  27. data/lib/bookbinder/configuration_validator.rb +21 -0
  28. data/lib/bookbinder/distributor.rb +1 -1
  29. data/lib/bookbinder/dita_html_to_middleman_formatter.rb +37 -0
  30. data/lib/bookbinder/dita_section.rb +7 -0
  31. data/lib/bookbinder/dita_section_gatherer.rb +28 -0
  32. data/lib/bookbinder/git_accessor.rb +17 -0
  33. data/lib/bookbinder/git_client.rb +10 -7
  34. data/lib/bookbinder/git_hub_repository.rb +46 -41
  35. data/lib/bookbinder/local_dita_preprocessor.rb +27 -0
  36. data/lib/bookbinder/local_dita_to_html_converter.rb +49 -0
  37. data/lib/bookbinder/local_file_system_accessor.rb +68 -0
  38. data/lib/bookbinder/middleman_runner.rb +30 -17
  39. data/lib/bookbinder/publisher.rb +16 -80
  40. data/lib/bookbinder/remote_yaml_credential_provider.rb +2 -3
  41. data/lib/bookbinder/repositories/command_repository.rb +156 -0
  42. data/lib/bookbinder/repositories/section_repository.rb +31 -0
  43. data/lib/bookbinder/section.rb +5 -67
  44. data/lib/bookbinder/shell_out.rb +1 -0
  45. data/lib/bookbinder/sheller.rb +19 -0
  46. data/lib/bookbinder/sieve.rb +6 -1
  47. data/lib/bookbinder/terminal.rb +10 -0
  48. data/lib/bookbinder/user_message.rb +6 -0
  49. data/lib/bookbinder/user_message_presenter.rb +21 -0
  50. data/lib/bookbinder/yaml_loader.rb +18 -7
  51. data/master_middleman/archive_drop_down_menu.rb +46 -0
  52. data/master_middleman/bookbinder_helpers.rb +47 -40
  53. metadata +33 -87
  54. data/lib/bookbinder/commands/publish.rb +0 -138
  55. data/lib/bookbinder/usage_messenger.rb +0 -33
@@ -5,7 +5,7 @@ require_relative '../archive'
5
5
  module Bookbinder
6
6
  module Commands
7
7
  class BuildAndPushTarball < BookbinderCommand
8
- extend Commands::Naming
8
+ include Commands::Naming
9
9
 
10
10
  class MissingBuildNumber < StandardError
11
11
  def initialize
@@ -13,17 +13,18 @@ module Bookbinder
13
13
  end
14
14
  end
15
15
 
16
- def self.usage
17
- "build_and_push_tarball \t \t \t Create a tarball from the final_app directory and push to the S3 bucket specified in your credentials.yml"
16
+ def usage
17
+ [command_name,
18
+ "Create a tarball from the final_app directory and push to the S3 bucket specified in your credentials.yml"]
18
19
  end
19
20
 
20
21
  def run(_)
21
22
  raise MissingBuildNumber unless ENV['BUILD_NUMBER']
22
23
  config = configuration_fetcher.fetch_config
23
24
  aws_credentials = config.aws_credentials
24
- repository = Archive.new(logger: @logger, key: aws_credentials.access_key, secret: aws_credentials.secret_key)
25
- repository.create_and_upload_tarball(build_number: ENV['BUILD_NUMBER'], bucket: aws_credentials.green_builds_bucket,
26
- namespace: GitHubRepository.new(logger: @logger, full_name: config.book_repo).short_name)
25
+ archive = Archive.new(logger: @logger, key: aws_credentials.access_key, secret: aws_credentials.secret_key)
26
+ archive.create_and_upload_tarball(build_number: ENV['BUILD_NUMBER'], bucket: aws_credentials.green_builds_bucket,
27
+ namespace: GitHubRepository.new(logger: @logger, full_name: config.book_repo, git_accessor: Git).short_name)
27
28
  0
28
29
  end
29
30
  end
@@ -0,0 +1,11 @@
1
+ module Bookbinder
2
+ module Commands
3
+ module Chain
4
+ private
5
+
6
+ def command_chain(*commands)
7
+ commands.all? {|command| command[] == 0} ? 0 : 1
8
+ end
9
+ end
10
+ end
11
+ end
@@ -6,7 +6,7 @@ require_relative 'naming'
6
6
  module Bookbinder
7
7
  module Commands
8
8
  class GeneratePDF < BookbinderCommand
9
- extend Commands::Naming
9
+ include Commands::Naming
10
10
 
11
11
  class AppNotPublished < StandardError
12
12
  def initialize(msg='You must publish locally before you generate a PDF.')
@@ -32,8 +32,9 @@ module Bookbinder
32
32
  end
33
33
  end
34
34
 
35
- def self.usage
36
- "generate_pdf [<file_name>.yml] \t \t Generate a PDF from the files specified in <file_name.yml>"
35
+ def usage
36
+ ["generate_pdf [<file_name>.yml]",
37
+ "Generate a PDF from the files specified in <file_name.yml>"]
37
38
  end
38
39
 
39
40
  def run(params)
@@ -1,21 +1,21 @@
1
+ require_relative 'naming'
2
+
1
3
  module Bookbinder
2
4
  module Commands
3
5
  class Help
4
- def initialize(logger, usage_message)
5
- @logger = logger
6
- @usage_message = usage_message
7
- end
6
+ include Commands::Naming
8
7
 
9
- def self.to_s
10
- 'help'
8
+ def initialize(logger, other_commands)
9
+ @logger = logger
10
+ @other_commands = other_commands
11
11
  end
12
12
 
13
- def self.command_name
13
+ def command_name
14
14
  '--help'
15
15
  end
16
16
 
17
- def self.usage
18
- "--help \t \t \t \t \t Print this message"
17
+ def usage
18
+ [command_name, "Print this message"]
19
19
  end
20
20
 
21
21
  def run(*)
@@ -23,9 +23,48 @@ module Bookbinder
23
23
  0
24
24
  end
25
25
 
26
+ def usage_message
27
+ [usage_header, command_usage_messages].join("\n")
28
+ end
29
+
26
30
  private
27
31
 
28
- attr_reader :logger, :usage_message
32
+ def command_usage_messages
33
+ (flags + standard_commands).reduce('') { |message, command|
34
+ "#{message}#{usage_indent}#{formatted_usage(command)}\n"
35
+ }
36
+ end
37
+
38
+ def formatted_usage(command)
39
+ "#{command.usage[0].ljust(chars_for_usage_definition)}#{command.usage[1]}"
40
+ end
41
+
42
+ def usage_indent
43
+ " " * 4
44
+ end
45
+
46
+ def chars_for_usage_definition
47
+ 33
48
+ end
49
+
50
+ def flags
51
+ other_commands.select(&:flag?) + [self]
52
+ end
53
+
54
+ def standard_commands
55
+ other_commands.reject(&:flag?)
56
+ end
57
+
58
+ def usage_header
59
+ <<TEXT
60
+
61
+ \e[1;39;49mDocumentation\e[0m: https://github.com/pivotal-cf/docs-bookbinder
62
+
63
+ \e[1;39;49mUsage\e[0m: bookbinder <command|flag> [args]
64
+ TEXT
65
+ end
66
+
67
+ attr_reader :logger, :other_commands
29
68
  end
30
69
  end
31
70
  end
@@ -2,7 +2,15 @@ module Bookbinder
2
2
  module Commands
3
3
  module Naming
4
4
  def command_name
5
- name.demodulize.underscore
5
+ self.class.name.demodulize.underscore
6
+ end
7
+
8
+ def command_for?(test_command_name)
9
+ command_name == test_command_name
10
+ end
11
+
12
+ def flag?
13
+ command_name.match(/^--/)
6
14
  end
7
15
  end
8
16
  end
@@ -5,10 +5,11 @@ require_relative 'naming'
5
5
  module Bookbinder
6
6
  module Commands
7
7
  class PushLocalToStaging < BookbinderCommand
8
- extend Commands::Naming
8
+ include Commands::Naming
9
9
 
10
- def self.usage
11
- "push_local_to_staging \t \t \t Push the contents of final_app to the staging host specified in credentials.yml"
10
+ def usage
11
+ [command_name,
12
+ "Push the contents of final_app to the staging host specified in credentials.yml"]
12
13
  end
13
14
 
14
15
  def run(_)
@@ -3,21 +3,35 @@ require_relative 'bookbinder_command'
3
3
  require_relative 'naming'
4
4
 
5
5
  module Bookbinder
6
+ class PushToProdValidator
7
+ MissingRequiredKeyError = Class.new(RuntimeError)
8
+ end
9
+
6
10
  module Commands
7
- class PushToProd < BookbinderCommand
8
- extend Commands::Naming
11
+ class PushToProd
12
+ include Commands::Naming
13
+ CONFIG_REQUIRED_KEYS = %w(cred_repo)
14
+
15
+ def initialize(logger, configuration_fetcher)
16
+ @logger = logger
17
+ @configuration_fetcher = configuration_fetcher
18
+ end
9
19
 
10
- def self.usage
11
- "push_to_prod [build_#] \t \t \t Push latest or <build_#> from your S3 bucket to the production host specified in credentials.yml"
20
+ def usage
21
+ ["push_to_prod [build_#]",
22
+ "Push latest or <build_#> from your S3 bucket to the production host specified in credentials.yml"]
12
23
  end
13
24
 
14
25
  def run(arguments)
26
+ validate
15
27
  Distributor.build(@logger, options(arguments)).distribute
16
28
  0
17
29
  end
18
30
 
19
31
  private
20
32
 
33
+ attr_reader :configuration_fetcher
34
+
21
35
  def options(arguments)
22
36
  {
23
37
  app_dir: Dir.mktmpdir,
@@ -30,6 +44,24 @@ module Bookbinder
30
44
  production: true
31
45
  }
32
46
  end
47
+
48
+ def config
49
+ @config ||= configuration_fetcher.fetch_config
50
+ end
51
+
52
+ def validate
53
+ missing_keys = []
54
+ CONFIG_REQUIRED_KEYS.map do |required_key|
55
+ unless config.has_option?(required_key)
56
+ missing_keys.push(required_key)
57
+ end
58
+ end
59
+
60
+ if missing_keys.length > 0
61
+ raise PushToProdValidator::MissingRequiredKeyError.new "Your config.yml is missing required key(s). The require keys for this commands are " + missing_keys.join(", ")
62
+ end
63
+ end
64
+
33
65
  end
34
66
  end
35
67
  end
@@ -1,42 +1,39 @@
1
- require_relative 'bookbinder_command'
1
+ require_relative 'bind'
2
+ require_relative 'build_and_push_tarball'
3
+ require_relative 'chain'
2
4
  require_relative 'naming'
3
- require_relative 'publish'
4
5
  require_relative 'push_local_to_staging'
5
- require_relative 'build_and_push_tarball'
6
6
 
7
7
  module Bookbinder
8
8
  module Commands
9
- class RunPublishCI < BookbinderCommand
10
- extend Commands::Naming
9
+ class RunPublishCI
10
+ include Commands::Naming
11
+ include Commands::Chain
11
12
 
12
- def self.usage
13
- "run_publish_ci \t \t \t \t Run publish, push_local_to_staging, and build_and_push_tarball for CI purposes"
13
+ def usage
14
+ [command_name,
15
+ "Run publish, push_local_to_staging, and build_and_push_tarball for CI purposes"]
14
16
  end
15
17
 
16
- def run(cli_args)
17
- check_params
18
- all_successfully_ran = publish(cli_args) == 0 && push_to_staging == 0 && push_tarball == 0
19
- all_successfully_ran ? 0 : 1
18
+ def initialize(publish_command, push_local_to_staging_command, build_and_push_tarball_command)
19
+ @publish_command = publish_command
20
+ @push_local_to_staging_command = push_local_to_staging_command
21
+ @build_and_push_tarball_command = build_and_push_tarball_command
20
22
  end
21
23
 
22
- private
23
-
24
- def check_params
24
+ def run(cli_args)
25
25
  raise BuildAndPushTarball::MissingBuildNumber unless ENV['BUILD_NUMBER']
26
- config.book_repo
27
- end
28
26
 
29
- def publish(cli_args)
30
- Publish.new(@logger, @configuration_fetcher).run(['github'] + cli_args)
27
+ command_chain(
28
+ ->{publish_command.run(['github'] + cli_args)},
29
+ ->{push_local_to_staging_command.run([])},
30
+ ->{build_and_push_tarball_command.run([])}
31
+ )
31
32
  end
32
33
 
33
- def push_to_staging
34
- PushLocalToStaging.new(@logger, @configuration_fetcher).run []
35
- end
34
+ private
36
35
 
37
- def push_tarball
38
- BuildAndPushTarball.new(@logger, @configuration_fetcher).run []
39
- end
36
+ attr_reader :publish_command, :push_local_to_staging_command, :build_and_push_tarball_command
40
37
  end
41
38
  end
42
39
  end
@@ -8,10 +8,10 @@ require_relative 'naming'
8
8
  module Bookbinder
9
9
  module Commands
10
10
  class Tag < BookbinderCommand
11
- extend Commands::Naming
11
+ include Commands::Naming
12
12
 
13
- def self.usage
14
- "tag <git tag> \t \t \t \t Apply the specified <git tag> to your book and all sections of your book"
13
+ def usage
14
+ ["tag <git tag>", "Apply the specified <git tag> to your book and all sections of your book"]
15
15
  end
16
16
 
17
17
  def run(params)
@@ -4,10 +4,11 @@ require_relative 'naming'
4
4
  module Bookbinder
5
5
  module Commands
6
6
  class UpdateLocalDocRepos < BookbinderCommand
7
- extend Commands::Naming
7
+ include Commands::Naming
8
8
 
9
- def self.usage
10
- "update_local_doc_repos \t \t \t Run `git pull` on all sections that exist at the same directory level as your book directory"
9
+ def usage
10
+ [command_name,
11
+ "Run `git pull` on all sections that exist at the same directory level as your book directory"]
11
12
  end
12
13
 
13
14
  def run(_)
@@ -20,7 +21,7 @@ module Bookbinder
20
21
  def repo_for(section_config)
21
22
  local_repo_dir = File.absolute_path('../')
22
23
  GitHubRepository.new(logger: @logger, full_name: section_config['repository']['name'],
23
- local_repo_dir: local_repo_dir)
24
+ local_repo_dir: local_repo_dir, git_accessor: Git)
24
25
  end
25
26
  end
26
27
  end
@@ -1,22 +1,25 @@
1
- require_relative 'bookbinder_command'
1
+ require_relative 'naming'
2
2
 
3
3
  module Bookbinder
4
4
  module Commands
5
- class Version < BookbinderCommand
6
- def self.to_s
7
- 'version'
5
+ class Version
6
+ include Commands::Naming
7
+
8
+ def initialize(logger)
9
+ @logger = logger
8
10
  end
9
11
 
10
- def self.command_name
12
+ def command_name
11
13
  '--version'
12
14
  end
13
15
 
14
- def self.usage
15
- "--version \t \t \t \t Print the version of bookbinder"
16
+ def usage
17
+ [command_name, "Print the version of bookbinder"]
16
18
  end
17
19
 
18
20
  def run(*)
19
- @logger.log "bookbinder #{Gem::Specification::load(File.join GEM_ROOT, "bookbinder.gemspec").version}"
21
+ root = File.expand_path('../../../../', __FILE__)
22
+ @logger.log "bookbinder #{Gem::Specification::load(File.join root, "bookbinder.gemspec").version}"
20
23
  0
21
24
  end
22
25
 
@@ -1,5 +1,6 @@
1
1
  require_relative 'remote_yaml_credential_provider'
2
2
  require_relative 'git_hub_repository'
3
+ require 'git'
3
4
 
4
5
  module Bookbinder
5
6
  class Configuration
@@ -105,8 +106,8 @@ module Bookbinder
105
106
  @config = config_hash
106
107
  end
107
108
 
108
- CONFIG_REQUIRED_KEYS = %w(book_repo layout_repo cred_repo sections public_host pdf pdf_index versions)
109
- CONFIG_OPTIONAL_KEYS = %w(archive_menu)
109
+ CONFIG_REQUIRED_KEYS = %w(book_repo public_host pdf)
110
+ CONFIG_OPTIONAL_KEYS = %w(archive_menu dita_sections layout_repo versions pdf_index cred_repo)
110
111
 
111
112
  CONFIG_REQUIRED_KEYS.each do |method_name|
112
113
  define_method(method_name) do
@@ -120,6 +121,10 @@ module Bookbinder
120
121
  end
121
122
  end
122
123
 
124
+ def sections
125
+ config.fetch('sections', [])
126
+ end
127
+
123
128
  def has_option?(key)
124
129
  @config.has_key?(key)
125
130
  end
@@ -157,7 +162,7 @@ module Bookbinder
157
162
  end
158
163
 
159
164
  def credentials_repository
160
- @credentials_repository ||= GitHubRepository.new(logger: @logger, full_name: cred_repo)
165
+ @credentials_repository ||= GitHubRepository.new(logger: @logger, full_name: cred_repo, git_accessor: Git)
161
166
  end
162
167
  end
163
168
  end
@@ -1,13 +1,8 @@
1
+ require_relative 'configuration'
1
2
  require_relative 'yaml_loader'
2
3
 
3
4
  module Bookbinder
4
-
5
5
  class ConfigurationFetcher
6
- attr_reader :logger,
7
- :configuration_validator,
8
- :config,
9
- :config_file_path
10
-
11
6
  def initialize(logger, configuration_validator, loader)
12
7
  @loader = loader
13
8
  @logger = logger
@@ -22,30 +17,17 @@ module Bookbinder
22
17
  @config_file_path = config_file_path
23
18
  end
24
19
 
25
-
26
20
  private
27
21
 
28
- attr_reader :loader
22
+ attr_reader(:loader, :logger, :configuration_validator, :config, :config_file_path)
29
23
 
30
24
  def read_config_file
25
+ loader.load(config_file_path).merge('pdf_index' => nil)
31
26
 
32
- begin
33
- config_hash = loader.load(config_file_path)
34
- rescue FileNotFoundError => e
35
- raise "The configuration file specified does not exist. Please create a config #{e} file at #{config_file_path} and try again."
36
- rescue InvalidSyntaxError => e
37
- raise "There is a syntax error in your config file: \n #{e}"
38
- end
39
-
40
- if config_hash
41
- if File.exists?('./pdf_index.yml')
42
- config_hash['pdf_index'] = loader.load(config_file_path)
43
- else
44
- config_hash['pdf_index'] = nil
45
- end
46
- end
47
-
48
- config_hash
27
+ rescue FileNotFoundError => e
28
+ raise "The configuration file specified does not exist. Please create a config #{e} file at #{config_file_path} and try again."
29
+ rescue InvalidSyntaxError => e
30
+ raise "There is a syntax error in your config file: \n #{e}"
49
31
  end
50
32
 
51
33
  def validate(config_hash)