bookbindery 1.0.3 → 2.0.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 (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)