bookbindery 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bookbinder.rb +2 -2
  3. data/lib/bookbinder/app_fetcher.rb +2 -6
  4. data/lib/bookbinder/archive.rb +1 -1
  5. data/lib/bookbinder/book.rb +7 -2
  6. data/lib/bookbinder/cli.rb +4 -5
  7. data/lib/bookbinder/code_example_reader.rb +1 -1
  8. data/lib/bookbinder/command_validator.rb +30 -10
  9. data/lib/bookbinder/commands/bind.rb +58 -53
  10. data/lib/bookbinder/commands/help.rb +4 -4
  11. data/lib/bookbinder/commands/naming.rb +14 -4
  12. data/lib/bookbinder/commands/push_from_local.rb +51 -0
  13. data/lib/bookbinder/commands/push_to_prod.rb +1 -2
  14. data/lib/bookbinder/commands/run_publish_ci.rb +1 -1
  15. data/lib/bookbinder/commands/tag.rb +1 -1
  16. data/lib/bookbinder/commands/version.rb +5 -4
  17. data/lib/bookbinder/configuration.rb +49 -28
  18. data/lib/bookbinder/configuration_fetcher.rb +1 -1
  19. data/lib/bookbinder/configuration_validator.rb +40 -37
  20. data/lib/bookbinder/{bookbinder_logger.rb → deprecated_logger.rb} +1 -1
  21. data/lib/bookbinder/distributor.rb +16 -9
  22. data/lib/bookbinder/dita_html_to_middleman_formatter.rb +26 -8
  23. data/lib/bookbinder/dita_section.rb +8 -2
  24. data/lib/bookbinder/git_hub_repository.rb +7 -20
  25. data/lib/bookbinder/html_document_manipulator.rb +21 -0
  26. data/lib/bookbinder/ingest/cloner_factory.rb +25 -0
  27. data/lib/bookbinder/ingest/git_hub_repository_cloner_facade.rb +26 -0
  28. data/lib/bookbinder/ingest/local_filesystem_cloner_facade.rb +28 -0
  29. data/lib/bookbinder/local_dita_preprocessor.rb +33 -5
  30. data/lib/bookbinder/local_dita_to_html_converter.rb +26 -28
  31. data/lib/bookbinder/local_file_system_accessor.rb +0 -5
  32. data/lib/bookbinder/publisher.rb +1 -1
  33. data/lib/bookbinder/remote_yaml_credential_provider.rb +1 -1
  34. data/lib/bookbinder/repositories/command_repository.rb +21 -5
  35. data/lib/bookbinder/section.rb +12 -1
  36. data/lib/bookbinder/subnav.rb +4 -0
  37. data/lib/bookbinder/subnav_formatter.rb +37 -0
  38. data/lib/bookbinder/user_message.rb +10 -1
  39. data/master_middleman/bookbinder_helpers.rb +3 -3
  40. metadata +46 -40
  41. data/lib/bookbinder/commands/push_local_to_staging.rb +0 -36
@@ -38,10 +38,9 @@ module Bookbinder
38
38
  build_number: arguments[0],
39
39
 
40
40
  aws_credentials: config.aws_credentials,
41
- cf_credentials: config.cf_production_credentials,
41
+ cf_credentials: config.cf_credentials('production'),
42
42
 
43
43
  book_repo: config.book_repo,
44
- production: true
45
44
  }
46
45
  end
47
46
 
@@ -2,7 +2,7 @@ require_relative 'bind'
2
2
  require_relative 'build_and_push_tarball'
3
3
  require_relative 'chain'
4
4
  require_relative 'naming'
5
- require_relative 'push_local_to_staging'
5
+ require_relative 'push_from_local'
6
6
 
7
7
  module Bookbinder
8
8
  module Commands
@@ -1,6 +1,6 @@
1
1
  require_relative '../book'
2
- require_relative '../bookbinder_logger'
3
2
  require_relative '../cli_error'
3
+ require_relative '../deprecated_logger'
4
4
 
5
5
  require_relative 'bookbinder_command'
6
6
  require_relative 'naming'
@@ -9,10 +9,6 @@ module Bookbinder
9
9
  @logger = logger
10
10
  end
11
11
 
12
- def command_name
13
- '--version'
14
- end
15
-
16
12
  def usage
17
13
  [command_name, "Print the version of bookbinder"]
18
14
  end
@@ -23,6 +19,11 @@ module Bookbinder
23
19
  0
24
20
  end
25
21
 
22
+ private
23
+
24
+ def command_name
25
+ '--version'
26
+ end
26
27
  end
27
28
  end
28
29
  end
@@ -1,6 +1,6 @@
1
- require_relative 'remote_yaml_credential_provider'
2
- require_relative 'git_hub_repository'
3
1
  require 'git'
2
+ require_relative 'git_hub_repository'
3
+ require_relative 'remote_yaml_credential_provider'
4
4
 
5
5
  module Bookbinder
6
6
  class Configuration
@@ -8,14 +8,11 @@ module Bookbinder
8
8
  CURRENT_SCHEMA_VERSION = '1.0.0'
9
9
  STARTING_SCHEMA_VERSION = '1.0.0'
10
10
 
11
- class CredentialKeyError < StandardError;
12
- end
13
-
14
- class ConfigSchemaUnsupportedError < StandardError;
15
- end
11
+ CredentialKeyError = Class.new(StandardError)
12
+ ConfigSchemaUnsupportedError = Class.new(StandardError)
16
13
 
17
14
  class AwsCredentials
18
- REQUIRED_KEYS = %w(access_key secret_key green_builds_bucket).freeze
15
+ REQUIRED_KEYS = %w(access_key secret_key green_builds_bucket)
19
16
 
20
17
  def initialize(cred_hash)
21
18
  @creds = cred_hash
@@ -37,12 +34,11 @@ module Bookbinder
37
34
  end
38
35
 
39
36
  class CfCredentials
40
- REQUIRED_KEYS = %w(api_endpoint organization app_name).freeze
41
- OPTIONAL_KEYS = %w(username password production_space production_host staging_space staging_host).freeze
37
+ REQUIRED_KEYS = %w(api_endpoint organization app_name)
42
38
 
43
- def initialize(cred_hash, is_production)
39
+ def initialize(cred_hash, environment)
44
40
  @creds = cred_hash
45
- @is_production = is_production
41
+ @environment = environment
46
42
  end
47
43
 
48
44
  REQUIRED_KEYS.each do |method_name|
@@ -51,15 +47,33 @@ module Bookbinder
51
47
  end
52
48
  end
53
49
 
54
- OPTIONAL_KEYS.each do |method_name|
55
- define_method(method_name) do
56
- creds.fetch(method_name, nil)
50
+ def ==(other)
51
+ [@creds, @environment] == [
52
+ other.instance_variable_get(:@creds),
53
+ other.instance_variable_get(:@environment)
54
+ ]
55
+ end
56
+
57
+ def username
58
+ creds['username']
59
+ end
60
+
61
+ def password
62
+ creds['password']
63
+ end
64
+
65
+ def download_archive_before_push?
66
+ production?
67
+ end
68
+
69
+ def push_warning
70
+ if production?
71
+ 'Warning: You are pushing to CF Docs production. Be careful.'
57
72
  end
58
73
  end
59
74
 
60
75
  def routes
61
- key = is_production ? 'production_host' : 'staging_host'
62
- fetch(key) if correctly_formatted_domain_and_routes?(key)
76
+ fetch(host_key) if correctly_formatted_domain_and_routes?(host_key)
63
77
  end
64
78
 
65
79
  def flat_routes
@@ -70,13 +84,16 @@ module Bookbinder
70
84
  end
71
85
 
72
86
  def space
73
- key = is_production ? 'production_space' : 'staging_space'
74
- fetch(key)
87
+ fetch(space_key)
75
88
  end
76
89
 
77
90
  private
78
91
 
79
- attr_reader :creds, :is_production
92
+ attr_reader :creds, :environment
93
+
94
+ def production?
95
+ environment == 'production'
96
+ end
80
97
 
81
98
  def fetch(key)
82
99
  creds.fetch(key)
@@ -97,6 +114,14 @@ module Bookbinder
97
114
  raise "Hosts in credentials must be nested as an array under the desired domain #{domain}." unless routes_hash[domain].is_a? Array
98
115
  raise "Did you mean to provide a hostname for the domain #{domain}? Check your credentials.yml." if routes_hash[domain].any?(&:nil?)
99
116
  end
117
+
118
+ def host_key
119
+ "#{environment}_host"
120
+ end
121
+
122
+ def space_key
123
+ "#{environment}_space"
124
+ end
100
125
  end
101
126
 
102
127
  attr_reader :schema_version, :schema_major_version, :schema_minor_version, :schema_patch_version
@@ -106,8 +131,8 @@ module Bookbinder
106
131
  @config = config_hash
107
132
  end
108
133
 
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)
134
+ CONFIG_REQUIRED_KEYS = %w(book_repo public_host)
135
+ CONFIG_OPTIONAL_KEYS = %w(archive_menu dita_sections layout_repo versions pdf_index cred_repo pdf)
111
136
 
112
137
  CONFIG_REQUIRED_KEYS.each do |method_name|
113
138
  define_method(method_name) do
@@ -137,12 +162,8 @@ module Bookbinder
137
162
  @aws_creds ||= AwsCredentials.new(credentials.fetch('aws'))
138
163
  end
139
164
 
140
- def cf_staging_credentials
141
- @cf_staging_creds ||= CfCredentials.new(credentials.fetch('cloud_foundry'), false)
142
- end
143
-
144
- def cf_production_credentials
145
- @cf_prod_creds ||= CfCredentials.new(credentials.fetch('cloud_foundry'), true)
165
+ def cf_credentials(environment)
166
+ CfCredentials.new(credentials.fetch('cloud_foundry'), environment)
146
167
  end
147
168
 
148
169
  def ==(o)
@@ -14,7 +14,7 @@ module Bookbinder
14
14
  end
15
15
 
16
16
  def set_config_file_path config_file_path
17
- @config_file_path = config_file_path
17
+ @config_file_path = File.expand_path config_file_path
18
18
  end
19
19
 
20
20
  private
@@ -1,6 +1,40 @@
1
1
  require 'active_support/core_ext/object/blank'
2
2
 
3
3
  module Bookbinder
4
+ class ConfigurationValidator
5
+ DuplicateSectionNameError = Class.new(RuntimeError)
6
+ MissingArchiveMenuPartialError = Class.new(RuntimeError)
7
+ EmptyArchiveItemsError = Class.new(RuntimeError)
8
+ ArchiveMenuNotDefinedError = Class.new(RuntimeError)
9
+ MissingRequiredKeyError = Class.new(RuntimeError)
10
+
11
+ def initialize(logger, file_system_accessor)
12
+ @logger = logger
13
+ @file_system_accessor = file_system_accessor
14
+ end
15
+
16
+ def valid?(config_hash, bookbinder_schema_version, starting_schema_version)
17
+ raise 'Your config.yml appears to be empty. Please check and try again.' unless config_hash
18
+
19
+ user_config_schema_version = config_hash['schema_version']
20
+ exceptions = [
21
+ RequiredKeysChecker.new,
22
+ ConfigVersionChecker.new(Version.parse(bookbinder_schema_version),
23
+ Version.parse(starting_schema_version),
24
+ VersionCheckerMessages.new(Version.parse(user_config_schema_version),
25
+ bookbinder_schema_version),
26
+ @logger),
27
+ DuplicateSectionNameChecker.new,
28
+ ArchiveMenuChecker.new(@file_system_accessor)
29
+ ].map do |checker|
30
+ checker.check(config_hash)
31
+ end
32
+ exception = exceptions.compact.first
33
+ raise exception if exception
34
+
35
+ true
36
+ end
37
+ end
4
38
 
5
39
  class DuplicateSectionNameChecker
6
40
  def check(config)
@@ -12,8 +46,12 @@ module Bookbinder
12
46
  private
13
47
 
14
48
  def duplicate_section_names?(config)
15
- directory_names = config['sections'].map {|section| section['directory']}
16
- directory_names.length != directory_names.uniq.length
49
+ if config['sections']
50
+ directory_names = config['sections'].map {|section| section['directory']}
51
+ directory_names.length != directory_names.uniq.length
52
+ else
53
+ false
54
+ end
17
55
  end
18
56
 
19
57
  end
@@ -147,39 +185,4 @@ module Bookbinder
147
185
  end
148
186
  end
149
187
  end
150
-
151
- class ConfigurationValidator
152
- DuplicateSectionNameError = Class.new(RuntimeError)
153
- MissingArchiveMenuPartialError = Class.new(RuntimeError)
154
- EmptyArchiveItemsError = Class.new(RuntimeError)
155
- ArchiveMenuNotDefinedError = Class.new(RuntimeError)
156
- MissingRequiredKeyError = Class.new(RuntimeError)
157
-
158
- def initialize(logger, file_system_accessor)
159
- @logger = logger
160
- @file_system_accessor = file_system_accessor
161
- end
162
-
163
- def valid?(config_hash, bookbinder_schema_version, starting_schema_version)
164
- raise 'Your config.yml appears to be empty. Please check and try again.' unless config_hash
165
-
166
- user_config_schema_version = config_hash['schema_version']
167
- exceptions = [
168
- RequiredKeysChecker.new,
169
- ConfigVersionChecker.new(Version.parse(bookbinder_schema_version),
170
- Version.parse(starting_schema_version),
171
- VersionCheckerMessages.new(Version.parse(user_config_schema_version),
172
- bookbinder_schema_version),
173
- @logger),
174
- DuplicateSectionNameChecker.new,
175
- ArchiveMenuChecker.new(@file_system_accessor)
176
- ].map do |checker|
177
- checker.check(config_hash)
178
- end
179
- exception = exceptions.compact.first
180
- raise exception if exception
181
-
182
- true
183
- end
184
- end
185
188
  end
@@ -5,7 +5,7 @@ class String
5
5
  end
6
6
 
7
7
  module Bookbinder
8
- class BookbinderLogger
8
+ class DeprecatedLogger
9
9
  def log(message)
10
10
  puts message
11
11
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'app_fetcher'
2
+ require_relative 'artifact_namer'
2
3
 
3
4
  module Bookbinder
4
5
  class Distributor
@@ -27,14 +28,18 @@ module Bookbinder
27
28
 
28
29
  def distribute
29
30
  begin
30
- download if options[:production]
31
+ download if cf_credentials.download_archive_before_push?
31
32
  push_app
32
33
  nil
33
34
  rescue => e
34
- cf_credentials = options[:cf_credentials]
35
- cf_space = options[:production] ? cf_credentials.production_space : cf_credentials.staging_space
36
- cf_routes = options[:production] ? cf_credentials.production_host : cf_credentials.staging_host
37
- @logger.error "[ERROR] #{e.message}\n[DEBUG INFO]\nCF organization: #{cf_credentials.organization}\nCF space: #{cf_space}\nCF account: #{cf_credentials.username}\nroutes: #{cf_routes}"
35
+ @logger.error(<<-ERROR.chomp)
36
+ [ERROR] #{e.message}
37
+ [DEBUG INFO]
38
+ CF organization: #{cf_credentials.organization}
39
+ CF space: #{cf_credentials.space}
40
+ CF account: #{cf_credentials.username}
41
+ routes: #{cf_credentials.routes}
42
+ ERROR
38
43
  ensure
39
44
  upload_trace
40
45
  end
@@ -45,12 +50,14 @@ module Bookbinder
45
50
  attr_reader :options, :archive, :namer, :namespace, :pusher
46
51
 
47
52
  def download
48
- archive.download(download_dir: options[:app_dir], bucket: options[:aws_credentials].green_builds_bucket, build_number: options[:build_number],
53
+ archive.download(download_dir: options[:app_dir],
54
+ bucket: options[:aws_credentials].green_builds_bucket,
55
+ build_number: options[:build_number],
49
56
  namespace: namespace)
50
57
  end
51
58
 
52
59
  def push_app
53
- warn if options[:production]
60
+ @logger.warn(cf_credentials.push_warning) if cf_credentials.push_warning
54
61
  pusher.push(options[:app_dir])
55
62
  end
56
63
 
@@ -62,8 +69,8 @@ module Bookbinder
62
69
  @logger.error "Could not find CF trace file: #{namer.full_path}"
63
70
  end
64
71
 
65
- def warn
66
- @logger.warn 'Warning: You are pushing to CF Docs production. Be careful.'
72
+ def cf_credentials
73
+ options[:cf_credentials]
67
74
  end
68
75
  end
69
76
  end
@@ -1,19 +1,24 @@
1
+ require_relative 'subnav'
2
+
1
3
  module Bookbinder
2
4
 
3
5
  class DitaHtmlToMiddlemanFormatter
4
- def initialize(file_system_accessor)
6
+ def initialize(file_system_accessor, subnav_formatter, html_document_manipulator)
5
7
  @file_system_accessor = file_system_accessor
8
+ @subnav_formatter = subnav_formatter
9
+ @html_document_manipulator = html_document_manipulator
6
10
  end
7
11
 
8
- def format(src, dest)
12
+ def format_html(src, dest)
9
13
  all_files_with_ext = file_system_accessor.find_files_with_ext('.html', src)
10
14
 
11
15
  all_files_with_ext.map do |filepath|
12
- file_title_text = file_system_accessor.read_html_in_tag(path: filepath,
13
- marker: 'title')
16
+ file_text = file_system_accessor.read filepath
17
+ file_title_text = html_document_manipulator.read_html_in_tag(document: file_text,
18
+ tag: 'title')
14
19
 
15
- file_body_text = file_system_accessor.read_html_in_tag(path: filepath,
16
- marker: 'body')
20
+ file_body_text = html_document_manipulator.read_html_in_tag(document: file_text,
21
+ tag: 'body')
17
22
 
18
23
  relative_path_to_file = file_system_accessor.relative_path_from(src, filepath)
19
24
  new_filepath = File.join dest, "#{relative_path_to_file}.erb"
@@ -24,14 +29,27 @@ module Bookbinder
24
29
  end
25
30
  end
26
31
 
32
+ def format_subnav(dita_section,
33
+ subnav_template_text,
34
+ json_props_location,
35
+ unformatted_subnav_text)
36
+ formatted_json_links = subnav_formatter.get_links_as_json(unformatted_subnav_text, dita_section.directory)
37
+
38
+ nav_text = html_document_manipulator.set_attribute(document: subnav_template_text,
39
+ selector: 'div.nav-content',
40
+ attribute: 'data-props-location',
41
+ value: json_props_location)
42
+ Subnav.new(formatted_json_links, nav_text)
43
+ end
44
+
27
45
  private
28
46
 
29
- attr_reader :file_system_accessor
47
+ attr_reader :file_system_accessor, :subnav_formatter, :html_document_manipulator
30
48
 
31
49
  def frontmatter(title)
32
50
  sanitized_title = title.gsub('"', '\"')
33
51
  "---\ntitle: \"#{sanitized_title}\"\ndita: true\n---\n"
34
52
  end
35
-
36
53
  end
54
+
37
55
  end
@@ -3,5 +3,11 @@ module Bookbinder
3
3
  :ditamap_location,
4
4
  :full_name,
5
5
  :target_ref,
6
- :directory)
7
- end
6
+ :directory) do
7
+ def subnav
8
+ namespace = directory.gsub('/', '_')
9
+ template = "#{directory}_subnav"
10
+ {namespace => template}
11
+ end
12
+ end
13
+ end
@@ -1,7 +1,7 @@
1
- require 'bookbinder/shell_out'
2
1
  require 'git'
3
- require_relative 'bookbinder_logger'
2
+ require_relative 'deprecated_logger'
4
3
  require_relative 'git_client'
4
+ require_relative 'shell_out'
5
5
 
6
6
  module Bookbinder
7
7
  class GitHubRepository
@@ -13,14 +13,11 @@ module Bookbinder
13
13
 
14
14
  def self.build_from_remote(logger,
15
15
  section_hash,
16
- target_ref,
17
16
  git_accessor)
18
17
  full_name = section_hash.fetch('repository', {}).fetch('name')
19
- target_ref = target_ref || section_hash.fetch('repository', {})['ref']
20
18
  directory = section_hash['directory']
21
19
  new(logger: logger,
22
20
  full_name: full_name,
23
- target_ref: target_ref,
24
21
  github_token: ENV['GITHUB_API_TOKEN'],
25
22
  directory: directory,
26
23
  git_accessor: git_accessor)
@@ -42,7 +39,6 @@ module Bookbinder
42
39
 
43
40
  def initialize(logger: nil,
44
41
  full_name: nil,
45
- target_ref: nil,
46
42
  github_token: nil,
47
43
  directory: nil,
48
44
  local_repo_dir: nil,
@@ -50,7 +46,6 @@ module Bookbinder
50
46
  @logger = logger
51
47
  raise 'No full_name provided ' unless full_name
52
48
  @full_name = full_name
53
- @target_ref = target_ref
54
49
  @directory = directory
55
50
  @local_repo_dir = local_repo_dir
56
51
 
@@ -75,7 +70,7 @@ module Bookbinder
75
70
  @directory || short_name
76
71
  end
77
72
 
78
- def copy_from_remote(destination_dir)
73
+ def copy_from_remote(destination_dir, target_ref)
79
74
  begin
80
75
  @git_base_object = git_accessor.clone("git@github.com:#{full_name}",
81
76
  directory,
@@ -131,22 +126,14 @@ module Bookbinder
131
126
  @logger.log ' skipping (not found) '.magenta + path_to_local_repo
132
127
  end
133
128
 
134
- def path_to_local_repo
135
- if @local_repo_dir
136
- File.join(@local_repo_dir, short_name)
137
- end
138
- end
139
-
140
- def has_git_object?
141
- !!@git_base_object
142
- end
143
-
144
129
  private
145
130
 
146
131
  attr_reader :git_accessor
147
132
 
148
- def target_ref
149
- @target_ref ||= 'master'
133
+ def path_to_local_repo
134
+ if @local_repo_dir
135
+ File.join(@local_repo_dir, short_name)
136
+ end
150
137
  end
151
138
 
152
139
  def tags