lib/licensed/commands/status.rb in licensed-4.3.1 vs lib/licensed/commands/status.rb in licensed-4.4.0

- old
+ new

@@ -21,16 +21,54 @@ # report - A Licensed::Report object for this command # # Returns whether the command succeeded based on the call to super def run_command(report) super do |result| - next if result + stale_records = stale_cached_records + if stale_records.any? + messages = stale_records.map { |f| "Stale dependency record found: #{f}" } + messages << "Please run the licensed cache command to clean up stale records" + case config["stale_records_action"].to_s + when "error" + report.errors.concat messages + result = false + when "warn", "" + report.warnings.concat messages + end + end + + next result if result + report.errors << "Licensed found errors during source enumeration. Please see https://github.com/github/licensed/tree/master/docs/commands/status.md#status-errors-and-resolutions for possible resolutions." + + result end + ensure + cache_paths.clear + files.clear end + # Run the command for all enumerated dependencies found in a dependency source, + # recording results in a report. + # Enumerating dependencies in the source is skipped if a :sources option + # is provided and the evaluated `source.class.type` is not in the :sources values + # + # app - The application configuration for the source + # source - A dependency source enumerator + # + # Returns whether the command succeeded for the dependency source enumerator + def run_source(app, source, report) + result = super + + # add the full cache path to the list of cache paths + # that should be checked for extra files after the command run + cache_paths << app.cache_path.join(source.class.type) unless result == :skipped + + result + end + # Evaluates a dependency for any compliance errors. # Checks a dependency against either a cached metadata record or # reviewed entries in the configuration file. # # app - The application configuration for the dependency @@ -47,10 +85,13 @@ record = dependency.record else filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}") report["filename"] = filename record = cached_record(filename) + + # add the absolute dependency file path to the list of files seen during this licensed run + files << filename.to_s end if record.nil? report["license"] = nil report.errors << "cached dependency record not found" @@ -130,9 +171,29 @@ Licensee::ProjectFiles::ReadmeFile.new(text).license&.key, "other" ].compact licenses.sort_by { |license| license != "other" ? 0 : 1 }.first + end + + # Check for cached files that don't match current dependencies + # + # Returns an array of any cached records that do not match a currently used dependency + def stale_cached_records + cache_paths.flat_map do |cache_path| + record_search_glob_pattern = cache_path.join("**/*.#{DependencyRecord::EXTENSION}") + Dir.glob(record_search_glob_pattern).select { |file| !files.include?(file) } + end.uniq + end + + # Set of unique cache paths that are evaluted during the run + def cache_paths + @cache_paths ||= Set.new + end + + # Set of unique absolute file paths of cached records evaluted during the run + def files + @files ||= Set.new end end end end