diff --git a/.gitignore b/.gitignore index 61bec8db6..535a8eee0 100644 --- a/.gitignore +++ b/.gitignore @@ -39,8 +39,8 @@ Gemfile.lock /log/ /*.gem /spec/acceptance/nodesets/ -/spec/fixtures/manifests/ /spec/fixtures/modules/ +/spec/fixtures/manifests/ /inventory.yaml ## local coverage results diff --git a/.rubocop.yml b/.rubocop.yml index d1391afd1..85e3be868 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,6 +7,7 @@ AllCops: - 'lib/puppet-strings/yard/templates/**/*' # Ignore fixtures we do not control - spec/fixtures/modules/**/* + - spec/fixtures/ruby/**/* # DISABLED - not useful Bundler/OrderedGems: diff --git a/Rakefile b/Rakefile index 3d3315476..36556685c 100644 --- a/Rakefile +++ b/Rakefile @@ -43,6 +43,8 @@ RSpec::Core::RakeTask.new(:spec) do |t| t.exclude_pattern = "spec/acceptance/**/*.rb" end +task :spec => :spec_clean + # Add our own tasks require 'puppet-strings/tasks' diff --git a/lib/puppet-strings.rb b/lib/puppet-strings.rb index 6023154c0..529574104 100644 --- a/lib/puppet-strings.rb +++ b/lib/puppet-strings.rb @@ -27,8 +27,9 @@ def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {}) # Format the arguments to YARD args = ['doc'] + args << '--no-progress' args << '--debug' if options[:debug] - args << '--backtrace' if options[:backtrace] + args << '--backtrace' if options[:debug] args << "-m#{options[:markup] || 'markdown'}" file = nil @@ -42,7 +43,6 @@ def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {}) args << '-n' args << '-q' unless file args << '--no-stats' unless file - args << '--no-progress' unless file end yard_args = options[:yard_args] diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb index 5a2bca9da..ef8bfd763 100644 --- a/lib/puppet-strings/markdown.rb +++ b/lib/puppet-strings/markdown.rb @@ -14,7 +14,7 @@ module PuppetStrings::Markdown # generates markdown documentation # @return [String] markdown doc def self.generate - final = "# Reference\n" + final = "# Reference\n\n" final << "\n\n" final << PuppetStrings::Markdown::TableOfContents.render final << PuppetStrings::Markdown::PuppetClasses.render diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb index 57ba6d746..539ee1d58 100644 --- a/lib/puppet-strings/markdown/base.rb +++ b/lib/puppet-strings/markdown/base.rb @@ -169,6 +169,12 @@ def private? @tags.any? { |tag| tag[:tag_name] == 'api' && tag[:text] == 'private' } end + def word_wrap(text, line_width: 120, break_sequence: "\n") + text.split("\n").collect! do |line| + line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line + end * break_sequence + end + # @return [String] full markdown rendering of a component def render(template) file = File.join(File.dirname(__FILE__),"templates/#{template}") diff --git a/lib/puppet-strings/markdown/templates/classes_and_defines.erb b/lib/puppet-strings/markdown/templates/classes_and_defines.erb index 9ebbfb766..5860def39 100644 --- a/lib/puppet-strings/markdown/templates/classes_and_defines.erb +++ b/lib/puppet-strings/markdown/templates/classes_and_defines.erb @@ -24,10 +24,10 @@ * **See also** <% see.each do |sa| -%> <% if sa[:name] -%> -<%= sa[:name] %> +<%= " * #{sa[:name]}" %> <% end -%> <% if sa[:text] -%> -<%= sa[:text] %> + <%= " * #{sa[:text]}" %> <% end -%> <% end -%> diff --git a/lib/puppet-strings/markdown/templates/data_type.erb b/lib/puppet-strings/markdown/templates/data_type.erb index 0631a2b64..d6fed8e56 100644 --- a/lib/puppet-strings/markdown/templates/data_type.erb +++ b/lib/puppet-strings/markdown/templates/data_type.erb @@ -24,10 +24,10 @@ * **See also** <% see.each do |sa| -%> <% if sa[:name] -%> -<%= sa[:name] %> +<%= " * #{sa[:name]}" %> <% end -%> <% if sa[:text] -%> -<%= sa[:text] %> +<%= " * #{sa[:text]}" %> <% end -%> <% end -%> diff --git a/lib/puppet-strings/markdown/templates/function.erb b/lib/puppet-strings/markdown/templates/function.erb index 4c520fe51..5b39acc79 100644 --- a/lib/puppet-strings/markdown/templates/function.erb +++ b/lib/puppet-strings/markdown/templates/function.erb @@ -55,6 +55,7 @@ Returns: `<%= sig.return_type %>`<% if sig.return_val %> <%= sig.return_val %><% <% end -%> <% if raises -%> Raises: + <% raises.each do |r| -%> * <%= error_type(r[:text]) %> <%= error_text(r[:text]) %> <% end -%> diff --git a/lib/puppet-strings/markdown/templates/resource_type.erb b/lib/puppet-strings/markdown/templates/resource_type.erb index befac4cfa..141711875 100644 --- a/lib/puppet-strings/markdown/templates/resource_type.erb +++ b/lib/puppet-strings/markdown/templates/resource_type.erb @@ -24,10 +24,10 @@ * **See also** <% see.each do |sa| -%> <% if sa[:name] -%> -<%= sa[:name] %> +<%= " * #{sa[:name]}" %> <% end -%> <% if sa[:text] -%> -<%= sa[:text] %> +<%= " * #{sa[:text]}" %> <% end -%> <% end -%> @@ -116,7 +116,7 @@ Aliases: <%= param[:aliases].to_s.delete('{').delete('}') %> Data type: `<%= param[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(param[:data_type]) %> <% end -%> -<%= param[:description] %> +<%= word_wrap(param[:description]) %> <% if options_for_param(param[:name]) -%> Options: diff --git a/lib/puppet-strings/markdown/templates/table_of_contents.erb b/lib/puppet-strings/markdown/templates/table_of_contents.erb index cf0c60f4e..f20582a3a 100644 --- a/lib/puppet-strings/markdown/templates/table_of_contents.erb +++ b/lib/puppet-strings/markdown/templates/table_of_contents.erb @@ -1,8 +1,8 @@ <% if group.length > 0 -%> -**<%= group_name %>** +### <%= group_name %> <% if priv -%> -_Public <%= group_name %>_ +#### Public <%= group_name %> <% group.each do |item| -%> <% unless item[:private] -%> @@ -10,7 +10,7 @@ _Public <%= group_name %>_ <% end -%> <% end -%> -_Private <%= group_name %>_ +#### Private <%= group_name %> <% group.each do |item| -%> <% if item[:private] -%> diff --git a/spec/fixtures/json/backup.json b/spec/fixtures/json/backup.json new file mode 100644 index 000000000..c93f76d05 --- /dev/null +++ b/spec/fixtures/json/backup.json @@ -0,0 +1,22 @@ +{ + "description": "Allows you to backup your database to local file.", + "input_method": "stdin", + "parameters": { + "database": { + "description": "Database to connect to", + "type": "Optional[String[1]]" + }, + "user": { + "description": "The user", + "type": "Optional[String[1]]" + }, + "password": { + "description": "The password", + "type": "Optional[String[1]]" + }, + "sql": { + "description": "Path to file you want backup to", + "type": "String[1]" + } + } +} diff --git a/spec/fixtures/puppet/class.pp b/spec/fixtures/puppet/class.pp new file mode 100644 index 000000000..a56c97c3d --- /dev/null +++ b/spec/fixtures/puppet/class.pp @@ -0,0 +1,66 @@ +# An overview for a simple class. +# @summary A simple class. +# @todo Do a thing +# @note some note +# @since 1.0.0 +# @see www.puppet.com +# @example This is an example +# class { 'klass': +# param1 => 1, +# param3 => 'foo', +# } +# @example This is another example +# class { 'klass': +# param1 => 1, +# param3 => 'foo', +# } +# @raise SomeError +# @param param1 First param. +# @param param2 Second param. +# @option param2 [String] :opt1 something about opt1 +# @option param2 [Hash] :opt2 a hash of stuff +# @param param3 Third param. +# @param param4 Fourth param. +# @enum param4 :one One option +# @enum param4 :two Second option +# +class klass ( + Integer $param1 = 1, + $param2 = undef, + String $param3 = 'hi', + Enum['one', 'two'] $param4 = 'two', +) inherits foo::bar { +} + +# Overview for class noparams +# @api private +class noparams () {} + +# An overview for a simple defined type. +# @summary A simple defined type. +# @since 1.1.0 +# @see www.puppet.com +# @example Here's an example of this type: +# klass::dt { 'foo': +# param1 => 33, +# param4 => false, +# } +# @return shouldn't return squat +# @raise SomeError +# @param param1 First param. +# @param param2 Second param. +# @option param2 [String] :opt1 something about opt1 +# @option param2 [Hash] :opt2 a hash of stuff +# @param param3 Third param. +# @param param4 Fourth param. +# @param param5 Fifth param. +# @enum param5 :a Option A +# @enum param5 :b Option B +define klass::dt ( + Integer $param1 = 44, + $param2, + String $param3 = 'hi', + Boolean $param4 = true, + Enum['a', 'b'] $param5 = 'a' +) { +} diff --git a/spec/fixtures/puppet/function.pp b/spec/fixtures/puppet/function.pp new file mode 100644 index 000000000..abf48291a --- /dev/null +++ b/spec/fixtures/puppet/function.pp @@ -0,0 +1,14 @@ +# A simple Puppet function. +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +# @option param3 [Array] :param3opt Something about this option +# @param param4 Fourth param. +# @enum param4 :yes Yes option. +# @enum param4 :no No option. +# @raise SomeError this is some error +# @return [Undef] Returns nothing. +# @example Test +# $result = func(1, 2) +function func(Integer $param1, $param2, String $param3 = hi, Enum['yes', 'no'] $param4 = 'yes') { +} diff --git a/spec/fixtures/puppet/plan.pp b/spec/fixtures/puppet/plan.pp new file mode 100644 index 000000000..594cc86db --- /dev/null +++ b/spec/fixtures/puppet/plan.pp @@ -0,0 +1,6 @@ +# A simple plan. +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +plan plann(String $param1, $param2, Integer $param3 = 1) { +} diff --git a/spec/fixtures/puppet/type_alias.pp b/spec/fixtures/puppet/type_alias.pp new file mode 100644 index 000000000..65a50fc16 --- /dev/null +++ b/spec/fixtures/puppet/type_alias.pp @@ -0,0 +1,8 @@ +# Documentation for Amodule::SimpleAlias +type Amodule::SimpleAlias = Variant[Numeric,String[1,20]] + +# Documentation for Amodule::ComplexAlias +type Amodule::ComplexAlias = Struct[{ + value_type => Optional[ValueType], + merge => Optional[MergeType] +}] diff --git a/spec/fixtures/ruby/data_type.rb b/spec/fixtures/ruby/data_type.rb new file mode 100644 index 000000000..0326983d7 --- /dev/null +++ b/spec/fixtures/ruby/data_type.rb @@ -0,0 +1,12 @@ +# An example Puppet Data Type in Ruby. +# +# @param param1 A variant parameter. +# @param param2 Optional String parameter. +Puppet::DataTypes.create_type('UnitDataType') do + interface <<-PUPPET + attributes => { + param1 => Variant[Numeric, String[1,2]], + param2 => { type => Optional[String[1]], value => "param2" } + } + PUPPET +end diff --git a/spec/fixtures/ruby/func3x.rb b/spec/fixtures/ruby/func3x.rb new file mode 100644 index 000000000..e278ca0d1 --- /dev/null +++ b/spec/fixtures/ruby/func3x.rb @@ -0,0 +1,12 @@ +# An example 3.x function +Puppet::Parser::Functions.newfunction(:func3x, doc: <<-DOC + Documentation for an example 3.x function. + @param param1 [String] The first parameter. + @param param2 [Integer] The second parameter. + @return [Undef] + @example Calling the function. + func3x('hi', 10) + DOC + ) do |*args| + #... +end diff --git a/spec/fixtures/ruby/func4x.rb b/spec/fixtures/ruby/func4x.rb new file mode 100644 index 000000000..76c35db88 --- /dev/null +++ b/spec/fixtures/ruby/func4x.rb @@ -0,0 +1,42 @@ +# An example 4.x function. +# +# @example Calling the function +# $result = func4x(1, 'foo') +# +# @example Calling the function with all args +# $result = func4x(1, 'foo', ['bar']) +Puppet::Functions.create_function(:func4x) do + # An overview for the first overload. + # @raise SomeError this is some error + # @param param1 The first parameter. + # @param param2 The second parameter. + # @option param2 [String] :option an option + # @option param2 [String] :option2 another option + # @param param3 The third parameter. + # @param param4 The fourth parameter. + # @enum param4 :one Option one. + # @enum param4 :two Option two. + # @return Returns nothing. + # @example Calling the function foo + # $result = func4x(1, 'foooo') + # + dispatch :foo do + param 'Integer', :param1 + param 'Any', :param2 + optional_param 'Array[String]', :param3 + optional_param 'Enum[one, two]', :param4 + return_type 'Undef' + end + + # An overview for the second overload. + # @param param The first parameter. + # @param block The block parameter. + # @return Returns a string. + # @example Calling the function bar + # $result = func4x(1, 'bar', ['foo']) + dispatch :other do + param 'Boolean', :param + block_param + return_type 'String' + end +end diff --git a/spec/fixtures/ruby/func4x_1.rb b/spec/fixtures/ruby/func4x_1.rb new file mode 100644 index 000000000..d2cbed693 --- /dev/null +++ b/spec/fixtures/ruby/func4x_1.rb @@ -0,0 +1,9 @@ +# An example 4.x function with only one signature. +Puppet::Functions.create_function(:func4x_1) do + # @param param1 The first parameter. + # @return [Undef] Returns nothing. + dispatch :foobarbaz do + param 'Integer', :param1 + end +end + diff --git a/spec/fixtures/ruby/provider.rb b/spec/fixtures/ruby/provider.rb new file mode 100644 index 000000000..65f4cae5b --- /dev/null +++ b/spec/fixtures/ruby/provider.rb @@ -0,0 +1,11 @@ +Puppet::Type.type(:database).provide :linux do + desc 'An example provider on Linux.' + confine kernel: 'Linux' + confine osfamily: 'RedHat' + defaultfor :kernel => 'Linux' + defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7' + has_feature :implements_some_feature + has_feature :some_other_feature + commands foo: '/usr/bin/foo' +end + diff --git a/spec/fixtures/ruby/resource_api.rb b/spec/fixtures/ruby/resource_api.rb new file mode 100644 index 000000000..13de6771f --- /dev/null +++ b/spec/fixtures/ruby/resource_api.rb @@ -0,0 +1,39 @@ +Puppet::ResourceApi.register_type( + name: 'apt_key', + docs: <<-EOS, +@summary Example resource type using the new API. +@raise SomeError +This type provides Puppet with the capabilities to manage GPG keys needed +by apt to perform package validation. Apt has it's own GPG keyring that can +be manipulated through the `apt-key` command. +@example here's an example + apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': + source => 'http://apt.puppetlabs.com/pubkey.gpg' + } + +**Autorequires**: +If Puppet is given the location of a key file which looks like an absolute +path this type will autorequire that file. + EOS + attributes: { + ensure: { + type: 'Enum[present, absent]', + desc: 'Whether this apt key should be present or absent on the target system.' + }, + id: { + type: 'Variant[Pattern[/\A(0x)?[0-9a-fA-F]{8}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{16}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{40}\Z/]]', + behaviour: :namevar, + desc: 'The ID of the key you want to manage.', + }, + # ... + created: { + type: 'String', + behaviour: :read_only, + desc: 'Date the key was created, in ISO format.', + }, + }, + autorequires: { + file: '$source', # will evaluate to the value of the `source` attribute + package: 'apt', + }, +) diff --git a/spec/fixtures/ruby/resource_type.rb b/spec/fixtures/ruby/resource_type.rb new file mode 100644 index 000000000..8d1ed54d4 --- /dev/null +++ b/spec/fixtures/ruby/resource_type.rb @@ -0,0 +1,47 @@ +Puppet::Type.newtype(:database) do + desc <<-DESC +An example database server type. +@option opts :foo bar +@enum ensure :up Upstate +@enum ensure :down Downstate +@raise SomeError +@example here's an example + database { 'foo': + address => 'qux.baz.bar', + } +DESC + feature :encryption, 'The provider supports encryption.', methods: [:encrypt] + ensurable do + desc 'What state the database should be in.' + defaultvalues + aliasvalue(:up, :present) + aliasvalue(:down, :absent) + defaultto :up + end + + newparam(:address) do + isnamevar + desc 'The database server name.' + end + + newparam(:encryption_key, required_features: :encryption) do + desc 'The encryption key to use.' + end + + newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do + desc 'Whether or not to encrypt the database.' + defaultto false + end + + newproperty(:file) do + desc 'The database file to use.' + end + + newproperty(:log_level) do + desc 'The log level to use.' + newvalue(:debug) + newvalue(:warn) + newvalue(:error) + defaultto 'warn' + end +end diff --git a/spec/markdownlint_style.rb b/spec/markdownlint_style.rb new file mode 100644 index 000000000..16d45890c --- /dev/null +++ b/spec/markdownlint_style.rb @@ -0,0 +1,10 @@ +all + +# Update line length to 120 chars. +rule 'MD013', line_length: 120 + +# Allow duplicate headings. +exclude_rule 'MD024' + +# Allow trailing punctuation in headings. +exclude_rule 'MD026' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce06a04a0..53f1f196c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -56,11 +56,11 @@ def lint_markdown(content) return [] unless mdl_available require 'mdl' - ruleset = MarkdownLint::RuleSet.new - ruleset.load_default + # Load default mdl ruleset + ruleset = MarkdownLint::RuleSet.new.tap { |r| r.load_default } - # All rules - style = MarkdownLint::Style.load('all', ruleset.rules) + # Apply custom style to ruleset rules + MarkdownLint::Style.load(File.join(__dir__, 'markdownlint_style.rb'), ruleset.rules) # Create a document doc = MarkdownLint::Doc.new(content, false) @@ -73,7 +73,7 @@ def lint_markdown(content) # record the error error_lines.each do |line| line += doc.offset # Correct line numbers for any yaml front matter - violations << "#{filename}:#{line}: #{id} #{rule.description}" + violations << "#{line}: #{id} #{rule.description}: #{doc.lines[line - 1]}" end end violations diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index 1abe3410e..1fe05eb16 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -4,388 +4,114 @@ require 'tempfile' describe PuppetStrings::Markdown do - def parse_shared_content - # Populate the YARD registry with both Puppet and Ruby source - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) -# An overview for a simple class. -# @summary A simple class. -# @todo Do a thing -# @note some note -# @since 1.0.0 -# @see www.puppet.com -# @example This is an example -# class { 'klass': -# param1 => 1, -# param3 => 'foo', -# } -# @example This is another example -# class { 'klass': -# param1 => 1, -# param3 => 'foo', -# } -# @raise SomeError -# @param param1 First param. -# @param param2 Second param. -# @option param2 [String] :opt1 something about opt1 -# @option param2 [Hash] :opt2 a hash of stuff -# @param param3 Third param. -# @param param4 Fourth param. -# @enum param4 :one One option -# @enum param4 :two Second option -# -class klass ( - Integer $param1 = 1, - $param2 = undef, - String $param3 = 'hi', - Enum['one', 'two'] $param4 = 'two', -) inherits foo::bar { -} - -# Overview for class noparams -# @api private -class noparams () {} - -# An overview for a simple defined type. -# @summary A simple defined type. -# @since 1.1.0 -# @see www.puppet.com -# @example Here's an example of this type: -# klass::dt { 'foo': -# param1 => 33, -# param4 => false, -# } -# @return shouldn't return squat -# @raise SomeError -# @param param1 First param. -# @param param2 Second param. -# @option param2 [String] :opt1 something about opt1 -# @option param2 [Hash] :opt2 a hash of stuff -# @param param3 Third param. -# @param param4 Fourth param. -# @param param5 Fifth param. -# @enum param5 :a Option A -# @enum param5 :b Option B -define klass::dt ( - Integer $param1 = 44, - $param2, - String $param3 = 'hi', - Boolean $param4 = true, - Enum['a', 'b'] $param5 = 'a' -) { -} - SOURCE - - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :json) -{ - "description": "Allows you to backup your database to local file.", - "input_method": "stdin", - "parameters": { - "database": { - "description": "Database to connect to", - "type": "Optional[String[1]]" - }, - "user": { - "description": "The user", - "type": "Optional[String[1]]" - }, - "password": { - "description": "The password", - "type": "Optional[String[1]]" - }, - "sql": { - "description": "Path to file you want backup to", - "type": "String[1]" - } - } -} - SOURCE - - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) -# A simple Puppet function. -# @param param1 First param. -# @param param2 Second param. -# @param param3 Third param. -# @option param3 [Array] :param3opt Something about this option -# @param param4 Fourth param. -# @enum param4 :yes Yes option. -# @enum param4 :no No option. -# @raise SomeError this is some error -# @return [Undef] Returns nothing. -# @example Test -# $result = func(1, 2) -function func(Integer $param1, $param2, String $param3 = hi, Enum['yes', 'no'] $param4 = 'yes') { -} - SOURCE - - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :ruby) -# An example 4.x function. -# -# @example Calling the function -# $result = func4x(1, 'foo') -# -# @example Calling the function with all args -# $result = func4x(1, 'foo', ['bar']) -Puppet::Functions.create_function(:func4x) do - # An overview for the first overload. - # @raise SomeError this is some error - # @param param1 The first parameter. - # @param param2 The second parameter. - # @option param2 [String] :option an option - # @option param2 [String] :option2 another option - # @param param3 The third parameter. - # @param param4 The fourth parameter. - # @enum param4 :one Option one. - # @enum param4 :two Option two. - # @return Returns nothing. - # @example Calling the function foo - # $result = func4x(1, 'foooo') - # - dispatch :foo do - param 'Integer', :param1 - param 'Any', :param2 - optional_param 'Array[String]', :param3 - optional_param 'Enum[one, two]', :param4 - return_type 'Undef' + let(:fixture_path) do + File.expand_path("../../fixtures", __dir__) end - # An overview for the second overload. - # @param param The first parameter. - # @param block The block parameter. - # @return Returns a string. - # @example Calling the function bar - # $result = func4x(1, 'bar', ['foo']) - dispatch :other do - param 'Boolean', :param - block_param - return_type 'String' + def fixture_content(fixture) + @fixtures ||= {} + @fixtures[fixture] ||= File.read(File.join(fixture_path, fixture)) end -end - -# An example 4.x function with only one signature. -Puppet::Functions.create_function(:func4x_1) do - # @param param1 The first parameter. - # @return [Undef] Returns nothing. - dispatch :foobarbaz do - param 'Integer', :param1 - end -end - -# An example 3.x function -Puppet::Parser::Functions.newfunction(:func3x, doc: <<-DOC - Documentation for an example 3.x function. - @param param1 [String] The first parameter. - @param param2 [Integer] The second parameter. - @return [Undef] - @example Calling the function. - func3x('hi', 10) - DOC - ) do |*args| - #... -end - -Puppet::Type.type(:database).provide :linux do - desc 'An example provider on Linux.' - confine kernel: 'Linux' - confine osfamily: 'RedHat' - defaultfor :kernel => 'Linux' - defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7' - has_feature :implements_some_feature - has_feature :some_other_feature - commands foo: '/usr/bin/foo' -end - -Puppet::Type.newtype(:database) do - desc <<-DESC -An example database server type. -@option opts :foo bar -@enum ensure :up Upstate -@enum ensure :down Downstate -@raise SomeError -@example here's an example - database { 'foo': - address => 'qux.baz.bar', - } -DESC - feature :encryption, 'The provider supports encryption.', methods: [:encrypt] - ensurable do - desc 'What state the database should be in.' - defaultvalues - aliasvalue(:up, :present) - aliasvalue(:down, :absent) - defaultto :up - end - - newparam(:address) do - isnamevar - desc 'The database server name.' - end - - newparam(:encryption_key, required_features: :encryption) do - desc 'The encryption key to use.' - end - - newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do - desc 'Whether or not to encrypt the database.' - defaultto false - end - - newproperty(:file) do - desc 'The database file to use.' - end - - newproperty(:log_level) do - desc 'The log level to use.' - newvalue(:debug) - newvalue(:warn) - newvalue(:error) - defaultto 'warn' - end -end - -Puppet::ResourceApi.register_type( - name: 'apt_key', - docs: <<-EOS, -@summary Example resource type using the new API. -@raise SomeError -This type provides Puppet with the capabilities to manage GPG keys needed -by apt to perform package validation. Apt has it's own GPG keyring that can -be manipulated through the `apt-key` command. -@example here's an example - apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': - source => 'http://apt.puppetlabs.com/pubkey.gpg' - } -**Autorequires**: -If Puppet is given the location of a key file which looks like an absolute -path this type will autorequire that file. - EOS - attributes: { - ensure: { - type: 'Enum[present, absent]', - desc: 'Whether this apt key should be present or absent on the target system.' - }, - id: { - type: 'Variant[Pattern[/\A(0x)?[0-9a-fA-F]{8}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{16}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{40}\Z/]]', - behaviour: :namevar, - desc: 'The ID of the key you want to manage.', - }, - # ... - created: { - type: 'String', - behaviour: :read_only, - desc: 'Date the key was created, in ISO format.', - }, - }, - autorequires: { - file: '$source', # will evaluate to the value of the `source` attribute - package: 'apt', - }, -) - SOURCE + def parse_shared_content + # Populate the YARD registry with both Puppet and Ruby source + YARD::Parser::SourceParser.parse_string(fixture_content("puppet/class.pp"), :puppet) + YARD::Parser::SourceParser.parse_string(fixture_content("puppet/function.pp"), :puppet) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/func4x.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/func4x_1.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/func3x.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/func3x.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/provider.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/resource_type.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/resource_api.rb"), :ruby) + + # task metadata derives the task name from the filename, so we have to parse + # directly from the filesystem to correctly pick up the name + YARD::Parser::SourceParser.parse(File.join(fixture_path, "json/backup.json")) end def parse_plan_content - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) -# A simple plan. -# @param param1 First param. -# @param param2 Second param. -# @param param3 Third param. -plan plann(String $param1, $param2, Integer $param3 = 1) { -} - SOURCE + YARD::Parser::SourceParser.parse_string(fixture_content("puppet/plan.pp"), :puppet) end def parse_data_type_content - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :ruby) -# An example Puppet Data Type in Ruby. -# -# @param param1 A variant parameter. -# @param param2 Optional String parameter. -Puppet::DataTypes.create_type('UnitDataType') do - interface <<-PUPPET - attributes => { - param1 => Variant[Numeric, String[1,2]], - param2 => { type => Optional[String[1]], value => "param2" } - } - PUPPET -end - SOURCE - - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) -# Documentation for Amodule::SimpleAlias -type Amodule::SimpleAlias = Variant[Numeric,String[1,20]] - -# Documentation for Amodule::ComplexAlias -type Amodule::ComplexAlias = Struct[{ - value_type => Optional[ValueType], - merge => Optional[MergeType] -}] - SOURCE + YARD::Parser::SourceParser.parse_string(fixture_content("ruby/data_type.rb"), :ruby) + YARD::Parser::SourceParser.parse_string(fixture_content("puppet/type_alias.pp"), :puppet) end - let(:baseline_path) { File.join(File.dirname(__FILE__), "../../fixtures/unit/markdown/#{filename}") } - let(:baseline) { File.read(baseline_path) } + + let(:output) { PuppetStrings::Markdown.generate } RSpec.shared_examples 'markdown lint checker' do |parameter| it 'should not generate markdown lint errors from the rendered markdown', if: mdl_available do - pending('Failures are expected') - Tempfile.open('md') do |file| - PuppetStrings::Markdown.render(file.path) - - expect(File.read(file.path)).to have_no_markdown_lint_errors - end + expect(output).to have_no_markdown_lint_errors end end - describe 'rendering markdown to a file' do + describe 'markdown rendering' do before(:each) do parse_shared_content end - context 'with common Puppet and ruby content' do - let(:filename) { 'output.md' } + include_examples 'markdown lint checker' - it 'should output the expected markdown content' do - Tempfile.open('md') do |file| - PuppetStrings::Markdown.render(file.path) - expect(File.read(file.path)).to eq(baseline) - end + describe 'table of contents' do + it 'includes links to public classes' do + expect(output).to match(/\[`klass`\]\(#.*\).*simple class/i) end - include_examples 'markdown lint checker' + it 'includes links to private classes' do + expect(output).to match(/`noparams`.*overview.*noparams/i) + end + + it 'includes links to defined types' do + expect(output).to match(/\[`klass::dt`\]\(#.*\).*simple defined type/i) + end + + it 'includes links to resource types' do + expect(output).to match(/\[`apt_key`\]\(#.*\).*resource type.*new api/i) + expect(output).to match(/\[`database`\]\(#.*\).*example database.*type/i) + end + + it 'includes links to functions' do + expect(output).to match(/\[`func`\]\(#.*\).*simple puppet function/i) + expect(output).to match(/\[`func3x`\]\(#.*\).*example 3\.x function/i) + expect(output).to match(/\[`func4x`\]\(#.*\).*example 4\.x function/i) + expect(output).to match(/\[`func4x_1`\]\(#.*\).*example 4\.x function.*one signature/i) + end + + it 'includes links to tasks' do + expect(output).to match(/\[`backup`\]\(#.*\).*backup your database/i) + end end describe 'with Puppet Plans', :if => TEST_PUPPET_PLANS do - let(:filename) { 'output_with_plan.md' } - before(:each) do parse_plan_content end - it 'should output the expected markdown content' do - Tempfile.open('md') do |file| - PuppetStrings::Markdown.render(file.path) - expect(File.read(file.path)).to eq(baseline) + include_examples 'markdown lint checker' + + describe "table of contents" do + it 'includes links to plans' do + expect(output).to match(/\[`plann`\]\(#.*\).*simple plan/i) end end - - include_examples 'markdown lint checker' end describe 'with Puppet Data Types', :if => TEST_PUPPET_DATATYPES do - let(:filename) { 'output_with_data_types.md' } - before(:each) do parse_data_type_content end - it 'should output the expected markdown content' do - Tempfile.open('md') do |file| - PuppetStrings::Markdown.render(file.path) - expect(File.read(file.path)).to eq(baseline) + include_examples 'markdown lint checker' + + describe "table of contents" do + it 'includes links to data types' do + expect(output).to match(/\[`Amodule::ComplexAlias`\]\(#.*\).*Amodule::ComplexAlias/i) + expect(output).to match(/\[`Amodule::SimpleAlias`\]\(#.*\).*Amodule::SimpleAlias/i) + expect(output).to match(/\[`UnitDataType`\]\(#.*\).*data type in ruby/i) end end - - include_examples 'markdown lint checker' end end end diff --git a/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb b/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb index 472d59521..0357bd22c 100644 --- a/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb +++ b/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb @@ -241,6 +241,8 @@ def suppress_yard_logging } it 'should register a partial data type object' do + suppress_yard_logging + expect(subject.size).to eq(1) object = subject.first expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType)