-
Notifications
You must be signed in to change notification settings - Fork 32
Implement HTML report generation and update report formats #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a5a960d
a43d18d
dc14401
6789fa7
0b33ec4
4aa19a1
d0939b6
e59ce7e
de91302
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,8 @@ Skunk is a RubyCritic extension to calculate a SkunkScore for a file or project. | |||||
| * [Help commands](#help-commands) | ||||||
| * [Generate the SkunkCore for your project](#generate-the-skunkcore-for-your-project) | ||||||
| * [Comparing Feature Branches](#comparing-feature-branches) | ||||||
| * [Configuration](#configuration) | ||||||
| * [Setting Output Formats](#setting-output-formats) | ||||||
| * [Sharing your SkunkScore](#sharing-your-skunkscore) | ||||||
| * [Contributing](#contributing) | ||||||
| * [Sponsorship](#sponsorship) | ||||||
|
|
@@ -152,6 +154,36 @@ Score: 340.3 | |||||
|
|
||||||
| This should give you an idea if you're moving in the direction of maintaining the code quality or not. In this case, the feature branch is decreasing the code quality because it has a higher SkunkScore than the main branch. | ||||||
|
|
||||||
| ## Configuration | ||||||
|
|
||||||
| ### Setting Output Formats | ||||||
|
|
||||||
| Skunk provides a simple configuration class to control output formats programmatically. You can use `Skunk::Config` to set which formats should be generated when running Skunk. | ||||||
|
|
||||||
| **Supported formats:** | ||||||
| - `:json` - JSON report (default) | ||||||
| - `:html` - HTML report with visual charts and tables | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| ```ruby | ||||||
| require 'skunk/config' | ||||||
|
|
||||||
| # Set multiple formats | ||||||
| Skunk::Config.formats = [:json, :html] | ||||||
|
|
||||||
| # Add a format to the existing list | ||||||
| Skunk::Config.add_format(:html) | ||||||
|
|
||||||
| # Remove a format | ||||||
| Skunk::Config.remove_format(:json) | ||||||
|
|
||||||
| # Check supported formats | ||||||
| Skunk::Config.supported_formats # => [:json, :html] | ||||||
| Skunk::Config.supported_format?(:json) # => true | ||||||
|
|
||||||
| # Reset to defaults | ||||||
| Skunk::Config.reset | ||||||
| ``` | ||||||
|
|
||||||
| ## Sharing your SkunkScore | ||||||
|
|
||||||
| If you want to share the results of your Skunk report with the Ruby community, run: | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,4 +11,7 @@ puts ARGV.inspect | |
|
|
||
| # Run skunk CLI application with the provided arguments | ||
| require "skunk/cli/application" | ||
| require "skunk/config" | ||
|
|
||
| Skunk::Config.formats = %i[json html] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For testing purposes you can use this script to run skunk against any path and setting any format. Take into account that for now the console report is generated all the time no matter if you just select or > ./bin/console . |
||
| Skunk::Cli::Application.new(ARGV).execute | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,8 +26,6 @@ def initialize(options) | |
| # | ||
| # @return [Skunk::Command::StatusReporter] | ||
| def execute | ||
| RubyCritic::Config.formats = [:json] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was blocking on purpose the generation of more |
||
|
|
||
| report(critique) | ||
|
|
||
| status_reporter | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,13 @@ def share(reporter) | |
| # @return [Boolean] If the environment is set to share to an external | ||
| # service | ||
| def sharing? | ||
| share_enabled? | ||
| end | ||
|
|
||
| private | ||
|
|
||
| # @return [Boolean] Check if sharing is enabled via environment variable | ||
| def share_enabled? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ruby 2.7 CI was running into some segmentation failures because the mocking of AI says: The Problem: |
||
| ENV["SHARE"] == "true" | ||
| end | ||
| end | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,7 @@ def share | |
| response = post_payload | ||
|
|
||
| @status_message = | ||
| if Net::HTTPOK === response | ||
| if response.is_a?(Net::HTTPOK) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ruby 2.6 CI was running into some segmentation failures: AI says: Segmentation Fault |
||
| data = JSON.parse response.body | ||
| "Shared at: #{File.join(base_url, data['id'])}" | ||
| else | ||
|
|
@@ -62,7 +62,17 @@ def json_results | |
|
|
||
| # :reek:UtilityFunction | ||
| def not_sharing? | ||
| ENV["SHARE"] != "true" && ENV["SHARE_URL"].to_s == "" | ||
| !share_enabled? && share_url_empty? | ||
| end | ||
|
|
||
| # @return [Boolean] Check if sharing is enabled via environment variable | ||
| def share_enabled? | ||
| ENV["SHARE"] == "true" | ||
| end | ||
|
|
||
| # @return [Boolean] Check if share URL is empty | ||
| def share_url_empty? | ||
| ENV["SHARE_URL"].to_s == "" | ||
| end | ||
|
|
||
| def payload | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Skunk | ||
| # Utility module for format validation | ||
| module FormatValidator | ||
| # Supported output formats | ||
| SUPPORTED_FORMATS = %i[json html].freeze | ||
|
|
||
| # Check if a format is supported | ||
| # @param format [Symbol] Format to check | ||
| # @return [Boolean] True if format is supported | ||
| def self.supported_format?(format) | ||
| SUPPORTED_FORMATS.include?(format) | ||
| end | ||
|
|
||
| # Get all supported formats | ||
| # @return [Array<Symbol>] All supported formats | ||
| def self.supported_formats | ||
| SUPPORTED_FORMATS.dup | ||
| end | ||
| end | ||
|
|
||
| # Configuration class for Skunk that supports formats | ||
| # Similar to RubyCritic::Configuration but focused only on Skunk's needs | ||
| class Configuration | ||
| # Default format | ||
| DEFAULT_FORMAT = :json | ||
|
|
||
| def initialize | ||
| @formats = [DEFAULT_FORMAT] | ||
| end | ||
|
|
||
| def set(options = {}) | ||
| self.formats = options[:formats] if options.key?(:formats) | ||
| end | ||
|
|
||
| # Get the configured formats | ||
| # @return [Array<Symbol>] Array of format symbols | ||
| attr_reader :formats | ||
|
|
||
| # Set the formats with validation | ||
| # @param format_list [Array<Symbol>, Symbol] Format(s) to set | ||
| def formats=(format_list) | ||
| format_array = Array(format_list) | ||
| @formats = format_array.select { |format| FormatValidator.supported_format?(format) } | ||
| @formats = [DEFAULT_FORMAT] if @formats.empty? | ||
| end | ||
|
|
||
| # Add a format to the existing list | ||
| # @param format [Symbol] Format to add | ||
| def add_format(format) | ||
| return unless FormatValidator.supported_format?(format) | ||
|
|
||
| @formats << format unless @formats.include?(format) | ||
| end | ||
|
|
||
| # Remove a format from the list | ||
| # @param format [Symbol] Format to remove | ||
| def remove_format(format) | ||
| @formats.delete(format) | ||
| @formats = [DEFAULT_FORMAT] if @formats.empty? | ||
| end | ||
|
|
||
| # Check if a format is supported | ||
| # @param format [Symbol] Format to check | ||
| # @return [Boolean] True if format is supported | ||
| def supported_format?(format) | ||
| FormatValidator.supported_format?(format) | ||
| end | ||
|
|
||
| # Get all supported formats | ||
| # @return [Array<Symbol>] All supported formats | ||
| def supported_formats | ||
| FormatValidator.supported_formats | ||
| end | ||
|
|
||
| # Reset to default configuration | ||
| def reset | ||
| @formats = [DEFAULT_FORMAT] | ||
| end | ||
| end | ||
|
|
||
| # Config module that delegates to Configuration instance | ||
| # Similar to RubyCritic::Config pattern | ||
| module Config | ||
| def self.configuration | ||
| @configuration ||= Configuration.new | ||
| end | ||
|
|
||
| def self.set(options = {}) | ||
| configuration.set(options) | ||
| end | ||
|
|
||
| def self.method_missing(method, *args, &block) | ||
| if configuration.respond_to?(method) | ||
| configuration.public_send(method, *args, &block) | ||
| else | ||
| super | ||
| end | ||
| end | ||
|
|
||
| def self.respond_to_missing?(symbol, include_private = false) | ||
| configuration.respond_to?(symbol, include_private) || super | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Skunk | ||
| module Generator | ||
| module Html | ||
| # Data object for individual file information in the HTML overview report | ||
| class FileData | ||
| attr_reader :file, :skunk_score, :churn_times_cost, :churn, :cost, :coverage | ||
|
|
||
| def initialize(module_data) | ||
| @file = PathTruncator.truncate(module_data.pathname) | ||
|
||
| @skunk_score = module_data.skunk_score | ||
| @churn_times_cost = module_data.churn_times_cost | ||
| @churn = module_data.churn | ||
| @cost = module_data.cost.round(2) | ||
| @coverage = module_data.coverage.round(2) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "rubycritic/generators/html/base" | ||
|
|
||
| require "skunk/generators/html/path_truncator" | ||
| require "skunk/generators/html/skunk_data" | ||
|
|
||
| module Skunk | ||
| module Generator | ||
| module Html | ||
| # Generates an HTML overview report for the analysed modules. | ||
| class Overview < RubyCritic::Generator::Html::Base | ||
| def self.erb_template(template_path) | ||
| ERB.new(File.read(File.join(TEMPLATES_DIR, template_path))) | ||
| end | ||
|
|
||
| TEMPLATES_DIR = File.expand_path("templates", __dir__) | ||
| TEMPLATE = erb_template("skunk_overview.html.erb") | ||
|
|
||
| def initialize(analysed_modules) | ||
| @analysed_modules = analysed_modules | ||
| @data = SkunkData.new(analysed_modules) | ||
| end | ||
|
|
||
| def file_name | ||
| "skunk_overview.html" | ||
| end | ||
|
|
||
| def render | ||
| TEMPLATE.result(binding) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we to do anything about the new offenses? Because I saw you added exceptions. Maybe this file needs another update?