dbdoc 0.1.0 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35a675eef6484bf4c2c6bb78521c9f322ff057804feec72e34061eb899153352
4
- data.tar.gz: 5e80744c319d0e2ea77b321704e317467e871e9d93a53ad77871c655106b8f3b
3
+ metadata.gz: c25899d4d18291f22be12f731230d64669f353e422f63d069791bd030ba3d9a8
4
+ data.tar.gz: be30d30193572b1b4dcf5141c010e9593e373d90c099f5e41ab40f5a06cf7e40
5
5
  SHA512:
6
- metadata.gz: b49a2edb0d2e31280b4bd8ed29ef109da6ff38fd6669df30a260f049ad5ad841bea5425d3c68fd9862f8e74116f4cbcb90e767f69e44aeed2c0910429ba13ac1
7
- data.tar.gz: 18b09c76bc60de2ffb1a574a9695d03b1be0ba5c40b3bedbeb2d59eaefbd4b431b4a370ea52cb46defb34a388b9a177e2dd6c4496e7a78bdf1c3d7ed0d607a82
6
+ metadata.gz: ecc79a5cabb4a5cea63e5ae92c9b2c5b331c539590da6464aef4a789c96167a50a9aa876a840186b8e4ac3d29c5db4db6024b0bc5c2183c02bf44037c89cf09b
7
+ data.tar.gz: d7b19650e610c9a2b0c4b7c26250571f3811f459016740b85925d6e82d56d8c72b7119a2b0c6c14237638b295d832156e7a4ab7784da9748670e290a96a33618
@@ -0,0 +1,2 @@
1
+ github: makaroni4
2
+ ko_fi: makaroni4
@@ -1,2 +1,27 @@
1
1
  Style/StringLiterals:
2
2
  EnforcedStyle: double_quotes
3
+
4
+ Metrics/ClassLength:
5
+ Max: 200
6
+
7
+ Metrics/MethodLength:
8
+ Max: 50
9
+
10
+ Style/Documentation:
11
+ Exclude:
12
+ - lib/confluence/api.rb
13
+ - lib/dbdoc/cli.rb
14
+
15
+ Metrics/AbcSize:
16
+ Exclude:
17
+ - lib/dbdoc/cli.rb
18
+
19
+ Layout/FirstHashElementIndentation:
20
+ EnforcedStyle: consistent
21
+
22
+ Metrics/BlockLength:
23
+ Exclude:
24
+ - spec/**/*_spec.rb
25
+
26
+ Security/YAMLLoad:
27
+ Enabled: false
data/Gemfile CHANGED
@@ -1,13 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  gemspec
4
6
 
5
- gem "httparty"
6
-
7
7
  group :development do
8
8
  gem "byebug"
9
9
  gem "coveralls", require: false
10
- gem "rubocop"
11
10
  gem "rake", "~> 12.0"
12
11
  gem "rspec", "~> 3.0"
12
+ gem "rubocop"
13
13
  end
@@ -1,7 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dbdoc (0.1.0)
4
+ dbdoc (0.3.5)
5
+ httparty (~> 0.18)
6
+ kramdown (~> 2.3)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
@@ -20,6 +22,8 @@ GEM
20
22
  mime-types (~> 3.0)
21
23
  multi_xml (>= 0.5.2)
22
24
  json (2.3.1)
25
+ kramdown (2.3.0)
26
+ rexml
23
27
  mime-types (3.3.1)
24
28
  mime-types-data (~> 3.2015)
25
29
  mime-types-data (3.2020.0512)
@@ -76,7 +80,6 @@ DEPENDENCIES
76
80
  byebug
77
81
  coveralls
78
82
  dbdoc!
79
- httparty
80
83
  rake (~> 12.0)
81
84
  rspec (~> 3.0)
82
85
  rubocop
data/README.md CHANGED
@@ -40,7 +40,11 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
40
40
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
41
41
 
42
42
  ```
43
- gem uninstall dbdoc && gem build dbdoc.gemspec && bundle && rake build && rake install && dbdoc help
43
+ Y | gem uninstall dbdoc && gem build dbdoc.gemspec && bundle && rake build && rake install && dbdoc help
44
+ ```
45
+
46
+ ```
47
+ Y | gem uninstall dbdoc && gem build dbdoc.gemspec && bundle && rake build && rake release
44
48
  ```
45
49
 
46
50
  ## Contributing
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
  require "rubocop/rake_task"
data/bin/dbdoc CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #!/usr/bin/env ruby
2
4
 
3
5
  require "dbdoc"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "lib/dbdoc/version"
2
4
 
3
5
  Gem::Specification.new do |spec|
@@ -22,4 +24,7 @@ Gem::Specification.new do |spec|
22
24
 
23
25
  spec.executables = ["dbdoc"]
24
26
  spec.require_paths = ["lib"]
27
+
28
+ spec.add_runtime_dependency "httparty", "~> 0.18"
29
+ spec.add_runtime_dependency "kramdown", "~> 2.3"
25
30
  end
@@ -1,4 +1,4 @@
1
- ||Name||Type||Description||
1
+ ||Name||Type||Foreign Key||Description||
2
2
  <%- columns.each do |column| -%>
3
- |<%= column[:name] %>|<%= column[:type] %>|<%= column[:description].strip %>|
3
+ |<%= column[:name] %>|<%= column[:type] %>|<%= column[:foreign_key] || " " %>|<%= column[:description].strip %>|
4
4
  <%- end -%>
@@ -3,6 +3,7 @@
3
3
  - :name: <%= name %>
4
4
  :type: <%= type %>
5
5
  :position: <%= position %>
6
+ :foreign_key: TODO
6
7
  :description: |
7
8
  TODO
8
9
  <%- end -%>
@@ -1 +1,5 @@
1
- Write table description here
1
+ This is a table description in a normal Markdown.
2
+
3
+ This is **bold**.
4
+
5
+ This is *italic*.
@@ -1,10 +1,8 @@
1
- h3. Count all users
1
+ ### How to count all users
2
2
 
3
3
  Use this query to count all user records:
4
4
 
5
- (!) This is a warning note.
6
-
7
- {code:language=sql}
5
+ ~~~sql
8
6
  SELECT COUNT(*)
9
7
  FROM users
10
- {code}
8
+ ~~~
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "httparty"
2
4
  require "json"
3
5
  require "yaml"
@@ -18,22 +20,25 @@ module Confluence
18
20
  end
19
21
 
20
22
  def delete_page(page_id:)
21
- HTTParty.delete(
23
+ response = HTTParty.delete(
22
24
  "https://dbdoc.atlassian.net/wiki/rest/api/content/#{page_id}", {
23
25
  headers: {
24
26
  "Authorization" => "Basic #{basic_auth}",
25
- "Content-Type" => "application/json"
27
+ "Content-Type" => "application/json"
26
28
  }
27
29
  }
28
30
  )
31
+
32
+ response.code == 200
29
33
  end
30
34
 
31
35
  def existing_pages
36
+ # TODO: paginate over all pages in the space
32
37
  response = HTTParty.get(
33
38
  "https://dbdoc.atlassian.net/wiki/rest/api/content/?&spaceKey=#{@space}", {
34
39
  headers: {
35
40
  "Authorization" => "Basic #{basic_auth}",
36
- "Content-Type" => "application/json"
41
+ "Content-Type" => "application/json"
37
42
  }
38
43
  }
39
44
  )
@@ -64,7 +69,7 @@ module Confluence
64
69
  "https://dbdoc.atlassian.net/wiki/rest/api/content/#{page_id}", {
65
70
  headers: {
66
71
  "Authorization" => "Basic #{basic_auth}",
67
- "Content-Type" => "application/json"
72
+ "Content-Type" => "application/json"
68
73
  },
69
74
  body: payload.to_json
70
75
  }
@@ -112,7 +117,7 @@ module Confluence
112
117
  "https://dbdoc.atlassian.net/wiki/rest/api/content/", {
113
118
  headers: {
114
119
  "Authorization" => "Basic #{basic_auth}",
115
- "Content-Type" => "application/json"
120
+ "Content-Type" => "application/json"
116
121
  },
117
122
  body: payload.to_json
118
123
  }
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "kramdown"
4
+
5
+ module Confluence
6
+ # By default, all documentation should be written in a normal
7
+ # Markdown format. Later, when we're generating/uploading final documentation,
8
+ # we'll use Confluence::MarkdownConverter to convert normal Markdown
9
+ # into Confluence specific Markdown
10
+ # https://confluence.atlassian.com/bitbucketserver/markdown-syntax-guide-776639995.html
11
+ class MarkdownConverter
12
+ CONVERTERS = %w[
13
+ convert_h1
14
+ convert_h2
15
+ convert_h3
16
+ convert_h4
17
+ convert_h5
18
+ convert_bold
19
+ convert_italic
20
+ convert_code
21
+ convert_unordered_list
22
+ ].freeze
23
+
24
+ def convert(original_markdown)
25
+ return if original_markdown.nil?
26
+
27
+ output = original_markdown
28
+
29
+ CONVERTERS.each do |converter_method|
30
+ output = send(converter_method, output)
31
+ end
32
+
33
+ output
34
+ end
35
+
36
+ private
37
+
38
+ def convert_h1(markdown)
39
+ markdown.gsub(/^(#)([^#].+)$/, 'h1.\2')
40
+ end
41
+
42
+ def convert_h2(markdown)
43
+ markdown.gsub(/^(##)([^\#].+)$/, 'h2.\2')
44
+ end
45
+
46
+ def convert_h3(markdown)
47
+ markdown.gsub(/^(###)([^\#].+)$/, 'h3.\2')
48
+ end
49
+
50
+ def convert_h4(markdown)
51
+ markdown.gsub(/^(####)([^\#].+)$/, 'h4.\2')
52
+ end
53
+
54
+ def convert_h5(markdown)
55
+ markdown.gsub(/^(#####)([^\#].+)$/, 'h5.\2')
56
+ end
57
+
58
+ def convert_bold(markdown)
59
+ markdown.gsub(/(\*\*)(\w+)(\*\*)/, '*\2*')
60
+ end
61
+
62
+ def convert_italic(markdown)
63
+ markdown.gsub(/(\*)(\w+)(\*)/, '_\2_')
64
+ end
65
+
66
+ def convert_code(markdown)
67
+ output_lines = []
68
+
69
+ markdown.each_line do |line|
70
+ if line =~ /^\~{3}\w+$/
71
+ language = line.gsub("~~~", "").strip
72
+
73
+ output_lines.push("{code:language=#{language}}\n")
74
+ elsif line =~ /^\~{3}$/
75
+ output_lines.push("{code}")
76
+ else
77
+ output_lines.push(line)
78
+ end
79
+ end
80
+
81
+ output_lines.join
82
+ end
83
+
84
+ def convert_unordered_list(markdown)
85
+ markdown.gsub(/^\*\s(.+)$/, '- \1')
86
+ end
87
+
88
+ # TODO: add nested list convertion
89
+ # TODO: add numbered list convertion
90
+
91
+ # TODO: add emoji
92
+ # https://support.atlassian.com/confluence-cloud/docs/use-symbols-emojis-and-special-characters/
93
+ end
94
+ end
@@ -1,10 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "dbdoc/constants"
4
+ require_relative "../confluence/markdown_converter"
2
5
  require_relative "../confluence/api"
3
6
 
4
- module Dbdoc
7
+ module Confluence
8
+ # Confluence::Uploader class knows how to uploaded
9
+ # documentation to the Confluence Space provided in the config.yml.
10
+ #
11
+ # Uploader creates a root page with the database name from config.yml
12
+ # and creates nested pages for schemas and tables.
13
+ #
14
+ # A Confluence ID of each page created by dbdoc
15
+ # is logged to pages.yml file stored in the user's folder
16
+ # with the documentation.
5
17
  class Uploader
6
- def initialize(config: {})
7
- @config = config
18
+ def initialize(local_path: Dir.pwd)
19
+ @config = Dbdoc::Config.new(local_path: local_path).load
8
20
  @confluence_api = Confluence::Api.new
9
21
  @doc_folder = File.join(Dir.pwd, "doc")
10
22
  end
@@ -14,24 +26,45 @@ module Dbdoc
14
26
  delete_pages_for_dropped_schemas_or_tables
15
27
  end
16
28
 
29
+ def space_pages
30
+ @confluence_api.existing_pages["results"]
31
+ end
32
+
33
+ def print_space_pages
34
+ space_pages.each do |page|
35
+ page_title = page["title"]
36
+ page_id = page["id"]
37
+
38
+ puts "#{page_title}: #{page_id}"
39
+ end
40
+ end
41
+
17
42
  def clear_confluence_space
18
- # TODO paginate and fetch all Confluence pages
19
- # TODO ask user to Yn if they want to proceed with deletion
20
- # TODO iterate over each page_id, unlog it from page_ids.yml and @confluence_api.delete_page(page_id:)
43
+ YAML.load(File.read(page_ids_file))
44
+
45
+ space_pages.each do |page|
46
+ page_key = page["title"]
47
+ page_id = page["id"]
48
+
49
+ puts "--> Deleting #{page_key} #{page_id}"
50
+
51
+ unlog_page_id(key: page_key) if @confluence_api.delete_page(page_id: page_id)
52
+ end
21
53
  end
22
54
 
23
55
  private
24
56
 
57
+ # rubocop:disable Metrics/AbcSize
25
58
  def delete_pages_for_dropped_schemas_or_tables
26
59
  uploaded_pages = YAML.load(File.read(page_ids_file))
27
60
 
28
- uploaded_pages.each do |key, params|
61
+ uploaded_pages.each do |key, _params|
29
62
  next if key == "root"
30
63
 
31
64
  if key.start_with?("schema:")
32
65
  schema_name = key.gsub("schema:", "")
33
66
 
34
- unless Dir.exists?(File.join(@doc_folder, schema_name))
67
+ unless Dir.exist?(File.join(@doc_folder, schema_name))
35
68
  page_id = uploaded_pages[key][:page_id]
36
69
  puts "--> delete page #{key}: #{page_id}"
37
70
  @confluence_api.delete_page(page_id: page_id)
@@ -40,7 +73,7 @@ module Dbdoc
40
73
  elsif key.start_with?("table:")
41
74
  schema_name, table_name = key.gsub("table:", "").split(".")
42
75
 
43
- unless Dir.exists?(File.join(@doc_folder, schema_name, table_name))
76
+ unless Dir.exist?(File.join(@doc_folder, schema_name, table_name))
44
77
  page_id = uploaded_pages[key][:page_id]
45
78
  puts "--> delete page #{key}: #{page_id}"
46
79
  @confluence_api.delete_page(page_id: page_id)
@@ -49,6 +82,7 @@ module Dbdoc
49
82
  end
50
83
  end
51
84
  end
85
+ # rubocop:enable Metrics/AbcSize
52
86
 
53
87
  def create_or_updates_pages
54
88
  root_page_id = create_root_db_page[:page_id]
@@ -71,7 +105,7 @@ module Dbdoc
71
105
  def page_ids_file
72
106
  file = File.join(Dir.pwd, "page_ids.yml")
73
107
 
74
- unless File.exists?(file)
108
+ unless File.exist?(file)
75
109
  File.open(file, "w") do |f|
76
110
  f.puts("--- {}")
77
111
  end
@@ -97,7 +131,7 @@ module Dbdoc
97
131
  version: 0
98
132
  }
99
133
 
100
- if page_ids[key][:version] == 0
134
+ if page_ids.dig(key, :version).zero?
101
135
  puts "--> create page #{key}: #{page_id}"
102
136
  else
103
137
  puts "--> update page #{key}: #{page_id}"
@@ -123,9 +157,11 @@ module Dbdoc
123
157
  def create_root_db_page
124
158
  page_id = latest_page_id(key: "root")
125
159
 
126
- return {
127
- page_id: page_id
128
- } if page_id
160
+ if page_id
161
+ return {
162
+ page_id: page_id
163
+ }
164
+ end
129
165
 
130
166
  db_name = @config["db"]["name"]
131
167
  @confluence_api.create_page(
@@ -162,37 +198,50 @@ module Dbdoc
162
198
  end
163
199
  end
164
200
 
201
+ def markdown(input)
202
+ Confluence::MarkdownConverter.new.convert(input)
203
+ end
204
+
205
+ # rubocop:disable Metrics/AbcSize
165
206
  def upload_table(schema_name:, table_name:, schema_page_id:)
166
207
  table_folder = File.join(@doc_folder, schema_name, table_name)
167
208
 
168
- table_description = File.read(File.join(table_folder, "description.md"))
209
+ table_description = markdown(File.read(File.join(table_folder, "description.md")))
169
210
 
170
211
  examples_folder = File.join(table_folder, "examples")
171
- table_examples = Dir[File.join(examples_folder, "*.md")].map { |f| File.read(f) }
212
+ table_examples = Dir[File.join(examples_folder, "*.md")].map do |f|
213
+ markdown(File.read(f))
214
+ end
172
215
 
173
- columns_markdown_template_file = File.join(DBDOC_HOME, "doc_files", "columns.md.erb")
216
+ columns_markdown_template_file = File.join(Dbdoc::DBDOC_HOME, "doc_files", "columns.md.erb")
174
217
 
175
218
  columns_table_template = ERB.new(
176
219
  File.read(columns_markdown_template_file),
177
220
  nil,
178
221
  "-"
179
222
  )
223
+
224
+ columns_doc = YAML.load(File.read(File.join(table_folder, "columns.yml")))
225
+ columns_doc.each do |col|
226
+ col[:description] = markdown(col[:description])
227
+ end
228
+
180
229
  columns_table = columns_table_template.result_with_hash({
181
- columns: YAML.load(File.read(File.join(table_folder, "columns.yml")))
230
+ columns: columns_doc
182
231
  })
183
232
 
184
- page_body = <<-MARKDOWN
185
- h2. Description
233
+ page_body = <<~MARKDOWN
234
+ h2. Description
186
235
 
187
- #{table_description}
236
+ #{table_description}
188
237
 
189
- h2. Columns
238
+ h2. Columns
190
239
 
191
- #{columns_table}
240
+ #{columns_table}
192
241
 
193
- h2. Examples
242
+ h2. Examples
194
243
 
195
- #{table_examples.join("\n") }
244
+ #{table_examples.join("\n")}
196
245
  MARKDOWN
197
246
 
198
247
  page_title = schema_name == "public" ? table_name : "#{schema_name}.#{table_name}"
@@ -201,7 +250,7 @@ h2. Examples
201
250
  page_id = latest_page_id(key: page_key)
202
251
 
203
252
  if page_id
204
- response = @confluence_api.update_page(
253
+ @confluence_api.update_page(
205
254
  page_id: page_id,
206
255
  page_title: page_title,
207
256
  body: page_body,
@@ -221,5 +270,6 @@ h2. Examples
221
270
  log_page_id(key: "table:#{schema_name}.#{table_name}", page_id: table_page_id)
222
271
  end
223
272
  end
273
+ # rubocop:enable Metrics/AbcSize
224
274
  end
225
275
  end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "dbdoc/constants"
2
4
  require "dbdoc/version"
3
5
  require "dbdoc/config"
4
6
  require "dbdoc/manager"
5
- require "dbdoc/uploader"
7
+ require "dbdoc/folder_initializer"
8
+ require "confluence/uploader"
6
9
 
7
10
  module Dbdoc
8
11
  class Error < StandardError; end
@@ -1,130 +1,116 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "optparse"
2
4
 
3
5
  $LOAD_PATH << File.expand_path(__dir__)
4
6
 
5
7
  module Dbdoc
6
8
  class CLI
9
+ COMMANDS = {
10
+ install: %(
11
+ Generates all necessary config files and documentation folders.
12
+
13
+ Run this command in an empty directory.
14
+ ),
15
+ query: %(
16
+ Prints a query that you need to run in the database \
17
+ you're going to document.
18
+
19
+ Export the result of this query to the "schema.csv" file \
20
+ and copy it over to the "schema" folder for processing.
21
+ ),
22
+ plan: %(
23
+ Shows you what columns/tables/schemas are new and \
24
+ going to be added/deleted from the documentation.
25
+ ),
26
+ apply: %(
27
+ Generates boilerplate documentation for newly added \
28
+ columns/tables/schemas.
29
+
30
+ Drops documentation for columns/tables/schemas that \
31
+ were deleted from the database.
32
+ ),
33
+ "confluence:upload": %(
34
+ Uploads current documentation to Confluence: pages for \
35
+ new tables/schemas will be added, pages for dropped tables/schemas \
36
+ will be deleted from your Confluence space.
37
+ ),
38
+ "confluece:pages": %(
39
+ Lists all pages in your dbdoc Confluence space \
40
+ (created manually or via dbdoc).
41
+ ),
42
+ "confluence:clear": %(
43
+ IMPORTANT This command will delete ALL pages from \
44
+ the Confluence space (pages created via dbdoc AND pages that were added manually).
45
+ ),
46
+ todo: %(
47
+ Shows you the documentation that needs to be written.
48
+ )
49
+ }.freeze
50
+
51
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
7
52
  def run(args = [])
8
- if args.first == "init"
9
- require "fileutils"
10
-
11
- schema_folder = File.join(Dir.pwd, "schema")
12
- unless Dir.exists?(schema_folder)
13
- Dir.mkdir(schema_folder)
14
- end
15
-
16
- doc_folder = File.join(Dir.pwd, "doc")
17
- unless Dir.exists?(doc_folder)
18
- Dir.mkdir(doc_folder)
19
- end
20
-
21
- target_file = File.join(Dir.pwd, "config.yml")
22
- config_file = File.join(File.expand_path(__dir__), "../..", "config", "default.yml")
23
-
24
- FileUtils.cp(config_file, target_file) unless File.exists?(target_file)
25
-
26
- target_file = File.join(Dir.pwd, ".gitignore")
27
- config_file = File.join(File.expand_path(__dir__), "../..", "config", "gitignore.template")
28
-
29
- FileUtils.cp(config_file, target_file) unless File.exists?(target_file)
30
-
31
- target_file = File.join(Dir.pwd, "confluence.yml")
32
- config_file = File.join(File.expand_path(__dir__), "../..", "config", "confluence.yml")
33
-
34
- FileUtils.cp(config_file, target_file) unless File.exists?(target_file)
35
-
36
- 0
53
+ if args.first == "install"
54
+ Dbdoc::FolderInitializer.new.init
37
55
  elsif args.first == "query"
38
- options = extract_options(args)
39
-
40
- config = Dbdoc::Config.load
41
- config.merge!(options)
42
-
43
- db_type = config["db"]["type"]
44
- query_file = File.join(File.expand_path(__dir__), "../..", "config", "schema_queries", "#{db_type}.sql")
45
- query = File.read(query_file)
46
-
47
- puts query
48
-
49
- 0
56
+ puts manager.query
50
57
  elsif args.first == "plan"
51
- options = extract_options(args)
58
+ plan = manager.plan
52
59
 
53
- config = Dbdoc::Config.load
54
- config.merge!(options)
55
-
56
- manager = Dbdoc::Manager.new(config: config)
57
- manager.plan
60
+ puts "--> New columns:"
61
+ plan[:new_columns].each do |column|
62
+ puts column
63
+ end
58
64
 
59
- 0
65
+ puts "--> Columns to drop:"
66
+ plan[:columns_to_drop].each do |column|
67
+ puts column
68
+ end
60
69
  elsif args.first == "apply"
61
- options = extract_options(args)
62
-
63
- config = Dbdoc::Config.load
64
- config.merge!(options)
65
-
66
- manager = Dbdoc::Manager.new(config: config)
67
70
  manager.apply
68
-
69
- 0
70
- elsif args.first == "upload"
71
- options = extract_options(args)
72
-
73
- config = Dbdoc::Config.load
74
- config.merge!(options)
75
-
76
- uploader = Dbdoc::Uploader.new(config: config)
71
+ elsif args.first == "confluence:upload"
77
72
  uploader.upload
78
-
79
- 0
80
- elsif args.first == "clear_confluence_space"
81
- options = extract_options(args)
82
-
83
- config = Dbdoc::Config.load
84
- config.merge!(options)
85
-
86
- uploader = Dbdoc::Uploader.new(config: config)
73
+ elsif args.first == "confluence:pages"
74
+ uploader.print_space_pages
75
+ elsif args.first == "confluence:clear"
87
76
  uploader.clear_confluence_space
88
-
89
- 0
77
+ elsif args.first == "todo"
78
+ manager.todo
90
79
  elsif args.first == "help"
91
- puts "--> SOME HELP"
92
-
93
- 0
80
+ print_help
81
+ elsif args.first == "version"
82
+ puts Dbdoc::VERSION
94
83
  end
95
84
 
96
85
  0
97
86
  end
87
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
98
88
 
99
89
  private
100
90
 
101
- # This method is needed to unindent
102
- # ["here document"](https://en.wikibooks.org/wiki/Ruby_Programming/Here_documents)
103
- # help description.
104
- #
105
91
  def unindent(str)
106
92
  str.gsub(/^#{str.scan(/^[ \t]+(?=\S)/).min}/, "")
107
93
  end
108
94
 
109
- def extract_options(args)
110
- options = {}
111
-
112
- OptionParser.new do |opts|
113
- opts.banner = unindent(<<-TEXT)
114
- dbdoc help
115
-
116
- 1. dbdoc query
95
+ def manager
96
+ @manager ||= Dbdoc::Manager.new
97
+ end
117
98
 
118
- This will print you a query you need to run to export your database schema.
119
- TEXT
99
+ def uploader
100
+ @uploader ||= Confluence::Uploader.new
101
+ end
120
102
 
121
- opts.on("-v", "--version", "Prints current version of dbdoc") do
122
- puts Dbdoc::VERSION
123
- exit 0
124
- end
125
- end.parse!(args)
103
+ def print_help
104
+ puts unindent <<-TEXT
105
+ Usage: dbdoc [command]
106
+ TEXT
107
+ puts
126
108
 
127
- options
109
+ COMMANDS.each do |command, description|
110
+ puts "dbdoc #{command}"
111
+ puts
112
+ puts unindent(description)
113
+ end
128
114
  end
129
115
  end
130
116
  end
@@ -1,27 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
  require "dbdoc/constants"
3
5
 
4
6
  module Dbdoc
7
+ # Dbdoc::Config class knows how to load the default config from the
8
+ # dbdoc gem folder. Later, if needed, this class could be used to merge
9
+ # user-defined config with the default one.
5
10
  class Config
6
- FILE_NAME = "config.yml".freeze
7
- DEFAULT_FILE = File.join(DBDOC_HOME, "config", "default.yml")
8
-
9
- class << self
10
- # Be default gem will try to load config file in user's project folder.
11
- # Then user's config (or empty object) will be merge with the default config
12
- # from gem's folder.
13
- #
14
- def load
15
- user_config = File.exist?(user_file) ? YAML.safe_load(File.read(user_file)) : {}
16
- default_config = YAML.safe_load(File.read(DEFAULT_FILE))
17
-
18
- default_config.merge(user_config)
19
- end
11
+ def initialize(local_path: Dir.pwd)
12
+ @local_path = local_path
13
+ end
20
14
 
21
- private
15
+ def load
16
+ local_config_file = File.join(@local_path, "config.yml")
22
17
 
23
- def user_file
24
- File.join(Dir.pwd, FILE_NAME)
18
+ if File.exist?(local_config_file)
19
+ YAML.load(File.read(local_config_file))
20
+ else
21
+ {}
25
22
  end
26
23
  end
27
24
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dbdoc
2
4
  DBDOC_HOME = File.realpath(File.join(__dir__, "..", ".."))
3
5
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+ require "dbdoc/constants"
6
+
7
+ module Dbdoc
8
+ # Dbdoc::FolderInitializer class knows how to turn an emtpy
9
+ # folder into a dbdoc folder.
10
+ #
11
+ class FolderInitializer
12
+ def initialize(local_path: Dir.pwd)
13
+ @config = Dbdoc::Config.new(local_path: local_path).load
14
+ end
15
+
16
+ def init
17
+ create_schema_folder
18
+ create_doc_folder
19
+ create_config_file
20
+ create_gitignore_file
21
+ create_confluence_config_file
22
+ end
23
+
24
+ private
25
+
26
+ # schema folder is the one user copies the schema.csv to
27
+ # before updating/generating documentation
28
+ def create_schema_folder
29
+ schema_folder = File.join(Dir.pwd, "schema")
30
+ Dir.mkdir(schema_folder) unless Dir.exist?(schema_folder)
31
+ end
32
+
33
+ # doc folder stores all the database documentation files
34
+ def create_doc_folder
35
+ doc_folder = File.join(Dir.pwd, "doc")
36
+ Dir.mkdir(doc_folder) unless Dir.exist?(doc_folder)
37
+ end
38
+
39
+ def create_file(default_file_name, target_file_name)
40
+ target_file = File.join(Dir.pwd, target_file_name)
41
+
42
+ return if File.exist?(target_file)
43
+
44
+ config_file = File.join(File.expand_path(__dir__), "../..", "config", default_file_name)
45
+
46
+ FileUtils.cp(config_file, target_file)
47
+ end
48
+
49
+ def create_config_file
50
+ create_file("default.yml", "config.yml")
51
+ end
52
+
53
+ def create_gitignore_file
54
+ create_file("gitignore.template", ".gitignore")
55
+ end
56
+
57
+ def create_confluence_config_file
58
+ create_file("confluence.yml", "confluence.yml")
59
+ end
60
+ end
61
+ end
@@ -1,30 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
4
+ require "erb"
5
+ require "fileutils"
2
6
  require "dbdoc/constants"
3
7
 
4
8
  module Dbdoc
9
+ # Dbdoc::Manager class manages database schema documentation.
10
+ #
11
+ # It knows how to generate and update documentation based on the database
12
+ # schema generated by the schema query for user's database.
5
13
  class Manager
6
- def initialize(config: {})
7
- @config = Dbdoc::Config.load.merge(config)
14
+ def initialize(local_path: Dir.pwd)
15
+ @local_path = local_path
16
+ @config = Dbdoc::Config.new(local_path: local_path).load
8
17
  end
9
18
 
10
- def plan(verbose: true)
11
- puts "--> PLAN"
12
- puts
13
- puts
14
-
15
- input_schema = read_input_schema.map { |r| r.first(4) }.map { |r| r.join(":") }
19
+ def plan
20
+ input_schema = read_input_schema.map { |r| r.first(4).join(":") }
16
21
  current_schema = read_documented_schema
17
22
 
18
- puts "--> New columns:"
19
- pp input_schema - current_schema
20
- puts
21
- puts
23
+ {
24
+ new_columns: input_schema - current_schema,
25
+ columns_to_drop: current_schema - input_schema
26
+ }
27
+ end
28
+
29
+ def todo
30
+ doc_folder_files = File.join(@local_path, "doc", "**/*")
31
+
32
+ Dir[doc_folder_files].each do |file|
33
+ next if file == "."
34
+ next if file == ".."
35
+ next if File.directory?(file)
22
36
 
23
- puts "--> Columns to drop:"
24
- pp current_schema - input_schema
37
+ File.read(file).split("\n").each_with_index do |line, i|
38
+ next unless line.include?("TODO")
39
+
40
+ relative_path = file.gsub(@local_path, "")
41
+
42
+ puts "#{relative_path}:#{i + 1}"
43
+ end
44
+ end
45
+ end
46
+
47
+ def query
48
+ db_type = @config["db"]["type"]
49
+ query_file = File.join(File.expand_path(__dir__), "../..", "config", "schema_queries", "#{db_type}.sql")
50
+
51
+ File.read(query_file)
25
52
  end
26
53
 
27
- def apply(path: Dir.pwd, verbose: true)
54
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
55
+ def apply
28
56
  puts "--> APPLY"
29
57
  puts
30
58
  puts
@@ -35,14 +63,16 @@ module Dbdoc
35
63
  added_columns = input_schema - current_schema
36
64
  dropped_columns = current_schema - input_schema
37
65
 
38
- doc_folder = File.join(Dir.pwd, "doc")
66
+ doc_folder = File.join(@local_path, "doc")
67
+
68
+ Dir.mkdir(doc_folder) unless Dir.exist?(doc_folder)
39
69
 
40
70
  ## DROP COLUMNS
41
71
  dropped_columns.each do |column|
42
- schema_name, table_name, column_name, column_type = column.split(":")
72
+ schema_name, table_name, column_name = column.split(":")
43
73
 
44
74
  columns_file = File.join(doc_folder, schema_name, table_name, "columns.yml")
45
- next unless File.exists?(columns_file)
75
+ next unless File.exist?(columns_file)
46
76
 
47
77
  columns = YAML.load(File.read(columns_file))
48
78
  columns.reject! { |c| c[:name] == column_name }
@@ -69,7 +99,7 @@ module Dbdoc
69
99
  next unless File.directory?(table_folder)
70
100
 
71
101
  columns_file = File.join(table_folder, "columns.yml")
72
- next unless File.exists?(columns_file)
102
+ next unless File.exist?(columns_file)
73
103
 
74
104
  columns = YAML.load(File.read(columns_file))
75
105
 
@@ -93,16 +123,18 @@ module Dbdoc
93
123
 
94
124
  create_new_columns(added_columns)
95
125
  end
126
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
96
127
 
97
128
  private
98
129
 
99
130
  def input_schema
100
- File.read(File.join(Dir.pwd, "schema", "schema.csv"))
131
+ File.read(File.join(@local_path, "schema", "schema.csv"))
101
132
  end
102
133
 
134
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
103
135
  def read_input_schema
104
136
  rows = input_schema.split("\n")
105
- with_header = rows[0].include?("schema_name")
137
+ with_header = rows[0].include?("table_schema")
106
138
 
107
139
  rows.shift if with_header
108
140
 
@@ -110,38 +142,37 @@ module Dbdoc
110
142
  r.split(",").map(&:strip).map { |c| c.gsub('"', "") }.first(5)
111
143
  end
112
144
 
113
- config = YAML.load(File.read("config.yml"))
114
-
115
- if @config["ignorelist"]
116
- @config["ignorelist"].map { |r| r.split(/[\.\#]/) }.each do |b|
117
- schema_pattern, table_pattern, column_pattern = b
145
+ @config["ignorelist"]&.map { |r| r.split(/[\.\#]/) }&.each do |b|
146
+ schema_pattern, table_pattern, column_pattern = b
118
147
 
119
- rows.reject! do |row|
120
- schema_name, table_name, column_name, _, _ = row
148
+ rows.reject! do |row|
149
+ schema_name, table_name, column_name, = row
121
150
 
122
- if column_pattern
123
- next unless column_name =~ Regexp.new(column_pattern.gsub("*", ".*"))
124
- end
125
-
126
- if table_pattern
127
- next unless table_name =~ Regexp.new(table_pattern.gsub("*", ".*"))
128
- end
151
+ if column_pattern
152
+ next unless column_name =~ Regexp.new(column_pattern.gsub("*", ".*"))
153
+ end
129
154
 
130
- if schema_pattern
131
- next unless schema_name =~ Regexp.new(schema_pattern.gsub("*", ".*"))
132
- end
155
+ if table_pattern
156
+ next unless table_name =~ Regexp.new(table_pattern.gsub("*", ".*"))
157
+ end
133
158
 
134
- true
159
+ if schema_pattern
160
+ next unless schema_name =~ Regexp.new(schema_pattern.gsub("*", ".*"))
135
161
  end
162
+
163
+ true
136
164
  end
137
165
  end
138
166
 
139
167
  rows
140
168
  end
169
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
141
170
 
171
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
142
172
  def read_documented_schema
143
- doc_folder = File.join(Dir.pwd, "doc")
173
+ doc_folder = File.join(@local_path, "doc")
144
174
 
175
+ return [] unless Dir.exist?(doc_folder)
145
176
  return [] if Dir.empty?(doc_folder)
146
177
 
147
178
  keys = []
@@ -160,9 +191,9 @@ module Dbdoc
160
191
  next unless File.directory?(table_folder)
161
192
 
162
193
  columns_file = File.join(table_folder, "columns.yml")
163
- next unless File.exists?(columns_file)
194
+ next unless File.exist?(columns_file)
164
195
 
165
- columns = YAML.load(File.read(columns_file))
196
+ columns = YAML.load(File.read(columns_file), [Symbol])
166
197
  columns.each do |column|
167
198
  keys.push([
168
199
  schema_name,
@@ -176,9 +207,11 @@ module Dbdoc
176
207
 
177
208
  keys
178
209
  end
210
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
179
211
 
212
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
180
213
  def create_new_columns(added_columns)
181
- doc_folder = File.join(Dir.pwd, "doc")
214
+ doc_folder = File.join(@local_path, "doc")
182
215
 
183
216
  added_columns.map! { |r| r.split(":") }
184
217
  new_columns = read_input_schema.select do |row|
@@ -224,17 +257,18 @@ module Dbdoc
224
257
  # 4. create table columns.yml
225
258
  columns_yaml = File.join(table_folder, "columns.yml")
226
259
 
227
- unless File.exists?(columns_yaml)
228
- columns_erb_tamplate_file = File.join(DBDOC_HOME, "doc_files", "columns.yml.erb")
229
- columns_yaml_template = ERB.new(File.read(columns_erb_tamplate_file), nil, "-")
230
- File.open(columns_yaml, "w") do |f|
231
- f.puts columns_yaml_template.result_with_hash({
232
- columns: columns
233
- })
234
- end
260
+ next if File.exist?(columns_yaml)
261
+
262
+ columns_erb_tamplate_file = File.join(DBDOC_HOME, "doc_files", "columns.yml.erb")
263
+ columns_yaml_template = ERB.new(File.read(columns_erb_tamplate_file), nil, "-")
264
+ File.open(columns_yaml, "w") do |f|
265
+ f.puts columns_yaml_template.result_with_hash({
266
+ columns: columns
267
+ })
235
268
  end
236
269
  end
237
270
  end
238
271
  end
272
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
239
273
  end
240
274
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dbdoc
2
- VERSION = "0.1.0".freeze
4
+ VERSION = "0.3.5"
3
5
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbdoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anatoli Makarevich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-29 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2020-09-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.18'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.18'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kramdown
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.3'
13
41
  description: Dbdoc is a tool to keep your database documentation up-to-date and version
14
42
  controlled.
15
43
  email:
@@ -19,6 +47,7 @@ executables:
19
47
  extensions: []
20
48
  extra_rdoc_files: []
21
49
  files:
50
+ - ".github/FUNDING.yml"
22
51
  - ".gitignore"
23
52
  - ".rspec"
24
53
  - ".rubocop.yml"
@@ -43,12 +72,14 @@ files:
43
72
  - doc_files/table_description.md
44
73
  - doc_files/table_example.md
45
74
  - lib/confluence/api.rb
75
+ - lib/confluence/markdown_converter.rb
76
+ - lib/confluence/uploader.rb
46
77
  - lib/dbdoc.rb
47
78
  - lib/dbdoc/cli.rb
48
79
  - lib/dbdoc/config.rb
49
80
  - lib/dbdoc/constants.rb
81
+ - lib/dbdoc/folder_initializer.rb
50
82
  - lib/dbdoc/manager.rb
51
- - lib/dbdoc/uploader.rb
52
83
  - lib/dbdoc/version.rb
53
84
  homepage: https://github.com/sqlhabit/dbdoc
54
85
  licenses: