diff --git a/README.md b/README.md index 6d693e86..e01ab260 100644 --- a/README.md +++ b/README.md @@ -179,12 +179,21 @@ license_content | A URL to a file where the raw text of the license can be downl In addition to including any files Licensee identified as potential license files (but couldn't identify), License Scout will also include the Fallback License you specified in the Dependency Manifest. +### Searching Nested Subdirectories + +The default behavior of License Scout is to only look for dependency manager files in the root of the `directories` you configure. This is the default behavior to provide the maximum control over which dependencies you want to appear in your report. For example, your project may include an internal only tool for which you do not wish to enforce license acceptance. + +However, License Scout also supports deep scanning all of the listed directories for all dependency manager files and generating a full report on all dependencies that the project uses. To do this, either specify the `--include-sub-directories` command line flag, or set `include_subdirectories` to true in your configuration file. + +A common use case for this functionality is to run `license_scout` from the root of a project and get a full report for that project. + +``` +license_scout --include-sub-directories +``` + ## Habitat Channel Configuration -By default License Scout searches for Habitat package in the `stable` -channel. If your build process publishes packages to another channel -by default, you can use the `channel_for_origin` habitat configuration -option: +By default License Scout searches for Habitat package in the `stable` channel. If your build process publishes packages to another channel by default, you can use the `channel_for_origin` habitat configuration option: ```yaml habitat: @@ -216,6 +225,7 @@ Format | Description Value | Description | Default --- | --- | --- directories | The fully-qualified local paths to the directories you wish to scan | _The current working directory._ | +include_subdirectories | Whether or not to include all nested sub-directories of `directories` in the search. | `false` | name | The name you want to give to the scan result. | _The basename of the first directory to be scanned._ | output_directory | The path to the directory where the output JSON file should be saved. | _The current working directory._ | log_level | What log information should be included in STDOUT | `info` | diff --git a/lib/license_scout/cli.rb b/lib/license_scout/cli.rb index 116bb82e..2269d292 100644 --- a/lib/license_scout/cli.rb +++ b/lib/license_scout/cli.rb @@ -42,6 +42,11 @@ class CLI description: "Comma-separated list of directories to scan", proc: Proc.new { |d| d.split(",") } + option :include_subdirectories, + long: "--include-sub-directories", + description: "Include all sub-directories of 'directories' in the analysis", + boolean: true + option :format, long: "--format FORMAT", description: "When exporting a Dependency Manifest, export to this format", diff --git a/lib/license_scout/collector.rb b/lib/license_scout/collector.rb index 458488d4..b7fb0ce8 100644 --- a/lib/license_scout/collector.rb +++ b/lib/license_scout/collector.rb @@ -57,7 +57,7 @@ def collect_licenses_from(dep_mgr) end def dependency_managers - @dependency_managers ||= LicenseScout::Config.directories.map do |dir| + @dependency_managers ||= LicenseScout::Config.all_directories.map do |dir| LicenseScout::DependencyManager.implementations.map do |implementation| dep_mgr = implementation.new(File.expand_path(dir)) if dep_mgr.detected? diff --git a/lib/license_scout/config.rb b/lib/license_scout/config.rb index c122cd88..ad8724fc 100644 --- a/lib/license_scout/config.rb +++ b/lib/license_scout/config.rb @@ -28,6 +28,7 @@ module Config # Inputs default :directories, [File.expand_path(Dir.pwd)] + default :include_subdirectories, false default :name, File.basename(directories.first) default :config_files, [File.join(File.expand_path(Dir.pwd), ".license_scout.yml")] @@ -79,6 +80,23 @@ module Config class << self + def all_directories + if include_subdirectories + new_directories = [] + + directories.each do |old_directory| + new_directories << old_directory + Dir.chdir(old_directory) do + new_directories << Dir.glob("**/*").select { |f| File.directory?(f) }.map { |d| File.join(old_directory, d) } + end + end + + new_directories.flatten.compact + else + directories + end + end + def validate! if !allowed_licenses.empty? && !flagged_licenses.empty? raise LicenseScout::Exceptions::ConfigError.new("You may specify a list of licenses to allow or flag. You may not specify both.") diff --git a/spec/license_scout/config_spec.rb b/spec/license_scout/config_spec.rb index 6ab0acde..6b4c98cf 100644 --- a/spec/license_scout/config_spec.rb +++ b/spec/license_scout/config_spec.rb @@ -75,6 +75,58 @@ end end + describe ".all_directories" do + let(:initial_config) do + { + directories: [ + File.join(SPEC_FIXTURES_DIR, "deps_gopath"), + ] + } + end + + let(:expected_directories) do + %W{ + #{SPEC_FIXTURES_DIR}/deps_gopath + } + end + + it "returns the list of directories" do + LicenseScout::Config.merge!(initial_config) + + expect(LicenseScout::Config.all_directories).to match_array(expected_directories) + end + + context "with include-sub-directories" do + let(:initial_config) do + { + include_subdirectories: true, + directories: [ + File.join(SPEC_FIXTURES_DIR, "deps_gopath"), + ] + } + end + + let(:expected_directories) do + %W{ + #{SPEC_FIXTURES_DIR}/deps_gopath + #{SPEC_FIXTURES_DIR}/deps_gopath/src + #{SPEC_FIXTURES_DIR}/deps_gopath/src/gopkg.in + #{SPEC_FIXTURES_DIR}/deps_gopath/src/gopkg.in/foo + #{SPEC_FIXTURES_DIR}/deps_gopath/src/gopkg.in/foo/baz + #{SPEC_FIXTURES_DIR}/deps_gopath/src/github.com + #{SPEC_FIXTURES_DIR}/deps_gopath/src/github.com/foo + #{SPEC_FIXTURES_DIR}/deps_gopath/src/github.com/foo/bar + } + end + + it "returns all subdirectories as well" do + LicenseScout::Config.merge!(initial_config) + + expect(LicenseScout::Config.all_directories).to match_array(expected_directories) + end + end + end + describe ".validate!" do context "when both an allowed and flagged list are specified" do before do