lib/apkstats/plugin.rb in danger-apkstats-0.0.2 vs lib/apkstats/plugin.rb in danger-apkstats-0.1.0

- old
+ new

@@ -1,80 +1,241 @@ +# frozen_string_literal: true + +require_relative "helper/bytes" + +require_relative "entity/apk_info" +require_relative "entity/apk_info_diff" +require_relative "entity/feature" +require_relative "entity/permission" + +require_relative "command/executable" +require_relative "command/apk_analyzer" + module Danger - # This is your plugin class. Any attributes or methods you expose here will - # be available from within your Dangerfile. + # Show stats of your apk file. + # By default, it's done using apkanalyzer in android sdk. # - # To be published on the Danger plugins site, you will need to have - # the public interface documented. Danger uses [YARD](http://yardoc.org/) - # for generating documentation from your plugin source, and you can verify - # by running `danger plugins lint` or `bundle exec rake spec`. + # All command need your apk filepath like below # - # You should replace these comments with a public description of your library. + # apkstats.apk_filepath=<your new apk filepath> # - # @example Ensure people are well warned about merging on Mondays + # @example Compare two apk files and print it. # - # my_plugin.warn_on_mondays + # apkstats.compare_with(<your old apk filepath>, do_report: true) # report it in markdown table + # apkstats.compare_with(<your old apk filepath>, do_report: false) # just return results # + # @example Show the file size of your apk file. + # + # apkstats.file_size + # + # @example Show the download size of your apk file. + # + # apkstats.download_size + # + # @example Show all required features of your apk file. + # + # apkstats.required_features + # + # @example Show all non-required features of your apk file. + # + # apkstats.non_required_features + # + # @example Show all requested permissions of your apk file. + # + # apkstats.permissions + # + # @example Show the min sdk version of your apk file. + # + # apkstats.min_sdk + # + # @example Show the target sdk version of your apk file. + # + # apkstats.target_sdk + # # @see Jumpei Matsuda/danger-apkstats # @tags android, apk_stats # class DangerApkstats < Plugin - require_relative 'command/executable_command' - require_relative 'command/apk_analyzer' - COMMAND_TYPE_MAP = { - apk_analyzer: Danger::Apkstats::ApkAnalyzer, + apk_analyzer: Apkstats::Command::ApkAnalyzer, }.freeze private_constant(:COMMAND_TYPE_MAP) - # A command type to be run + # *Optional* + # A command type to be run. + # One of keys of COMMAND_TYPE_MAP # - # @return [Symbol, String] either of array( apk_analyzer ) + # @return [Symbol, Nil] _ attr_accessor :command_type - # An apk file to be operated + # *Optional* + # A custom command path # + # @return [Symbol, Nil] _ + attr_accessor :command_path + + # *Required* + # Your target apk filepath. + # # @return [String] attr_accessor :apk_filepath - # TODO multiple apks + # rubocop:disable Metrics/AbcSize - def compare_with(other_apk_filepath, opts={}) - raise 'apks must be specified' if apk_filepath.nil? || apk_filepath.empty? + # Get stats of two apk files and calculate diffs between them. + # + # @param [String] other_apk_filepath your old apk + # @param [Boolean] do_report report markdown table if true, otherwise just return results + # @return [Hash] see command/executable#compare_with for more detail + def compare_with(other_apk_filepath, do_report: true) + raise "apk filepaths must be specified" if apk_filepath.nil? || apk_filepath.empty? - out, err = command.compare_with(apk_filepath, other_apk_filepath) + base_apk = Apkstats::Entity::ApkInfo.new(command, apk_filepath) + other_apk = Apkstats::Entity::ApkInfo.new(command, other_apk_filepath) - if opts[:do_report] - if out&.empty? - message("Apk file size was not changed") - elsif out - left, right, diff, = out.split("\s") - message("Apk file size was changed by #{diff} : from #{left} to #{right}") - else - warn(err) + return { + base: base_apk.to_h, + other: base_apk.to_h, + diff: Apkstats::Entity::ApkInfoDiff.new(base_apk, other_apk).to_h, + }.tap do |result| + break unless do_report + + diff = result[:diff] + + md = +"### Apk comparision results" << "\n\n" + md << "Property | Summary" << "\n" + md << ":--- | :---" << "\n" + + diff[:min_sdk].tap do |min_sdk| + break if min_sdk.size == 1 + + md << "Min SDK Change | Before #{min_sdk[1]} / After #{min_sdk[0]}" << "\n" end + + diff[:target_sdk].tap do |target_sdk| + break if target_sdk.size == 1 + + md << "Target SDK Change | Before #{target_sdk[1]} / After #{target_sdk[0]}" << "\n" + end + + result[:base][:file_size].tap do |file_size| + size = Apkstats::Helper::Bytes.from_b(file_size) + + md << "New File Size | #{size.to_b} Bytes. (#{size.to_mb} MB " << "\n" + end + + diff[:file_size].tap do |file_size| + size = Apkstats::Helper::Bytes.from_b(file_size) + + md << "File Size Change | #{size.to_s_b} Bytes. (#{size.to_s_kb} KB) " << "\n" + end + + diff[:download_size].tap do |download_size| + size = Apkstats::Helper::Bytes.from_b(download_size) + + md << "Download Size Change | #{size.to_s_b} Bytes. (#{size.to_s_kb} KB) " << "\n" + end + + report_hash_and_arrays = lambda { |key, name| + list_up_entities = lambda { |type_key, label| + diff[key][type_key].tap do |features| + break if features.empty? + + md << "#{label} | " << features.map { |f| "- #{f}" }.join("<br>").to_s << "\n" + end + } + + list_up_entities.call(:new, "New #{name}") + list_up_entities.call(:removed, "Removed #{name}") + } + + report_hash_and_arrays.call(:required_features, "Required Features") + report_hash_and_arrays.call(:non_required_features, "Non-required Features") + report_hash_and_arrays.call(:permissions, "Permissions") + + markdown(md) end + rescue StandardError => e + warn("apkstats failed to execute the command due to #{e.message}") - return out, err + e.backtrace&.each { |line| STDOUT.puts line } end - def filesize(opts={}) - raise 'apks must be specified' if apk_filepath.nil? || apk_filepath.empty? + # rubocop:enable Metrics/AbcSize - out, = command.filesize(apk_filepath) - out + # Show the file size of your apk file. + # + # @return [Fixnum] return positive value if exists, otherwise -1. + def file_size(_opts = {}) + result = run_command(__method__) + result ? result.to_i : -1 end - def downloadsize(opts={}) - raise 'apks must be specified' if apk_filepath.nil? || apk_filepath.empty? + # Show the download size of your apk file. + # + # @return [Fixnum] return positive value if exists, otherwise -1. + def download_size(_opts = {}) + result = run_command(__method__) + result ? result.to_i : -1 + end - out, = command.downloadsize(apk_filepath) - out + # Show all required features of your apk file. + # The result doesn't contain non-required features. + # + # @return [Array<String>, Nil] return nil unless retrieved. + def required_features(_opts = {}) + result = run_command(__method__) + result ? result.to_a : nil end + # Show all non-required features of your apk file. + # The result doesn't contain required features. + # + # @return [Array<String>, Nil] return nil unless retrieved. + def non_required_features(_opts = {}) + result = run_command(__method__) + result ? result.to_a : nil + end + + # Show all permissions of your apk file. + # + # @return [Array<String>, Nil] return nil unless retrieved. + def permissions(_opts = {}) + result = run_command(__method__) + result ? result.to_a : nil + end + + # Show the min sdk version of your apk file. + # + # @return [String, Nil] return nil unless retrieved. + def min_sdk(_opts = {}) + run_command(__method__) + end + + # Show the target sdk version of your apk file. + # + # @return [String, Nil] return nil unless retrieved. + def target_sdk(_opts = {}) + run_command(__method__) + end + private + def run_command(name) + raise "#{command.command_path} is not found or is not executable" unless command.executable? + + return command.send(name, apk_filepath) + rescue StandardError => e + warn("apkstats failed to execute the command #{name} due to #{e.message}") + + e.backtrace&.each { |line| puts line } + + nil + end + def command - @command ||= COMMAND_TYPE_MAP[command_type.to_sym].new + command_type ||= :apk_analyzer + @command ||= COMMAND_TYPE_MAP[command_type.to_sym].new(command_path: command_path) end end end